15
15
#include <unistd.h>
16
16
#include <dirent.h>
17
17
#include <pci/pci.h>
20
21
#include "dmidecode/dmidecode.h"
24
/* Borrowed from kernel vpd code */
25
#define PCI_VPD_LRDT 0x80
26
#define PCI_VPD_SRDT_END 0x78
28
#define PCI_VPD_SRDT_LEN_MASK 0x7
29
#define PCI_VPD_LRDT_TAG_SIZE 3
30
#define PCI_VPD_SRDT_TAG_SIZE 1
31
#define PCI_VPD_INFO_FLD_HDR_SIZE 3
33
static inline u16 pci_vpd_lrdt_size(const u8 *lrdt)
35
return (u16)lrdt[1] + ((u16)lrdt[2] << 8L);
38
static inline u8 pci_vpd_srdt_size(const u8* srdt)
40
return (*srdt) & PCI_VPD_SRDT_LEN_MASK;
43
static inline u8 pci_vpd_info_field_size(const u8 *info_field)
48
static int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt)
52
for (i = off; i < len;) {
55
if (val & PCI_VPD_LRDT) {
56
if (i + PCI_VPD_LRDT_TAG_SIZE > len)
60
i += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&buf[i]);
62
u8 tag = val & ~PCI_VPD_SRDT_LEN_MASK;
66
if (tag == PCI_VPD_SRDT_END)
68
i += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(&buf[i]);
74
/* Search for matching key/subkey in the VPD data */
75
static int pci_vpd_find_info_subkey(const u8 *buf, unsigned int off, unsigned int len,
76
const char *kw, const char *skw)
80
for (i = off; i + PCI_VPD_INFO_FLD_HDR_SIZE <= off+len;) {
81
/* Match key and subkey names, can use * for regex */
82
if ((kw[0] == '*' || buf[i+0] == kw[0]) &&
83
(kw[1] == '*' || buf[i+1] == kw[1]) &&
84
(skw[0] == '*' || !memcmp(&buf[i+3], skw, 3)))
86
i += PCI_VPD_INFO_FLD_HDR_SIZE + pci_vpd_info_field_size(&buf[i]);
91
static int parse_vpd(struct pci_device *pdev, int len, unsigned char *vpd)
93
int i, j, k, isz, jsz, port, func, pfi;
95
i = pci_vpd_find_tag(vpd, 0, len, 0x90);
98
isz = pci_vpd_lrdt_size(&vpd[i]);
99
i += PCI_VPD_LRDT_TAG_SIZE;
102
j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DSV");
105
jsz = pci_vpd_info_field_size(&vpd[j]);
106
j += PCI_VPD_INFO_FLD_HDR_SIZE;
107
if (memcmp(vpd+j+3, "1028VPDR.VER1.0", 15))
110
/* Lookup NPY Num Ports */
111
j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "NPY");
114
jsz = pci_vpd_info_field_size(&vpd[j]);
115
j += PCI_VPD_INFO_FLD_HDR_SIZE;
116
sscanf((char *)vpd+j+3, "%1x", &port);
117
pdev->vpd_nports = port;
119
/* Lookup Port Mappings */
120
j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DCM");
123
jsz = pci_vpd_info_field_size(&vpd[j]);
124
j += PCI_VPD_INFO_FLD_HDR_SIZE;
126
for (k=3; k<jsz; k+=10) {
127
/* Parse Port Info */
128
sscanf((char *)vpd+j+k, "%1x%1x%2x", &port, &func, &pfi);
129
if (func == pdev->pci_dev->func) {
130
pdev->vpd_port = port;
137
/* Read and parse PCI VPD section if it exists */
138
static int read_pci_vpd(struct pci_device *pdev)
147
unparse_pci_name(pci_name, sizeof(pci_name), pdev->pci_dev);
148
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/vpd", pci_name);
149
if ((fd = open(path, O_RDONLY)) >= 0) {
150
size = lseek(fd, 0, SEEK_END);
153
if ((nrd = pread(fd, vpd, size, 0)) > 0)
154
rc = parse_vpd(pdev, nrd, vpd);
162
static void set_pci_vpd_instance(struct libbiosdevname_state *state)
164
struct pci_device *dev;
166
list_for_each_entry(dev, &state->pci_devices, node) {
23
171
static int read_pci_sysfs_path(char *buf, size_t bufsize, const struct pci_dev *pdev)
25
173
char path[PATH_MAX];
545
696
s += snprintf(s, size-(s-buf), "Index in slot: %u\n", p->index_in_slot);
546
697
if (p->embedded_index_valid)
547
698
s += snprintf(s, size-(s-buf), "Embedded Index: %u\n", p->embedded_index);
699
if (p->vpd_port < INT_MAX) {
700
s += snprintf(s, size-(s-buf), "VPD Port: %u\n", p->vpd_port);
701
s += snprintf(s, size-(s-buf), "VPD Index: %u\n", p->vpd_pfi);
702
s += snprintf(s, size-(s-buf), "VPD #Ports: %u\n", p->vpd_nports);
549
704
if (!list_empty(&p->vfs)) {
550
705
s += snprintf(s, size-(s-buf), "Virtual Functions:\n");
551
706
list_for_each_entry(dev, &p->vfs, vfnode) {