xref: /dpdk/drivers/raw/ifpga/base/ifpga_feature_dev.c (revision ca6eb0f7c836bcdc8fda8522297776c772b86ca3)
1473c88f9SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2473c88f9SBruce Richardson  * Copyright(c) 2010-2018 Intel Corporation
3473c88f9SBruce Richardson  */
4473c88f9SBruce Richardson 
5473c88f9SBruce Richardson #include <sys/ioctl.h>
69bf03321STianfei Zhang #include <rte_vfio.h>
7473c88f9SBruce Richardson 
8473c88f9SBruce Richardson #include "ifpga_feature_dev.h"
9473c88f9SBruce Richardson 
10473c88f9SBruce Richardson /*
11473c88f9SBruce Richardson  * Enable Port by clear the port soft reset bit, which is set by default.
12473c88f9SBruce Richardson  * The AFU is unable to respond to any MMIO access while in reset.
13473c88f9SBruce Richardson  * __fpga_port_enable function should only be used after __fpga_port_disable
14473c88f9SBruce Richardson  * function.
15473c88f9SBruce Richardson  */
__fpga_port_enable(struct ifpga_port_hw * port)16473c88f9SBruce Richardson void __fpga_port_enable(struct ifpga_port_hw *port)
17473c88f9SBruce Richardson {
18473c88f9SBruce Richardson 	struct feature_port_header *port_hdr;
19473c88f9SBruce Richardson 	struct feature_port_control control;
20473c88f9SBruce Richardson 
21473c88f9SBruce Richardson 	WARN_ON(!port->disable_count);
22473c88f9SBruce Richardson 
23473c88f9SBruce Richardson 	if (--port->disable_count != 0)
24473c88f9SBruce Richardson 		return;
25473c88f9SBruce Richardson 
26473c88f9SBruce Richardson 	port_hdr = get_port_feature_ioaddr_by_index(port,
27473c88f9SBruce Richardson 						    PORT_FEATURE_ID_HEADER);
28473c88f9SBruce Richardson 	WARN_ON(!port_hdr);
29473c88f9SBruce Richardson 
30473c88f9SBruce Richardson 	control.csr = readq(&port_hdr->control);
31473c88f9SBruce Richardson 	control.port_sftrst = 0x0;
32473c88f9SBruce Richardson 	writeq(control.csr, &port_hdr->control);
33473c88f9SBruce Richardson }
34473c88f9SBruce Richardson 
__fpga_port_disable(struct ifpga_port_hw * port)35473c88f9SBruce Richardson int __fpga_port_disable(struct ifpga_port_hw *port)
36473c88f9SBruce Richardson {
37473c88f9SBruce Richardson 	struct feature_port_header *port_hdr;
38473c88f9SBruce Richardson 	struct feature_port_control control;
39473c88f9SBruce Richardson 
40473c88f9SBruce Richardson 	if (port->disable_count++ != 0)
41473c88f9SBruce Richardson 		return 0;
42473c88f9SBruce Richardson 
43473c88f9SBruce Richardson 	port_hdr = get_port_feature_ioaddr_by_index(port,
44473c88f9SBruce Richardson 						    PORT_FEATURE_ID_HEADER);
45473c88f9SBruce Richardson 	WARN_ON(!port_hdr);
46473c88f9SBruce Richardson 
47473c88f9SBruce Richardson 	/* Set port soft reset */
48473c88f9SBruce Richardson 	control.csr = readq(&port_hdr->control);
49473c88f9SBruce Richardson 	control.port_sftrst = 0x1;
50473c88f9SBruce Richardson 	writeq(control.csr, &port_hdr->control);
51473c88f9SBruce Richardson 
52473c88f9SBruce Richardson 	/*
53473c88f9SBruce Richardson 	 * HW sets ack bit to 1 when all outstanding requests have been drained
54473c88f9SBruce Richardson 	 * on this port and minimum soft reset pulse width has elapsed.
55473c88f9SBruce Richardson 	 * Driver polls port_soft_reset_ack to determine if reset done by HW.
56473c88f9SBruce Richardson 	 */
57473c88f9SBruce Richardson 	control.port_sftrst_ack = 1;
58473c88f9SBruce Richardson 
59473c88f9SBruce Richardson 	if (fpga_wait_register_field(port_sftrst_ack, control,
60473c88f9SBruce Richardson 				     &port_hdr->control, RST_POLL_TIMEOUT,
61473c88f9SBruce Richardson 				     RST_POLL_INVL)) {
62673c897fSWei Huang 		dev_err(port, "timeout, fail to reset FIM port\n");
63473c88f9SBruce Richardson 		return -ETIMEDOUT;
64473c88f9SBruce Richardson 	}
65473c88f9SBruce Richardson 
66473c88f9SBruce Richardson 	return 0;
67473c88f9SBruce Richardson }
68473c88f9SBruce Richardson 
fpga_get_afu_uuid(struct ifpga_port_hw * port,struct uuid * uuid)69473c88f9SBruce Richardson int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid)
70473c88f9SBruce Richardson {
71473c88f9SBruce Richardson 	struct feature_port_header *port_hdr;
72473c88f9SBruce Richardson 	u64 guidl, guidh;
73473c88f9SBruce Richardson 
74473c88f9SBruce Richardson 	if (!uuid)
75473c88f9SBruce Richardson 		return -EINVAL;
76473c88f9SBruce Richardson 
77473c88f9SBruce Richardson 	port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU);
78473c88f9SBruce Richardson 
79473c88f9SBruce Richardson 	spinlock_lock(&port->lock);
80473c88f9SBruce Richardson 	guidl = readq(&port_hdr->afu_header.guid.b[0]);
81473c88f9SBruce Richardson 	guidh = readq(&port_hdr->afu_header.guid.b[8]);
82473c88f9SBruce Richardson 	spinlock_unlock(&port->lock);
83473c88f9SBruce Richardson 
84473c88f9SBruce Richardson 	opae_memcpy(uuid->b, &guidl, sizeof(u64));
85473c88f9SBruce Richardson 	opae_memcpy(uuid->b + 8, &guidh, sizeof(u64));
86473c88f9SBruce Richardson 
87473c88f9SBruce Richardson 	return 0;
88473c88f9SBruce Richardson }
89473c88f9SBruce Richardson 
fpga_get_pr_uuid(struct ifpga_fme_hw * fme,struct uuid * uuid)90cf38bcd7SWei Huang int fpga_get_pr_uuid(struct ifpga_fme_hw *fme, struct uuid *uuid)
91cf38bcd7SWei Huang {
92cf38bcd7SWei Huang 	struct feature_fme_pr *fme_pr;
93cf38bcd7SWei Huang 	u64 guidl, guidh;
94cf38bcd7SWei Huang 
95cf38bcd7SWei Huang 	if (!fme || !uuid)
96cf38bcd7SWei Huang 		return -EINVAL;
97cf38bcd7SWei Huang 
98cf38bcd7SWei Huang 	fme_pr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_PR_MGMT);
99cf38bcd7SWei Huang 
100cf38bcd7SWei Huang 	spinlock_lock(&fme->lock);
101cf38bcd7SWei Huang 	guidl = readq(&fme_pr->fme_pr_intfc_id_l);
102cf38bcd7SWei Huang 	guidh = readq(&fme_pr->fme_pr_intfc_id_h);
103cf38bcd7SWei Huang 	spinlock_unlock(&fme->lock);
104cf38bcd7SWei Huang 
105cf38bcd7SWei Huang 	opae_memcpy(uuid->b, &guidl, sizeof(u64));
106cf38bcd7SWei Huang 	opae_memcpy(uuid->b + 8, &guidh, sizeof(u64));
107cf38bcd7SWei Huang 
108cf38bcd7SWei Huang 	return 0;
109cf38bcd7SWei Huang }
110cf38bcd7SWei Huang 
111473c88f9SBruce Richardson /* Mask / Unmask Port Errors by the Error Mask register. */
port_err_mask(struct ifpga_port_hw * port,bool mask)112473c88f9SBruce Richardson void port_err_mask(struct ifpga_port_hw *port, bool mask)
113473c88f9SBruce Richardson {
114473c88f9SBruce Richardson 	struct feature_port_error *port_err;
115473c88f9SBruce Richardson 	struct feature_port_err_key err_mask;
116473c88f9SBruce Richardson 
117473c88f9SBruce Richardson 	port_err = get_port_feature_ioaddr_by_index(port,
118473c88f9SBruce Richardson 						    PORT_FEATURE_ID_ERROR);
119473c88f9SBruce Richardson 
120473c88f9SBruce Richardson 	if (mask)
121473c88f9SBruce Richardson 		err_mask.csr = PORT_ERR_MASK;
122473c88f9SBruce Richardson 	else
123473c88f9SBruce Richardson 		err_mask.csr = 0;
124473c88f9SBruce Richardson 
125473c88f9SBruce Richardson 	writeq(err_mask.csr, &port_err->error_mask);
126473c88f9SBruce Richardson }
127473c88f9SBruce Richardson 
128473c88f9SBruce Richardson /* Clear All Port Errors. */
port_err_clear(struct ifpga_port_hw * port,u64 err)129473c88f9SBruce Richardson int port_err_clear(struct ifpga_port_hw *port, u64 err)
130473c88f9SBruce Richardson {
131473c88f9SBruce Richardson 	struct feature_port_header *port_hdr;
132473c88f9SBruce Richardson 	struct feature_port_error *port_err;
133473c88f9SBruce Richardson 	struct feature_port_err_key mask;
134473c88f9SBruce Richardson 	struct feature_port_first_err_key first;
135473c88f9SBruce Richardson 	struct feature_port_status status;
136473c88f9SBruce Richardson 	int ret = 0;
137473c88f9SBruce Richardson 
138473c88f9SBruce Richardson 	port_err = get_port_feature_ioaddr_by_index(port,
139473c88f9SBruce Richardson 						    PORT_FEATURE_ID_ERROR);
140473c88f9SBruce Richardson 	port_hdr = get_port_feature_ioaddr_by_index(port,
141473c88f9SBruce Richardson 						    PORT_FEATURE_ID_HEADER);
142473c88f9SBruce Richardson 
143473c88f9SBruce Richardson 	/*
144473c88f9SBruce Richardson 	 * Clear All Port Errors
145473c88f9SBruce Richardson 	 *
146473c88f9SBruce Richardson 	 * - Check for AP6 State
147473c88f9SBruce Richardson 	 * - Halt Port by keeping Port in reset
148473c88f9SBruce Richardson 	 * - Set PORT Error mask to all 1 to mask errors
149473c88f9SBruce Richardson 	 * - Clear all errors
150473c88f9SBruce Richardson 	 * - Set Port mask to all 0 to enable errors
151473c88f9SBruce Richardson 	 * - All errors start capturing new errors
152473c88f9SBruce Richardson 	 * - Enable Port by pulling the port out of reset
153473c88f9SBruce Richardson 	 */
154473c88f9SBruce Richardson 
155473c88f9SBruce Richardson 	/* If device is still in AP6 state, can not clear any error.*/
156473c88f9SBruce Richardson 	status.csr = readq(&port_hdr->status);
157473c88f9SBruce Richardson 	if (status.power_state == PORT_POWER_STATE_AP6) {
158473c88f9SBruce Richardson 		dev_err(dev, "Could not clear errors, device in AP6 state.\n");
159473c88f9SBruce Richardson 		return -EBUSY;
160473c88f9SBruce Richardson 	}
161473c88f9SBruce Richardson 
162473c88f9SBruce Richardson 	/* Halt Port by keeping Port in reset */
163473c88f9SBruce Richardson 	ret = __fpga_port_disable(port);
164473c88f9SBruce Richardson 	if (ret)
165473c88f9SBruce Richardson 		return ret;
166473c88f9SBruce Richardson 
167473c88f9SBruce Richardson 	/* Mask all errors */
168473c88f9SBruce Richardson 	port_err_mask(port, true);
169473c88f9SBruce Richardson 
170473c88f9SBruce Richardson 	/* Clear errors if err input matches with current port errors.*/
171473c88f9SBruce Richardson 	mask.csr = readq(&port_err->port_error);
172473c88f9SBruce Richardson 
173473c88f9SBruce Richardson 	if (mask.csr == err) {
174473c88f9SBruce Richardson 		writeq(mask.csr, &port_err->port_error);
175473c88f9SBruce Richardson 
176473c88f9SBruce Richardson 		first.csr = readq(&port_err->port_first_error);
177473c88f9SBruce Richardson 		writeq(first.csr, &port_err->port_first_error);
178473c88f9SBruce Richardson 	} else {
179473c88f9SBruce Richardson 		ret = -EBUSY;
180473c88f9SBruce Richardson 	}
181473c88f9SBruce Richardson 
182473c88f9SBruce Richardson 	/* Clear mask */
183473c88f9SBruce Richardson 	port_err_mask(port, false);
184473c88f9SBruce Richardson 
185473c88f9SBruce Richardson 	/* Enable the Port by clear the reset */
186473c88f9SBruce Richardson 	__fpga_port_enable(port);
187473c88f9SBruce Richardson 
188473c88f9SBruce Richardson 	return ret;
189473c88f9SBruce Richardson }
190473c88f9SBruce Richardson 
port_clear_error(struct ifpga_port_hw * port)191473c88f9SBruce Richardson int port_clear_error(struct ifpga_port_hw *port)
192473c88f9SBruce Richardson {
193473c88f9SBruce Richardson 	struct feature_port_error *port_err;
194473c88f9SBruce Richardson 	struct feature_port_err_key error;
195473c88f9SBruce Richardson 
196473c88f9SBruce Richardson 	port_err = get_port_feature_ioaddr_by_index(port,
197473c88f9SBruce Richardson 						    PORT_FEATURE_ID_ERROR);
198473c88f9SBruce Richardson 	error.csr = readq(&port_err->port_error);
199473c88f9SBruce Richardson 
200473c88f9SBruce Richardson 	dev_info(port, "read port error: 0x%lx\n", (unsigned long)error.csr);
201473c88f9SBruce Richardson 
202473c88f9SBruce Richardson 	return port_err_clear(port, error.csr);
203473c88f9SBruce Richardson }
204473c88f9SBruce Richardson 
205473c88f9SBruce Richardson static struct feature_driver fme_feature_drvs[] = {
206473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_HEADER, FME_FEATURE_HEADER,
207473c88f9SBruce Richardson 			&fme_hdr_ops),},
208473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_THERMAL_MGMT, FME_FEATURE_THERMAL_MGMT,
209473c88f9SBruce Richardson 			&fme_thermal_mgmt_ops),},
210473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_POWER_MGMT, FME_FEATURE_POWER_MGMT,
211473c88f9SBruce Richardson 			&fme_power_mgmt_ops),},
212473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_GLOBAL_ERR, FME_FEATURE_GLOBAL_ERR,
213473c88f9SBruce Richardson 			&fme_global_err_ops),},
214473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_PR_MGMT, FME_FEATURE_PR_MGMT,
215473c88f9SBruce Richardson 			&fme_pr_mgmt_ops),},
216473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_GLOBAL_DPERF, FME_FEATURE_GLOBAL_DPERF,
217473c88f9SBruce Richardson 			&fme_global_dperf_ops),},
218473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_HSSI_ETH, FME_FEATURE_HSSI_ETH,
219473c88f9SBruce Richardson 	&fme_hssi_eth_ops),},
220473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT,
221473c88f9SBruce Richardson 	&fme_emif_ops),},
222473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_MAX10_SPI, FME_FEATURE_MAX10_SPI,
223473c88f9SBruce Richardson 	&fme_spi_master_ops),},
224473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_NIOS_SPI, FME_FEATURE_NIOS_SPI,
225473c88f9SBruce Richardson 	&fme_nios_spi_master_ops),},
226473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_I2C_MASTER, FME_FEATURE_I2C_MASTER,
227473c88f9SBruce Richardson 	&fme_i2c_master_ops),},
228473c88f9SBruce Richardson 	{FEATURE_DRV(FME_FEATURE_ID_ETH_GROUP, FME_FEATURE_ETH_GROUP,
229473c88f9SBruce Richardson 	&fme_eth_group_ops),},
230*ca6eb0f7SWei Huang 	{FEATURE_DRV(FME_FEATURE_ID_PMCI, FME_FEATURE_PMCI,
231*ca6eb0f7SWei Huang 	&fme_pmci_ops),},
232473c88f9SBruce Richardson 	{0, NULL, NULL}, /* end of arrary */
233473c88f9SBruce Richardson };
234473c88f9SBruce Richardson 
235473c88f9SBruce Richardson static struct feature_driver port_feature_drvs[] = {
236473c88f9SBruce Richardson 	{FEATURE_DRV(PORT_FEATURE_ID_HEADER, PORT_FEATURE_HEADER,
237473c88f9SBruce Richardson 			&ifpga_rawdev_port_hdr_ops)},
238473c88f9SBruce Richardson 	{FEATURE_DRV(PORT_FEATURE_ID_ERROR, PORT_FEATURE_ERR,
239473c88f9SBruce Richardson 			&ifpga_rawdev_port_error_ops)},
240473c88f9SBruce Richardson 	{FEATURE_DRV(PORT_FEATURE_ID_UINT, PORT_FEATURE_UINT,
241473c88f9SBruce Richardson 			&ifpga_rawdev_port_uint_ops)},
242473c88f9SBruce Richardson 	{FEATURE_DRV(PORT_FEATURE_ID_STP, PORT_FEATURE_STP,
243473c88f9SBruce Richardson 			&ifpga_rawdev_port_stp_ops)},
244473c88f9SBruce Richardson 	{FEATURE_DRV(PORT_FEATURE_ID_UAFU, PORT_FEATURE_UAFU,
245473c88f9SBruce Richardson 			&ifpga_rawdev_port_afu_ops)},
246473c88f9SBruce Richardson 	{0, NULL, NULL}, /* end of array */
247473c88f9SBruce Richardson };
248473c88f9SBruce Richardson 
get_fme_feature_name(unsigned int id)249473c88f9SBruce Richardson const char *get_fme_feature_name(unsigned int id)
250473c88f9SBruce Richardson {
251473c88f9SBruce Richardson 	struct feature_driver *drv = fme_feature_drvs;
252473c88f9SBruce Richardson 
253473c88f9SBruce Richardson 	while (drv->name) {
254473c88f9SBruce Richardson 		if (drv->id == id)
255473c88f9SBruce Richardson 			return drv->name;
256473c88f9SBruce Richardson 
257473c88f9SBruce Richardson 		drv++;
258473c88f9SBruce Richardson 	}
259473c88f9SBruce Richardson 
260473c88f9SBruce Richardson 	return NULL;
261473c88f9SBruce Richardson }
262473c88f9SBruce Richardson 
get_port_feature_name(unsigned int id)263473c88f9SBruce Richardson const char *get_port_feature_name(unsigned int id)
264473c88f9SBruce Richardson {
265473c88f9SBruce Richardson 	struct feature_driver *drv = port_feature_drvs;
266473c88f9SBruce Richardson 
267473c88f9SBruce Richardson 	while (drv->name) {
268473c88f9SBruce Richardson 		if (drv->id == id)
269473c88f9SBruce Richardson 			return drv->name;
270473c88f9SBruce Richardson 
271473c88f9SBruce Richardson 		drv++;
272473c88f9SBruce Richardson 	}
273473c88f9SBruce Richardson 
274473c88f9SBruce Richardson 	return NULL;
275473c88f9SBruce Richardson }
276473c88f9SBruce Richardson 
feature_uinit(struct ifpga_feature_list * list)277473c88f9SBruce Richardson static void feature_uinit(struct ifpga_feature_list *list)
278473c88f9SBruce Richardson {
279473c88f9SBruce Richardson 	struct ifpga_feature *feature;
280473c88f9SBruce Richardson 
281473c88f9SBruce Richardson 	TAILQ_FOREACH(feature, list, next) {
282673c897fSWei Huang 		if (feature->state != IFPGA_FEATURE_INITED)
283473c88f9SBruce Richardson 			continue;
284473c88f9SBruce Richardson 		if (feature->ops && feature->ops->uinit)
285473c88f9SBruce Richardson 			feature->ops->uinit(feature);
286673c897fSWei Huang 		feature->state = IFPGA_FEATURE_ATTACHED;
287473c88f9SBruce Richardson 	}
288473c88f9SBruce Richardson }
289473c88f9SBruce Richardson 
feature_init(struct feature_driver * drv,struct ifpga_feature_list * list)290473c88f9SBruce Richardson static int feature_init(struct feature_driver *drv,
291473c88f9SBruce Richardson 		struct ifpga_feature_list *list)
292473c88f9SBruce Richardson {
293473c88f9SBruce Richardson 	struct ifpga_feature *feature;
294473c88f9SBruce Richardson 	int ret;
295473c88f9SBruce Richardson 
296473c88f9SBruce Richardson 	while (drv->ops) {
297473c88f9SBruce Richardson 		TAILQ_FOREACH(feature, list, next) {
298473c88f9SBruce Richardson 			if (feature->state != IFPGA_FEATURE_ATTACHED)
299473c88f9SBruce Richardson 				continue;
300473c88f9SBruce Richardson 			if (feature->id == drv->id) {
301473c88f9SBruce Richardson 				feature->ops = drv->ops;
302473c88f9SBruce Richardson 				feature->name = drv->name;
303473c88f9SBruce Richardson 				if (feature->ops->init) {
304473c88f9SBruce Richardson 					ret = feature->ops->init(feature);
305473c88f9SBruce Richardson 					if (ret)
306473c88f9SBruce Richardson 						goto error;
307673c897fSWei Huang 					else
308673c897fSWei Huang 						feature->state =
309673c897fSWei Huang 							IFPGA_FEATURE_INITED;
310473c88f9SBruce Richardson 				}
311473c88f9SBruce Richardson 			}
312473c88f9SBruce Richardson 		}
313473c88f9SBruce Richardson 		drv++;
314473c88f9SBruce Richardson 	}
315473c88f9SBruce Richardson 
316473c88f9SBruce Richardson 	return 0;
317473c88f9SBruce Richardson error:
318473c88f9SBruce Richardson 	feature_uinit(list);
319473c88f9SBruce Richardson 	return ret;
320473c88f9SBruce Richardson }
321473c88f9SBruce Richardson 
fme_hw_init(struct ifpga_fme_hw * fme)322473c88f9SBruce Richardson int fme_hw_init(struct ifpga_fme_hw *fme)
323473c88f9SBruce Richardson {
324673c897fSWei Huang 	if (fme->state == IFPGA_FME_IMPLEMENTED)
325673c897fSWei Huang 		return feature_init(fme_feature_drvs, &fme->feature_list);
326473c88f9SBruce Richardson 
327473c88f9SBruce Richardson 	return 0;
328473c88f9SBruce Richardson }
329473c88f9SBruce Richardson 
fme_hw_uinit(struct ifpga_fme_hw * fme)330473c88f9SBruce Richardson void fme_hw_uinit(struct ifpga_fme_hw *fme)
331473c88f9SBruce Richardson {
332473c88f9SBruce Richardson 	feature_uinit(&fme->feature_list);
333473c88f9SBruce Richardson }
334473c88f9SBruce Richardson 
port_hw_uinit(struct ifpga_port_hw * port)335473c88f9SBruce Richardson void port_hw_uinit(struct ifpga_port_hw *port)
336473c88f9SBruce Richardson {
337473c88f9SBruce Richardson 	feature_uinit(&port->feature_list);
338473c88f9SBruce Richardson }
339473c88f9SBruce Richardson 
port_hw_init(struct ifpga_port_hw * port)340473c88f9SBruce Richardson int port_hw_init(struct ifpga_port_hw *port)
341473c88f9SBruce Richardson {
342473c88f9SBruce Richardson 	int ret;
343473c88f9SBruce Richardson 
344473c88f9SBruce Richardson 	if (port->state == IFPGA_PORT_UNUSED)
345473c88f9SBruce Richardson 		return 0;
346473c88f9SBruce Richardson 
347473c88f9SBruce Richardson 	ret = feature_init(port_feature_drvs, &port->feature_list);
348473c88f9SBruce Richardson 	if (ret)
349473c88f9SBruce Richardson 		goto error;
350473c88f9SBruce Richardson 
351473c88f9SBruce Richardson 	return 0;
352473c88f9SBruce Richardson error:
353473c88f9SBruce Richardson 	port_hw_uinit(port);
354473c88f9SBruce Richardson 	return ret;
355473c88f9SBruce Richardson }
3569bf03321STianfei Zhang 
3579bf03321STianfei Zhang #define FPGA_MAX_MSIX_VEC_COUNT	128
3589bf03321STianfei Zhang /* irq set buffer length for interrupt */
3599bf03321STianfei Zhang #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
3609bf03321STianfei Zhang 				sizeof(int) * FPGA_MAX_MSIX_VEC_COUNT)
3619bf03321STianfei Zhang 
3629bf03321STianfei Zhang /* only support msix for now*/
vfio_msix_enable_block(s32 vfio_dev_fd,unsigned int vec_start,unsigned int count,s32 * fds)3639bf03321STianfei Zhang static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start,
3649bf03321STianfei Zhang 				  unsigned int count, s32 *fds)
3659bf03321STianfei Zhang {
3669bf03321STianfei Zhang 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
3679bf03321STianfei Zhang 	struct vfio_irq_set *irq_set;
3689bf03321STianfei Zhang 	int len, ret;
3699bf03321STianfei Zhang 	int *fd_ptr;
3709bf03321STianfei Zhang 
3719bf03321STianfei Zhang 	len = sizeof(irq_set_buf);
3729bf03321STianfei Zhang 
3739bf03321STianfei Zhang 	irq_set = (struct vfio_irq_set *)irq_set_buf;
3749bf03321STianfei Zhang 	irq_set->argsz = len;
3759bf03321STianfei Zhang 	/* 0 < irq_set->count < FPGA_MAX_MSIX_VEC_COUNT */
3769bf03321STianfei Zhang 	irq_set->count = count ?
3779bf03321STianfei Zhang 		(count > FPGA_MAX_MSIX_VEC_COUNT ?
3789bf03321STianfei Zhang 		 FPGA_MAX_MSIX_VEC_COUNT : count) : 1;
3799bf03321STianfei Zhang 	irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
3809bf03321STianfei Zhang 				VFIO_IRQ_SET_ACTION_TRIGGER;
3819bf03321STianfei Zhang 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
3829bf03321STianfei Zhang 	irq_set->start = vec_start;
3839bf03321STianfei Zhang 
3849bf03321STianfei Zhang 	fd_ptr = (int *)&irq_set->data;
3859bf03321STianfei Zhang 	opae_memcpy(fd_ptr, fds, sizeof(int) * count);
3869bf03321STianfei Zhang 
3879bf03321STianfei Zhang 	ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
3889bf03321STianfei Zhang 	if (ret)
3899bf03321STianfei Zhang 		printf("Error enabling MSI-X interrupts\n");
3909bf03321STianfei Zhang 
3919bf03321STianfei Zhang 	return ret;
3929bf03321STianfei Zhang }
3939bf03321STianfei Zhang 
fpga_msix_set_block(struct ifpga_feature * feature,unsigned int start,unsigned int count,s32 * fds)3949bf03321STianfei Zhang int fpga_msix_set_block(struct ifpga_feature *feature, unsigned int start,
3959bf03321STianfei Zhang 			unsigned int count, s32 *fds)
3969bf03321STianfei Zhang {
3979bf03321STianfei Zhang 	struct feature_irq_ctx *ctx = feature->ctx;
3989bf03321STianfei Zhang 	unsigned int i;
3999bf03321STianfei Zhang 	int ret;
4009bf03321STianfei Zhang 
4019bf03321STianfei Zhang 	if (start >= feature->ctx_num || start + count > feature->ctx_num)
4029bf03321STianfei Zhang 		return -EINVAL;
4039bf03321STianfei Zhang 
4049bf03321STianfei Zhang 	/* assume that each feature has continuous vector space in msix*/
4059bf03321STianfei Zhang 	ret = vfio_msix_enable_block(feature->vfio_dev_fd,
4069bf03321STianfei Zhang 				     ctx[start].idx, count, fds);
4079bf03321STianfei Zhang 	if (!ret) {
4089bf03321STianfei Zhang 		for (i = 0; i < count; i++)
4099bf03321STianfei Zhang 			ctx[i].eventfd = fds[i];
4109bf03321STianfei Zhang 	}
4119bf03321STianfei Zhang 
4129bf03321STianfei Zhang 	return ret;
4139bf03321STianfei Zhang }
414