xref: /illumos-gate/usr/src/uts/i86pc/io/amd_iommu/amd_iommu_log.c (revision 6732dbb379bf754b70168b01ba56793737f9f3e7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/sunddi.h>
28 #include <sys/amd_iommu.h>
29 #include "amd_iommu_impl.h"
30 #include "amd_iommu_log.h"
31 
32 
33 static const char *
get_hw_error(uint8_t type)34 get_hw_error(uint8_t type)
35 {
36 	const char *hwerr;
37 
38 	switch (type) {
39 	case 0:
40 		hwerr = "Reserved";
41 		break;
42 	case 1:
43 		hwerr = "Master Abort";
44 		break;
45 	case 2:
46 		hwerr = "Target Abort";
47 		break;
48 	case 3:
49 		hwerr = "Data Error";
50 		break;
51 	default:
52 		hwerr = "Unknown";
53 		break;
54 	}
55 
56 	return (hwerr);
57 }
58 
59 const char *
get_illegal_req(uint8_t type,uint8_t TR)60 get_illegal_req(uint8_t type, uint8_t TR)
61 {
62 	const char *illreq;
63 
64 	switch (type) {
65 	case 0:
66 		illreq = (TR == 1) ? "Translation I=0/V=0/V=1&&TV=0" :
67 		    "Read or Non-posted Write in INTR Range";
68 		break;
69 	case 1:
70 		illreq = (TR == 1) ? "Translation INTR/Port-IO/SysMgt; OR"
71 		    "Translation when SysMgt=11b/Port-IO when IOCTL=10b "
72 		    "while V=1 && TV=0" :
73 		    "Pre-translated transaction from device with I=0 or V=0";
74 		break;
75 	case 2:
76 		illreq = (TR == 1) ? "Reserved":
77 		    "Port-IO transaction for device with IoCtl = 00b";
78 		break;
79 	case 3:
80 		illreq = (TR == 1) ? "Reserved":
81 		    "Posted write to SysMgt with device SysMgt=00b "
82 		    "OR SysMgt=10b && message not INTx "
83 		    "OR Posted write to addr transaltion range with "
84 		    "HtAtsResv=1";
85 		break;
86 	case 4:
87 		illreq = (TR == 1) ? "Reserved":
88 		    "Read request or non-posted write in SysMgt with "
89 		    "device SysMgt=10b or 0xb"
90 		    "OR Read request or non-posted write in "
91 		    "addr translation range with HtAtsResv=1";
92 		break;
93 	case 5:
94 		illreq = (TR == 1) ? "Reserved":
95 		    "Posted write to Interrupt/EOI Range "
96 		    "for device that has IntCtl=00b";
97 		break;
98 	case 6:
99 		illreq = (TR == 1) ? "Reserved":
100 		    "Posted write to reserved Interrupt Address Range";
101 		break;
102 	case 7:
103 		illreq = (TR == 1) ? "Reserved":
104 		    "transaction to SysMgt when SysMgt=11b OR "
105 		    "transaction to Port-IO when IoCtl=10b while "
106 		    "while V=1 TV=0";
107 		break;
108 	default:
109 		illreq = "Unknown error";
110 		break;
111 	}
112 	return (illreq);
113 }
114 
115 static void
devtab_illegal_entry(amd_iommu_t * iommu,uint32_t * event)116 devtab_illegal_entry(amd_iommu_t *iommu, uint32_t *event)
117 {
118 	uint16_t deviceid;
119 	uint8_t TR;
120 	uint8_t RZ;
121 	uint8_t RW;
122 	uint8_t I;
123 	uint32_t vaddr_lo;
124 	uint32_t vaddr_hi;
125 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
126 	int instance = ddi_get_instance(iommu->aiomt_dip);
127 	const char *f = "devtab_illegal_entry";
128 
129 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
130 	    AMD_IOMMU_EVENT_DEVTAB_ILLEGAL_ENTRY);
131 
132 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
133 	    AMD_IOMMU_EVENT_DEVTAB_ILL_DEVICEID);
134 
135 	TR = AMD_IOMMU_REG_GET32(&event[1],
136 	    AMD_IOMMU_EVENT_DEVTAB_ILL_TR);
137 
138 	RZ = AMD_IOMMU_REG_GET32(&event[1],
139 	    AMD_IOMMU_EVENT_DEVTAB_ILL_RZ);
140 
141 	RW = AMD_IOMMU_REG_GET32(&event[1],
142 	    AMD_IOMMU_EVENT_DEVTAB_ILL_RW);
143 
144 	I = AMD_IOMMU_REG_GET32(&event[1],
145 	    AMD_IOMMU_EVENT_DEVTAB_ILL_INTR);
146 
147 	vaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
148 	    AMD_IOMMU_EVENT_DEVTAB_ILL_VADDR_LO);
149 
150 	vaddr_hi = event[3];
151 
152 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. Illegal device table entry "
153 	    "deviceid=%u, %s request, %s %s transaction, %s request, "
154 	    "virtual address = %p",
155 	    f, driver, instance, iommu->aiomt_idx,
156 	    deviceid,
157 	    TR == 1 ? "Translation" : "Transaction",
158 	    RZ == 1 ? "Non-zero reserved bit" : "Illegal Level encoding",
159 	    RW == 1 ? "Write" : "Read",
160 	    I == 1 ? "Interrupt" : "Memory",
161 	    (void *)(uintptr_t)(((uint64_t)vaddr_hi) << 32 | vaddr_lo));
162 }
163 
164 static void
io_page_fault(amd_iommu_t * iommu,uint32_t * event)165 io_page_fault(amd_iommu_t *iommu, uint32_t *event)
166 {
167 	uint16_t deviceid;
168 	uint16_t domainid;
169 	uint8_t TR;
170 	uint8_t RZ;
171 	uint8_t RW;
172 	uint8_t PE;
173 	uint8_t PR;
174 	uint8_t I;
175 	uint32_t vaddr_lo;
176 	uint32_t vaddr_hi;
177 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
178 	int instance = ddi_get_instance(iommu->aiomt_dip);
179 	const char *f = "io_page_fault";
180 
181 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
182 	    AMD_IOMMU_EVENT_IO_PAGE_FAULT);
183 
184 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
185 	    AMD_IOMMU_EVENT_IO_PGFAULT_DEVICEID);
186 
187 	TR = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_TR);
188 
189 	RZ = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_RZ);
190 
191 	PE = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_PE);
192 
193 	RW = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_RW);
194 
195 	PR = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_PR);
196 
197 	I = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_IO_PGFAULT_INTR);
198 
199 	domainid = AMD_IOMMU_REG_GET32(&event[1],
200 	    AMD_IOMMU_EVENT_IO_PGFAULT_DOMAINID);
201 
202 	vaddr_lo = event[2];
203 
204 	vaddr_hi = event[3];
205 
206 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. IO Page Fault. "
207 	    "deviceid=%u, %s request, %s, %s permissions, %s transaction, "
208 	    "%s, %s request, domainid=%u, virtual address = %p",
209 	    f, driver, instance, iommu->aiomt_idx,
210 	    deviceid,
211 	    TR == 1 ? "Translation" : "Transaction",
212 	    RZ == 1 ? "Non-zero reserved bit" : "Illegal Level encoding",
213 	    PE == 1 ? "did not have" : "had",
214 	    RW == 1 ? "Write" : "Read",
215 	    PR == 1 ? "Page present or Interrupt Remapped" :
216 	    "Page not present or Interrupt Blocked",
217 	    I == 1 ? "Interrupt" : "Memory",
218 	    domainid,
219 	    (void *)(uintptr_t)(((uint64_t)vaddr_hi) << 32 | vaddr_lo));
220 }
221 
222 static void
devtab_hw_error(amd_iommu_t * iommu,uint32_t * event)223 devtab_hw_error(amd_iommu_t *iommu, uint32_t *event)
224 {
225 	uint16_t deviceid;
226 	uint8_t type;
227 	uint8_t TR;
228 	uint8_t RW;
229 	uint8_t I;
230 	uint32_t physaddr_lo;
231 	uint32_t physaddr_hi;
232 	const char *hwerr;
233 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
234 	int instance = ddi_get_instance(iommu->aiomt_dip);
235 	const char *f = "devtab_hw_error";
236 
237 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
238 	    AMD_IOMMU_EVENT_DEVTAB_HW_ERROR);
239 
240 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
241 	    AMD_IOMMU_EVENT_DEVTAB_HWERR_DEVICEID);
242 
243 	type = AMD_IOMMU_REG_GET32(&event[1],
244 	    AMD_IOMMU_EVENT_DEVTAB_HWERR_TYPE);
245 
246 	hwerr = get_hw_error(type);
247 
248 	TR = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_DEVTAB_HWERR_TR);
249 
250 	RW = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_DEVTAB_HWERR_RW);
251 
252 	I = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_DEVTAB_HWERR_INTR);
253 
254 	physaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
255 	    AMD_IOMMU_EVENT_DEVTAB_HWERR_PHYSADDR_LO);
256 
257 	physaddr_hi = event[3];
258 
259 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. Device Table HW Error. "
260 	    "deviceid=%u, HW error type: %s, %s request, %s transaction, "
261 	    "%s request, physical address = %p",
262 	    f, driver, instance, iommu->aiomt_idx,
263 	    deviceid, hwerr,
264 	    TR == 1 ? "Translation" : "Transaction",
265 	    RW == 1 ? "Write" : "Read",
266 	    I == 1 ? "Interrupt" : "Memory",
267 	    (void *)(uintptr_t)(((uint64_t)physaddr_hi) << 32 | physaddr_lo));
268 }
269 
270 
271 static void
pgtable_hw_error(amd_iommu_t * iommu,uint32_t * event)272 pgtable_hw_error(amd_iommu_t *iommu, uint32_t *event)
273 {
274 	uint16_t deviceid;
275 	uint16_t domainid;
276 	uint8_t type;
277 	uint8_t TR;
278 	uint8_t RW;
279 	uint8_t I;
280 	uint32_t physaddr_lo;
281 	uint32_t physaddr_hi;
282 	const char *hwerr;
283 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
284 	int instance = ddi_get_instance(iommu->aiomt_dip);
285 	const char *f = "pgtable_hw_error";
286 
287 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
288 	    AMD_IOMMU_EVENT_PGTABLE_HW_ERROR);
289 
290 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
291 	    AMD_IOMMU_EVENT_PGTABLE_HWERR_DEVICEID);
292 
293 	type = AMD_IOMMU_REG_GET32(&event[1],
294 	    AMD_IOMMU_EVENT_DEVTAB_HWERR_TYPE);
295 
296 	hwerr = get_hw_error(type);
297 
298 	TR = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_PGTABLE_HWERR_TR);
299 
300 	RW = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_PGTABLE_HWERR_RW);
301 
302 	I = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_PGTABLE_HWERR_INTR);
303 
304 	domainid = AMD_IOMMU_REG_GET32(&event[1],
305 	    AMD_IOMMU_EVENT_PGTABLE_HWERR_DOMAINID);
306 
307 	physaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
308 	    AMD_IOMMU_EVENT_PGTABLE_HWERR_PHYSADDR_LO);
309 
310 	physaddr_hi = event[3];
311 
312 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. Page Table HW Error. "
313 	    "deviceid=%u, HW error type: %s, %s request, %s transaction, "
314 	    "%s request, domainid=%u, physical address = %p",
315 	    f, driver, instance, iommu->aiomt_idx,
316 	    deviceid, hwerr,
317 	    TR == 1 ? "Translation" : "Transaction",
318 	    RW == 1 ? "Write" : "Read",
319 	    I == 1 ? "Interrupt" : "Memory",
320 	    domainid,
321 	    (void *)(uintptr_t)(((uint64_t)physaddr_hi) << 32 | physaddr_lo));
322 }
323 
324 static void
cmdbuf_illegal_cmd(amd_iommu_t * iommu,uint32_t * event)325 cmdbuf_illegal_cmd(amd_iommu_t *iommu, uint32_t *event)
326 {
327 	uint32_t physaddr_lo;
328 	uint32_t physaddr_hi;
329 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
330 	int instance = ddi_get_instance(iommu->aiomt_dip);
331 	const char *f = "cmdbuf_illegal_cmd";
332 
333 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
334 	    AMD_IOMMU_EVENT_CMDBUF_ILLEGAL_CMD);
335 
336 	physaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
337 	    AMD_IOMMU_EVENT_CMDBUF_ILLEGAL_CMD_PHYS_LO);
338 
339 	physaddr_hi = event[3];
340 
341 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. Illegal IOMMU command. "
342 	    "command physical address = %p",
343 	    f, driver, instance, iommu->aiomt_idx,
344 	    (void *)(uintptr_t)(((uint64_t)physaddr_hi) << 32 | physaddr_lo));
345 }
346 
347 static void
cmdbuf_hw_error(amd_iommu_t * iommu,uint32_t * event)348 cmdbuf_hw_error(amd_iommu_t *iommu, uint32_t *event)
349 {
350 	uint32_t physaddr_lo;
351 	uint32_t physaddr_hi;
352 	uint8_t type;
353 	const char *hwerr;
354 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
355 	int instance = ddi_get_instance(iommu->aiomt_dip);
356 	const char *f = "cmdbuf_hw_error";
357 
358 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
359 	    AMD_IOMMU_EVENT_CMDBUF_HW_ERROR);
360 
361 	type = AMD_IOMMU_REG_GET32(&event[1],
362 	    AMD_IOMMU_EVENT_CMDBUF_HWERR_TYPE);
363 
364 	hwerr = get_hw_error(type);
365 
366 	physaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
367 	    AMD_IOMMU_EVENT_CMDBUF_HWERR_PHYS_LO);
368 
369 	physaddr_hi = event[3];
370 
371 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. Command Buffer HW error. "
372 	    "HW error type = %s, command buffer physical address = %p",
373 	    f, driver, instance, iommu->aiomt_idx,
374 	    hwerr,
375 	    (void *)(uintptr_t)(((uint64_t)physaddr_hi) << 32 | physaddr_lo));
376 }
377 
378 static void
iotlb_inval_to(amd_iommu_t * iommu,uint32_t * event)379 iotlb_inval_to(amd_iommu_t *iommu, uint32_t *event)
380 {
381 	uint16_t deviceid;
382 	uint32_t physaddr_lo;
383 	uint32_t physaddr_hi;
384 	uint8_t type;
385 	const char *hwerr;
386 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
387 	int instance = ddi_get_instance(iommu->aiomt_dip);
388 	const char *f = "iotlb_inval_to";
389 
390 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
391 	    AMD_IOMMU_EVENT_IOTLB_INVAL_TO);
392 
393 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
394 	    AMD_IOMMU_EVENT_IOTLB_INVAL_TO_DEVICEID);
395 
396 	/*
397 	 * XXX bug in spec. Is the type field available +04 26:25 or is
398 	 * it reserved
399 	 */
400 	type = AMD_IOMMU_REG_GET32(&event[1],
401 	    AMD_IOMMU_EVENT_IOTLB_INVAL_TO_TYPE);
402 	hwerr = get_hw_error(type);
403 
404 	physaddr_lo = AMD_IOMMU_REG_GET32(&event[2],
405 	    AMD_IOMMU_EVENT_IOTLB_INVAL_TO_PHYS_LO);
406 
407 	physaddr_hi = event[3];
408 
409 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. deviceid = %u "
410 	    "IOTLB invalidation Timeout. "
411 	    "HW error type = %s, invalidation command physical address = %p",
412 	    f, driver, instance, iommu->aiomt_idx, deviceid,
413 	    hwerr,
414 	    (void *)(uintptr_t)(((uint64_t)physaddr_hi) << 32 | physaddr_lo));
415 }
416 
417 static void
device_illegal_req(amd_iommu_t * iommu,uint32_t * event)418 device_illegal_req(amd_iommu_t *iommu, uint32_t *event)
419 {
420 	uint16_t deviceid;
421 	uint8_t TR;
422 	uint32_t addr_lo;
423 	uint32_t addr_hi;
424 	uint8_t type;
425 	const char *reqerr;
426 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
427 	int instance = ddi_get_instance(iommu->aiomt_dip);
428 	const char *f = "device_illegal_req";
429 
430 	ASSERT(AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE) ==
431 	    AMD_IOMMU_EVENT_DEVICE_ILLEGAL_REQ);
432 
433 	deviceid = AMD_IOMMU_REG_GET32(&event[0],
434 	    AMD_IOMMU_EVENT_DEVICE_ILLEGAL_REQ_DEVICEID);
435 
436 	TR = AMD_IOMMU_REG_GET32(&event[1],
437 	    AMD_IOMMU_EVENT_DEVICE_ILLEGAL_REQ_TR);
438 
439 	type = AMD_IOMMU_REG_GET32(&event[1],
440 	    AMD_IOMMU_EVENT_DEVICE_ILLEGAL_REQ_TYPE);
441 
442 	reqerr = get_illegal_req(type, TR);
443 
444 
445 	addr_lo = event[2];
446 	addr_hi = event[3];
447 
448 	cmn_err(CE_WARN, "%s: %s%d: idx = %d. deviceid = %d "
449 	    "Illegal Device Request. "
450 	    "Illegal Request type = %s, %s request, address accessed = %p",
451 	    f, driver, instance, iommu->aiomt_idx, deviceid,
452 	    reqerr,
453 	    TR == 1 ? "Translation" : "Transaction",
454 	    (void *)(uintptr_t)(((uint64_t)addr_hi) << 32 | addr_lo));
455 }
456 
457 static void
amd_iommu_process_one_event(amd_iommu_t * iommu)458 amd_iommu_process_one_event(amd_iommu_t *iommu)
459 {
460 	uint32_t event[4];
461 	amd_iommu_event_t event_type;
462 	int i;
463 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
464 	int instance = ddi_get_instance(iommu->aiomt_dip);
465 	const char *f = "amd_iommu_process_one_event";
466 
467 	ASSERT(MUTEX_HELD(&iommu->aiomt_eventlock));
468 
469 	SYNC_FORKERN(iommu->aiomt_dmahdl);
470 	for (i = 0; i < 4; i++) {
471 		event[i] =  iommu->aiomt_event_head[i];
472 	}
473 
474 	event_type = AMD_IOMMU_REG_GET32(&event[1], AMD_IOMMU_EVENT_TYPE);
475 
476 	switch (event_type) {
477 	case AMD_IOMMU_EVENT_DEVTAB_ILLEGAL_ENTRY:
478 		devtab_illegal_entry(iommu, event);
479 		break;
480 	case AMD_IOMMU_EVENT_IO_PAGE_FAULT:
481 		io_page_fault(iommu, event);
482 		break;
483 	case AMD_IOMMU_EVENT_DEVTAB_HW_ERROR:
484 		devtab_hw_error(iommu, event);
485 		break;
486 	case AMD_IOMMU_EVENT_PGTABLE_HW_ERROR:
487 		pgtable_hw_error(iommu, event);
488 		break;
489 	case AMD_IOMMU_EVENT_CMDBUF_HW_ERROR:
490 		cmdbuf_hw_error(iommu, event);
491 		break;
492 	case AMD_IOMMU_EVENT_CMDBUF_ILLEGAL_CMD:
493 		cmdbuf_illegal_cmd(iommu, event);
494 		break;
495 	case AMD_IOMMU_EVENT_IOTLB_INVAL_TO:
496 		iotlb_inval_to(iommu, event);
497 		break;
498 	case AMD_IOMMU_EVENT_DEVICE_ILLEGAL_REQ:
499 		device_illegal_req(iommu, event);
500 		break;
501 	default:
502 		cmn_err(CE_WARN, "%s: %s%d: idx = %d. Unknown event: %u",
503 		    f, driver, instance, iommu->aiomt_idx, event_type);
504 		break;
505 	}
506 }
507 
508 int
amd_iommu_read_log(amd_iommu_t * iommu,amd_iommu_log_op_t op)509 amd_iommu_read_log(amd_iommu_t *iommu, amd_iommu_log_op_t op)
510 {
511 	caddr_t evtail;
512 	uint64_t evtail_off;
513 	uint64_t evhead_off;
514 
515 	ASSERT(op != AMD_IOMMU_LOG_INVALID_OP);
516 
517 	mutex_enter(&iommu->aiomt_eventlock);
518 
519 	ASSERT(iommu->aiomt_event_head != NULL);
520 
521 	/* XXX verify */
522 	evtail_off = AMD_IOMMU_REG_GET64(
523 	    REGADDR64(iommu->aiomt_reg_eventlog_tail_va),
524 	    AMD_IOMMU_EVENTTAILPTR);
525 
526 	evtail_off = EV2OFF(evtail_off);
527 
528 	ASSERT(evtail_off <  iommu->aiomt_eventlog_sz);
529 
530 	evtail = iommu->aiomt_eventlog + evtail_off;
531 
532 	if (op == AMD_IOMMU_LOG_DISCARD) {
533 		/*LINTED*/
534 		iommu->aiomt_event_head = (uint32_t *)evtail;
535 		AMD_IOMMU_REG_SET64(REGADDR64(
536 		    iommu->aiomt_reg_eventlog_head_va),
537 		    AMD_IOMMU_EVENTHEADPTR, OFF2EV(evtail_off));
538 		cmn_err(CE_NOTE, "Discarded IOMMU event log");
539 		mutex_exit(&iommu->aiomt_eventlock);
540 		return (DDI_SUCCESS);
541 	}
542 
543 	/*LINTED*/
544 	while (1) {
545 		if ((caddr_t)iommu->aiomt_event_head == evtail)
546 			break;
547 
548 		cmn_err(CE_WARN, "evtail_off = %p, head = %p, tail = %p",
549 		    (void *)(uintptr_t)evtail_off,
550 		    (void *)iommu->aiomt_event_head,
551 		    (void *)evtail);
552 
553 		amd_iommu_process_one_event(iommu);
554 
555 		/*
556 		 * Update the head pointer in soft state
557 		 * and the head pointer register
558 		 */
559 		iommu->aiomt_event_head += 4;
560 		if ((caddr_t)iommu->aiomt_event_head >=
561 		    iommu->aiomt_eventlog + iommu->aiomt_eventlog_sz) {
562 			/* wraparound */
563 			iommu->aiomt_event_head =
564 			/*LINTED*/
565 			    (uint32_t *)iommu->aiomt_eventlog;
566 			evhead_off = 0;
567 		} else {
568 			evhead_off =  (caddr_t)iommu->aiomt_event_head
569 			/*LINTED*/
570 			    - iommu->aiomt_eventlog;
571 		}
572 
573 		ASSERT(evhead_off < iommu->aiomt_eventlog_sz);
574 
575 		AMD_IOMMU_REG_SET64(REGADDR64(
576 		    iommu->aiomt_reg_eventlog_head_va),
577 		    AMD_IOMMU_EVENTHEADPTR, OFF2EV(evhead_off));
578 	}
579 	mutex_exit(&iommu->aiomt_eventlock);
580 
581 	return (DDI_SUCCESS);
582 }
583