-
Notifications
You must be signed in to change notification settings - Fork 16
/
change-ddio.c
176 lines (157 loc) · 4.45 KB
/
change-ddio.c
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
* Changing DDIO State
*
* Copyright (c) 2020, Alireza Farshin, KTH Royal Institute of Technology - All Rights Reserved
*/
#include <stdio.h>
#include <stdlib.h>
#include <pci/pci.h>
#include <sys/io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <inttypes.h>
#include <unistd.h>
#define PCI_VENDOR_ID_INTEL 0x8086
#define SKX_PERFCTRLSTS_0 0x180
#define SKX_use_allocating_flow_wr_MASK 0x80
#define SKX_nosnoopopwren_MASK 0x8
/*
* Find the proper pci device (i.e., PCIe Root Port) based on the nic device
* For instance, if the NIC is located on 0000:17:00.0 (i.e., BDF)
* 0x17 is the nic_bus (B)
* 0x00 is the nic_device (D)
* 0x0 is the nic_function (F)
*/
struct pci_access *pacc;
void
init_pci_access(void)
{
pacc = pci_alloc(); /* Get the pci_access structure */
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
}
struct pci_dev*
find_ddio_device(uint8_t nic_bus)
{
struct pci_dev* dev;
for(dev = pacc->devices; dev; dev=dev->next) {
pci_fill_info(dev,PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_NUMA_NODE | PCI_FILL_PHYS_SLOT);
/*
* Find the proper PCIe root based on the nic device
* For instance, if the NIC is located on 0000:17:00.0 (i.e., BDF)
* 0x17 is the nic_bus (B)
* 0x00 is the nic_device (D)
* 0x0 is the nic_function (F)
* TODO: Fix this for Haswell, i.e., 03:00.0 -- Dev and Fun might be different
*/
if(/*dev->func == 0 && dev->dev == 0 && */pci_read_byte(dev,PCI_SUBORDINATE_BUS) == nic_bus /*&& dev->numa_node==1 && dev->domain==0x10001*/) {
return dev;
}
}
printf("Could not find the proper PCIe root!\n");
return NULL;
}
/*
* perfctrlsts_0
* bit 3: NoSnoopOpWrEn -> Should be 1b
* bit 7: Use_Allocating_Flow_Wr -> Should be 0b
* Check p. 68 of Intel® Xeon® Processor Scalable Family
* Datasheet, Volume Two: Registers
* May 2019
* link: https://www.intel.com/content/www/us/en/processors/xeon/scalable/xeon-scalable-datasheet-vol-2.html
*/
int
ddio_status(uint8_t nic_bus)
{
uint32_t val;
if(!pacc)
init_pci_access();
struct pci_dev* dev=find_ddio_device(nic_bus);
if(!dev){
printf("No device found!\n");
exit(1);
}
val=pci_read_long(dev,SKX_PERFCTRLSTS_0);
printf("perfctrlsts_0 val: 0x%" PRIx32 "\n",val);
printf("NoSnoopOpWrEn val: 0x%" PRIx32 "\n",val&SKX_nosnoopopwren_MASK);
printf("Use_Allocating_Flow_Wr val: 0x%" PRIx32 "\n",val&SKX_use_allocating_flow_wr_MASK);
if(val&SKX_use_allocating_flow_wr_MASK)
return 1;
else
return 0;
}
void
ddio_enable(uint8_t nic_bus)
{
uint32_t val;
if(!pacc)
init_pci_access();
if(!ddio_status(nic_bus))
{
struct pci_dev* dev=find_ddio_device(nic_bus);
if(!dev){
printf("No device found!\n");
exit(1);
}
val=pci_read_long(dev,SKX_PERFCTRLSTS_0);
pci_write_long(dev,SKX_PERFCTRLSTS_0,val|SKX_use_allocating_flow_wr_MASK);
printf("DDIO is enabled!\n");
} else
{
printf("DDIO was already enabled!\n");
}
}
void
ddio_disable(uint8_t nic_bus)
{
uint32_t val;
if(!pacc)
init_pci_access();
if(ddio_status(nic_bus))
{
struct pci_dev* dev=find_ddio_device(nic_bus);
if(!dev){
printf("No device found!\n");
exit(1);
}
val=pci_read_long(dev,SKX_PERFCTRLSTS_0);
pci_write_long(dev,SKX_PERFCTRLSTS_0,val&(~SKX_use_allocating_flow_wr_MASK));
printf("DDIO is disabled!\n");
} else
{
printf("DDIO was already disabled\n");
}
}
void
print_dev_info(struct pci_dev *dev)
{
if(!dev){
printf("No device found!\n");
exit(1);
}
unsigned int c;
char namebuf[1024], *name;
printf("========================\n");
printf("%04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x irq=%d (pin %d) base0=%lx \n",
dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id,
dev->device_class, dev->irq, c, (long) dev->base_addr[0]);
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
printf(" (%s)\n", name);
printf("========================\n");
}
int main(void)
{
init_pci_access();
/* Define nic_bus and ddio_state */
uint8_t nic_bus=0x17, ddio_state=0;
struct pci_dev *dev=find_ddio_device(nic_bus);
print_dev_info(dev);
if(ddio_state) {
ddio_enable(nic_bus);
} else {
ddio_disable(nic_bus);
}
pci_cleanup(pacc); /* Close everything */
return 0;
}