xref: /libpciaccess/src/common_interface.c (revision 790e93c3)
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