Skip to content

Commit 4ffe722

Browse files
westeridavem330
authored andcommitted
thunderbolt: Add polling mode for rings
In order to support things like networking over Thunderbolt cable, there needs to be a way to switch the ring to a mode where it can be polled with the interrupt masked. We implement such mode so that the caller can allocate a ring by passing pointer to a function that is then called when an interrupt is triggered. Completed frames can be fetched using tb_ring_poll() and the interrupt can be re-enabled when the caller is finished with polling by using tb_ring_poll_complete(). Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Michael Jamet <michael.jamet@intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 59120e0 commit 4ffe722

File tree

3 files changed

+134
-17
lines changed

3 files changed

+134
-17
lines changed

drivers/thunderbolt/ctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data)
619619
goto err;
620620

621621
ctl->rx = tb_ring_alloc_rx(nhi, 0, 10, RING_FLAG_NO_SUSPEND, 0xffff,
622-
0xffff);
622+
0xffff, NULL, NULL);
623623
if (!ctl->rx)
624624
goto err;
625625

drivers/thunderbolt/nhi.c

Lines changed: 117 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ static void ring_work(struct work_struct *work)
252252
* Do not hold on to it.
253253
*/
254254
list_del_init(&frame->list);
255-
frame->callback(ring, frame, canceled);
255+
if (frame->callback)
256+
frame->callback(ring, frame, canceled);
256257
}
257258
}
258259

@@ -273,11 +274,106 @@ int __tb_ring_enqueue(struct tb_ring *ring, struct ring_frame *frame)
273274
}
274275
EXPORT_SYMBOL_GPL(__tb_ring_enqueue);
275276

277+
/**
278+
* tb_ring_poll() - Poll one completed frame from the ring
279+
* @ring: Ring to poll
280+
*
281+
* This function can be called when @start_poll callback of the @ring
282+
* has been called. It will read one completed frame from the ring and
283+
* return it to the caller. Returns %NULL if there is no more completed
284+
* frames.
285+
*/
286+
struct ring_frame *tb_ring_poll(struct tb_ring *ring)
287+
{
288+
struct ring_frame *frame = NULL;
289+
unsigned long flags;
290+
291+
spin_lock_irqsave(&ring->lock, flags);
292+
if (!ring->running)
293+
goto unlock;
294+
if (ring_empty(ring))
295+
goto unlock;
296+
297+
if (ring->descriptors[ring->tail].flags & RING_DESC_COMPLETED) {
298+
frame = list_first_entry(&ring->in_flight, typeof(*frame),
299+
list);
300+
list_del_init(&frame->list);
301+
302+
if (!ring->is_tx) {
303+
frame->size = ring->descriptors[ring->tail].length;
304+
frame->eof = ring->descriptors[ring->tail].eof;
305+
frame->sof = ring->descriptors[ring->tail].sof;
306+
frame->flags = ring->descriptors[ring->tail].flags;
307+
}
308+
309+
ring->tail = (ring->tail + 1) % ring->size;
310+
}
311+
312+
unlock:
313+
spin_unlock_irqrestore(&ring->lock, flags);
314+
return frame;
315+
}
316+
EXPORT_SYMBOL_GPL(tb_ring_poll);
317+
318+
static void __ring_interrupt_mask(struct tb_ring *ring, bool mask)
319+
{
320+
int idx = ring_interrupt_index(ring);
321+
int reg = REG_RING_INTERRUPT_BASE + idx / 32 * 4;
322+
int bit = idx % 32;
323+
u32 val;
324+
325+
val = ioread32(ring->nhi->iobase + reg);
326+
if (mask)
327+
val &= ~BIT(bit);
328+
else
329+
val |= BIT(bit);
330+
iowrite32(val, ring->nhi->iobase + reg);
331+
}
332+
333+
/* Both @nhi->lock and @ring->lock should be held */
334+
static void __ring_interrupt(struct tb_ring *ring)
335+
{
336+
if (!ring->running)
337+
return;
338+
339+
if (ring->start_poll) {
340+
__ring_interrupt_mask(ring, false);
341+
ring->start_poll(ring->poll_data);
342+
} else {
343+
schedule_work(&ring->work);
344+
}
345+
}
346+
347+
/**
348+
* tb_ring_poll_complete() - Re-start interrupt for the ring
349+
* @ring: Ring to re-start the interrupt
350+
*
351+
* This will re-start (unmask) the ring interrupt once the user is done
352+
* with polling.
353+
*/
354+
void tb_ring_poll_complete(struct tb_ring *ring)
355+
{
356+
unsigned long flags;
357+
358+
spin_lock_irqsave(&ring->nhi->lock, flags);
359+
spin_lock(&ring->lock);
360+
if (ring->start_poll)
361+
__ring_interrupt_mask(ring, false);
362+
spin_unlock(&ring->lock);
363+
spin_unlock_irqrestore(&ring->nhi->lock, flags);
364+
}
365+
EXPORT_SYMBOL_GPL(tb_ring_poll_complete);
366+
276367
static irqreturn_t ring_msix(int irq, void *data)
277368
{
278369
struct tb_ring *ring = data;
279370

280-
schedule_work(&ring->work);
371+
spin_lock(&ring->nhi->lock);
372+
spin_lock(&ring->lock);
373+
__ring_interrupt(ring);
374+
spin_unlock(&ring->lock);
375+
spin_unlock(&ring->nhi->lock);
376+
281377
return IRQ_HANDLED;
282378
}
283379

@@ -317,7 +413,9 @@ static void ring_release_msix(struct tb_ring *ring)
317413

318414
static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
319415
bool transmit, unsigned int flags,
320-
u16 sof_mask, u16 eof_mask)
416+
u16 sof_mask, u16 eof_mask,
417+
void (*start_poll)(void *),
418+
void *poll_data)
321419
{
322420
struct tb_ring *ring = NULL;
323421
dev_info(&nhi->pdev->dev, "allocating %s ring %d of size %d\n",
@@ -346,6 +444,8 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
346444
ring->head = 0;
347445
ring->tail = 0;
348446
ring->running = false;
447+
ring->start_poll = start_poll;
448+
ring->poll_data = poll_data;
349449

350450
ring->descriptors = dma_alloc_coherent(&ring->nhi->pdev->dev,
351451
size * sizeof(*ring->descriptors),
@@ -399,7 +499,7 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
399499
struct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size,
400500
unsigned int flags)
401501
{
402-
return tb_ring_alloc(nhi, hop, size, true, flags, 0, 0);
502+
return tb_ring_alloc(nhi, hop, size, true, flags, 0, 0, NULL, NULL);
403503
}
404504
EXPORT_SYMBOL_GPL(tb_ring_alloc_tx);
405505

@@ -411,11 +511,17 @@ EXPORT_SYMBOL_GPL(tb_ring_alloc_tx);
411511
* @flags: Flags for the ring
412512
* @sof_mask: Mask of PDF values that start a frame
413513
* @eof_mask: Mask of PDF values that end a frame
514+
* @start_poll: If not %NULL the ring will call this function when an
515+
* interrupt is triggered and masked, instead of callback
516+
* in each Rx frame.
517+
* @poll_data: Optional data passed to @start_poll
414518
*/
415519
struct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,
416-
unsigned int flags, u16 sof_mask, u16 eof_mask)
520+
unsigned int flags, u16 sof_mask, u16 eof_mask,
521+
void (*start_poll)(void *), void *poll_data)
417522
{
418-
return tb_ring_alloc(nhi, hop, size, false, flags, sof_mask, eof_mask);
523+
return tb_ring_alloc(nhi, hop, size, false, flags, sof_mask, eof_mask,
524+
start_poll, poll_data);
419525
}
420526
EXPORT_SYMBOL_GPL(tb_ring_alloc_rx);
421527

@@ -556,6 +662,7 @@ void tb_ring_free(struct tb_ring *ring)
556662
dev_WARN(&ring->nhi->pdev->dev, "%s %d still running\n",
557663
RING_TYPE(ring), ring->hop);
558664
}
665+
spin_unlock_irq(&ring->nhi->lock);
559666

560667
ring_release_msix(ring);
561668

@@ -572,7 +679,6 @@ void tb_ring_free(struct tb_ring *ring)
572679
RING_TYPE(ring),
573680
ring->hop);
574681

575-
spin_unlock_irq(&ring->nhi->lock);
576682
/**
577683
* ring->work can no longer be scheduled (it is scheduled only
578684
* by nhi_interrupt_work, ring_stop and ring_msix). Wait for it
@@ -682,8 +788,10 @@ static void nhi_interrupt_work(struct work_struct *work)
682788
hop);
683789
continue;
684790
}
685-
/* we do not check ring->running, this is done in ring->work */
686-
schedule_work(&ring->work);
791+
792+
spin_lock(&ring->lock);
793+
__ring_interrupt(ring);
794+
spin_unlock(&ring->lock);
687795
}
688796
spin_unlock_irq(&nhi->lock);
689797
}

include/linux/thunderbolt.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ struct tb_nhi {
446446
* @flags: Ring specific flags
447447
* @sof_mask: Bit mask used to detect start of frame PDF
448448
* @eof_mask: Bit mask used to detect end of frame PDF
449+
* @start_poll: Called when ring interrupt is triggered to start
450+
* polling. Passing %NULL keeps the ring in interrupt mode.
451+
* @poll_data: Data passed to @start_poll
449452
*/
450453
struct tb_ring {
451454
spinlock_t lock;
@@ -466,6 +469,8 @@ struct tb_ring {
466469
unsigned int flags;
467470
u16 sof_mask;
468471
u16 eof_mask;
472+
void (*start_poll)(void *data);
473+
void *poll_data;
469474
};
470475

471476
/* Leave ring interrupt enabled on suspend */
@@ -499,7 +504,7 @@ enum ring_desc_flags {
499504
/**
500505
* struct ring_frame - For use with ring_rx/ring_tx
501506
* @buffer_phy: DMA mapped address of the frame
502-
* @callback: Callback called when the frame is finished
507+
* @callback: Callback called when the frame is finished (optional)
503508
* @list: Frame is linked to a queue using this
504509
* @size: Size of the frame in bytes (%0 means %4096)
505510
* @flags: Flags for the frame (see &enum ring_desc_flags)
@@ -522,8 +527,8 @@ struct ring_frame {
522527
struct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size,
523528
unsigned int flags);
524529
struct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,
525-
unsigned int flags, u16 sof_mask,
526-
u16 eof_mask);
530+
unsigned int flags, u16 sof_mask, u16 eof_mask,
531+
void (*start_poll)(void *), void *poll_data);
527532
void tb_ring_start(struct tb_ring *ring);
528533
void tb_ring_stop(struct tb_ring *ring);
529534
void tb_ring_free(struct tb_ring *ring);
@@ -535,8 +540,8 @@ int __tb_ring_enqueue(struct tb_ring *ring, struct ring_frame *frame);
535540
* @ring: Ring to enqueue the frame
536541
* @frame: Frame to enqueue
537542
*
538-
* @frame->buffer, @frame->buffer_phy and @frame->callback have to be set. The
539-
* buffer must contain at least %TB_FRAME_SIZE bytes.
543+
* @frame->buffer, @frame->buffer_phy have to be set. The buffer must
544+
* contain at least %TB_FRAME_SIZE bytes.
540545
*
541546
* @frame->callback will be invoked with @frame->size, @frame->flags,
542547
* @frame->eof, @frame->sof set once the frame has been received.
@@ -557,8 +562,8 @@ static inline int tb_ring_rx(struct tb_ring *ring, struct ring_frame *frame)
557562
* @ring: Ring the enqueue the frame
558563
* @frame: Frame to enqueue
559564
*
560-
* @frame->buffer, @frame->buffer_phy, @frame->callback, @frame->size,
561-
* @frame->eof and @frame->sof have to be set.
565+
* @frame->buffer, @frame->buffer_phy, @frame->size, @frame->eof and
566+
* @frame->sof have to be set.
562567
*
563568
* @frame->callback will be invoked with once the frame has been transmitted.
564569
*
@@ -573,4 +578,8 @@ static inline int tb_ring_tx(struct tb_ring *ring, struct ring_frame *frame)
573578
return __tb_ring_enqueue(ring, frame);
574579
}
575580

581+
/* Used only when the ring is in polling mode */
582+
struct ring_frame *tb_ring_poll(struct tb_ring *ring);
583+
void tb_ring_poll_complete(struct tb_ring *ring);
584+
576585
#endif /* THUNDERBOLT_H_ */

0 commit comments

Comments
 (0)