3 * Copyright (C) 2010 coresystems GmbH
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <libpayload.h>
34 static pcidev_t
libpci_to_lb(struct pci_dev
*dev
)
36 return PCI_DEV(dev
->bus
, dev
->dev
, dev
->func
);
39 /* libpci interface */
40 u8
pci_read_byte(struct pci_dev
*dev
, int pos
)
42 return pci_read_config8(libpci_to_lb(dev
), (uint16_t)pos
);
45 u16
pci_read_word(struct pci_dev
*dev
, int pos
)
47 return pci_read_config16(libpci_to_lb(dev
), (uint16_t)pos
);
50 u32
pci_read_long(struct pci_dev
*dev
, int pos
)
52 return pci_read_config32(libpci_to_lb(dev
), (uint16_t)pos
);
55 int pci_write_byte(struct pci_dev
*dev
, int pos
, u8 data
)
57 pci_write_config8(libpci_to_lb(dev
), (uint16_t)pos
, data
);
58 return 1; /* success */
61 int pci_write_word(struct pci_dev
*dev
, int pos
, u16 data
)
63 pci_write_config16(libpci_to_lb(dev
), (uint16_t)pos
, data
);
64 return 1; /* success */
67 int pci_write_long(struct pci_dev
*dev
, int pos
, u32 data
)
69 pci_write_config32(libpci_to_lb(dev
), (uint16_t)pos
, data
);
70 return 1; /* success */
73 struct pci_access
*pci_alloc(void)
75 return malloc(sizeof(struct pci_access
));
78 void pci_init(struct pci_access
*pacc
)
80 memset(pacc
, 0, sizeof(*pacc
));
83 void pci_cleanup(__attribute__((unused
)) struct pci_access
*pacc
)
87 void pci_filter_init(struct pci_access
* pacc
, struct pci_filter
* pf
)
97 static char invalid_pci_device_string
[] = "invalid pci device string";
99 /* parse domain:bus:dev.func (with all components but "dev" optional)
101 * Returns NULL on success, a string pointer to the error message otherwise.
103 char *pci_filter_parse_slot(struct pci_filter
* filter
, const char* id
)
107 filter
->func
= filter
->dev
= filter
->bus
= filter
->domain
= -1;
109 char *funcp
= strrchr(id
, '.');
111 filter
->func
= strtol(funcp
+1, &endptr
, 0);
112 if (endptr
[0] != '\0') return invalid_pci_device_string
;
115 char *devp
= strrchr(id
, ':');
117 filter
->dev
= strtol(id
, &endptr
, 0);
119 filter
->dev
= strtol(devp
+1, &endptr
, 0);
121 if (endptr
!= funcp
) return invalid_pci_device_string
;
122 if (!devp
) return NULL
;
124 char *busp
= strchr(id
, ':');
126 filter
->bus
= strtol(id
, &endptr
, 0);
128 filter
->bus
= strtol(busp
+1, &endptr
, 0);
130 if (endptr
!= funcp
) return invalid_pci_device_string
;
131 if (busp
== devp
) return NULL
;
133 filter
->domain
= strtol(id
, &endptr
, 0);
134 if (endptr
!= busp
) return invalid_pci_device_string
;
139 int pci_filter_match(struct pci_filter
* pf
, struct pci_dev
* dev
)
141 if ((pf
->domain
> -1) && (pf
->domain
!= dev
->domain
))
143 if ((pf
->bus
> -1) && (pf
->bus
!= dev
->bus
))
145 if ((pf
->dev
> -1) && (pf
->dev
!= dev
->dev
))
147 if ((pf
->func
> -1) && (pf
->func
!= dev
->func
))
149 if ((pf
->vendor
> -1) && (pf
->vendor
!= dev
->vendor_id
))
151 if ((pf
->device
> -1) && (pf
->device
!= dev
->device_id
))
156 static struct pci_dev
*pci_scan_single_bus(struct pci_dev
*dev
, uint8_t bus
)
162 for (devfn
= 0; devfn
< 0x100; devfn
++) {
163 uint8_t func
= devfn
& 0x7;
164 uint8_t slot
= (devfn
>> 3) & 0x1f;
166 val
= pci_read_config32(PCI_DEV(bus
, slot
, func
),
169 if (val
== 0xffffffff || val
== 0x00000000 ||
170 val
== 0x0000ffff || val
== 0xffff0000)
173 dev
->next
= malloc(sizeof(struct pci_dev
));
179 dev
->vendor_id
= val
& 0xffff;
180 dev
->device_id
= (uint16_t)(val
>> 16);
181 dev
->device_class
= pci_read_config16(PCI_DEV(bus
, slot
, func
), PCI_CLASS_DEVICE
);
184 hdr
= pci_read_config8(PCI_DEV(bus
, slot
, func
),
188 if (hdr
== HEADER_TYPE_BRIDGE
|| hdr
== HEADER_TYPE_CARDBUS
) {
190 busses
= (uint8_t)(pci_read_config32(
191 PCI_DEV(bus
, slot
, func
),
192 REG_PRIMARY_BUS
) >> 8);
194 /* Avoid recursion if the new bus is the same as
195 * the old bus (insert lame The Who joke here) */
198 dev
= pci_scan_single_bus(dev
, busses
);
205 void pci_scan_bus(struct pci_access
* pacc
)
207 struct pci_dev rootdev
;
208 pci_scan_single_bus(&rootdev
, 0);
209 pacc
->devices
= rootdev
.next
;
212 struct pci_dev
*pci_get_dev(struct pci_access
* pacc
, u16 domain
, u8 bus
, u8 dev
, u8 func
)
214 struct pci_dev
*cur
= malloc(sizeof(*cur
));
215 cur
->domain
= domain
;
222 void pci_free_dev(struct pci_dev
*const dev
)