Linux Audio

Check our new training course

Loading...
v4.17
  1/*
  2 * Copyright 2014 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 20 * OTHER DEALINGS IN THE SOFTWARE.
 21 *
 22 */
 23#include <drm/drmP.h>
 
 
 24#include "amdgpu.h"
 25#include "amdgpu_ih.h"
 26#include "vid.h"
 27
 28#include "oss/oss_3_0_d.h"
 29#include "oss/oss_3_0_sh_mask.h"
 30
 31#include "bif/bif_5_1_d.h"
 32#include "bif/bif_5_1_sh_mask.h"
 33
 34/*
 35 * Interrupts
 36 * Starting with r6xx, interrupts are handled via a ring buffer.
 37 * Ring buffers are areas of GPU accessible memory that the GPU
 38 * writes interrupt vectors into and the host reads vectors out of.
 39 * There is a rptr (read pointer) that determines where the
 40 * host is currently reading, and a wptr (write pointer)
 41 * which determines where the GPU has written.  When the
 42 * pointers are equal, the ring is idle.  When the GPU
 43 * writes vectors to the ring buffer, it increments the
 44 * wptr.  When there is an interrupt, the host then starts
 45 * fetching commands and processing them until the pointers are
 46 * equal again at which point it updates the rptr.
 47 */
 48
 49static void tonga_ih_set_interrupt_funcs(struct amdgpu_device *adev);
 50
 51/**
 52 * tonga_ih_enable_interrupts - Enable the interrupt ring buffer
 53 *
 54 * @adev: amdgpu_device pointer
 55 *
 56 * Enable the interrupt ring buffer (VI).
 57 */
 58static void tonga_ih_enable_interrupts(struct amdgpu_device *adev)
 59{
 60	u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
 61
 62	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
 63	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
 64	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
 65	adev->irq.ih.enabled = true;
 66}
 67
 68/**
 69 * tonga_ih_disable_interrupts - Disable the interrupt ring buffer
 70 *
 71 * @adev: amdgpu_device pointer
 72 *
 73 * Disable the interrupt ring buffer (VI).
 74 */
 75static void tonga_ih_disable_interrupts(struct amdgpu_device *adev)
 76{
 77	u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
 78
 79	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
 80	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
 81	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
 82	/* set rptr, wptr to 0 */
 83	WREG32(mmIH_RB_RPTR, 0);
 84	WREG32(mmIH_RB_WPTR, 0);
 85	adev->irq.ih.enabled = false;
 86	adev->irq.ih.rptr = 0;
 87}
 88
 89/**
 90 * tonga_ih_irq_init - init and enable the interrupt ring
 91 *
 92 * @adev: amdgpu_device pointer
 93 *
 94 * Allocate a ring buffer for the interrupt controller,
 95 * enable the RLC, disable interrupts, enable the IH
 96 * ring buffer and enable it (VI).
 97 * Called at device load and reume.
 98 * Returns 0 for success, errors for failure.
 99 */
100static int tonga_ih_irq_init(struct amdgpu_device *adev)
101{
102	int rb_bufsz;
103	u32 interrupt_cntl, ih_rb_cntl, ih_doorbell_rtpr;
104	u64 wptr_off;
 
105
106	/* disable irqs */
107	tonga_ih_disable_interrupts(adev);
108
109	/* setup interrupt control */
110	WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
111	interrupt_cntl = RREG32(mmINTERRUPT_CNTL);
112	/* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
113	 * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
114	 */
115	interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_DUMMY_RD_OVERRIDE, 0);
116	/* INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
117	interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_REQ_NONSNOOP_EN, 0);
118	WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
119
120	/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
121	if (adev->irq.ih.use_bus_addr)
122		WREG32(mmIH_RB_BASE, adev->irq.ih.rb_dma_addr >> 8);
123	else
124		WREG32(mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
125
126	rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
127	ih_rb_cntl = REG_SET_FIELD(0, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
128	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
129	/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
130	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
131	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
132
133	if (adev->irq.msi_enabled)
134		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM, 1);
135
136	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
137
138	/* set the writeback address whether it's enabled or not */
139	if (adev->irq.ih.use_bus_addr)
140		wptr_off = adev->irq.ih.rb_dma_addr + (adev->irq.ih.wptr_offs * 4);
141	else
142		wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
143	WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
144	WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
145
146	/* set rptr, wptr to 0 */
147	WREG32(mmIH_RB_RPTR, 0);
148	WREG32(mmIH_RB_WPTR, 0);
149
150	ih_doorbell_rtpr = RREG32(mmIH_DOORBELL_RPTR);
151	if (adev->irq.ih.use_doorbell) {
152		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
153						 OFFSET, adev->irq.ih.doorbell_index);
154		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
155						 ENABLE, 1);
156	} else {
157		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
158						 ENABLE, 0);
159	}
160	WREG32(mmIH_DOORBELL_RPTR, ih_doorbell_rtpr);
161
162	pci_set_master(adev->pdev);
163
164	/* enable interrupts */
165	tonga_ih_enable_interrupts(adev);
166
167	return 0;
168}
169
170/**
171 * tonga_ih_irq_disable - disable interrupts
172 *
173 * @adev: amdgpu_device pointer
174 *
175 * Disable interrupts on the hw (VI).
176 */
177static void tonga_ih_irq_disable(struct amdgpu_device *adev)
178{
179	tonga_ih_disable_interrupts(adev);
180
181	/* Wait and acknowledge irq */
182	mdelay(1);
183}
184
185/**
186 * tonga_ih_get_wptr - get the IH ring buffer wptr
187 *
188 * @adev: amdgpu_device pointer
 
189 *
190 * Get the IH ring buffer wptr from either the register
191 * or the writeback memory buffer (VI).  Also check for
192 * ring buffer overflow and deal with it.
193 * Used by cz_irq_process(VI).
194 * Returns the value of the wptr.
195 */
196static u32 tonga_ih_get_wptr(struct amdgpu_device *adev)
 
197{
198	u32 wptr, tmp;
199
200	if (adev->irq.ih.use_bus_addr)
201		wptr = le32_to_cpu(adev->irq.ih.ring[adev->irq.ih.wptr_offs]);
202	else
203		wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
204
205	if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
206		wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
207		/* When a ring buffer overflow happen start parsing interrupt
208		 * from the last not overwritten vector (wptr + 16). Hopefully
209		 * this should allow us to catchup.
210		 */
211		dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
212			wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
213		adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
214		tmp = RREG32(mmIH_RB_CNTL);
215		tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
216		WREG32(mmIH_RB_CNTL, tmp);
217	}
218	return (wptr & adev->irq.ih.ptr_mask);
219}
220
221/**
222 * tonga_ih_prescreen_iv - prescreen an interrupt vector
223 *
224 * @adev: amdgpu_device pointer
225 *
226 * Returns true if the interrupt vector should be further processed.
227 */
228static bool tonga_ih_prescreen_iv(struct amdgpu_device *adev)
229{
230	u32 ring_index = adev->irq.ih.rptr >> 2;
231	u16 pasid;
232
233	switch (le32_to_cpu(adev->irq.ih.ring[ring_index]) & 0xff) {
234	case 146:
235	case 147:
236		pasid = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]) >> 16;
237		if (!pasid || amdgpu_vm_pasid_fault_credit(adev, pasid))
238			return true;
239		break;
240	default:
241		/* Not a VM fault */
242		return true;
243	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
245	adev->irq.ih.rptr += 16;
246	return false;
247}
248
249/**
250 * tonga_ih_decode_iv - decode an interrupt vector
251 *
252 * @adev: amdgpu_device pointer
 
 
253 *
254 * Decodes the interrupt vector at the current rptr
255 * position and also advance the position.
256 */
257static void tonga_ih_decode_iv(struct amdgpu_device *adev,
258				 struct amdgpu_iv_entry *entry)
 
259{
260	/* wptr/rptr are in bytes! */
261	u32 ring_index = adev->irq.ih.rptr >> 2;
262	uint32_t dw[4];
263
264	dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
265	dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
266	dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
267	dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
268
269	entry->client_id = AMDGPU_IH_CLIENTID_LEGACY;
270	entry->src_id = dw[0] & 0xff;
271	entry->src_data[0] = dw[1] & 0xfffffff;
272	entry->ring_id = dw[2] & 0xff;
273	entry->vmid = (dw[2] >> 8) & 0xff;
274	entry->pasid = (dw[2] >> 16) & 0xffff;
275
276	/* wptr/rptr are in bytes! */
277	adev->irq.ih.rptr += 16;
278}
279
280/**
281 * tonga_ih_set_rptr - set the IH ring buffer rptr
282 *
283 * @adev: amdgpu_device pointer
 
284 *
285 * Set the IH ring buffer rptr.
286 */
287static void tonga_ih_set_rptr(struct amdgpu_device *adev)
 
288{
289	if (adev->irq.ih.use_doorbell) {
290		/* XXX check if swapping is necessary on BE */
291		if (adev->irq.ih.use_bus_addr)
292			adev->irq.ih.ring[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
293		else
294			adev->wb.wb[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
295		WDOORBELL32(adev->irq.ih.doorbell_index, adev->irq.ih.rptr);
296	} else {
297		WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
298	}
299}
300
301static int tonga_ih_early_init(void *handle)
302{
303	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
304	int ret;
305
306	ret = amdgpu_irq_add_domain(adev);
307	if (ret)
308		return ret;
309
310	tonga_ih_set_interrupt_funcs(adev);
311
312	return 0;
313}
314
315static int tonga_ih_sw_init(void *handle)
316{
317	int r;
318	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
319
320	r = amdgpu_ih_ring_init(adev, 64 * 1024, true);
321	if (r)
322		return r;
323
324	adev->irq.ih.use_doorbell = true;
325	adev->irq.ih.doorbell_index = AMDGPU_DOORBELL_IH;
326
327	r = amdgpu_irq_init(adev);
328
329	return r;
330}
331
332static int tonga_ih_sw_fini(void *handle)
333{
334	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
335
336	amdgpu_irq_fini(adev);
337	amdgpu_ih_ring_fini(adev);
338	amdgpu_irq_remove_domain(adev);
339
340	return 0;
341}
342
343static int tonga_ih_hw_init(void *handle)
344{
345	int r;
346	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
347
348	r = tonga_ih_irq_init(adev);
349	if (r)
350		return r;
351
352	return 0;
353}
354
355static int tonga_ih_hw_fini(void *handle)
356{
357	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
358
359	tonga_ih_irq_disable(adev);
360
361	return 0;
362}
363
364static int tonga_ih_suspend(void *handle)
365{
366	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
367
368	return tonga_ih_hw_fini(adev);
369}
370
371static int tonga_ih_resume(void *handle)
372{
373	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
374
375	return tonga_ih_hw_init(adev);
376}
377
378static bool tonga_ih_is_idle(void *handle)
379{
380	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
381	u32 tmp = RREG32(mmSRBM_STATUS);
382
383	if (REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
384		return false;
385
386	return true;
387}
388
389static int tonga_ih_wait_for_idle(void *handle)
390{
391	unsigned i;
392	u32 tmp;
393	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
394
395	for (i = 0; i < adev->usec_timeout; i++) {
396		/* read MC_STATUS */
397		tmp = RREG32(mmSRBM_STATUS);
398		if (!REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
399			return 0;
400		udelay(1);
401	}
402	return -ETIMEDOUT;
403}
404
405static bool tonga_ih_check_soft_reset(void *handle)
406{
407	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
408	u32 srbm_soft_reset = 0;
409	u32 tmp = RREG32(mmSRBM_STATUS);
410
411	if (tmp & SRBM_STATUS__IH_BUSY_MASK)
412		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
413						SOFT_RESET_IH, 1);
414
415	if (srbm_soft_reset) {
416		adev->irq.srbm_soft_reset = srbm_soft_reset;
417		return true;
418	} else {
419		adev->irq.srbm_soft_reset = 0;
420		return false;
421	}
422}
423
424static int tonga_ih_pre_soft_reset(void *handle)
425{
426	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
427
428	if (!adev->irq.srbm_soft_reset)
429		return 0;
430
431	return tonga_ih_hw_fini(adev);
432}
433
434static int tonga_ih_post_soft_reset(void *handle)
435{
436	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
437
438	if (!adev->irq.srbm_soft_reset)
439		return 0;
440
441	return tonga_ih_hw_init(adev);
442}
443
444static int tonga_ih_soft_reset(void *handle)
445{
446	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
447	u32 srbm_soft_reset;
448
449	if (!adev->irq.srbm_soft_reset)
450		return 0;
451	srbm_soft_reset = adev->irq.srbm_soft_reset;
452
453	if (srbm_soft_reset) {
454		u32 tmp;
455
456		tmp = RREG32(mmSRBM_SOFT_RESET);
457		tmp |= srbm_soft_reset;
458		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
459		WREG32(mmSRBM_SOFT_RESET, tmp);
460		tmp = RREG32(mmSRBM_SOFT_RESET);
461
462		udelay(50);
463
464		tmp &= ~srbm_soft_reset;
465		WREG32(mmSRBM_SOFT_RESET, tmp);
466		tmp = RREG32(mmSRBM_SOFT_RESET);
467
468		/* Wait a little for things to settle down */
469		udelay(50);
470	}
471
472	return 0;
473}
474
475static int tonga_ih_set_clockgating_state(void *handle,
476					  enum amd_clockgating_state state)
477{
478	return 0;
479}
480
481static int tonga_ih_set_powergating_state(void *handle,
482					  enum amd_powergating_state state)
483{
484	return 0;
485}
486
487static const struct amd_ip_funcs tonga_ih_ip_funcs = {
488	.name = "tonga_ih",
489	.early_init = tonga_ih_early_init,
490	.late_init = NULL,
491	.sw_init = tonga_ih_sw_init,
492	.sw_fini = tonga_ih_sw_fini,
493	.hw_init = tonga_ih_hw_init,
494	.hw_fini = tonga_ih_hw_fini,
495	.suspend = tonga_ih_suspend,
496	.resume = tonga_ih_resume,
497	.is_idle = tonga_ih_is_idle,
498	.wait_for_idle = tonga_ih_wait_for_idle,
499	.check_soft_reset = tonga_ih_check_soft_reset,
500	.pre_soft_reset = tonga_ih_pre_soft_reset,
501	.soft_reset = tonga_ih_soft_reset,
502	.post_soft_reset = tonga_ih_post_soft_reset,
503	.set_clockgating_state = tonga_ih_set_clockgating_state,
504	.set_powergating_state = tonga_ih_set_powergating_state,
505};
506
507static const struct amdgpu_ih_funcs tonga_ih_funcs = {
508	.get_wptr = tonga_ih_get_wptr,
509	.prescreen_iv = tonga_ih_prescreen_iv,
510	.decode_iv = tonga_ih_decode_iv,
511	.set_rptr = tonga_ih_set_rptr
512};
513
514static void tonga_ih_set_interrupt_funcs(struct amdgpu_device *adev)
515{
516	if (adev->irq.ih_funcs == NULL)
517		adev->irq.ih_funcs = &tonga_ih_funcs;
518}
519
520const struct amdgpu_ip_block_version tonga_ih_ip_block =
521{
522	.type = AMD_IP_BLOCK_TYPE_IH,
523	.major = 3,
524	.minor = 0,
525	.rev = 0,
526	.funcs = &tonga_ih_ip_funcs,
527};
v6.13.7
  1/*
  2 * Copyright 2014 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 20 * OTHER DEALINGS IN THE SOFTWARE.
 21 *
 22 */
 23
 24#include <linux/pci.h>
 25
 26#include "amdgpu.h"
 27#include "amdgpu_ih.h"
 28#include "vid.h"
 29
 30#include "oss/oss_3_0_d.h"
 31#include "oss/oss_3_0_sh_mask.h"
 32
 33#include "bif/bif_5_1_d.h"
 34#include "bif/bif_5_1_sh_mask.h"
 35
 36/*
 37 * Interrupts
 38 * Starting with r6xx, interrupts are handled via a ring buffer.
 39 * Ring buffers are areas of GPU accessible memory that the GPU
 40 * writes interrupt vectors into and the host reads vectors out of.
 41 * There is a rptr (read pointer) that determines where the
 42 * host is currently reading, and a wptr (write pointer)
 43 * which determines where the GPU has written.  When the
 44 * pointers are equal, the ring is idle.  When the GPU
 45 * writes vectors to the ring buffer, it increments the
 46 * wptr.  When there is an interrupt, the host then starts
 47 * fetching commands and processing them until the pointers are
 48 * equal again at which point it updates the rptr.
 49 */
 50
 51static void tonga_ih_set_interrupt_funcs(struct amdgpu_device *adev);
 52
 53/**
 54 * tonga_ih_enable_interrupts - Enable the interrupt ring buffer
 55 *
 56 * @adev: amdgpu_device pointer
 57 *
 58 * Enable the interrupt ring buffer (VI).
 59 */
 60static void tonga_ih_enable_interrupts(struct amdgpu_device *adev)
 61{
 62	u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
 63
 64	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
 65	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
 66	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
 67	adev->irq.ih.enabled = true;
 68}
 69
 70/**
 71 * tonga_ih_disable_interrupts - Disable the interrupt ring buffer
 72 *
 73 * @adev: amdgpu_device pointer
 74 *
 75 * Disable the interrupt ring buffer (VI).
 76 */
 77static void tonga_ih_disable_interrupts(struct amdgpu_device *adev)
 78{
 79	u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
 80
 81	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
 82	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 0);
 83	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
 84	/* set rptr, wptr to 0 */
 85	WREG32(mmIH_RB_RPTR, 0);
 86	WREG32(mmIH_RB_WPTR, 0);
 87	adev->irq.ih.enabled = false;
 88	adev->irq.ih.rptr = 0;
 89}
 90
 91/**
 92 * tonga_ih_irq_init - init and enable the interrupt ring
 93 *
 94 * @adev: amdgpu_device pointer
 95 *
 96 * Allocate a ring buffer for the interrupt controller,
 97 * enable the RLC, disable interrupts, enable the IH
 98 * ring buffer and enable it (VI).
 99 * Called at device load and reume.
100 * Returns 0 for success, errors for failure.
101 */
102static int tonga_ih_irq_init(struct amdgpu_device *adev)
103{
 
104	u32 interrupt_cntl, ih_rb_cntl, ih_doorbell_rtpr;
105	struct amdgpu_ih_ring *ih = &adev->irq.ih;
106	int rb_bufsz;
107
108	/* disable irqs */
109	tonga_ih_disable_interrupts(adev);
110
111	/* setup interrupt control */
112	WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
113	interrupt_cntl = RREG32(mmINTERRUPT_CNTL);
114	/* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
115	 * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
116	 */
117	interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_DUMMY_RD_OVERRIDE, 0);
118	/* INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
119	interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_REQ_NONSNOOP_EN, 0);
120	WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
121
122	/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
123	WREG32(mmIH_RB_BASE, ih->gpu_addr >> 8);
 
 
 
124
125	rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
126	ih_rb_cntl = REG_SET_FIELD(0, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
127	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
128	/* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
129	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
130	ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
131
132	if (adev->irq.msi_enabled)
133		ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM, 1);
134
135	WREG32(mmIH_RB_CNTL, ih_rb_cntl);
136
137	/* set the writeback address whether it's enabled or not */
138	WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
139	WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
 
 
 
 
140
141	/* set rptr, wptr to 0 */
142	WREG32(mmIH_RB_RPTR, 0);
143	WREG32(mmIH_RB_WPTR, 0);
144
145	ih_doorbell_rtpr = RREG32(mmIH_DOORBELL_RPTR);
146	if (adev->irq.ih.use_doorbell) {
147		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
148						 OFFSET, adev->irq.ih.doorbell_index);
149		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
150						 ENABLE, 1);
151	} else {
152		ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
153						 ENABLE, 0);
154	}
155	WREG32(mmIH_DOORBELL_RPTR, ih_doorbell_rtpr);
156
157	pci_set_master(adev->pdev);
158
159	/* enable interrupts */
160	tonga_ih_enable_interrupts(adev);
161
162	return 0;
163}
164
165/**
166 * tonga_ih_irq_disable - disable interrupts
167 *
168 * @adev: amdgpu_device pointer
169 *
170 * Disable interrupts on the hw (VI).
171 */
172static void tonga_ih_irq_disable(struct amdgpu_device *adev)
173{
174	tonga_ih_disable_interrupts(adev);
175
176	/* Wait and acknowledge irq */
177	mdelay(1);
178}
179
180/**
181 * tonga_ih_get_wptr - get the IH ring buffer wptr
182 *
183 * @adev: amdgpu_device pointer
184 * @ih: IH ring buffer to fetch wptr
185 *
186 * Get the IH ring buffer wptr from either the register
187 * or the writeback memory buffer (VI).  Also check for
188 * ring buffer overflow and deal with it.
189 * Used by cz_irq_process(VI).
190 * Returns the value of the wptr.
191 */
192static u32 tonga_ih_get_wptr(struct amdgpu_device *adev,
193			     struct amdgpu_ih_ring *ih)
194{
195	u32 wptr, tmp;
196
197	wptr = le32_to_cpu(*ih->wptr_cpu);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
199	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
200		goto out;
 
 
 
 
 
 
 
 
 
201
202	/* Double check that the overflow wasn't already cleared. */
203	wptr = RREG32(mmIH_RB_WPTR);
204
205	if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
206		goto out;
207
208	wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
209
210	/* When a ring buffer overflow happen start parsing interrupt
211	 * from the last not overwritten vector (wptr + 16). Hopefully
212	 * this should allow us to catchup.
213	 */
214
215	dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
216		wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
217	ih->rptr = (wptr + 16) & ih->ptr_mask;
218	tmp = RREG32(mmIH_RB_CNTL);
219	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
220	WREG32(mmIH_RB_CNTL, tmp);
221
222	/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
223	 * can be detected.
224	 */
225	tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
226	WREG32(mmIH_RB_CNTL, tmp);
227
228out:
229	return (wptr & ih->ptr_mask);
230}
231
232/**
233 * tonga_ih_decode_iv - decode an interrupt vector
234 *
235 * @adev: amdgpu_device pointer
236 * @ih: IH ring buffer to decode
237 * @entry: IV entry to place decoded information into
238 *
239 * Decodes the interrupt vector at the current rptr
240 * position and also advance the position.
241 */
242static void tonga_ih_decode_iv(struct amdgpu_device *adev,
243			       struct amdgpu_ih_ring *ih,
244			       struct amdgpu_iv_entry *entry)
245{
246	/* wptr/rptr are in bytes! */
247	u32 ring_index = ih->rptr >> 2;
248	uint32_t dw[4];
249
250	dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
251	dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
252	dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
253	dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
254
255	entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
256	entry->src_id = dw[0] & 0xff;
257	entry->src_data[0] = dw[1] & 0xfffffff;
258	entry->ring_id = dw[2] & 0xff;
259	entry->vmid = (dw[2] >> 8) & 0xff;
260	entry->pasid = (dw[2] >> 16) & 0xffff;
261
262	/* wptr/rptr are in bytes! */
263	ih->rptr += 16;
264}
265
266/**
267 * tonga_ih_set_rptr - set the IH ring buffer rptr
268 *
269 * @adev: amdgpu_device pointer
270 * @ih: IH ring buffer to set rptr
271 *
272 * Set the IH ring buffer rptr.
273 */
274static void tonga_ih_set_rptr(struct amdgpu_device *adev,
275			      struct amdgpu_ih_ring *ih)
276{
277	if (ih->use_doorbell) {
278		/* XXX check if swapping is necessary on BE */
279		*ih->rptr_cpu = ih->rptr;
280		WDOORBELL32(ih->doorbell_index, ih->rptr);
 
 
 
281	} else {
282		WREG32(mmIH_RB_RPTR, ih->rptr);
283	}
284}
285
286static int tonga_ih_early_init(struct amdgpu_ip_block *ip_block)
287{
288	struct amdgpu_device *adev = ip_block->adev;
289	int ret;
290
291	ret = amdgpu_irq_add_domain(adev);
292	if (ret)
293		return ret;
294
295	tonga_ih_set_interrupt_funcs(adev);
296
297	return 0;
298}
299
300static int tonga_ih_sw_init(struct amdgpu_ip_block *ip_block)
301{
302	int r;
303	struct amdgpu_device *adev = ip_block->adev;
304
305	r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, true);
306	if (r)
307		return r;
308
309	adev->irq.ih.use_doorbell = true;
310	adev->irq.ih.doorbell_index = adev->doorbell_index.ih;
311
312	r = amdgpu_irq_init(adev);
313
314	return r;
315}
316
317static int tonga_ih_sw_fini(struct amdgpu_ip_block *ip_block)
318{
319	struct amdgpu_device *adev = ip_block->adev;
320
321	amdgpu_irq_fini_sw(adev);
 
322	amdgpu_irq_remove_domain(adev);
323
324	return 0;
325}
326
327static int tonga_ih_hw_init(struct amdgpu_ip_block *ip_block)
328{
329	int r;
330	struct amdgpu_device *adev = ip_block->adev;
331
332	r = tonga_ih_irq_init(adev);
333	if (r)
334		return r;
335
336	return 0;
337}
338
339static int tonga_ih_hw_fini(struct amdgpu_ip_block *ip_block)
340{
341	tonga_ih_irq_disable(ip_block->adev);
 
 
342
343	return 0;
344}
345
346static int tonga_ih_suspend(struct amdgpu_ip_block *ip_block)
347{
348	return tonga_ih_hw_fini(ip_block);
 
 
349}
350
351static int tonga_ih_resume(struct amdgpu_ip_block *ip_block)
352{
353	return tonga_ih_hw_init(ip_block);
 
 
354}
355
356static bool tonga_ih_is_idle(void *handle)
357{
358	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
359	u32 tmp = RREG32(mmSRBM_STATUS);
360
361	if (REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
362		return false;
363
364	return true;
365}
366
367static int tonga_ih_wait_for_idle(struct amdgpu_ip_block *ip_block)
368{
369	unsigned i;
370	u32 tmp;
371	struct amdgpu_device *adev = ip_block->adev;
372
373	for (i = 0; i < adev->usec_timeout; i++) {
374		/* read MC_STATUS */
375		tmp = RREG32(mmSRBM_STATUS);
376		if (!REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
377			return 0;
378		udelay(1);
379	}
380	return -ETIMEDOUT;
381}
382
383static bool tonga_ih_check_soft_reset(struct amdgpu_ip_block *ip_block)
384{
385	struct amdgpu_device *adev = ip_block->adev;
386	u32 srbm_soft_reset = 0;
387	u32 tmp = RREG32(mmSRBM_STATUS);
388
389	if (tmp & SRBM_STATUS__IH_BUSY_MASK)
390		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
391						SOFT_RESET_IH, 1);
392
393	if (srbm_soft_reset) {
394		adev->irq.srbm_soft_reset = srbm_soft_reset;
395		return true;
396	} else {
397		adev->irq.srbm_soft_reset = 0;
398		return false;
399	}
400}
401
402static int tonga_ih_pre_soft_reset(struct amdgpu_ip_block *ip_block)
403{
404	if (!ip_block->adev->irq.srbm_soft_reset)
 
 
405		return 0;
406
407	return tonga_ih_hw_fini(ip_block);
408}
409
410static int tonga_ih_post_soft_reset(struct amdgpu_ip_block *ip_block)
411{
412	struct amdgpu_device *adev = ip_block->adev;
413
414	if (!adev->irq.srbm_soft_reset)
415		return 0;
416
417	return tonga_ih_hw_init(ip_block);
418}
419
420static int tonga_ih_soft_reset(struct amdgpu_ip_block *ip_block)
421{
422	struct amdgpu_device *adev = ip_block->adev;
423	u32 srbm_soft_reset;
424
425	if (!adev->irq.srbm_soft_reset)
426		return 0;
427	srbm_soft_reset = adev->irq.srbm_soft_reset;
428
429	if (srbm_soft_reset) {
430		u32 tmp;
431
432		tmp = RREG32(mmSRBM_SOFT_RESET);
433		tmp |= srbm_soft_reset;
434		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
435		WREG32(mmSRBM_SOFT_RESET, tmp);
436		tmp = RREG32(mmSRBM_SOFT_RESET);
437
438		udelay(50);
439
440		tmp &= ~srbm_soft_reset;
441		WREG32(mmSRBM_SOFT_RESET, tmp);
442		tmp = RREG32(mmSRBM_SOFT_RESET);
443
444		/* Wait a little for things to settle down */
445		udelay(50);
446	}
447
448	return 0;
449}
450
451static int tonga_ih_set_clockgating_state(void *handle,
452					  enum amd_clockgating_state state)
453{
454	return 0;
455}
456
457static int tonga_ih_set_powergating_state(void *handle,
458					  enum amd_powergating_state state)
459{
460	return 0;
461}
462
463static const struct amd_ip_funcs tonga_ih_ip_funcs = {
464	.name = "tonga_ih",
465	.early_init = tonga_ih_early_init,
 
466	.sw_init = tonga_ih_sw_init,
467	.sw_fini = tonga_ih_sw_fini,
468	.hw_init = tonga_ih_hw_init,
469	.hw_fini = tonga_ih_hw_fini,
470	.suspend = tonga_ih_suspend,
471	.resume = tonga_ih_resume,
472	.is_idle = tonga_ih_is_idle,
473	.wait_for_idle = tonga_ih_wait_for_idle,
474	.check_soft_reset = tonga_ih_check_soft_reset,
475	.pre_soft_reset = tonga_ih_pre_soft_reset,
476	.soft_reset = tonga_ih_soft_reset,
477	.post_soft_reset = tonga_ih_post_soft_reset,
478	.set_clockgating_state = tonga_ih_set_clockgating_state,
479	.set_powergating_state = tonga_ih_set_powergating_state,
480};
481
482static const struct amdgpu_ih_funcs tonga_ih_funcs = {
483	.get_wptr = tonga_ih_get_wptr,
 
484	.decode_iv = tonga_ih_decode_iv,
485	.set_rptr = tonga_ih_set_rptr
486};
487
488static void tonga_ih_set_interrupt_funcs(struct amdgpu_device *adev)
489{
490	adev->irq.ih_funcs = &tonga_ih_funcs;
 
491}
492
493const struct amdgpu_ip_block_version tonga_ih_ip_block = {
 
494	.type = AMD_IP_BLOCK_TYPE_IH,
495	.major = 3,
496	.minor = 0,
497	.rev = 0,
498	.funcs = &tonga_ih_ip_funcs,
499};