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