1221828Sgrehan/*-
2221828Sgrehan * Copyright (c) 2011 NetApp, Inc.
3221828Sgrehan * All rights reserved.
4221828Sgrehan *
5221828Sgrehan * Redistribution and use in source and binary forms, with or without
6221828Sgrehan * modification, are permitted provided that the following conditions
7221828Sgrehan * are met:
8221828Sgrehan * 1. Redistributions of source code must retain the above copyright
9221828Sgrehan *    notice, this list of conditions and the following disclaimer.
10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11221828Sgrehan *    notice, this list of conditions and the following disclaimer in the
12221828Sgrehan *    documentation and/or other materials provided with the distribution.
13221828Sgrehan *
14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17221828Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24221828Sgrehan * SUCH DAMAGE.
25221828Sgrehan *
26221828Sgrehan * $FreeBSD$
27221828Sgrehan */
28221828Sgrehan
29221828Sgrehan#ifndef _PCI_EMUL_H_
30221828Sgrehan#define _PCI_EMUL_H_
31221828Sgrehan
32221828Sgrehan#include <sys/types.h>
33221828Sgrehan#include <sys/queue.h>
34221828Sgrehan#include <sys/kernel.h>
35267393Sjhb#include <sys/_pthreadtypes.h>
36221828Sgrehan
37221828Sgrehan#include <dev/pci/pcireg.h>
38221828Sgrehan
39221828Sgrehan#include <assert.h>
40221828Sgrehan
41221828Sgrehan#define	PCI_BARMAX	PCIR_MAX_BAR_0	/* BAR registers in a Type 0 header */
42221828Sgrehan
43221828Sgrehanstruct vmctx;
44221828Sgrehanstruct pci_devinst;
45234761Sgrehanstruct memory_region;
46221828Sgrehan
47221828Sgrehanstruct pci_devemu {
48221828Sgrehan	char      *pe_emu;		/* Name of device emulation */
49221828Sgrehan
50221828Sgrehan	/* instance creation */
51241744Sgrehan	int       (*pe_init)(struct vmctx *, struct pci_devinst *,
52241744Sgrehan			     char *opts);
53221828Sgrehan
54261265Sjhb	/* ACPI DSDT enumeration */
55261265Sjhb	void	(*pe_write_dsdt)(struct pci_devinst *);
56261265Sjhb
57221828Sgrehan	/* config space read/write callbacks */
58221828Sgrehan	int	(*pe_cfgwrite)(struct vmctx *ctx, int vcpu,
59221828Sgrehan			       struct pci_devinst *pi, int offset,
60221828Sgrehan			       int bytes, uint32_t val);
61221828Sgrehan	int	(*pe_cfgread)(struct vmctx *ctx, int vcpu,
62221828Sgrehan			      struct pci_devinst *pi, int offset,
63221828Sgrehan			      int bytes, uint32_t *retval);
64221828Sgrehan
65241744Sgrehan	/* BAR read/write callbacks */
66241744Sgrehan	void      (*pe_barwrite)(struct vmctx *ctx, int vcpu,
67241744Sgrehan				 struct pci_devinst *pi, int baridx,
68241744Sgrehan				 uint64_t offset, int size, uint64_t value);
69241744Sgrehan	uint64_t  (*pe_barread)(struct vmctx *ctx, int vcpu,
70241744Sgrehan				struct pci_devinst *pi, int baridx,
71241744Sgrehan				uint64_t offset, int size);
72221828Sgrehan};
73221828Sgrehan#define PCI_EMUL_SET(x)   DATA_SET(pci_devemu_set, x);
74221828Sgrehan
75221828Sgrehanenum pcibar_type {
76221828Sgrehan	PCIBAR_NONE,
77221828Sgrehan	PCIBAR_IO,
78221828Sgrehan	PCIBAR_MEM32,
79221828Sgrehan	PCIBAR_MEM64,
80221828Sgrehan	PCIBAR_MEMHI64
81221828Sgrehan};
82221828Sgrehan
83221828Sgrehanstruct pcibar {
84221828Sgrehan	enum pcibar_type	type;		/* io or memory */
85221828Sgrehan	uint64_t		size;
86221828Sgrehan	uint64_t		addr;
87221828Sgrehan};
88221828Sgrehan
89221828Sgrehan#define PI_NAMESZ	40
90221828Sgrehan
91234761Sgrehanstruct msix_table_entry {
92234761Sgrehan	uint64_t	addr;
93234761Sgrehan	uint32_t	msg_data;
94234761Sgrehan	uint32_t	vector_control;
95234761Sgrehan} __packed;
96234761Sgrehan
97234761Sgrehan/*
98234761Sgrehan * In case the structure is modified to hold extra information, use a define
99234761Sgrehan * for the size that should be emulated.
100234761Sgrehan */
101245749Sneel#define	MSIX_TABLE_ENTRY_SIZE	16
102246109Sneel#define MAX_MSIX_TABLE_ENTRIES	2048
103268887Sjhb#define	PBA_SIZE(msgnum)	(roundup2((msgnum), 64) / 8)
104234761Sgrehan
105267393Sjhbenum lintr_stat {
106267393Sjhb	IDLE,
107267393Sjhb	ASSERTED,
108267393Sjhb	PENDING
109267393Sjhb};
110267393Sjhb
111221828Sgrehanstruct pci_devinst {
112221828Sgrehan	struct pci_devemu *pi_d;
113221828Sgrehan	struct vmctx *pi_vmctx;
114221828Sgrehan	uint8_t	  pi_bus, pi_slot, pi_func;
115221828Sgrehan	char	  pi_name[PI_NAMESZ];
116221828Sgrehan	int	  pi_bar_getsize;
117268887Sjhb	int	  pi_prevcap;
118268887Sjhb	int	  pi_capend;
119221828Sgrehan
120221828Sgrehan	struct {
121267393Sjhb		int8_t    	pin;
122267393Sjhb		enum lintr_stat	state;
123268972Sjhb		int		pirq_pin;
124267393Sjhb		int	  	ioapic_irq;
125267393Sjhb		pthread_mutex_t	lock;
126267393Sjhb	} pi_lintr;
127267393Sjhb
128267393Sjhb	struct {
129262350Sjhb		int		enabled;
130262350Sjhb		uint64_t	addr;
131262350Sjhb		uint64_t	msg_data;
132262350Sjhb		int		maxmsgnum;
133221828Sgrehan	} pi_msi;
134221828Sgrehan
135234761Sgrehan	struct {
136234761Sgrehan		int	enabled;
137234761Sgrehan		int	table_bar;
138234761Sgrehan		int	pba_bar;
139268887Sjhb		uint32_t table_offset;
140234761Sgrehan		int	table_count;
141268887Sjhb		uint32_t pba_offset;
142268887Sjhb		int	pba_size;
143246109Sneel		int	function_mask;
144245749Sneel		struct msix_table_entry *table;	/* allocated at runtime */
145234761Sgrehan	} pi_msix;
146234761Sgrehan
147221828Sgrehan	void      *pi_arg;		/* devemu-private data */
148221828Sgrehan
149221828Sgrehan	u_char	  pi_cfgdata[PCI_REGMAX + 1];
150221828Sgrehan	struct pcibar pi_bar[PCI_BARMAX + 1];
151221828Sgrehan};
152221828Sgrehan
153221828Sgrehanstruct msicap {
154221828Sgrehan	uint8_t		capid;
155221828Sgrehan	uint8_t		nextptr;
156221828Sgrehan	uint16_t	msgctrl;
157221828Sgrehan	uint32_t	addrlo;
158221828Sgrehan	uint32_t	addrhi;
159221828Sgrehan	uint16_t	msgdata;
160221828Sgrehan} __packed;
161221828Sgrehan
162234761Sgrehanstruct msixcap {
163234761Sgrehan	uint8_t		capid;
164234761Sgrehan	uint8_t		nextptr;
165234761Sgrehan	uint16_t	msgctrl;
166245749Sneel	uint32_t	table_info;	/* bar index and offset within it */
167245749Sneel	uint32_t	pba_info;	/* bar index and offset within it */
168234761Sgrehan} __packed;
169234761Sgrehan
170246846Sneelstruct pciecap {
171246846Sneel	uint8_t		capid;
172246846Sneel	uint8_t		nextptr;
173246846Sneel	uint16_t	pcie_capabilities;
174246846Sneel
175246846Sneel	uint32_t	dev_capabilities;	/* all devices */
176246846Sneel	uint16_t	dev_control;
177246846Sneel	uint16_t	dev_status;
178246846Sneel
179246846Sneel	uint32_t	link_capabilities;	/* devices with links */
180246846Sneel	uint16_t	link_control;
181246846Sneel	uint16_t	link_status;
182246846Sneel
183246846Sneel	uint32_t	slot_capabilities;	/* ports with slots */
184246846Sneel	uint16_t	slot_control;
185246846Sneel	uint16_t	slot_status;
186246846Sneel
187246846Sneel	uint16_t	root_control;		/* root ports */
188246846Sneel	uint16_t	root_capabilities;
189246846Sneel	uint32_t	root_status;
190246846Sneel
191246846Sneel	uint32_t	dev_capabilities2;	/* all devices */
192246846Sneel	uint16_t	dev_control2;
193246846Sneel	uint16_t	dev_status2;
194246846Sneel
195246846Sneel	uint32_t	link_capabilities2;	/* devices with links */
196246846Sneel	uint16_t	link_control2;
197246846Sneel	uint16_t	link_status2;
198246846Sneel
199246846Sneel	uint32_t	slot_capabilities2;	/* ports with slots */
200246846Sneel	uint16_t	slot_control2;
201246846Sneel	uint16_t	slot_status2;
202246846Sneel} __packed;
203246846Sneel
204268972Sjhbtypedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin,
205268972Sjhb    int ioapic_irq, void *arg);
206267393Sjhb
207252682Sgrehanint	init_pci(struct vmctx *ctx);
208234938Sgrehanvoid	msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
209234938Sgrehan	    int bytes, uint32_t val);
210234938Sgrehanvoid	msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
211234938Sgrehan	    int bytes, uint32_t val);
212234938Sgrehanvoid	pci_callback(void);
213241744Sgrehanint	pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,
214234938Sgrehan	    enum pcibar_type type, uint64_t size);
215241744Sgrehanint	pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx,
216241744Sgrehan	    uint64_t hostbase, enum pcibar_type type, uint64_t size);
217234938Sgrehanint	pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);
218246846Sneelint	pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);
219234938Sgrehanvoid	pci_generate_msi(struct pci_devinst *pi, int msgnum);
220241744Sgrehanvoid	pci_generate_msix(struct pci_devinst *pi, int msgnum);
221234938Sgrehanvoid	pci_lintr_assert(struct pci_devinst *pi);
222234938Sgrehanvoid	pci_lintr_deassert(struct pci_devinst *pi);
223268972Sjhbvoid	pci_lintr_request(struct pci_devinst *pi);
224234938Sgrehanint	pci_msi_enabled(struct pci_devinst *pi);
225241744Sgrehanint	pci_msix_enabled(struct pci_devinst *pi);
226246190Sneelint	pci_msix_table_bar(struct pci_devinst *pi);
227246190Sneelint	pci_msix_pba_bar(struct pci_devinst *pi);
228234938Sgrehanint	pci_msi_msgnum(struct pci_devinst *pi);
229267341Sjhbint	pci_parse_slot(char *opt);
230234938Sgrehanvoid	pci_populate_msicap(struct msicap *cap, int msgs, int nextptr);
231246109Sneelint	pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum);
232246109Sneelint	pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
233246109Sneel			     uint64_t value);
234246109Sneeluint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size);
235268887Sjhbint	pci_count_lintr(int bus);
236268887Sjhbvoid	pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg);
237261265Sjhbvoid	pci_write_dsdt(void);
238270159Sgrehanuint64_t pci_ecfg_base(void);
239268887Sjhbint	pci_bus_configured(int bus);
240221828Sgrehan
241221828Sgrehanstatic __inline void
242221828Sgrehanpci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val)
243221828Sgrehan{
244221828Sgrehan	assert(offset <= PCI_REGMAX);
245221828Sgrehan	*(uint8_t *)(pi->pi_cfgdata + offset) = val;
246221828Sgrehan}
247221828Sgrehan
248221828Sgrehanstatic __inline void
249221828Sgrehanpci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val)
250221828Sgrehan{
251221828Sgrehan	assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);
252221828Sgrehan	*(uint16_t *)(pi->pi_cfgdata + offset) = val;
253221828Sgrehan}
254221828Sgrehan
255221828Sgrehanstatic __inline void
256221828Sgrehanpci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val)
257221828Sgrehan{
258221828Sgrehan	assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);
259221828Sgrehan	*(uint32_t *)(pi->pi_cfgdata + offset) = val;
260221828Sgrehan}
261221828Sgrehan
262221828Sgrehanstatic __inline uint8_t
263221828Sgrehanpci_get_cfgdata8(struct pci_devinst *pi, int offset)
264221828Sgrehan{
265221828Sgrehan	assert(offset <= PCI_REGMAX);
266221828Sgrehan	return (*(uint8_t *)(pi->pi_cfgdata + offset));
267221828Sgrehan}
268221828Sgrehan
269221828Sgrehanstatic __inline uint16_t
270221828Sgrehanpci_get_cfgdata16(struct pci_devinst *pi, int offset)
271221828Sgrehan{
272221828Sgrehan	assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);
273221828Sgrehan	return (*(uint16_t *)(pi->pi_cfgdata + offset));
274221828Sgrehan}
275221828Sgrehan
276221828Sgrehanstatic __inline uint32_t
277221828Sgrehanpci_get_cfgdata32(struct pci_devinst *pi, int offset)
278221828Sgrehan{
279221828Sgrehan	assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);
280221828Sgrehan	return (*(uint32_t *)(pi->pi_cfgdata + offset));
281221828Sgrehan}
282221828Sgrehan
283221828Sgrehan#endif /* _PCI_EMUL_H_ */
284