aboutsummaryrefslogtreecommitdiff
path: root/sysutils/bhyve+/files/freebsd-12/patch-msi-x-mappings
blob: 76becc6a97a3c67e33a76ec2bd0fde7afbe923b5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
--- usr.sbin/bhyve/pci_emul.h.orig
+++ usr.sbin/bhyve/pci_emul.h
@@ -146,6 +146,7 @@ struct pci_devinst {
 		struct msix_table_entry *table;	/* allocated at runtime */
 		void	*pba_page;
 		int	pba_page_offset;
+		void	*table_page;
 	} pi_msix;
 
 	void      *pi_arg;		/* devemu-private data */
--- usr.sbin/bhyve/pci_passthru.c.orig
+++ usr.sbin/bhyve/pci_passthru.c
@@ -324,13 +324,14 @@ msix_table_read(struct passthru_softc *sc, uint64_t of
 		return (data);
 	}
 
+	/* Should make this an assert. */
 	if (offset < pi->pi_msix.table_offset)
 		return (-1);
 
 	offset -= pi->pi_msix.table_offset;
 	index = offset / MSIX_TABLE_ENTRY_SIZE;
 	if (index >= pi->pi_msix.table_count)
-		return (-1);
+		goto readbar;
 
 	entry = &pi->pi_msix.table[index];
 	entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
@@ -357,6 +358,33 @@ msix_table_read(struct passthru_softc *sc, uint64_t of
 	}
 
 	return (data);
+
+readbar:
+	if (pi->pi_msix.table_page != NULL && offset < 4096) {
+		switch(size) {
+		case 1:
+			src8 = (uint8_t *)(pi->pi_msix.table_page + offset);
+			data = *src8;
+			break;
+		case 2:
+			src16 = (uint16_t *)(pi->pi_msix.table_page + offset);
+			data = *src16;
+			break;
+		case 4:
+			src32 = (uint32_t *)(pi->pi_msix.table_page + offset);
+			data = *src32;
+			break;
+		case 8:
+			src64 = (uint64_t *)(pi->pi_msix.table_page + offset);
+			data = *src64;
+			break;
+		default:
+			return (-1);
+		}
+		return (data);
+	}
+
+	return (-1);
 }
 
 static void
@@ -403,13 +431,14 @@ msix_table_write(struct vmctx *ctx, int vcpu, struct p
 		return;
 	}
 
+	/* Should make this an assert. */
 	if (offset < pi->pi_msix.table_offset)
 		return;
 
 	offset -= pi->pi_msix.table_offset;
 	index = offset / MSIX_TABLE_ENTRY_SIZE;
 	if (index >= pi->pi_msix.table_count)
-		return;
+		goto writebar;
 
 	entry = &pi->pi_msix.table[index];
 	entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
@@ -432,6 +461,31 @@ msix_table_write(struct vmctx *ctx, int vcpu, struct p
 			    entry->msg_data, entry->vector_control);
 		}
 	}
+
+writebar:
+	if (pi->pi_msix.table_page != NULL && offset < 4096) {
+		switch(size) {
+		case 1:
+			dest8 = (uint8_t *)(pi->pi_msix.table_page + offset);
+			*dest8 = data;
+			break;
+		case 2:
+			dest16 = (uint16_t *)(pi->pi_msix.table_page + offset);
+			*dest16 = data;
+			break;
+		case 4:
+			dest32 = (uint32_t *)(pi->pi_msix.table_page + offset);
+			*dest32 = data;
+			break;
+		case 8:
+			dest64 = (uint64_t *)(pi->pi_msix.table_page + offset);
+			*dest64 = data;
+			break;
+		default:
+			break;
+		}
+		return;
+	}
 }
 
 static int
@@ -466,6 +520,21 @@ init_msix_table(struct vmctx *ctx, struct passthru_sof
 	idx = pi->pi_msix.table_bar;
 	start = pi->pi_bar[idx].addr;
 	remaining = pi->pi_bar[idx].size;
+
+	/*
+	 * Some device (against better documentation of the spec)
+	 * are mapping other usable address space into the same page
+	 * as the end of the MSI-X tables.
+	 * At least Intel AX200 being one of them apparently.
+	 * Map the page and fall back to it for any reads/writes outside
+	 * the MSI-X table in msix_table_{read,write}.
+	 */
+	pi->pi_msix.table_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+	    MAP_SHARED, memfd, sc->psc_bar[idx].addr + table_offset);
+	if (pi->pi_msix.table_page == MAP_FAILED) {
+		warn("Failed to map table page for MSI-X on %d/%d/%d", b, s, f);
+		return (-1);
+	}
 
 	if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) {
 		pba_offset = pi->pi_msix.pba_offset;