15a04522aSIan Romanick /*
25a04522aSIan Romanick * (C) Copyright IBM Corporation 2006
35a04522aSIan Romanick * All Rights Reserved.
45a04522aSIan Romanick *
55a04522aSIan Romanick * Permission is hereby granted, free of charge, to any person obtaining a
65a04522aSIan Romanick * copy of this software and associated documentation files (the "Software"),
75a04522aSIan Romanick * to deal in the Software without restriction, including without limitation
85a04522aSIan Romanick * on the rights to use, copy, modify, merge, publish, distribute, sub
95a04522aSIan Romanick * license, and/or sell copies of the Software, and to permit persons to whom
105a04522aSIan Romanick * the Software is furnished to do so, subject to the following conditions:
115a04522aSIan Romanick *
125a04522aSIan Romanick * The above copyright notice and this permission notice (including the next
135a04522aSIan Romanick * paragraph) shall be included in all copies or substantial portions of the
145a04522aSIan Romanick * Software.
155a04522aSIan Romanick *
165a04522aSIan Romanick * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175a04522aSIan Romanick * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185a04522aSIan Romanick * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
195a04522aSIan Romanick * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205a04522aSIan Romanick * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
215a04522aSIan Romanick * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
225a04522aSIan Romanick * DEALINGS IN THE SOFTWARE.
235a04522aSIan Romanick */
245a04522aSIan Romanick
255a04522aSIan Romanick /**
265a04522aSIan Romanick * \file common_interface.c
275a04522aSIan Romanick * Platform independent interface glue.
285a04522aSIan Romanick *
295a04522aSIan Romanick * \author Ian Romanick <[email protected]>
305a04522aSIan Romanick */
315a04522aSIan Romanick
325a04522aSIan Romanick #include <stdlib.h>
3308ff9f7fSIan Romanick #include <string.h>
345a04522aSIan Romanick #include <errno.h>
355a04522aSIan Romanick
365a04522aSIan Romanick #include "pciaccess.h"
375a04522aSIan Romanick #include "pciaccess_private.h"
385a04522aSIan Romanick
3925de45d2SJulien Cristau #if defined(__linux__) || defined(__GLIBC__)
405a04522aSIan Romanick #include <byteswap.h>
415a04522aSIan Romanick
425a04522aSIan Romanick #if __BYTE_ORDER == __BIG_ENDIAN
435a04522aSIan Romanick # define LETOH_16(x) bswap_16(x)
445a04522aSIan Romanick # define HTOLE_16(x) bswap_16(x)
455a04522aSIan Romanick # define LETOH_32(x) bswap_32(x)
465a04522aSIan Romanick # define HTOLE_32(x) bswap_32(x)
475a04522aSIan Romanick #else
485a04522aSIan Romanick # define LETOH_16(x) (x)
495a04522aSIan Romanick # define HTOLE_16(x) (x)
505a04522aSIan Romanick # define LETOH_32(x) (x)
515a04522aSIan Romanick # define HTOLE_32(x) (x)
52206e2921Sedward shu #endif /* linux */
53206e2921Sedward shu
54206e2921Sedward shu #elif defined(__sun)
55ccbfd4cfSAlan Coopersmith
56ccbfd4cfSAlan Coopersmith #include <sys/byteorder.h>
57ccbfd4cfSAlan Coopersmith
58ccbfd4cfSAlan Coopersmith #ifdef _BIG_ENDIAN
59ccbfd4cfSAlan Coopersmith # define LETOH_16(x) BSWAP_16(x)
60ccbfd4cfSAlan Coopersmith # define HTOLE_16(x) BSWAP_16(x)
61ccbfd4cfSAlan Coopersmith # define LETOH_32(x) BSWAP_32(x)
62ccbfd4cfSAlan Coopersmith # define HTOLE_32(x) BSWAP_32(x)
63ccbfd4cfSAlan Coopersmith #else
64206e2921Sedward shu # define LETOH_16(x) (x)
65206e2921Sedward shu # define HTOLE_16(x) (x)
66206e2921Sedward shu # define LETOH_32(x) (x)
67206e2921Sedward shu # define HTOLE_32(x) (x)
68ccbfd4cfSAlan Coopersmith #endif /* Solaris */
695a04522aSIan Romanick
70cf1b4d3dSEric Anholt #else
71cf1b4d3dSEric Anholt
72cf1b4d3dSEric Anholt #include <sys/endian.h>
73cf1b4d3dSEric Anholt
74cf1b4d3dSEric Anholt #define HTOLE_16(x) htole16(x)
75cf1b4d3dSEric Anholt #define HTOLE_32(x) htole32(x)
76cf1b4d3dSEric Anholt
774c1c607cSJuan RP #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
78d898072eSMark Kettenis #define LETOH_16(x) le16toh(x)
79d898072eSMark Kettenis #define LETOH_32(x) le32toh(x)
80d898072eSMark Kettenis #else
81d898072eSMark Kettenis #define LETOH_16(x) letoh16(x)
82d898072eSMark Kettenis #define LETOH_32(x) letoh32(x)
83d898072eSMark Kettenis #endif
84d898072eSMark Kettenis
85206e2921Sedward shu #endif /* others */
86cf1b4d3dSEric Anholt
875a04522aSIan Romanick /**
885a04522aSIan Romanick * Read a device's expansion ROM.
895a04522aSIan Romanick *
905a04522aSIan Romanick * Reads the device's expansion ROM and stores the data in the memory pointed
915a04522aSIan Romanick * to by \c buffer. The buffer must be at least \c pci_device::rom_size
925a04522aSIan Romanick * bytes.
935a04522aSIan Romanick *
945a04522aSIan Romanick * \param dev Device whose expansion ROM is to be read.
955a04522aSIan Romanick * \param buffer Memory in which to store the ROM.
965a04522aSIan Romanick *
975a04522aSIan Romanick * \return
985a04522aSIan Romanick * Zero on success or an \c errno value on failure.
995a04522aSIan Romanick */
1005a04522aSIan Romanick int
pci_device_read_rom(struct pci_device * dev,void * buffer)1015a04522aSIan Romanick pci_device_read_rom( struct pci_device * dev, void * buffer )
1025a04522aSIan Romanick {
1035a04522aSIan Romanick if ( (dev == NULL) || (buffer == NULL) ) {
1045a04522aSIan Romanick return EFAULT;
1055a04522aSIan Romanick }
1065a04522aSIan Romanick
1075a04522aSIan Romanick
1085a04522aSIan Romanick return (pci_sys->methods->read_rom)( dev, buffer );
1095a04522aSIan Romanick }
1105a04522aSIan Romanick
111b2838fb6SDave Airlie /**
112b2838fb6SDave Airlie * Probe a PCI (VGA) device to determine if its the boot VGA device
113b2838fb6SDave Airlie *
114b2838fb6SDave Airlie * \param dev Device whose VGA status to query
115b2838fb6SDave Airlie * \return
116b2838fb6SDave Airlie * Zero if not the boot VGA, 1 if the boot VGA.
117b2838fb6SDave Airlie */
118b2838fb6SDave Airlie int
pci_device_is_boot_vga(struct pci_device * dev)119b2838fb6SDave Airlie pci_device_is_boot_vga( struct pci_device * dev )
120b2838fb6SDave Airlie {
121b2838fb6SDave Airlie if (!pci_sys->methods->boot_vga)
122b2838fb6SDave Airlie return 0;
123b2838fb6SDave Airlie return pci_sys->methods->boot_vga( dev );
124b2838fb6SDave Airlie }
1255a04522aSIan Romanick
1265a04522aSIan Romanick /**
1275d1bdf0cSDave Airlie * Probe a PCI device to determine if a kernel driver is attached.
1285d1bdf0cSDave Airlie *
1295d1bdf0cSDave Airlie * \param dev Device to query
1305d1bdf0cSDave Airlie * \return
1315d1bdf0cSDave Airlie * Zero if no driver attached, 1 if attached kernel drviver
1325d1bdf0cSDave Airlie */
1335d1bdf0cSDave Airlie int
pci_device_has_kernel_driver(struct pci_device * dev)1345d1bdf0cSDave Airlie pci_device_has_kernel_driver( struct pci_device * dev )
1355d1bdf0cSDave Airlie {
1365d1bdf0cSDave Airlie if (!pci_sys->methods->has_kernel_driver)
1375d1bdf0cSDave Airlie return 0;
1385d1bdf0cSDave Airlie return pci_sys->methods->has_kernel_driver( dev );
1395d1bdf0cSDave Airlie }
1405d1bdf0cSDave Airlie
1415d1bdf0cSDave Airlie /**
1425a04522aSIan Romanick * Probe a PCI device to learn information about the device.
1435a04522aSIan Romanick *
1445a04522aSIan Romanick * Probes a PCI device to learn various information about the device. Before
1455a04522aSIan Romanick * calling this function, the only public fields in the \c pci_device
1465a04522aSIan Romanick * structure that have valid values are \c pci_device::domain,
1475a04522aSIan Romanick * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func.
1485a04522aSIan Romanick *
1495a04522aSIan Romanick * \param dev Device to be probed.
1505a04522aSIan Romanick *
1515a04522aSIan Romanick * \return
152d43d21c8SAlan Coopersmith * Zero on success or an \c errno value on failure.
1535a04522aSIan Romanick */
1545a04522aSIan Romanick int
pci_device_probe(struct pci_device * dev)1555a04522aSIan Romanick pci_device_probe( struct pci_device * dev )
1565a04522aSIan Romanick {
1575a04522aSIan Romanick if ( dev == NULL ) {
1585a04522aSIan Romanick return EFAULT;
1595a04522aSIan Romanick }
1605a04522aSIan Romanick
1615a04522aSIan Romanick
1625a04522aSIan Romanick return (pci_sys->methods->probe)( dev );
1635a04522aSIan Romanick }
1645a04522aSIan Romanick
1655a04522aSIan Romanick
1665a04522aSIan Romanick /**
1675a04522aSIan Romanick * Map the specified BAR so that it can be accessed by the CPU.
1685a04522aSIan Romanick *
169d43d21c8SAlan Coopersmith * Maps the specified BAR for access by the processor. The pointer to the
1705a04522aSIan Romanick * mapped region is stored in the \c pci_mem_region::memory pointer for the
1715a04522aSIan Romanick * BAR.
1725a04522aSIan Romanick *
1735a04522aSIan Romanick * \param dev Device whose memory region is to be mapped.
1745a04522aSIan Romanick * \param region Region, on the range [0, 5], that is to be mapped.
1755a04522aSIan Romanick * \param write_enable Map for writing (non-zero).
1765a04522aSIan Romanick *
1775a04522aSIan Romanick * \return
1785a04522aSIan Romanick * Zero on success or an \c errno value on failure.
1795a04522aSIan Romanick *
18008ff9f7fSIan Romanick * \sa pci_device_map_range, pci_device_unmap_range
18108ff9f7fSIan Romanick * \deprecated
1825a04522aSIan Romanick */
1835a04522aSIan Romanick int
pci_device_map_region(struct pci_device * dev,unsigned region,int write_enable)1845a04522aSIan Romanick pci_device_map_region(struct pci_device * dev, unsigned region,
1855a04522aSIan Romanick int write_enable)
1865a04522aSIan Romanick {
18708ff9f7fSIan Romanick const unsigned map_flags =
18808ff9f7fSIan Romanick (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0;
1895a04522aSIan Romanick
1905a04522aSIan Romanick if ((region > 5) || (dev->regions[region].size == 0)) {
1915a04522aSIan Romanick return ENOENT;
1925a04522aSIan Romanick }
1935a04522aSIan Romanick
1945a04522aSIan Romanick if (dev->regions[region].memory != NULL) {
1955a04522aSIan Romanick return 0;
1965a04522aSIan Romanick }
1975a04522aSIan Romanick
19808ff9f7fSIan Romanick return pci_device_map_range(dev, dev->regions[region].base_addr,
19908ff9f7fSIan Romanick dev->regions[region].size, map_flags,
20008ff9f7fSIan Romanick &dev->regions[region].memory);
2015a04522aSIan Romanick }
2025a04522aSIan Romanick
2035a04522aSIan Romanick
2045a04522aSIan Romanick /**
205c65aa763SIan Romanick * Map the specified memory range so that it can be accessed by the CPU.
206c65aa763SIan Romanick *
207c65aa763SIan Romanick * Maps the specified memory range for access by the processor. The pointer
208d43d21c8SAlan Coopersmith * to the mapped region is stored in \c addr. In addition, the
209c65aa763SIan Romanick * \c pci_mem_region::memory pointer for the BAR will be updated.
210c65aa763SIan Romanick *
211c65aa763SIan Romanick * \param dev Device whose memory region is to be mapped.
212c65aa763SIan Romanick * \param base Base address of the range to be mapped.
213c65aa763SIan Romanick * \param size Size of the range to be mapped.
21482a2ff0bSIan Romanick * \param write_enable Map for writing (non-zero).
21582a2ff0bSIan Romanick * \param addr Location to store the mapped address.
21682a2ff0bSIan Romanick *
21782a2ff0bSIan Romanick * \return
21882a2ff0bSIan Romanick * Zero on success or an \c errno value on failure.
21982a2ff0bSIan Romanick *
22082a2ff0bSIan Romanick * \sa pci_device_map_range
22182a2ff0bSIan Romanick */
pci_device_map_memory_range(struct pci_device * dev,pciaddr_t base,pciaddr_t size,int write_enable,void ** addr)22282a2ff0bSIan Romanick int pci_device_map_memory_range(struct pci_device *dev,
22382a2ff0bSIan Romanick pciaddr_t base, pciaddr_t size,
22482a2ff0bSIan Romanick int write_enable, void **addr)
22582a2ff0bSIan Romanick {
22682a2ff0bSIan Romanick return pci_device_map_range(dev, base, size,
22782a2ff0bSIan Romanick (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE : 0,
22882a2ff0bSIan Romanick addr);
22982a2ff0bSIan Romanick }
23082a2ff0bSIan Romanick
23182a2ff0bSIan Romanick
23282a2ff0bSIan Romanick /**
23382a2ff0bSIan Romanick * Map the specified memory range so that it can be accessed by the CPU.
23482a2ff0bSIan Romanick *
23582a2ff0bSIan Romanick * Maps the specified memory range for access by the processor. The pointer
236d43d21c8SAlan Coopersmith * to the mapped region is stored in \c addr. In addition, the
23782a2ff0bSIan Romanick * \c pci_mem_region::memory pointer for the BAR will be updated.
23882a2ff0bSIan Romanick *
23982a2ff0bSIan Romanick * \param dev Device whose memory region is to be mapped.
24082a2ff0bSIan Romanick * \param base Base address of the range to be mapped.
24182a2ff0bSIan Romanick * \param size Size of the range to be mapped.
24208ff9f7fSIan Romanick * \param map_flags Flag bits controlling how the mapping is accessed.
243c65aa763SIan Romanick * \param addr Location to store the mapped address.
244c65aa763SIan Romanick *
245c65aa763SIan Romanick * \return
246c65aa763SIan Romanick * Zero on success or an \c errno value on failure.
247c65aa763SIan Romanick *
24808ff9f7fSIan Romanick * \sa pci_device_unmap_range
249c65aa763SIan Romanick */
250c65aa763SIan Romanick int
pci_device_map_range(struct pci_device * dev,pciaddr_t base,pciaddr_t size,unsigned map_flags,void ** addr)25108ff9f7fSIan Romanick pci_device_map_range(struct pci_device *dev, pciaddr_t base,
25208ff9f7fSIan Romanick pciaddr_t size, unsigned map_flags,
253c65aa763SIan Romanick void **addr)
254c65aa763SIan Romanick {
25508ff9f7fSIan Romanick struct pci_device_private *const devp =
25608ff9f7fSIan Romanick (struct pci_device_private *) dev;
25708ff9f7fSIan Romanick struct pci_device_mapping *mappings;
258c65aa763SIan Romanick unsigned region;
25908ff9f7fSIan Romanick unsigned i;
260c65aa763SIan Romanick int err = 0;
261c65aa763SIan Romanick
262c65aa763SIan Romanick
263c65aa763SIan Romanick *addr = NULL;
264c65aa763SIan Romanick
265c65aa763SIan Romanick if (dev == NULL) {
266c65aa763SIan Romanick return EFAULT;
267c65aa763SIan Romanick }
268c65aa763SIan Romanick
269c65aa763SIan Romanick
270c65aa763SIan Romanick for (region = 0; region < 6; region++) {
271c65aa763SIan Romanick const struct pci_mem_region const* r = &dev->regions[region];
272c65aa763SIan Romanick
273c65aa763SIan Romanick if (r->size != 0) {
274c65aa763SIan Romanick if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) {
275c65aa763SIan Romanick if ((base + size) > (r->base_addr + r->size)) {
276c65aa763SIan Romanick return E2BIG;
277c65aa763SIan Romanick }
278c65aa763SIan Romanick
279c65aa763SIan Romanick break;
280c65aa763SIan Romanick }
281c65aa763SIan Romanick }
282c65aa763SIan Romanick }
283c65aa763SIan Romanick
284c65aa763SIan Romanick if (region > 5) {
285c65aa763SIan Romanick return ENOENT;
286c65aa763SIan Romanick }
287c65aa763SIan Romanick
28808ff9f7fSIan Romanick /* Make sure that there isn't already a mapping with the same base and
28908ff9f7fSIan Romanick * size.
29008ff9f7fSIan Romanick */
29108ff9f7fSIan Romanick for (i = 0; i < devp->num_mappings; i++) {
29208ff9f7fSIan Romanick if ((devp->mappings[i].base == base)
29308ff9f7fSIan Romanick && (devp->mappings[i].size == size)) {
29408ff9f7fSIan Romanick return EINVAL;
29508ff9f7fSIan Romanick }
29608ff9f7fSIan Romanick }
29708ff9f7fSIan Romanick
29808ff9f7fSIan Romanick
29908ff9f7fSIan Romanick mappings = realloc(devp->mappings,
30008ff9f7fSIan Romanick (sizeof(devp->mappings[0]) * (devp->num_mappings + 1)));
30108ff9f7fSIan Romanick if (mappings == NULL) {
30208ff9f7fSIan Romanick return ENOMEM;
30308ff9f7fSIan Romanick }
30408ff9f7fSIan Romanick
30508ff9f7fSIan Romanick mappings[devp->num_mappings].base = base;
30608ff9f7fSIan Romanick mappings[devp->num_mappings].size = size;
30708ff9f7fSIan Romanick mappings[devp->num_mappings].region = region;
30808ff9f7fSIan Romanick mappings[devp->num_mappings].flags = map_flags;
30908ff9f7fSIan Romanick mappings[devp->num_mappings].memory = NULL;
31008ff9f7fSIan Romanick
311c65aa763SIan Romanick if (dev->regions[region].memory == NULL) {
31208ff9f7fSIan Romanick err = (*pci_sys->methods->map_range)(dev,
31308ff9f7fSIan Romanick &mappings[devp->num_mappings]);
314c65aa763SIan Romanick }
315c65aa763SIan Romanick
316c65aa763SIan Romanick if (err == 0) {
31708ff9f7fSIan Romanick *addr = mappings[devp->num_mappings].memory;
31808ff9f7fSIan Romanick devp->num_mappings++;
31908ff9f7fSIan Romanick } else {
320e5159771SDave Airlie mappings = realloc(mappings,
321e5159771SDave Airlie (sizeof(mappings[0]) * devp->num_mappings));
322c65aa763SIan Romanick }
323c65aa763SIan Romanick
32408ff9f7fSIan Romanick devp->mappings = mappings;
32508ff9f7fSIan Romanick
326c65aa763SIan Romanick return err;
327c65aa763SIan Romanick }
328c65aa763SIan Romanick
329c65aa763SIan Romanick
330c65aa763SIan Romanick /**
3315a04522aSIan Romanick * Unmap the specified BAR so that it can no longer be accessed by the CPU.
3325a04522aSIan Romanick *
3335a04522aSIan Romanick * Unmaps the specified BAR that was previously mapped via
3345a04522aSIan Romanick * \c pci_device_map_region.
3355a04522aSIan Romanick *
3365a04522aSIan Romanick * \param dev Device whose memory region is to be mapped.
3375a04522aSIan Romanick * \param region Region, on the range [0, 5], that is to be mapped.
3385a04522aSIan Romanick *
3395a04522aSIan Romanick * \return
3405a04522aSIan Romanick * Zero on success or an \c errno value on failure.
3415a04522aSIan Romanick *
34208ff9f7fSIan Romanick * \sa pci_device_map_range, pci_device_unmap_range
34308ff9f7fSIan Romanick * \deprecated
3445a04522aSIan Romanick */
3455a04522aSIan Romanick int
pci_device_unmap_region(struct pci_device * dev,unsigned region)3465a04522aSIan Romanick pci_device_unmap_region( struct pci_device * dev, unsigned region )
3475a04522aSIan Romanick {
34808ff9f7fSIan Romanick int err;
34908ff9f7fSIan Romanick
3505a04522aSIan Romanick if (dev == NULL) {
3515a04522aSIan Romanick return EFAULT;
3525a04522aSIan Romanick }
3535a04522aSIan Romanick
3545a04522aSIan Romanick if ((region > 5) || (dev->regions[region].size == 0)) {
3555a04522aSIan Romanick return ENOENT;
3565a04522aSIan Romanick }
3575a04522aSIan Romanick
35808ff9f7fSIan Romanick err = pci_device_unmap_range(dev, dev->regions[region].memory,
35908ff9f7fSIan Romanick dev->regions[region].size);
36008ff9f7fSIan Romanick if (!err) {
36108ff9f7fSIan Romanick dev->regions[region].memory = NULL;
3625a04522aSIan Romanick }
3635a04522aSIan Romanick
36408ff9f7fSIan Romanick return err;
3655a04522aSIan Romanick }
3665a04522aSIan Romanick
3675a04522aSIan Romanick
3685a04522aSIan Romanick /**
369c65aa763SIan Romanick * Unmap the specified memory range so that it can no longer be accessed by the CPU.
370c65aa763SIan Romanick *
371c65aa763SIan Romanick * Unmaps the specified memory range that was previously mapped via
372c65aa763SIan Romanick * \c pci_device_map_memory_range.
373c65aa763SIan Romanick *
374c65aa763SIan Romanick * \param dev Device whose memory is to be unmapped.
375c65aa763SIan Romanick * \param memory Pointer to the base of the mapped range.
376c65aa763SIan Romanick * \param size Size, in bytes, of the range to be unmapped.
377c65aa763SIan Romanick *
378c65aa763SIan Romanick * \return
379c65aa763SIan Romanick * Zero on success or an \c errno value on failure.
380c65aa763SIan Romanick *
38108ff9f7fSIan Romanick * \sa pci_device_map_range, pci_device_unmap_range
38208ff9f7fSIan Romanick * \deprecated
383c65aa763SIan Romanick */
384c65aa763SIan Romanick int
pci_device_unmap_memory_range(struct pci_device * dev,void * memory,pciaddr_t size)385c65aa763SIan Romanick pci_device_unmap_memory_range(struct pci_device *dev, void *memory,
386c65aa763SIan Romanick pciaddr_t size)
387c65aa763SIan Romanick {
38808ff9f7fSIan Romanick return pci_device_unmap_range(dev, memory, size);
38908ff9f7fSIan Romanick }
39008ff9f7fSIan Romanick
39108ff9f7fSIan Romanick
39208ff9f7fSIan Romanick /**
39308ff9f7fSIan Romanick * Unmap the specified memory range so that it can no longer be accessed by the CPU.
39408ff9f7fSIan Romanick *
39508ff9f7fSIan Romanick * Unmaps the specified memory range that was previously mapped via
39608ff9f7fSIan Romanick * \c pci_device_map_memory_range.
39708ff9f7fSIan Romanick *
39808ff9f7fSIan Romanick * \param dev Device whose memory is to be unmapped.
39908ff9f7fSIan Romanick * \param memory Pointer to the base of the mapped range.
40008ff9f7fSIan Romanick * \param size Size, in bytes, of the range to be unmapped.
40108ff9f7fSIan Romanick *
40208ff9f7fSIan Romanick * \return
40308ff9f7fSIan Romanick * Zero on success or an \c errno value on failure.
40408ff9f7fSIan Romanick *
40508ff9f7fSIan Romanick * \sa pci_device_map_range
40608ff9f7fSIan Romanick */
40708ff9f7fSIan Romanick int
pci_device_unmap_range(struct pci_device * dev,void * memory,pciaddr_t size)40808ff9f7fSIan Romanick pci_device_unmap_range(struct pci_device *dev, void *memory,
40908ff9f7fSIan Romanick pciaddr_t size)
41008ff9f7fSIan Romanick {
41108ff9f7fSIan Romanick struct pci_device_private *const devp =
41208ff9f7fSIan Romanick (struct pci_device_private *) dev;
41308ff9f7fSIan Romanick unsigned i;
41408ff9f7fSIan Romanick int err;
415c65aa763SIan Romanick
416c65aa763SIan Romanick
417c65aa763SIan Romanick if (dev == NULL) {
418c65aa763SIan Romanick return EFAULT;
419c65aa763SIan Romanick }
420c65aa763SIan Romanick
42108ff9f7fSIan Romanick for (i = 0; i < devp->num_mappings; i++) {
42208ff9f7fSIan Romanick if ((devp->mappings[i].memory == memory)
42308ff9f7fSIan Romanick && (devp->mappings[i].size == size)) {
424c65aa763SIan Romanick break;
425c65aa763SIan Romanick }
426c65aa763SIan Romanick }
427c65aa763SIan Romanick
42808ff9f7fSIan Romanick if (i == devp->num_mappings) {
429c65aa763SIan Romanick return ENOENT;
430c65aa763SIan Romanick }
431c65aa763SIan Romanick
43208ff9f7fSIan Romanick
43308ff9f7fSIan Romanick err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]);
43408ff9f7fSIan Romanick if (!err) {
43508ff9f7fSIan Romanick const unsigned entries_to_move = (devp->num_mappings - i) - 1;
43608ff9f7fSIan Romanick
43708ff9f7fSIan Romanick if (entries_to_move > 0) {
43808ff9f7fSIan Romanick (void) memmove(&devp->mappings[i],
43908ff9f7fSIan Romanick &devp->mappings[i + 1],
44008ff9f7fSIan Romanick entries_to_move * sizeof(devp->mappings[0]));
44108ff9f7fSIan Romanick }
44208ff9f7fSIan Romanick
44308ff9f7fSIan Romanick devp->num_mappings--;
44408ff9f7fSIan Romanick devp->mappings = realloc(devp->mappings,
44508ff9f7fSIan Romanick (sizeof(devp->mappings[0]) * devp->num_mappings));
44608ff9f7fSIan Romanick }
44708ff9f7fSIan Romanick
44808ff9f7fSIan Romanick return err;
449c65aa763SIan Romanick }
450c65aa763SIan Romanick
451c65aa763SIan Romanick
452c65aa763SIan Romanick /**
4535a04522aSIan Romanick * Read arbitrary bytes from device's PCI config space
4545a04522aSIan Romanick *
4555a04522aSIan Romanick * Reads data from the device's PCI configuration space. As with the system
4565a04522aSIan Romanick * read command, less data may be returned, without an error, than was
457d43d21c8SAlan Coopersmith * requested. This is particularly the case if a non-root user tries to read
4585a04522aSIan Romanick * beyond the first 64-bytes of configuration space.
4595a04522aSIan Romanick *
4605a04522aSIan Romanick * \param dev Device whose PCI configuration data is to be read.
4615a04522aSIan Romanick * \param data Location to store the data
4625a04522aSIan Romanick * \param offset Initial byte offset to read
4635a04522aSIan Romanick * \param size Total number of bytes to read
4645a04522aSIan Romanick * \param bytes_read Location to store the actual number of bytes read. This
4655a04522aSIan Romanick * pointer may be \c NULL.
4665a04522aSIan Romanick *
4675a04522aSIan Romanick * \returns
4685a04522aSIan Romanick * Zero on success or an errno value on failure.
4695a04522aSIan Romanick *
4705a04522aSIan Romanick * \note
471d43d21c8SAlan Coopersmith * Data read from PCI configuration space using this routine is \b not
4725a04522aSIan Romanick * byte-swapped to the host's byte order. PCI configuration data is always
4735a04522aSIan Romanick * stored in little-endian order, and that is what this routine returns.
4745a04522aSIan Romanick */
4755a04522aSIan Romanick int
pci_device_cfg_read(struct pci_device * dev,void * data,pciaddr_t offset,pciaddr_t size,pciaddr_t * bytes_read)4765a04522aSIan Romanick pci_device_cfg_read( struct pci_device * dev, void * data,
4775a04522aSIan Romanick pciaddr_t offset, pciaddr_t size,
4785a04522aSIan Romanick pciaddr_t * bytes_read )
4795a04522aSIan Romanick {
4805a04522aSIan Romanick pciaddr_t scratch;
4815a04522aSIan Romanick
4825a04522aSIan Romanick if ( (dev == NULL) || (data == NULL) ) {
4835a04522aSIan Romanick return EFAULT;
4845a04522aSIan Romanick }
4855a04522aSIan Romanick
4865a04522aSIan Romanick return pci_sys->methods->read( dev, data, offset, size,
4875a04522aSIan Romanick (bytes_read == NULL)
4885a04522aSIan Romanick ? & scratch : bytes_read );
4895a04522aSIan Romanick }
4905a04522aSIan Romanick
4915a04522aSIan Romanick
4925a04522aSIan Romanick int
pci_device_cfg_read_u8(struct pci_device * dev,uint8_t * data,pciaddr_t offset)4935a04522aSIan Romanick pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data,
4945a04522aSIan Romanick pciaddr_t offset )
4955a04522aSIan Romanick {
496*790e93c3Sarsharma pciaddr_t bytes = 0;
4975a04522aSIan Romanick int err = pci_device_cfg_read( dev, data, offset, 1, & bytes );
4985a04522aSIan Romanick
4995a04522aSIan Romanick if ( (err == 0) && (bytes != 1) ) {
500edf39089SEric Anholt err = ENXIO;
5015a04522aSIan Romanick }
5025a04522aSIan Romanick
5035a04522aSIan Romanick return err;
5045a04522aSIan Romanick }
5055a04522aSIan Romanick
5065a04522aSIan Romanick
5075a04522aSIan Romanick int
pci_device_cfg_read_u16(struct pci_device * dev,uint16_t * data,pciaddr_t offset)5085a04522aSIan Romanick pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data,
5095a04522aSIan Romanick pciaddr_t offset )
5105a04522aSIan Romanick {
511*790e93c3Sarsharma pciaddr_t bytes = 0;
5125a04522aSIan Romanick int err = pci_device_cfg_read( dev, data, offset, 2, & bytes );
5135a04522aSIan Romanick
5145a04522aSIan Romanick if ( (err == 0) && (bytes != 2) ) {
515edf39089SEric Anholt err = ENXIO;
5165a04522aSIan Romanick }
5175a04522aSIan Romanick
5185a04522aSIan Romanick *data = LETOH_16( *data );
5195a04522aSIan Romanick return err;
5205a04522aSIan Romanick }
5215a04522aSIan Romanick
5225a04522aSIan Romanick
5235a04522aSIan Romanick int
pci_device_cfg_read_u32(struct pci_device * dev,uint32_t * data,pciaddr_t offset)5245a04522aSIan Romanick pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data,
5255a04522aSIan Romanick pciaddr_t offset )
5265a04522aSIan Romanick {
527*790e93c3Sarsharma pciaddr_t bytes = 0;
5285a04522aSIan Romanick int err = pci_device_cfg_read( dev, data, offset, 4, & bytes );
5295a04522aSIan Romanick
5305a04522aSIan Romanick if ( (err == 0) && (bytes != 4) ) {
531edf39089SEric Anholt err = ENXIO;
5325a04522aSIan Romanick }
5335a04522aSIan Romanick
5345a04522aSIan Romanick *data = LETOH_32( *data );
5355a04522aSIan Romanick return err;
5365a04522aSIan Romanick }
5375a04522aSIan Romanick
5385a04522aSIan Romanick
5395a04522aSIan Romanick /**
5405a04522aSIan Romanick * Write arbitrary bytes to device's PCI config space
5415a04522aSIan Romanick *
542d43d21c8SAlan Coopersmith * Writes data to the device's PCI configuration space. As with the system
5435a04522aSIan Romanick * write command, less data may be written, without an error, than was
5445a04522aSIan Romanick * requested.
5455a04522aSIan Romanick *
5465a04522aSIan Romanick * \param dev Device whose PCI configuration data is to be written.
5475a04522aSIan Romanick * \param data Location of the source data
5485a04522aSIan Romanick * \param offset Initial byte offset to write
5495a04522aSIan Romanick * \param size Total number of bytes to write
5505a04522aSIan Romanick * \param bytes_read Location to store the actual number of bytes written.
5515a04522aSIan Romanick * This pointer may be \c NULL.
5525a04522aSIan Romanick *
5535a04522aSIan Romanick * \returns
5545a04522aSIan Romanick * Zero on success or an errno value on failure.
5555a04522aSIan Romanick *
5565a04522aSIan Romanick * \note
557d43d21c8SAlan Coopersmith * Data written to PCI configuration space using this routine is \b not
5585a04522aSIan Romanick * byte-swapped from the host's byte order. PCI configuration data is always
5595a04522aSIan Romanick * stored in little-endian order, so data written with this routine should be
5605a04522aSIan Romanick * put in that order in advance.
5615a04522aSIan Romanick */
5625a04522aSIan Romanick int
pci_device_cfg_write(struct pci_device * dev,const void * data,pciaddr_t offset,pciaddr_t size,pciaddr_t * bytes_written)5635a04522aSIan Romanick pci_device_cfg_write( struct pci_device * dev, const void * data,
5645a04522aSIan Romanick pciaddr_t offset, pciaddr_t size,
5655a04522aSIan Romanick pciaddr_t * bytes_written )
5665a04522aSIan Romanick {
5675a04522aSIan Romanick pciaddr_t scratch;
5685a04522aSIan Romanick
5695a04522aSIan Romanick if ( (dev == NULL) || (data == NULL) ) {
5705a04522aSIan Romanick return EFAULT;
5715a04522aSIan Romanick }
5725a04522aSIan Romanick
5735a04522aSIan Romanick return pci_sys->methods->write( dev, data, offset, size,
5745a04522aSIan Romanick (bytes_written == NULL)
5755a04522aSIan Romanick ? & scratch : bytes_written );
5765a04522aSIan Romanick }
5775a04522aSIan Romanick
5785a04522aSIan Romanick
5795a04522aSIan Romanick int
pci_device_cfg_write_u8(struct pci_device * dev,uint8_t data,pciaddr_t offset)58037ce43c1SIan Romanick pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data,
5815a04522aSIan Romanick pciaddr_t offset)
5825a04522aSIan Romanick {
583*790e93c3Sarsharma pciaddr_t bytes = 0;
584cc1d08f1SIan Romanick int err = pci_device_cfg_write(dev, & data, offset, 1, & bytes);
5855a04522aSIan Romanick
5865a04522aSIan Romanick if ( (err == 0) && (bytes != 1) ) {
5875a04522aSIan Romanick err = ENOSPC;
5885a04522aSIan Romanick }
5895a04522aSIan Romanick
5905a04522aSIan Romanick
5915a04522aSIan Romanick return err;
5925a04522aSIan Romanick }
5935a04522aSIan Romanick
5945a04522aSIan Romanick
5955a04522aSIan Romanick int
pci_device_cfg_write_u16(struct pci_device * dev,uint16_t data,pciaddr_t offset)59637ce43c1SIan Romanick pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data,
5975a04522aSIan Romanick pciaddr_t offset)
5985a04522aSIan Romanick {
599*790e93c3Sarsharma pciaddr_t bytes = 0;
60037ce43c1SIan Romanick const uint16_t temp = HTOLE_16(data);
6015a04522aSIan Romanick int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes );
6025a04522aSIan Romanick
6035a04522aSIan Romanick if ( (err == 0) && (bytes != 2) ) {
6045a04522aSIan Romanick err = ENOSPC;
6055a04522aSIan Romanick }
6065a04522aSIan Romanick
6075a04522aSIan Romanick
6085a04522aSIan Romanick return err;
6095a04522aSIan Romanick }
6105a04522aSIan Romanick
6115a04522aSIan Romanick
6125a04522aSIan Romanick int
pci_device_cfg_write_u32(struct pci_device * dev,uint32_t data,pciaddr_t offset)61337ce43c1SIan Romanick pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data,
6145a04522aSIan Romanick pciaddr_t offset)
6155a04522aSIan Romanick {
616*790e93c3Sarsharma pciaddr_t bytes = 0;
61737ce43c1SIan Romanick const uint32_t temp = HTOLE_32(data);
6185a04522aSIan Romanick int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes );
6195a04522aSIan Romanick
6205a04522aSIan Romanick if ( (err == 0) && (bytes != 4) ) {
6215a04522aSIan Romanick err = ENOSPC;
6225a04522aSIan Romanick }
6235a04522aSIan Romanick
6245a04522aSIan Romanick
6255a04522aSIan Romanick return err;
6265a04522aSIan Romanick }
62764af050cSIan Romanick
62864af050cSIan Romanick
62964af050cSIan Romanick int
pci_device_cfg_write_bits(struct pci_device * dev,uint32_t mask,uint32_t data,pciaddr_t offset)63064af050cSIan Romanick pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
63164af050cSIan Romanick uint32_t data, pciaddr_t offset )
63264af050cSIan Romanick {
63364af050cSIan Romanick uint32_t temp;
63464af050cSIan Romanick int err;
63564af050cSIan Romanick
63664af050cSIan Romanick err = pci_device_cfg_read_u32( dev, & temp, offset );
63764af050cSIan Romanick if ( ! err ) {
63864af050cSIan Romanick temp &= ~mask;
63964af050cSIan Romanick temp |= data;
64064af050cSIan Romanick
64137ce43c1SIan Romanick err = pci_device_cfg_write_u32(dev, temp, offset);
64264af050cSIan Romanick }
64364af050cSIan Romanick
64464af050cSIan Romanick return err;
64564af050cSIan Romanick }
6464bc9292fSDave Airlie
6474bc9292fSDave Airlie void
pci_device_enable(struct pci_device * dev)6484bc9292fSDave Airlie pci_device_enable(struct pci_device *dev)
6494bc9292fSDave Airlie {
6504bc9292fSDave Airlie if (dev == NULL) {
6514bc9292fSDave Airlie return;
6524bc9292fSDave Airlie }
6534bc9292fSDave Airlie
6544bc9292fSDave Airlie if (pci_sys->methods->enable)
6554bc9292fSDave Airlie pci_sys->methods->enable(dev);
6564bc9292fSDave Airlie }
6578cc9a8feSAdam Jackson
6588cc9a8feSAdam Jackson /**
6598cc9a8feSAdam Jackson * Map the legacy memory space for the PCI domain containing \c dev.
6608cc9a8feSAdam Jackson *
6618cc9a8feSAdam Jackson * \param dev Device whose memory region is to be mapped.
6628cc9a8feSAdam Jackson * \param base Base address of the range to be mapped.
6638cc9a8feSAdam Jackson * \param size Size of the range to be mapped.
6648cc9a8feSAdam Jackson * \param map_flags Flag bits controlling how the mapping is accessed.
6658cc9a8feSAdam Jackson * \param addr Location to store the mapped address.
6668cc9a8feSAdam Jackson *
6678cc9a8feSAdam Jackson * \returns
6688cc9a8feSAdam Jackson * Zero on success or an \c errno value on failure.
6698cc9a8feSAdam Jackson */
6708cc9a8feSAdam Jackson int
pci_device_map_legacy(struct pci_device * dev,pciaddr_t base,pciaddr_t size,unsigned map_flags,void ** addr)6718cc9a8feSAdam Jackson pci_device_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size,
6728cc9a8feSAdam Jackson unsigned map_flags, void **addr)
6738cc9a8feSAdam Jackson {
6748cc9a8feSAdam Jackson if (base > 0x100000 || base + size > 0x100000)
6758cc9a8feSAdam Jackson return EINVAL;
6768cc9a8feSAdam Jackson
6778cc9a8feSAdam Jackson if (!pci_sys->methods->map_legacy)
6788cc9a8feSAdam Jackson return ENOSYS;
6798cc9a8feSAdam Jackson
6808cc9a8feSAdam Jackson return pci_sys->methods->map_legacy(dev, base, size, map_flags, addr);
6818cc9a8feSAdam Jackson }
6828cc9a8feSAdam Jackson
6838cc9a8feSAdam Jackson /**
6848cc9a8feSAdam Jackson * Unmap the legacy memory space for the PCI domain containing \c dev.
6858cc9a8feSAdam Jackson *
6868cc9a8feSAdam Jackson * \param dev Device whose memory region is to be unmapped.
6878cc9a8feSAdam Jackson * \param addr Location of the mapped address.
6888cc9a8feSAdam Jackson * \param size Size of the range to be unmapped.
6898cc9a8feSAdam Jackson *
6908cc9a8feSAdam Jackson * \returns
6918cc9a8feSAdam Jackson * Zero on success or an \c errno value on failure.
6928cc9a8feSAdam Jackson */
6938cc9a8feSAdam Jackson int
pci_device_unmap_legacy(struct pci_device * dev,void * addr,pciaddr_t size)6948cc9a8feSAdam Jackson pci_device_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size)
6958cc9a8feSAdam Jackson {
6968cc9a8feSAdam Jackson if (!pci_sys->methods->unmap_legacy)
6978cc9a8feSAdam Jackson return ENOSYS;
6988cc9a8feSAdam Jackson
6998cc9a8feSAdam Jackson return pci_sys->methods->unmap_legacy(dev, addr, size);
7008cc9a8feSAdam Jackson }
701