~ubuntu-branches/ubuntu/utopic/biosdevname/utopic-proposed

« back to all changes in this revision

Viewing changes to src/pci.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2011-07-07 15:02:48 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110707150248-c13p3mykepduefnr
Tags: 0.3.8-0ubuntu1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include <unistd.h>
16
16
#include <dirent.h>
17
17
#include <pci/pci.h>
 
18
#include <fcntl.h>
18
19
#include "pci.h"
19
20
#include "sysfs.h"
20
21
#include "dmidecode/dmidecode.h"
21
22
#include "pirq.h"
22
23
 
 
24
/* Borrowed from kernel vpd code */
 
25
#define PCI_VPD_LRDT                    0x80
 
26
#define PCI_VPD_SRDT_END                0x78
 
27
 
 
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
 
32
 
 
33
static inline u16 pci_vpd_lrdt_size(const u8 *lrdt)
 
34
{
 
35
        return (u16)lrdt[1] + ((u16)lrdt[2] << 8L);
 
36
}
 
37
 
 
38
static inline u8 pci_vpd_srdt_size(const u8* srdt)
 
39
{
 
40
        return (*srdt) & PCI_VPD_SRDT_LEN_MASK;
 
41
}
 
42
 
 
43
static inline u8 pci_vpd_info_field_size(const u8 *info_field)
 
44
{
 
45
        return info_field[2];
 
46
}
 
47
 
 
48
static int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt)
 
49
{
 
50
        int i;
 
51
 
 
52
        for (i = off; i < len;) {
 
53
                u8 val = buf[i];
 
54
 
 
55
                if (val & PCI_VPD_LRDT) {
 
56
                        if (i + PCI_VPD_LRDT_TAG_SIZE > len)
 
57
                                break;
 
58
                        if (val == rdt)
 
59
                                return i;
 
60
                        i += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&buf[i]);
 
61
                } else {
 
62
                        u8 tag = val & ~PCI_VPD_SRDT_LEN_MASK;
 
63
                        
 
64
                        if (tag == rdt)
 
65
                                return i;
 
66
                        if (tag == PCI_VPD_SRDT_END)
 
67
                                break;
 
68
                        i += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(&buf[i]);
 
69
                }
 
70
        }
 
71
        return -1;
 
72
}
 
73
 
 
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)
 
77
{
 
78
        int i;
 
79
 
 
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)))
 
85
                        return i;
 
86
                i += PCI_VPD_INFO_FLD_HDR_SIZE + pci_vpd_info_field_size(&buf[i]);
 
87
        }
 
88
        return -1;
 
89
}
 
90
 
 
91
static int parse_vpd(struct pci_device *pdev, int len, unsigned char *vpd)
 
92
{
 
93
        int i, j, k, isz, jsz, port, func, pfi;
 
94
 
 
95
        i = pci_vpd_find_tag(vpd, 0, len, 0x90);
 
96
        if (i < 0)
 
97
                return 1;
 
98
        isz = pci_vpd_lrdt_size(&vpd[i]);
 
99
        i += PCI_VPD_LRDT_TAG_SIZE;
 
100
 
 
101
        /* Lookup Version */
 
102
        j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DSV");
 
103
        if (j < 0)
 
104
                return 1;
 
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))
 
108
                return 1;
 
109
        
 
110
        /* Lookup NPY Num Ports */
 
111
        j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "NPY");
 
112
        if (j < 0)
 
113
                return 1;
 
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;
 
118
 
 
119
        /* Lookup Port Mappings */
 
120
        j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DCM");
 
121
        if (j < 0)
 
122
                return 1;
 
123
        jsz = pci_vpd_info_field_size(&vpd[j]);
 
124
        j += PCI_VPD_INFO_FLD_HDR_SIZE;
 
125
 
 
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;
 
131
                        pdev->vpd_pfi = pfi;
 
132
                }
 
133
        }
 
134
        return 0;
 
135
}
 
136
 
 
137
/* Read and parse PCI VPD section if it exists */
 
138
static int read_pci_vpd(struct pci_device *pdev)
 
139
{
 
140
        char path[PATH_MAX];
 
141
        char pci_name[16];
 
142
        int fd, rc=1;
 
143
        unsigned char *vpd;
 
144
        off_t size;
 
145
        ssize_t nrd;
 
146
 
 
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);
 
151
                vpd  = malloc(size);
 
152
                if (vpd != NULL) {
 
153
                        if ((nrd = pread(fd, vpd, size, 0)) > 0)
 
154
                                rc = parse_vpd(pdev, nrd, vpd);
 
155
                        free(vpd);
 
156
                }
 
157
                close(fd);
 
158
        }
 
159
        return rc;
 
160
}
 
161
 
 
162
static void set_pci_vpd_instance(struct libbiosdevname_state *state)
 
163
{
 
164
        struct pci_device *dev;
 
165
 
 
166
        list_for_each_entry(dev, &state->pci_devices, node) {
 
167
                read_pci_vpd(dev);
 
168
        }
 
169
}
 
170
 
23
171
static int read_pci_sysfs_path(char *buf, size_t bufsize, const struct pci_dev *pdev)
24
172
{
25
173
        char path[PATH_MAX];
317
465
        dev->physical_slot = PHYSICAL_SLOT_UNKNOWN;
318
466
        dev->class         = pci_read_word(p, PCI_CLASS_DEVICE);
319
467
        dev->vf_index = INT_MAX;
 
468
        dev->vpd_port = INT_MAX;
 
469
        dev->vpd_pfi  = INT_MAX;
320
470
        fill_pci_dev_sysfs(dev, p);
321
471
        list_add(&dev->node, &state->pci_devices);
322
472
}
470
620
        set_embedded_index(state);
471
621
        set_pci_slot_index(state);
472
622
        set_sriov_pf_vf(state);
 
623
        set_pci_vpd_instance(state);
473
624
 
474
625
        return rc;
475
626
}
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);
548
 
 
 
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);
 
703
        }
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) {