Home | History | Annotate | Line # | Download | only in gt
      1  1.5  riastrad /*	$NetBSD: intel_breadcrumbs.c,v 1.5 2021/12/19 12:32:15 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * Copyright  2015 Intel Corporation
      5  1.1  riastrad  *
      6  1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
      7  1.1  riastrad  * copy of this software and associated documentation files (the "Software"),
      8  1.1  riastrad  * to deal in the Software without restriction, including without limitation
      9  1.1  riastrad  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  1.1  riastrad  * and/or sell copies of the Software, and to permit persons to whom the
     11  1.1  riastrad  * Software is furnished to do so, subject to the following conditions:
     12  1.1  riastrad  *
     13  1.1  riastrad  * The above copyright notice and this permission notice (including the next
     14  1.1  riastrad  * paragraph) shall be included in all copies or substantial portions of the
     15  1.1  riastrad  * Software.
     16  1.1  riastrad  *
     17  1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  1.1  riastrad  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  1.1  riastrad  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22  1.1  riastrad  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     23  1.1  riastrad  * IN THE SOFTWARE.
     24  1.1  riastrad  *
     25  1.1  riastrad  */
     26  1.1  riastrad 
     27  1.1  riastrad #include <sys/cdefs.h>
     28  1.5  riastrad __KERNEL_RCSID(0, "$NetBSD: intel_breadcrumbs.c,v 1.5 2021/12/19 12:32:15 riastradh Exp $");
     29  1.1  riastrad 
     30  1.1  riastrad #include <linux/kthread.h>
     31  1.1  riastrad #include <trace/events/dma_fence.h>
     32  1.1  riastrad #include <uapi/linux/sched/types.h>
     33  1.1  riastrad 
     34  1.1  riastrad #include "i915_drv.h"
     35  1.1  riastrad #include "i915_trace.h"
     36  1.1  riastrad #include "intel_gt_pm.h"
     37  1.1  riastrad #include "intel_gt_requests.h"
     38  1.1  riastrad 
     39  1.4  riastrad #include <linux/nbsd-namespace.h>
     40  1.4  riastrad 
     41  1.1  riastrad static void irq_enable(struct intel_engine_cs *engine)
     42  1.1  riastrad {
     43  1.1  riastrad 	if (!engine->irq_enable)
     44  1.1  riastrad 		return;
     45  1.1  riastrad 
     46  1.1  riastrad 	/* Caller disables interrupts */
     47  1.1  riastrad 	spin_lock(&engine->gt->irq_lock);
     48  1.1  riastrad 	engine->irq_enable(engine);
     49  1.1  riastrad 	spin_unlock(&engine->gt->irq_lock);
     50  1.1  riastrad }
     51  1.1  riastrad 
     52  1.1  riastrad static void irq_disable(struct intel_engine_cs *engine)
     53  1.1  riastrad {
     54  1.1  riastrad 	if (!engine->irq_disable)
     55  1.1  riastrad 		return;
     56  1.1  riastrad 
     57  1.1  riastrad 	/* Caller disables interrupts */
     58  1.1  riastrad 	spin_lock(&engine->gt->irq_lock);
     59  1.1  riastrad 	engine->irq_disable(engine);
     60  1.1  riastrad 	spin_unlock(&engine->gt->irq_lock);
     61  1.1  riastrad }
     62  1.1  riastrad 
     63  1.1  riastrad static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
     64  1.1  riastrad {
     65  1.1  riastrad 	struct intel_engine_cs *engine =
     66  1.1  riastrad 		container_of(b, struct intel_engine_cs, breadcrumbs);
     67  1.1  riastrad 
     68  1.1  riastrad 	lockdep_assert_held(&b->irq_lock);
     69  1.1  riastrad 
     70  1.1  riastrad 	GEM_BUG_ON(!b->irq_enabled);
     71  1.1  riastrad 	if (!--b->irq_enabled)
     72  1.1  riastrad 		irq_disable(engine);
     73  1.1  riastrad 
     74  1.1  riastrad 	b->irq_armed = false;
     75  1.1  riastrad 	intel_gt_pm_put_async(engine->gt);
     76  1.1  riastrad }
     77  1.1  riastrad 
     78  1.1  riastrad void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
     79  1.1  riastrad {
     80  1.1  riastrad 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
     81  1.1  riastrad 	unsigned long flags;
     82  1.1  riastrad 
     83  1.1  riastrad 	if (!b->irq_armed)
     84  1.1  riastrad 		return;
     85  1.1  riastrad 
     86  1.1  riastrad 	spin_lock_irqsave(&b->irq_lock, flags);
     87  1.1  riastrad 	if (b->irq_armed)
     88  1.1  riastrad 		__intel_breadcrumbs_disarm_irq(b);
     89  1.1  riastrad 	spin_unlock_irqrestore(&b->irq_lock, flags);
     90  1.1  riastrad }
     91  1.1  riastrad 
     92  1.1  riastrad static inline bool __request_completed(const struct i915_request *rq)
     93  1.1  riastrad {
     94  1.1  riastrad 	return i915_seqno_passed(__hwsp_seqno(rq), rq->fence.seqno);
     95  1.1  riastrad }
     96  1.1  riastrad 
     97  1.1  riastrad __maybe_unused static bool
     98  1.1  riastrad check_signal_order(struct intel_context *ce, struct i915_request *rq)
     99  1.1  riastrad {
    100  1.1  riastrad 	if (!list_is_last(&rq->signal_link, &ce->signals) &&
    101  1.1  riastrad 	    i915_seqno_passed(rq->fence.seqno,
    102  1.1  riastrad 			      list_next_entry(rq, signal_link)->fence.seqno))
    103  1.1  riastrad 		return false;
    104  1.1  riastrad 
    105  1.1  riastrad 	if (!list_is_first(&rq->signal_link, &ce->signals) &&
    106  1.1  riastrad 	    i915_seqno_passed(list_prev_entry(rq, signal_link)->fence.seqno,
    107  1.1  riastrad 			      rq->fence.seqno))
    108  1.1  riastrad 		return false;
    109  1.1  riastrad 
    110  1.1  riastrad 	return true;
    111  1.1  riastrad }
    112  1.1  riastrad 
    113  1.3  riastrad #ifndef __NetBSD__
    114  1.3  riastrad 
    115  1.1  riastrad static bool
    116  1.1  riastrad __dma_fence_signal(struct dma_fence *fence)
    117  1.1  riastrad {
    118  1.1  riastrad 	return !test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags);
    119  1.1  riastrad }
    120  1.1  riastrad 
    121  1.1  riastrad static void
    122  1.1  riastrad __dma_fence_signal__timestamp(struct dma_fence *fence, ktime_t timestamp)
    123  1.1  riastrad {
    124  1.1  riastrad 	fence->timestamp = timestamp;
    125  1.1  riastrad 	set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
    126  1.1  riastrad 	trace_dma_fence_signaled(fence);
    127  1.1  riastrad }
    128  1.1  riastrad 
    129  1.1  riastrad static void
    130  1.1  riastrad __dma_fence_signal__notify(struct dma_fence *fence,
    131  1.1  riastrad 			   const struct list_head *list)
    132  1.1  riastrad {
    133  1.1  riastrad 	struct dma_fence_cb *cur, *tmp;
    134  1.1  riastrad 
    135  1.1  riastrad 	lockdep_assert_held(fence->lock);
    136  1.1  riastrad 
    137  1.1  riastrad 	list_for_each_entry_safe(cur, tmp, list, node) {
    138  1.1  riastrad 		INIT_LIST_HEAD(&cur->node);
    139  1.1  riastrad 		cur->func(fence, cur);
    140  1.1  riastrad 	}
    141  1.1  riastrad }
    142  1.1  riastrad 
    143  1.3  riastrad #endif
    144  1.3  riastrad 
    145  1.1  riastrad static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
    146  1.1  riastrad {
    147  1.1  riastrad 	struct intel_engine_cs *engine =
    148  1.1  riastrad 		container_of(b, struct intel_engine_cs, breadcrumbs);
    149  1.1  riastrad 
    150  1.1  riastrad 	if (unlikely(intel_engine_is_virtual(engine)))
    151  1.1  riastrad 		engine = intel_virtual_engine_get_sibling(engine, 0);
    152  1.1  riastrad 
    153  1.1  riastrad 	intel_engine_add_retire(engine, tl);
    154  1.1  riastrad }
    155  1.1  riastrad 
    156  1.1  riastrad static void signal_irq_work(struct irq_work *work)
    157  1.1  riastrad {
    158  1.1  riastrad 	struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work);
    159  1.1  riastrad 	const ktime_t timestamp = ktime_get();
    160  1.1  riastrad 	struct intel_context *ce, *cn;
    161  1.1  riastrad 	struct list_head *pos, *next;
    162  1.1  riastrad 	LIST_HEAD(signal);
    163  1.1  riastrad 
    164  1.1  riastrad 	spin_lock(&b->irq_lock);
    165  1.1  riastrad 
    166  1.1  riastrad 	if (b->irq_armed && list_empty(&b->signalers))
    167  1.1  riastrad 		__intel_breadcrumbs_disarm_irq(b);
    168  1.1  riastrad 
    169  1.1  riastrad 	list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) {
    170  1.1  riastrad 		GEM_BUG_ON(list_empty(&ce->signals));
    171  1.1  riastrad 
    172  1.1  riastrad 		list_for_each_safe(pos, next, &ce->signals) {
    173  1.1  riastrad 			struct i915_request *rq =
    174  1.1  riastrad 				list_entry(pos, typeof(*rq), signal_link);
    175  1.1  riastrad 
    176  1.1  riastrad 			GEM_BUG_ON(!check_signal_order(ce, rq));
    177  1.1  riastrad 
    178  1.1  riastrad 			if (!__request_completed(rq))
    179  1.1  riastrad 				break;
    180  1.1  riastrad 
    181  1.1  riastrad 			GEM_BUG_ON(!test_bit(I915_FENCE_FLAG_SIGNAL,
    182  1.1  riastrad 					     &rq->fence.flags));
    183  1.1  riastrad 			clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
    184  1.1  riastrad 
    185  1.1  riastrad 			if (!__dma_fence_signal(&rq->fence))
    186  1.1  riastrad 				continue;
    187  1.1  riastrad 
    188  1.1  riastrad 			/*
    189  1.1  riastrad 			 * Queue for execution after dropping the signaling
    190  1.1  riastrad 			 * spinlock as the callback chain may end up adding
    191  1.1  riastrad 			 * more signalers to the same context or engine.
    192  1.1  riastrad 			 */
    193  1.1  riastrad 			i915_request_get(rq);
    194  1.1  riastrad 			list_add_tail(&rq->signal_link, &signal);
    195  1.1  riastrad 		}
    196  1.1  riastrad 
    197  1.1  riastrad 		/*
    198  1.1  riastrad 		 * We process the list deletion in bulk, only using a list_add
    199  1.1  riastrad 		 * (not list_move) above but keeping the status of
    200  1.1  riastrad 		 * rq->signal_link known with the I915_FENCE_FLAG_SIGNAL bit.
    201  1.1  riastrad 		 */
    202  1.1  riastrad 		if (!list_is_first(pos, &ce->signals)) {
    203  1.1  riastrad 			/* Advance the list to the first incomplete request */
    204  1.1  riastrad 			__list_del_many(&ce->signals, pos);
    205  1.1  riastrad 			if (&ce->signals == pos) { /* now empty */
    206  1.1  riastrad 				list_del_init(&ce->signal_link);
    207  1.1  riastrad 				add_retire(b, ce->timeline);
    208  1.1  riastrad 			}
    209  1.1  riastrad 		}
    210  1.1  riastrad 	}
    211  1.1  riastrad 
    212  1.1  riastrad 	spin_unlock(&b->irq_lock);
    213  1.1  riastrad 
    214  1.1  riastrad 	list_for_each_safe(pos, next, &signal) {
    215  1.1  riastrad 		struct i915_request *rq =
    216  1.1  riastrad 			list_entry(pos, typeof(*rq), signal_link);
    217  1.3  riastrad #ifdef __NetBSD__
    218  1.3  riastrad 		__dma_fence_signal_wake(&rq->fence, timestamp);
    219  1.3  riastrad #else
    220  1.1  riastrad 		struct list_head cb_list;
    221  1.1  riastrad 
    222  1.1  riastrad 		spin_lock(&rq->lock);
    223  1.1  riastrad 		list_replace(&rq->fence.cb_list, &cb_list);
    224  1.1  riastrad 		__dma_fence_signal__timestamp(&rq->fence, timestamp);
    225  1.1  riastrad 		__dma_fence_signal__notify(&rq->fence, &cb_list);
    226  1.1  riastrad 		spin_unlock(&rq->lock);
    227  1.3  riastrad #endif
    228  1.1  riastrad 
    229  1.1  riastrad 		i915_request_put(rq);
    230  1.1  riastrad 	}
    231  1.1  riastrad }
    232  1.1  riastrad 
    233  1.1  riastrad static bool __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b)
    234  1.1  riastrad {
    235  1.1  riastrad 	struct intel_engine_cs *engine =
    236  1.1  riastrad 		container_of(b, struct intel_engine_cs, breadcrumbs);
    237  1.1  riastrad 
    238  1.1  riastrad 	lockdep_assert_held(&b->irq_lock);
    239  1.1  riastrad 	if (b->irq_armed)
    240  1.1  riastrad 		return true;
    241  1.1  riastrad 
    242  1.1  riastrad 	if (!intel_gt_pm_get_if_awake(engine->gt))
    243  1.1  riastrad 		return false;
    244  1.1  riastrad 
    245  1.1  riastrad 	/*
    246  1.1  riastrad 	 * The breadcrumb irq will be disarmed on the interrupt after the
    247  1.1  riastrad 	 * waiters are signaled. This gives us a single interrupt window in
    248  1.1  riastrad 	 * which we can add a new waiter and avoid the cost of re-enabling
    249  1.1  riastrad 	 * the irq.
    250  1.1  riastrad 	 */
    251  1.1  riastrad 	b->irq_armed = true;
    252  1.1  riastrad 
    253  1.1  riastrad 	/*
    254  1.1  riastrad 	 * Since we are waiting on a request, the GPU should be busy
    255  1.1  riastrad 	 * and should have its own rpm reference. This is tracked
    256  1.1  riastrad 	 * by i915->gt.awake, we can forgo holding our own wakref
    257  1.1  riastrad 	 * for the interrupt as before i915->gt.awake is released (when
    258  1.1  riastrad 	 * the driver is idle) we disarm the breadcrumbs.
    259  1.1  riastrad 	 */
    260  1.1  riastrad 
    261  1.1  riastrad 	if (!b->irq_enabled++)
    262  1.1  riastrad 		irq_enable(engine);
    263  1.1  riastrad 
    264  1.1  riastrad 	return true;
    265  1.1  riastrad }
    266  1.1  riastrad 
    267  1.1  riastrad void intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
    268  1.1  riastrad {
    269  1.1  riastrad 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
    270  1.1  riastrad 
    271  1.1  riastrad 	spin_lock_init(&b->irq_lock);
    272  1.1  riastrad 	INIT_LIST_HEAD(&b->signalers);
    273  1.1  riastrad 
    274  1.1  riastrad 	init_irq_work(&b->irq_work, signal_irq_work);
    275  1.1  riastrad }
    276  1.1  riastrad 
    277  1.1  riastrad void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
    278  1.1  riastrad {
    279  1.1  riastrad 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
    280  1.1  riastrad 	unsigned long flags;
    281  1.1  riastrad 
    282  1.1  riastrad 	spin_lock_irqsave(&b->irq_lock, flags);
    283  1.1  riastrad 
    284  1.1  riastrad 	if (b->irq_enabled)
    285  1.1  riastrad 		irq_enable(engine);
    286  1.1  riastrad 	else
    287  1.1  riastrad 		irq_disable(engine);
    288  1.1  riastrad 
    289  1.1  riastrad 	spin_unlock_irqrestore(&b->irq_lock, flags);
    290  1.1  riastrad }
    291  1.1  riastrad 
    292  1.1  riastrad void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
    293  1.1  riastrad {
    294  1.5  riastrad 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
    295  1.5  riastrad 
    296  1.5  riastrad 	spin_lock_destroy(&b->irq_lock);
    297  1.1  riastrad }
    298  1.1  riastrad 
    299  1.1  riastrad bool i915_request_enable_breadcrumb(struct i915_request *rq)
    300  1.1  riastrad {
    301  1.1  riastrad 	lockdep_assert_held(&rq->lock);
    302  1.1  riastrad 
    303  1.1  riastrad 	if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) {
    304  1.1  riastrad 		struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
    305  1.1  riastrad 		struct intel_context *ce = rq->context;
    306  1.1  riastrad 		struct list_head *pos;
    307  1.1  riastrad 
    308  1.1  riastrad 		spin_lock(&b->irq_lock);
    309  1.1  riastrad 		GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
    310  1.1  riastrad 
    311  1.1  riastrad 		if (!__intel_breadcrumbs_arm_irq(b))
    312  1.1  riastrad 			goto unlock;
    313  1.1  riastrad 
    314  1.1  riastrad 		/*
    315  1.1  riastrad 		 * We keep the seqno in retirement order, so we can break
    316  1.1  riastrad 		 * inside intel_engine_signal_breadcrumbs as soon as we've
    317  1.1  riastrad 		 * passed the last completed request (or seen a request that
    318  1.1  riastrad 		 * hasn't event started). We could walk the timeline->requests,
    319  1.1  riastrad 		 * but keeping a separate signalers_list has the advantage of
    320  1.1  riastrad 		 * hopefully being much smaller than the full list and so
    321  1.1  riastrad 		 * provides faster iteration and detection when there are no
    322  1.1  riastrad 		 * more interrupts required for this context.
    323  1.1  riastrad 		 *
    324  1.1  riastrad 		 * We typically expect to add new signalers in order, so we
    325  1.1  riastrad 		 * start looking for our insertion point from the tail of
    326  1.1  riastrad 		 * the list.
    327  1.1  riastrad 		 */
    328  1.1  riastrad 		list_for_each_prev(pos, &ce->signals) {
    329  1.1  riastrad 			struct i915_request *it =
    330  1.1  riastrad 				list_entry(pos, typeof(*it), signal_link);
    331  1.1  riastrad 
    332  1.1  riastrad 			if (i915_seqno_passed(rq->fence.seqno, it->fence.seqno))
    333  1.1  riastrad 				break;
    334  1.1  riastrad 		}
    335  1.1  riastrad 		list_add(&rq->signal_link, pos);
    336  1.1  riastrad 		if (pos == &ce->signals) /* catch transitions from empty list */
    337  1.1  riastrad 			list_move_tail(&ce->signal_link, &b->signalers);
    338  1.1  riastrad 		GEM_BUG_ON(!check_signal_order(ce, rq));
    339  1.1  riastrad 
    340  1.1  riastrad 		set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
    341  1.1  riastrad unlock:
    342  1.1  riastrad 		spin_unlock(&b->irq_lock);
    343  1.1  riastrad 	}
    344  1.1  riastrad 
    345  1.1  riastrad 	return !__request_completed(rq);
    346  1.1  riastrad }
    347  1.1  riastrad 
    348  1.1  riastrad void i915_request_cancel_breadcrumb(struct i915_request *rq)
    349  1.1  riastrad {
    350  1.1  riastrad 	struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
    351  1.1  riastrad 
    352  1.1  riastrad 	lockdep_assert_held(&rq->lock);
    353  1.1  riastrad 
    354  1.1  riastrad 	/*
    355  1.1  riastrad 	 * We must wait for b->irq_lock so that we know the interrupt handler
    356  1.1  riastrad 	 * has released its reference to the intel_context and has completed
    357  1.1  riastrad 	 * the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
    358  1.1  riastrad 	 * required).
    359  1.1  riastrad 	 */
    360  1.1  riastrad 	spin_lock(&b->irq_lock);
    361  1.1  riastrad 	if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
    362  1.1  riastrad 		struct intel_context *ce = rq->context;
    363  1.1  riastrad 
    364  1.1  riastrad 		list_del(&rq->signal_link);
    365  1.1  riastrad 		if (list_empty(&ce->signals))
    366  1.1  riastrad 			list_del_init(&ce->signal_link);
    367  1.1  riastrad 
    368  1.1  riastrad 		clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
    369  1.1  riastrad 	}
    370  1.1  riastrad 	spin_unlock(&b->irq_lock);
    371  1.1  riastrad }
    372  1.1  riastrad 
    373  1.1  riastrad void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
    374  1.1  riastrad 				    struct drm_printer *p)
    375  1.1  riastrad {
    376  1.1  riastrad 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
    377  1.1  riastrad 	struct intel_context *ce;
    378  1.1  riastrad 	struct i915_request *rq;
    379  1.1  riastrad 
    380  1.1  riastrad 	if (list_empty(&b->signalers))
    381  1.1  riastrad 		return;
    382  1.1  riastrad 
    383  1.1  riastrad 	drm_printf(p, "Signals:\n");
    384  1.1  riastrad 
    385  1.1  riastrad 	spin_lock_irq(&b->irq_lock);
    386  1.1  riastrad 	list_for_each_entry(ce, &b->signalers, signal_link) {
    387  1.1  riastrad 		list_for_each_entry(rq, &ce->signals, signal_link) {
    388  1.4  riastrad 			drm_printf(p, "\t[%"PRIx64":%"PRIx64"%s] @ %dms\n",
    389  1.4  riastrad 				   (uint64_t)rq->fence.context,
    390  1.4  riastrad 				   (uint64_t)rq->fence.seqno,
    391  1.1  riastrad 				   i915_request_completed(rq) ? "!" :
    392  1.1  riastrad 				   i915_request_started(rq) ? "*" :
    393  1.1  riastrad 				   "",
    394  1.1  riastrad 				   jiffies_to_msecs(jiffies - rq->emitted_jiffies));
    395  1.1  riastrad 		}
    396  1.1  riastrad 	}
    397  1.1  riastrad 	spin_unlock_irq(&b->irq_lock);
    398  1.1  riastrad }
    399