xref: /illumos-gate/usr/src/cmd/bhyve/pci_hostbridge.c (revision 1ba081ee9f36cc673e86a7218c97c558c5b193e1)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 NetApp, Inc.
5  * Copyright (c) 2018 Joyent, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef __FreeBSD__
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <strings.h>
38 #endif
39 __FBSDID("$FreeBSD$");
40 
41 #include <stdlib.h>
42 
43 #include "config.h"
44 #include "pci_emul.h"
45 
46 #ifndef __FreeBSD__
47 static struct pci_hostbridge_model {
48 	const char	*phm_model;
49 	uint16_t	phm_vendor;
50 	uint16_t	phm_device;
51 } pci_hb_models[] = {
52 	{ "amd",	0x1022, 0x7432 }, /* AMD/made-up */
53 	{ "netapp",	0x1275, 0x1275 }, /* NetApp/NetApp */
54 	{ "i440fx",	0x8086, 0x1237 }, /* Intel/82441 */
55 	{ "q35",	0x8086, 0x29b0 }, /* Intel/Q35 HB */
56 };
57 
58 #define	NUM_HB_MODELS	(sizeof (pci_hb_models) / sizeof (pci_hb_models[0]))
59 #endif
60 
61 static int
62 pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
63 {
64 	const char *value;
65 	u_int vendor, device;
66 
67 #ifdef __FreeBSD__
68 	vendor = 0x1275;	/* NetApp */
69 	device = 0x1275;	/* NetApp */
70 #else
71 	vendor = device = 0;
72 #endif
73 
74 	value = get_config_value_node(nvl, "vendor");
75 	if (value != NULL)
76 		vendor = strtol(value, NULL, 0);
77 	value = get_config_value_node(nvl, "devid");
78 	if (value != NULL)
79 		device = strtol(value, NULL, 0);
80 
81 #ifndef __FreeBSD__
82 	const char *model = get_config_value_node(nvl, "model");
83 
84 	if (model != NULL && (vendor != 0 || device != 0)) {
85 		fprintf(stderr, "pci_hostbridge: cannot specify model "
86 		    "and vendor/device");
87 		return (-1);
88 	} else if ((vendor != 0 && device == 0) ||
89 	    (vendor == 0 && device != 0)) {
90 		fprintf(stderr, "pci_hostbridge: must specify both vendor and"
91 		    "device for custom hostbridge");
92 		return (-1);
93 	}
94 	if (model == NULL && vendor == 0 && device == 0)
95 		model = "netapp";
96 
97 	if (model != NULL) {
98 		for (uint_t i = 0; i < NUM_HB_MODELS; i++) {
99 			if (strcmp(model, pci_hb_models[i].phm_model) != 0)
100 				continue;
101 
102 			/* found a model match */
103 			vendor = pci_hb_models[i].phm_vendor;
104 			device = pci_hb_models[i].phm_device;
105 			break;
106 		}
107 		if (vendor == 0) {
108 			fprintf(stderr, "pci_hostbridge: invalid model '%s'",
109 			    model);
110 			return (-1);
111 		}
112 	}
113 #endif /* !__FreeBSD__ */
114 
115 	/* config space */
116 	pci_set_cfgdata16(pi, PCIR_VENDOR, vendor);
117 	pci_set_cfgdata16(pi, PCIR_DEVICE, device);
118 	pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
119 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);
120 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST);
121 
122 	pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT);
123 
124 	return (0);
125 }
126 
127 static int
128 pci_amd_hostbridge_legacy_config(nvlist_t *nvl, const char *opts)
129 {
130 
131 	set_config_value_node(nvl, "vendor", "0x1022");	/* AMD */
132 	set_config_value_node(nvl, "devid", "0x7432");	/* made up */
133 
134 	return (0);
135 }
136 
137 struct pci_devemu pci_de_amd_hostbridge = {
138 	.pe_emu = "amd_hostbridge",
139 	.pe_legacy_config = pci_amd_hostbridge_legacy_config,
140 	.pe_alias = "hostbridge",
141 };
142 PCI_EMUL_SET(pci_de_amd_hostbridge);
143 
144 struct pci_devemu pci_de_hostbridge = {
145 	.pe_emu = "hostbridge",
146 	.pe_init = pci_hostbridge_init,
147 };
148 PCI_EMUL_SET(pci_de_hostbridge);
149