Rev 6320 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 6320 | Rev 6937 | ||
---|---|---|---|
Line 21... | Line 21... | ||
21 | * IN THE SOFTWARE. |
21 | * IN THE SOFTWARE. |
22 | * |
22 | * |
23 | */ |
23 | */ |
24 | #include |
24 | #include |
25 | #include |
25 | #include |
26 | #include "intel_drv.h" |
26 | #include "i915_drv.h" |
27 | #include "intel_guc.h" |
27 | #include "intel_guc.h" |
Line 28... | Line 28... | ||
28 | 28 | ||
29 | /** |
29 | /** |
30 | * DOC: GuC Client |
30 | * DOC: GuC-based command submission |
31 | * |
31 | * |
32 | * i915_guc_client: |
32 | * i915_guc_client: |
33 | * We use the term client to avoid confusion with contexts. A i915_guc_client is |
33 | * We use the term client to avoid confusion with contexts. A i915_guc_client is |
34 | * equivalent to GuC object guc_context_desc. This context descriptor is |
34 | * equivalent to GuC object guc_context_desc. This context descriptor is |
Line 84... | Line 84... | ||
84 | 84 | ||
85 | if (WARN_ON(len < 1 || len > 15)) |
85 | if (WARN_ON(len < 1 || len > 15)) |
Line 86... | Line 86... | ||
86 | return -EINVAL; |
86 | return -EINVAL; |
87 | - | ||
Line 88... | Line 87... | ||
88 | intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); |
87 | |
89 | spin_lock(&dev_priv->guc.host2guc_lock); |
88 | intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); |
Line 90... | Line 89... | ||
90 | 89 | ||
Line 117... | Line 116... | ||
117 | dev_priv->guc.action_fail += 1; |
116 | dev_priv->guc.action_fail += 1; |
118 | dev_priv->guc.action_err = ret; |
117 | dev_priv->guc.action_err = ret; |
119 | } |
118 | } |
120 | dev_priv->guc.action_status = status; |
119 | dev_priv->guc.action_status = status; |
Line 121... | Line -... | ||
121 | - | ||
122 | spin_unlock(&dev_priv->guc.host2guc_lock); |
120 | |
Line 123... | Line 121... | ||
123 | intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); |
121 | intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); |
124 | 122 | ||
Line 159... | Line 157... | ||
159 | u32 data[2]; |
157 | u32 data[2]; |
Line 160... | Line 158... | ||
160 | 158 | ||
161 | data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE; |
159 | data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE; |
162 | /* WaRsDisableCoarsePowerGating:skl,bxt */ |
160 | /* WaRsDisableCoarsePowerGating:skl,bxt */ |
163 | if (!intel_enable_rc6(dev_priv->dev) || |
161 | if (!intel_enable_rc6(dev_priv->dev) || |
164 | (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || |
162 | IS_BXT_REVID(dev, 0, BXT_REVID_A1) || |
165 | (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) || |
163 | (IS_SKL_GT3(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)) || |
166 | (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0))) |
164 | (IS_SKL_GT4(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0))) |
167 | data[1] = 0; |
165 | data[1] = 0; |
168 | else |
166 | else |
169 | /* bit 0 and 1 are for Render and Media domain separately */ |
167 | /* bit 0 and 1 are for Render and Media domain separately */ |
Line 256... | Line 254... | ||
256 | struct i915_guc_client *client) |
254 | struct i915_guc_client *client) |
257 | { |
255 | { |
258 | struct drm_i915_private *dev_priv = guc_to_i915(guc); |
256 | struct drm_i915_private *dev_priv = guc_to_i915(guc); |
259 | struct guc_doorbell_info *doorbell; |
257 | struct guc_doorbell_info *doorbell; |
260 | void *base; |
258 | void *base; |
261 | int drbreg = GEN8_DRBREGL(client->doorbell_id); |
259 | i915_reg_t drbreg = GEN8_DRBREGL(client->doorbell_id); |
262 | int value; |
260 | int value; |
Line 263... | Line 261... | ||
263 | 261 | ||
264 | base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); |
262 | base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); |
Line 290... | Line 288... | ||
290 | static uint32_t select_doorbell_cacheline(struct intel_guc *guc) |
288 | static uint32_t select_doorbell_cacheline(struct intel_guc *guc) |
291 | { |
289 | { |
292 | const uint32_t cacheline_size = cache_line_size(); |
290 | const uint32_t cacheline_size = cache_line_size(); |
293 | uint32_t offset; |
291 | uint32_t offset; |
Line 294... | Line -... | ||
294 | - | ||
295 | spin_lock(&guc->host2guc_lock); |
- | |
296 | 292 | ||
297 | /* Doorbell uses a single cache line within a page */ |
293 | /* Doorbell uses a single cache line within a page */ |
Line 298... | Line 294... | ||
298 | offset = offset_in_page(guc->db_cacheline); |
294 | offset = offset_in_page(guc->db_cacheline); |
299 | 295 | ||
Line 300... | Line -... | ||
300 | /* Moving to next cache line to reduce contention */ |
- | |
301 | guc->db_cacheline += cacheline_size; |
- | |
302 | 296 | /* Moving to next cache line to reduce contention */ |
|
303 | spin_unlock(&guc->host2guc_lock); |
297 | guc->db_cacheline += cacheline_size; |
Line 304... | Line 298... | ||
304 | 298 | ||
305 | DRM_DEBUG_DRIVER("selected doorbell cacheline 0x%x, next 0x%x, linesize %u\n", |
299 | DRM_DEBUG_DRIVER("selected doorbell cacheline 0x%x, next 0x%x, linesize %u\n", |
Line 320... | Line 314... | ||
320 | const uint16_t half = GUC_MAX_DOORBELLS / 2; |
314 | const uint16_t half = GUC_MAX_DOORBELLS / 2; |
321 | const uint16_t start = hi_pri ? half : 0; |
315 | const uint16_t start = hi_pri ? half : 0; |
322 | const uint16_t end = start + half; |
316 | const uint16_t end = start + half; |
323 | uint16_t id; |
317 | uint16_t id; |
Line 324... | Line -... | ||
324 | - | ||
325 | spin_lock(&guc->host2guc_lock); |
318 | |
326 | id = find_next_zero_bit(guc->doorbell_bitmap, end, start); |
319 | id = find_next_zero_bit(guc->doorbell_bitmap, end, start); |
327 | if (id == end) |
320 | if (id == end) |
328 | id = GUC_INVALID_DOORBELL_ID; |
321 | id = GUC_INVALID_DOORBELL_ID; |
329 | else |
322 | else |
330 | bitmap_set(guc->doorbell_bitmap, id, 1); |
- | |
Line 331... | Line 323... | ||
331 | spin_unlock(&guc->host2guc_lock); |
323 | bitmap_set(guc->doorbell_bitmap, id, 1); |
332 | 324 | ||
Line 333... | Line 325... | ||
333 | DRM_DEBUG_DRIVER("assigned %s priority doorbell id 0x%x\n", |
325 | DRM_DEBUG_DRIVER("assigned %s priority doorbell id 0x%x\n", |
334 | hi_pri ? "high" : "normal", id); |
326 | hi_pri ? "high" : "normal", id); |
Line 335... | Line 327... | ||
335 | 327 | ||
336 | return id; |
328 | return id; |
337 | } |
- | |
338 | 329 | } |
|
339 | static void release_doorbell(struct intel_guc *guc, uint16_t id) |
- | |
340 | { |
330 | |
Line 341... | Line 331... | ||
341 | spin_lock(&guc->host2guc_lock); |
331 | static void release_doorbell(struct intel_guc *guc, uint16_t id) |
342 | bitmap_clear(guc->doorbell_bitmap, id, 1); |
332 | { |
343 | spin_unlock(&guc->host2guc_lock); |
333 | bitmap_clear(guc->doorbell_bitmap, id, 1); |
Line 485... | Line 475... | ||
485 | static int guc_get_workqueue_space(struct i915_guc_client *gc, u32 *offset) |
475 | static int guc_get_workqueue_space(struct i915_guc_client *gc, u32 *offset) |
486 | { |
476 | { |
487 | struct guc_process_desc *desc; |
477 | struct guc_process_desc *desc; |
488 | void *base; |
478 | void *base; |
489 | u32 size = sizeof(struct guc_wq_item); |
479 | u32 size = sizeof(struct guc_wq_item); |
490 | int ret = 0, timeout_counter = 200; |
480 | int ret = -ETIMEDOUT, timeout_counter = 200; |
Line 491... | Line 481... | ||
491 | 481 | ||
492 | base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0)); |
482 | base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0)); |
Line 493... | Line 483... | ||
493 | desc = base + gc->proc_desc_offset; |
483 | desc = base + gc->proc_desc_offset; |
494 | 484 | ||
495 | while (timeout_counter-- > 0) { |
- | |
496 | ret = wait_for_atomic(CIRC_SPACE(gc->wq_tail, desc->head, |
- | |
497 | gc->wq_size) >= size, 1); |
- | |
498 | 485 | while (timeout_counter-- > 0) { |
|
Line 499... | Line 486... | ||
499 | if (!ret) { |
486 | if (CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size) >= size) { |
500 | *offset = gc->wq_tail; |
487 | *offset = gc->wq_tail; |
501 | 488 | ||
Line 502... | Line 489... | ||
502 | /* advance the tail for next workqueue item */ |
489 | /* advance the tail for next workqueue item */ |
503 | gc->wq_tail += size; |
490 | gc->wq_tail += size; |
- | 491 | gc->wq_tail &= gc->wq_size - 1; |
|
504 | gc->wq_tail &= gc->wq_size - 1; |
492 | |
- | 493 | /* this will break the loop */ |
|
- | 494 | timeout_counter = 0; |
|
- | 495 | ret = 0; |
|
505 | 496 | } |
|
Line 506... | Line 497... | ||
506 | /* this will break the loop */ |
497 | |
Line 507... | Line 498... | ||
507 | timeout_counter = 0; |
498 | if (timeout_counter) |
Line 575... | Line 566... | ||
575 | 566 | ||
576 | BUG_ON(!ctx_obj); |
567 | BUG_ON(!ctx_obj); |
577 | WARN_ON(!i915_gem_obj_is_pinned(ctx_obj)); |
568 | WARN_ON(!i915_gem_obj_is_pinned(ctx_obj)); |
Line 578... | Line 569... | ||
578 | WARN_ON(!i915_gem_obj_is_pinned(rb_obj)); |
569 | WARN_ON(!i915_gem_obj_is_pinned(rb_obj)); |
579 | 570 | ||
Line 580... | Line 571... | ||
580 | page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN); |
571 | page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN); |
Line 581... | Line 572... | ||
581 | reg_state = kmap_atomic(page); |
572 | reg_state = kmap_atomic(page); |
582 | 573 | ||
Line 583... | Line 574... | ||
583 | reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj); |
574 | reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj); |
584 | 575 | ||
585 | kunmap_atomic(reg_state); |
576 | kunmap_atomic(reg_state); |
586 | } |
- | |
587 | 577 | } |
|
588 | /** |
578 | |
589 | * i915_guc_submit() - Submit commands through GuC |
579 | /** |
590 | * @client: the guc client where commands will go through |
580 | * i915_guc_submit() - Submit commands through GuC |
591 | * @ctx: LRC where commands come from |
581 | * @client: the guc client where commands will go through |
592 | * @ring: HW engine that will excute the commands |
582 | * @rq: request associated with the commands |
593 | * |
583 | * |
594 | * Return: 0 if succeed |
584 | * Return: 0 if succeed |
595 | */ |
585 | */ |
596 | int i915_guc_submit(struct i915_guc_client *client, |
- | |
597 | struct drm_i915_gem_request *rq) |
586 | int i915_guc_submit(struct i915_guc_client *client, |
Line 598... | Line 587... | ||
598 | { |
587 | struct drm_i915_gem_request *rq) |
599 | struct intel_guc *guc = client->guc; |
588 | { |
600 | enum intel_ring_id ring_id = rq->ring->id; |
589 | struct intel_guc *guc = client->guc; |
Line 601... | Line -... | ||
601 | unsigned long flags; |
- | |
602 | int q_ret, b_ret; |
- | |
603 | 590 | enum intel_ring_id ring_id = rq->ring->id; |
|
604 | /* Need this because of the deferred pin ctx and ring */ |
591 | int q_ret, b_ret; |
605 | /* Shall we move this right after ring is pinned? */ |
592 | |
Line 606... | Line 593... | ||
606 | lr_context_update(rq); |
593 | /* Need this because of the deferred pin ctx and ring */ |
Line 619... | Line 606... | ||
619 | client->b_fail += 1; |
606 | client->b_fail += 1; |
620 | client->retcode = q_ret = b_ret; |
607 | client->retcode = q_ret = b_ret; |
621 | } else { |
608 | } else { |
622 | client->retcode = 0; |
609 | client->retcode = 0; |
623 | } |
610 | } |
624 | spin_unlock_irqrestore(&client->wq_lock, flags); |
- | |
625 | - | ||
626 | spin_lock(&guc->host2guc_lock); |
- | |
627 | guc->submissions[ring_id] += 1; |
611 | guc->submissions[ring_id] += 1; |
628 | guc->last_seqno[ring_id] = rq->seqno; |
612 | guc->last_seqno[ring_id] = rq->seqno; |
629 | spin_unlock(&guc->host2guc_lock); |
- | |
Line 630... | Line 613... | ||
630 | 613 | ||
631 | return q_ret; |
614 | return q_ret; |
Line 632... | Line 615... | ||
632 | } |
615 | } |
Line 729... | Line 712... | ||
729 | * @dev: drm device |
712 | * @dev: drm device |
730 | * @priority: four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW |
713 | * @priority: four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW |
731 | * The kernel client to replace ExecList submission is created with |
714 | * The kernel client to replace ExecList submission is created with |
732 | * NORMAL priority. Priority of a client for scheduler can be HIGH, |
715 | * NORMAL priority. Priority of a client for scheduler can be HIGH, |
733 | * while a preemption context can use CRITICAL. |
716 | * while a preemption context can use CRITICAL. |
734 | * @ctx the context to own the client (we use the default render context) |
717 | * @ctx: the context that owns the client (we use the default render |
- | 718 | * context) |
|
735 | * |
719 | * |
736 | * Return: An i915_guc_client object if success. |
720 | * Return: An i915_guc_client object if success. |
737 | */ |
721 | */ |
738 | static struct i915_guc_client *guc_client_alloc(struct drm_device *dev, |
722 | static struct i915_guc_client *guc_client_alloc(struct drm_device *dev, |
739 | uint32_t priority, |
723 | uint32_t priority, |
Line 766... | Line 750... | ||
766 | goto err; |
750 | goto err; |
Line 767... | Line 751... | ||
767 | 751 | ||
768 | client->client_obj = obj; |
752 | client->client_obj = obj; |
769 | client->wq_offset = GUC_DB_SIZE; |
753 | client->wq_offset = GUC_DB_SIZE; |
770 | client->wq_size = GUC_WQ_SIZE; |
- | |
Line 771... | Line 754... | ||
771 | spin_lock_init(&client->wq_lock); |
754 | client->wq_size = GUC_WQ_SIZE; |
Line 772... | Line 755... | ||
772 | 755 | ||
773 | client->doorbell_offset = select_doorbell_cacheline(guc); |
756 | client->doorbell_offset = select_doorbell_cacheline(guc); |
Line 869... | Line 852... | ||
869 | 852 | ||
870 | guc->ctx_pool_obj = gem_allocate_guc_obj(dev_priv->dev, gemsize); |
853 | guc->ctx_pool_obj = gem_allocate_guc_obj(dev_priv->dev, gemsize); |
871 | if (!guc->ctx_pool_obj) |
854 | if (!guc->ctx_pool_obj) |
Line 872... | Line -... | ||
872 | return -ENOMEM; |
- | |
873 | - | ||
874 | spin_lock_init(&dev_priv->guc.host2guc_lock); |
855 | return -ENOMEM; |
Line 875... | Line 856... | ||
875 | 856 | ||
Line 876... | Line 857... | ||
876 | ida_init(&guc->ctx_ids); |
857 | ida_init(&guc->ctx_ids); |