xref: /onnv-gate/usr/src/uts/i86pc/io/amd_iommu/amd_iommu_cmd.c (revision 10566:b09132fd6cd8)
1*10535SVikram.Hegde@Sun.COM /*
2*10535SVikram.Hegde@Sun.COM  * CDDL HEADER START
3*10535SVikram.Hegde@Sun.COM  *
4*10535SVikram.Hegde@Sun.COM  * The contents of this file are subject to the terms of the
5*10535SVikram.Hegde@Sun.COM  * Common Development and Distribution License (the "License").
6*10535SVikram.Hegde@Sun.COM  * You may not use this file except in compliance with the License.
7*10535SVikram.Hegde@Sun.COM  *
8*10535SVikram.Hegde@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10535SVikram.Hegde@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10535SVikram.Hegde@Sun.COM  * See the License for the specific language governing permissions
11*10535SVikram.Hegde@Sun.COM  * and limitations under the License.
12*10535SVikram.Hegde@Sun.COM  *
13*10535SVikram.Hegde@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10535SVikram.Hegde@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10535SVikram.Hegde@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10535SVikram.Hegde@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10535SVikram.Hegde@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10535SVikram.Hegde@Sun.COM  *
19*10535SVikram.Hegde@Sun.COM  * CDDL HEADER END
20*10535SVikram.Hegde@Sun.COM  */
21*10535SVikram.Hegde@Sun.COM 
22*10535SVikram.Hegde@Sun.COM /*
23*10535SVikram.Hegde@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10535SVikram.Hegde@Sun.COM  * Use is subject to license terms.
25*10535SVikram.Hegde@Sun.COM  */
26*10535SVikram.Hegde@Sun.COM 
27*10535SVikram.Hegde@Sun.COM #include <sys/sunddi.h>
28*10535SVikram.Hegde@Sun.COM #include <sys/amd_iommu.h>
29*10535SVikram.Hegde@Sun.COM #include "amd_iommu_impl.h"
30*10535SVikram.Hegde@Sun.COM 
31*10535SVikram.Hegde@Sun.COM extern int servicing_interrupt(void);
32*10535SVikram.Hegde@Sun.COM 
33*10535SVikram.Hegde@Sun.COM static void
amd_iommu_wait_for_completion(amd_iommu_t * iommu)34*10535SVikram.Hegde@Sun.COM amd_iommu_wait_for_completion(amd_iommu_t *iommu)
35*10535SVikram.Hegde@Sun.COM {
36*10535SVikram.Hegde@Sun.COM 	ASSERT(MUTEX_HELD(&iommu->aiomt_cmdlock));
37*10535SVikram.Hegde@Sun.COM 	while (AMD_IOMMU_REG_GET64(REGADDR64(
38*10535SVikram.Hegde@Sun.COM 	    iommu->aiomt_reg_status_va), AMD_IOMMU_COMWAIT_INT) != 1) {
39*10535SVikram.Hegde@Sun.COM 		AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
40*10535SVikram.Hegde@Sun.COM 		    AMD_IOMMU_CMDBUF_ENABLE, 1);
41*10535SVikram.Hegde@Sun.COM 		WAIT_SEC(1);
42*10535SVikram.Hegde@Sun.COM 	}
43*10535SVikram.Hegde@Sun.COM }
44*10535SVikram.Hegde@Sun.COM 
45*10535SVikram.Hegde@Sun.COM static int
create_compl_wait_cmd(amd_iommu_t * iommu,amd_iommu_cmdargs_t * cmdargsp,amd_iommu_cmd_flags_t flags,uint32_t * cmdptr)46*10535SVikram.Hegde@Sun.COM create_compl_wait_cmd(amd_iommu_t *iommu, amd_iommu_cmdargs_t *cmdargsp,
47*10535SVikram.Hegde@Sun.COM     amd_iommu_cmd_flags_t flags, uint32_t *cmdptr)
48*10535SVikram.Hegde@Sun.COM {
49*10535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
50*10535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(iommu->aiomt_dip);
51*10535SVikram.Hegde@Sun.COM 	const char *f = "create_compl_wait_cmd";
52*10535SVikram.Hegde@Sun.COM 
53*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdargsp == NULL);
54*10535SVikram.Hegde@Sun.COM 
55*10535SVikram.Hegde@Sun.COM 	if (flags & AMD_IOMMU_CMD_FLAGS_COMPL_WAIT_S) {
56*10535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: %s%d: idx=%d: 'store' completion "
57*10535SVikram.Hegde@Sun.COM 		    "not supported for completion wait command",
58*10535SVikram.Hegde@Sun.COM 		    f, driver, instance, iommu->aiomt_idx);
59*10535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
60*10535SVikram.Hegde@Sun.COM 	}
61*10535SVikram.Hegde@Sun.COM 
62*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_COMPL_WAIT_S, 0);
63*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_COMPL_WAIT_I, 1);
64*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_COMPL_WAIT_F,
65*10535SVikram.Hegde@Sun.COM 	    (flags & AMD_IOMMU_CMD_FLAGS_COMPL_WAIT_F) != 0);
66*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_COMPL_WAIT_STORE_ADDR_LO,
67*10535SVikram.Hegde@Sun.COM 	    0);
68*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_OPCODE, 0x01);
69*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_COMPL_WAIT_STORE_ADDR_HI,
70*10535SVikram.Hegde@Sun.COM 	    0);
71*10535SVikram.Hegde@Sun.COM 	cmdptr[2] = 0;
72*10535SVikram.Hegde@Sun.COM 	cmdptr[3] = 0;
73*10535SVikram.Hegde@Sun.COM 
74*10535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
75*10535SVikram.Hegde@Sun.COM }
76*10535SVikram.Hegde@Sun.COM 
77*10535SVikram.Hegde@Sun.COM static int
create_inval_devtab_entry_cmd(amd_iommu_t * iommu,amd_iommu_cmdargs_t * cmdargsp,amd_iommu_cmd_flags_t flags,uint32_t * cmdptr)78*10535SVikram.Hegde@Sun.COM create_inval_devtab_entry_cmd(amd_iommu_t *iommu, amd_iommu_cmdargs_t *cmdargsp,
79*10535SVikram.Hegde@Sun.COM     amd_iommu_cmd_flags_t flags, uint32_t *cmdptr)
80*10535SVikram.Hegde@Sun.COM {
81*10535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
82*10535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(iommu->aiomt_dip);
83*10535SVikram.Hegde@Sun.COM 	const char *f = "create_inval_devtab_entry_cmd";
84*10535SVikram.Hegde@Sun.COM 	uint16_t deviceid;
85*10535SVikram.Hegde@Sun.COM 
86*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdargsp);
87*10535SVikram.Hegde@Sun.COM 
88*10535SVikram.Hegde@Sun.COM 	if (flags != AMD_IOMMU_CMD_FLAGS_NONE) {
89*10535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: %s%d: idx=%d: invalidate devtab entry "
90*10535SVikram.Hegde@Sun.COM 		    "no flags supported", f, driver, instance,
91*10535SVikram.Hegde@Sun.COM 		    iommu->aiomt_idx);
92*10535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
93*10535SVikram.Hegde@Sun.COM 	}
94*10535SVikram.Hegde@Sun.COM 
95*10535SVikram.Hegde@Sun.COM 	deviceid = cmdargsp->ca_deviceid;
96*10535SVikram.Hegde@Sun.COM 
97*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_INVAL_DEVTAB_DEVICEID,
98*10535SVikram.Hegde@Sun.COM 	    deviceid);
99*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_OPCODE, 0x02);
100*10535SVikram.Hegde@Sun.COM 	cmdptr[2] = 0;
101*10535SVikram.Hegde@Sun.COM 	cmdptr[3] = 0;
102*10535SVikram.Hegde@Sun.COM 
103*10535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
104*10535SVikram.Hegde@Sun.COM }
105*10535SVikram.Hegde@Sun.COM 
106*10535SVikram.Hegde@Sun.COM /*ARGSUSED*/
107*10535SVikram.Hegde@Sun.COM static int
create_inval_iommu_pages_cmd(amd_iommu_t * iommu,amd_iommu_cmdargs_t * cmdargsp,amd_iommu_cmd_flags_t flags,uint32_t * cmdptr)108*10535SVikram.Hegde@Sun.COM create_inval_iommu_pages_cmd(amd_iommu_t *iommu, amd_iommu_cmdargs_t *cmdargsp,
109*10535SVikram.Hegde@Sun.COM     amd_iommu_cmd_flags_t flags, uint32_t *cmdptr)
110*10535SVikram.Hegde@Sun.COM {
111*10535SVikram.Hegde@Sun.COM 	uint32_t addr_lo;
112*10535SVikram.Hegde@Sun.COM 	uint32_t addr_hi;
113*10535SVikram.Hegde@Sun.COM 
114*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdargsp);
115*10535SVikram.Hegde@Sun.COM 
116*10535SVikram.Hegde@Sun.COM 	addr_lo = AMD_IOMMU_REG_GET64(REGADDR64(&cmdargsp->ca_addr),
117*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMD_INVAL_PAGES_ADDR_LO);
118*10535SVikram.Hegde@Sun.COM 	addr_hi = AMD_IOMMU_REG_GET64(REGADDR64(&cmdargsp->ca_addr),
119*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMD_INVAL_PAGES_ADDR_HI);
120*10535SVikram.Hegde@Sun.COM 
121*10535SVikram.Hegde@Sun.COM 	cmdptr[0] = 0;
122*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_INVAL_PAGES_DOMAINID,
123*10535SVikram.Hegde@Sun.COM 	    cmdargsp->ca_domainid);
124*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_OPCODE, 0x03);
125*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[2], AMD_IOMMU_CMD_INVAL_PAGES_PDE,
126*10535SVikram.Hegde@Sun.COM 	    (flags & AMD_IOMMU_CMD_FLAGS_PAGE_PDE_INVAL) != 0);
127*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[2], AMD_IOMMU_CMD_INVAL_PAGES_S,
128*10535SVikram.Hegde@Sun.COM 	    (flags & AMD_IOMMU_CMD_FLAGS_PAGE_INVAL_S) != 0);
129*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[2], AMD_IOMMU_CMD_INVAL_PAGES_ADDR_LO,
130*10535SVikram.Hegde@Sun.COM 	    addr_lo);
131*10535SVikram.Hegde@Sun.COM 	cmdptr[3] = addr_hi;
132*10535SVikram.Hegde@Sun.COM 
133*10535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
134*10535SVikram.Hegde@Sun.COM 
135*10535SVikram.Hegde@Sun.COM }
136*10535SVikram.Hegde@Sun.COM 
137*10535SVikram.Hegde@Sun.COM /*ARGSUSED*/
138*10535SVikram.Hegde@Sun.COM static int
create_inval_iotlb_pages_cmd(amd_iommu_t * iommu,amd_iommu_cmdargs_t * cmdargsp,amd_iommu_cmd_flags_t flags,uint32_t * cmdptr)139*10535SVikram.Hegde@Sun.COM create_inval_iotlb_pages_cmd(amd_iommu_t *iommu, amd_iommu_cmdargs_t *cmdargsp,
140*10535SVikram.Hegde@Sun.COM     amd_iommu_cmd_flags_t flags, uint32_t *cmdptr)
141*10535SVikram.Hegde@Sun.COM {
142*10535SVikram.Hegde@Sun.COM 	uint32_t addr_lo;
143*10535SVikram.Hegde@Sun.COM 	uint32_t addr_hi;
144*10535SVikram.Hegde@Sun.COM 
145*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdargsp);
146*10535SVikram.Hegde@Sun.COM 
147*10535SVikram.Hegde@Sun.COM 	addr_lo = AMD_IOMMU_REG_GET64(REGADDR64(&cmdargsp->ca_addr),
148*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMD_INVAL_IOTLB_ADDR_LO);
149*10535SVikram.Hegde@Sun.COM 
150*10535SVikram.Hegde@Sun.COM 	addr_hi = AMD_IOMMU_REG_GET64(REGADDR64(&cmdargsp->ca_addr),
151*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMD_INVAL_IOTLB_ADDR_HI);
152*10535SVikram.Hegde@Sun.COM 
153*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_INVAL_IOTLB_DEVICEID,
154*10535SVikram.Hegde@Sun.COM 	    cmdargsp->ca_deviceid);
155*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_INVAL_IOTLB_MAXPEND,
156*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_DEFAULT_MAXPEND);
157*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_OPCODE, 0x04);
158*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_INVAL_IOTLB_QUEUEID,
159*10535SVikram.Hegde@Sun.COM 	    cmdargsp->ca_deviceid);
160*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[2], AMD_IOMMU_CMD_INVAL_IOTLB_ADDR_LO,
161*10535SVikram.Hegde@Sun.COM 	    addr_lo);
162*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[2], AMD_IOMMU_CMD_INVAL_IOTLB_S,
163*10535SVikram.Hegde@Sun.COM 	    (flags & AMD_IOMMU_CMD_FLAGS_IOTLB_INVAL_S) != 0);
164*10535SVikram.Hegde@Sun.COM 	cmdptr[3] = addr_hi;
165*10535SVikram.Hegde@Sun.COM 
166*10535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
167*10535SVikram.Hegde@Sun.COM }
168*10535SVikram.Hegde@Sun.COM 
169*10535SVikram.Hegde@Sun.COM static int
create_inval_intr_table_cmd(amd_iommu_t * iommu,amd_iommu_cmdargs_t * cmdargsp,amd_iommu_cmd_flags_t flags,uint32_t * cmdptr)170*10535SVikram.Hegde@Sun.COM create_inval_intr_table_cmd(amd_iommu_t *iommu, amd_iommu_cmdargs_t *cmdargsp,
171*10535SVikram.Hegde@Sun.COM     amd_iommu_cmd_flags_t flags, uint32_t *cmdptr)
172*10535SVikram.Hegde@Sun.COM {
173*10535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
174*10535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(iommu->aiomt_dip);
175*10535SVikram.Hegde@Sun.COM 	const char *f = "create_inval_intr_table_cmd";
176*10535SVikram.Hegde@Sun.COM 
177*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdargsp);
178*10535SVikram.Hegde@Sun.COM 
179*10535SVikram.Hegde@Sun.COM 	if (flags != AMD_IOMMU_CMD_FLAGS_NONE) {
180*10535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: %s%d: idx=%d: flags not supported "
181*10535SVikram.Hegde@Sun.COM 		    "for invalidate interrupt table command",
182*10535SVikram.Hegde@Sun.COM 		    f, driver, instance, iommu->aiomt_idx);
183*10535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
184*10535SVikram.Hegde@Sun.COM 	}
185*10535SVikram.Hegde@Sun.COM 
186*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[0], AMD_IOMMU_CMD_INVAL_INTR_DEVICEID,
187*10535SVikram.Hegde@Sun.COM 	    cmdargsp->ca_deviceid);
188*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET32(&cmdptr[1], AMD_IOMMU_CMD_OPCODE, 0x05);
189*10535SVikram.Hegde@Sun.COM 	cmdptr[2] = 0;
190*10535SVikram.Hegde@Sun.COM 	cmdptr[3] = 0;
191*10535SVikram.Hegde@Sun.COM 
192*10535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
193*10535SVikram.Hegde@Sun.COM }
194*10535SVikram.Hegde@Sun.COM 
195*10535SVikram.Hegde@Sun.COM int
amd_iommu_cmd(amd_iommu_t * iommu,amd_iommu_cmd_t cmd,amd_iommu_cmdargs_t * cmdargs,amd_iommu_cmd_flags_t flags,int lock_held)196*10535SVikram.Hegde@Sun.COM amd_iommu_cmd(amd_iommu_t *iommu, amd_iommu_cmd_t cmd,
197*10535SVikram.Hegde@Sun.COM     amd_iommu_cmdargs_t *cmdargs, amd_iommu_cmd_flags_t flags, int lock_held)
198*10535SVikram.Hegde@Sun.COM {
199*10535SVikram.Hegde@Sun.COM 	int error;
200*10535SVikram.Hegde@Sun.COM 	int i;
201*10535SVikram.Hegde@Sun.COM 	uint32_t cmdptr[4] = {0};
202*10535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(iommu->aiomt_dip);
203*10535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(iommu->aiomt_dip);
204*10535SVikram.Hegde@Sun.COM 	uint64_t cmdhead_off;
205*10535SVikram.Hegde@Sun.COM 	uint64_t cmdtail_off;
206*10535SVikram.Hegde@Sun.COM 	const char *f = "amd_iommu_cmd";
207*10535SVikram.Hegde@Sun.COM 
208*10535SVikram.Hegde@Sun.COM 	ASSERT(lock_held == 0 || lock_held == 1);
209*10535SVikram.Hegde@Sun.COM 	ASSERT(lock_held == 0 || MUTEX_HELD(&iommu->aiomt_cmdlock));
210*10535SVikram.Hegde@Sun.COM 
211*10535SVikram.Hegde@Sun.COM 	if (!lock_held)
212*10535SVikram.Hegde@Sun.COM 		mutex_enter(&iommu->aiomt_cmdlock);
213*10535SVikram.Hegde@Sun.COM 
214*10535SVikram.Hegde@Sun.COM 	/*
215*10535SVikram.Hegde@Sun.COM 	 * Prepare the command
216*10535SVikram.Hegde@Sun.COM 	 */
217*10535SVikram.Hegde@Sun.COM 	switch (cmd) {
218*10535SVikram.Hegde@Sun.COM 	case AMD_IOMMU_CMD_COMPL_WAIT:
219*10535SVikram.Hegde@Sun.COM 		if (flags & AMD_IOMMU_CMD_FLAGS_COMPL_WAIT) {
220*10535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "%s: %s%d: idx=%d: No completion wait "
221*10535SVikram.Hegde@Sun.COM 			    " after completion wait command",
222*10535SVikram.Hegde@Sun.COM 			    f, driver, instance, iommu->aiomt_idx);
223*10535SVikram.Hegde@Sun.COM 			error = DDI_FAILURE;
224*10535SVikram.Hegde@Sun.COM 			goto out;
225*10535SVikram.Hegde@Sun.COM 		}
226*10535SVikram.Hegde@Sun.COM 		error = create_compl_wait_cmd(iommu, cmdargs, flags, cmdptr);
227*10535SVikram.Hegde@Sun.COM 		break;
228*10535SVikram.Hegde@Sun.COM 	case AMD_IOMMU_CMD_INVAL_DEVTAB_ENTRY:
229*10535SVikram.Hegde@Sun.COM 		error = create_inval_devtab_entry_cmd(iommu, cmdargs,
230*10535SVikram.Hegde@Sun.COM 		    flags & ~AMD_IOMMU_CMD_FLAGS_COMPL_WAIT, cmdptr);
231*10535SVikram.Hegde@Sun.COM 		break;
232*10535SVikram.Hegde@Sun.COM 	case AMD_IOMMU_CMD_INVAL_IOMMU_PAGES:
233*10535SVikram.Hegde@Sun.COM 		error = create_inval_iommu_pages_cmd(iommu, cmdargs,
234*10535SVikram.Hegde@Sun.COM 		    flags & ~AMD_IOMMU_CMD_FLAGS_COMPL_WAIT, cmdptr);
235*10535SVikram.Hegde@Sun.COM 		break;
236*10535SVikram.Hegde@Sun.COM 	case AMD_IOMMU_CMD_INVAL_IOTLB_PAGES:
237*10535SVikram.Hegde@Sun.COM 		error = create_inval_iotlb_pages_cmd(iommu, cmdargs,
238*10535SVikram.Hegde@Sun.COM 		    flags & ~AMD_IOMMU_CMD_FLAGS_COMPL_WAIT, cmdptr);
239*10535SVikram.Hegde@Sun.COM 		break;
240*10535SVikram.Hegde@Sun.COM 	case AMD_IOMMU_CMD_INVAL_INTR_TABLE:
241*10535SVikram.Hegde@Sun.COM 		error = create_inval_intr_table_cmd(iommu, cmdargs,
242*10535SVikram.Hegde@Sun.COM 		    flags & ~AMD_IOMMU_CMD_FLAGS_COMPL_WAIT, cmdptr);
243*10535SVikram.Hegde@Sun.COM 		break;
244*10535SVikram.Hegde@Sun.COM 	default:
245*10535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: %s%d: idx=%d: Unsupported cmd: %d",
246*10535SVikram.Hegde@Sun.COM 		    f, driver, instance, iommu->aiomt_idx, cmd);
247*10535SVikram.Hegde@Sun.COM 		error = DDI_FAILURE;
248*10535SVikram.Hegde@Sun.COM 		goto out;
249*10535SVikram.Hegde@Sun.COM 	}
250*10535SVikram.Hegde@Sun.COM 
251*10535SVikram.Hegde@Sun.COM 	if (error != DDI_SUCCESS) {
252*10535SVikram.Hegde@Sun.COM 		error = DDI_FAILURE;
253*10535SVikram.Hegde@Sun.COM 		goto out;
254*10535SVikram.Hegde@Sun.COM 	}
255*10535SVikram.Hegde@Sun.COM 
256*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
257*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMDBUF_ENABLE, 1);
258*10535SVikram.Hegde@Sun.COM 
259*10535SVikram.Hegde@Sun.COM 	ASSERT(iommu->aiomt_cmd_tail != NULL);
260*10535SVikram.Hegde@Sun.COM 
261*10535SVikram.Hegde@Sun.COM 	for (i = 0; i < 4; i++) {
262*10535SVikram.Hegde@Sun.COM 		iommu->aiomt_cmd_tail[i] = cmdptr[i];
263*10535SVikram.Hegde@Sun.COM 	}
264*10535SVikram.Hegde@Sun.COM 
265*10535SVikram.Hegde@Sun.COM wait_for_drain:
266*10535SVikram.Hegde@Sun.COM 	cmdhead_off = AMD_IOMMU_REG_GET64(
267*10535SVikram.Hegde@Sun.COM 	    REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
268*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMDHEADPTR);
269*10535SVikram.Hegde@Sun.COM 
270*10535SVikram.Hegde@Sun.COM 	cmdhead_off = CMD2OFF(cmdhead_off);
271*10535SVikram.Hegde@Sun.COM 
272*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdhead_off < iommu->aiomt_cmdbuf_sz);
273*10535SVikram.Hegde@Sun.COM 
274*10535SVikram.Hegde@Sun.COM 	/* check for overflow */
275*10535SVikram.Hegde@Sun.COM 	if ((caddr_t)iommu->aiomt_cmd_tail <
276*10535SVikram.Hegde@Sun.COM 	    (cmdhead_off + iommu->aiomt_cmdbuf)) {
277*10535SVikram.Hegde@Sun.COM 		if ((caddr_t)iommu->aiomt_cmd_tail + 16 >=
278*10535SVikram.Hegde@Sun.COM 		    (cmdhead_off + iommu->aiomt_cmdbuf))
279*10535SVikram.Hegde@Sun.COM #ifdef DEBUG
280*10535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "cmdbuffer overflow: waiting for "
281*10535SVikram.Hegde@Sun.COM 			    "drain");
282*10535SVikram.Hegde@Sun.COM #endif
283*10535SVikram.Hegde@Sun.COM 			goto wait_for_drain;
284*10535SVikram.Hegde@Sun.COM 	}
285*10535SVikram.Hegde@Sun.COM 
286*10535SVikram.Hegde@Sun.COM 	SYNC_FORDEV(iommu->aiomt_dmahdl);
287*10535SVikram.Hegde@Sun.COM 
288*10535SVikram.Hegde@Sun.COM 	/*
289*10535SVikram.Hegde@Sun.COM 	 * Update the tail pointer in soft state
290*10535SVikram.Hegde@Sun.COM 	 * and the tail pointer register
291*10535SVikram.Hegde@Sun.COM 	 */
292*10535SVikram.Hegde@Sun.COM 	iommu->aiomt_cmd_tail += 4;
293*10535SVikram.Hegde@Sun.COM 	if ((caddr_t)iommu->aiomt_cmd_tail >= (iommu->aiomt_cmdbuf
294*10535SVikram.Hegde@Sun.COM 	    + iommu->aiomt_cmdbuf_sz)) {
295*10535SVikram.Hegde@Sun.COM 		/* wraparound */
296*10535SVikram.Hegde@Sun.COM 		/*LINTED*/
297*10535SVikram.Hegde@Sun.COM 		iommu->aiomt_cmd_tail = (uint32_t *)iommu->aiomt_cmdbuf;
298*10535SVikram.Hegde@Sun.COM 		cmdtail_off = 0;
299*10535SVikram.Hegde@Sun.COM 	} else {
300*10535SVikram.Hegde@Sun.COM 		cmdtail_off = (caddr_t)iommu->aiomt_cmd_tail
301*10535SVikram.Hegde@Sun.COM 		/*LINTED*/
302*10535SVikram.Hegde@Sun.COM 		    - iommu->aiomt_cmdbuf;
303*10535SVikram.Hegde@Sun.COM 	}
304*10535SVikram.Hegde@Sun.COM 
305*10535SVikram.Hegde@Sun.COM 	ASSERT(cmdtail_off < iommu->aiomt_cmdbuf_sz);
306*10535SVikram.Hegde@Sun.COM 
307*10535SVikram.Hegde@Sun.COM 	AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_tail_va),
308*10535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_CMDTAILPTR, OFF2CMD(cmdtail_off));
309*10535SVikram.Hegde@Sun.COM 
310*10535SVikram.Hegde@Sun.COM 	if (cmd == AMD_IOMMU_CMD_COMPL_WAIT) {
311*10535SVikram.Hegde@Sun.COM 		amd_iommu_wait_for_completion(iommu);
312*10535SVikram.Hegde@Sun.COM 	} else if (flags & AMD_IOMMU_CMD_FLAGS_COMPL_WAIT) {
313*10535SVikram.Hegde@Sun.COM 		error = amd_iommu_cmd(iommu, AMD_IOMMU_CMD_COMPL_WAIT,
314*10535SVikram.Hegde@Sun.COM 		    NULL, 0, 1);
315*10535SVikram.Hegde@Sun.COM 	}
316*10535SVikram.Hegde@Sun.COM 
317*10535SVikram.Hegde@Sun.COM out:
318*10535SVikram.Hegde@Sun.COM 	if (!lock_held)
319*10535SVikram.Hegde@Sun.COM 		mutex_exit(&iommu->aiomt_cmdlock);
320*10535SVikram.Hegde@Sun.COM 	return (error);
321*10535SVikram.Hegde@Sun.COM }
322