1a7faac3dSIan Romanick /* 2a7faac3dSIan Romanick * (C) Copyright IBM Corporation 2007 3a7faac3dSIan Romanick * All Rights Reserved. 4a7faac3dSIan Romanick * 5a7faac3dSIan Romanick * Permission is hereby granted, free of charge, to any person obtaining a 6a7faac3dSIan Romanick * copy of this software and associated documentation files (the "Software"), 7a7faac3dSIan Romanick * to deal in the Software without restriction, including without limitation 8a7faac3dSIan Romanick * on the rights to use, copy, modify, merge, publish, distribute, sub 9a7faac3dSIan Romanick * license, and/or sell copies of the Software, and to permit persons to whom 10a7faac3dSIan Romanick * the Software is furnished to do so, subject to the following conditions: 11a7faac3dSIan Romanick * 12a7faac3dSIan Romanick * The above copyright notice and this permission notice (including the next 13a7faac3dSIan Romanick * paragraph) shall be included in all copies or substantial portions of the 14a7faac3dSIan Romanick * Software. 15a7faac3dSIan Romanick * 16a7faac3dSIan Romanick * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17a7faac3dSIan Romanick * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18a7faac3dSIan Romanick * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19a7faac3dSIan Romanick * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20a7faac3dSIan Romanick * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21a7faac3dSIan Romanick * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22a7faac3dSIan Romanick * DEALINGS IN THE SOFTWARE. 23a7faac3dSIan Romanick */ 24a7faac3dSIan Romanick 25a7faac3dSIan Romanick /** 26a7faac3dSIan Romanick * \file linux_devmem.c 27a7faac3dSIan Romanick * Access PCI subsystem using Linux's the old /dev/mem interface. 28a7faac3dSIan Romanick * 29a7faac3dSIan Romanick * \note 30a7faac3dSIan Romanick * This is currently just a skeleton. It only includes the /dev/mem based 31a7faac3dSIan Romanick * function for reading the device ROM. 32a7faac3dSIan Romanick * 33a7faac3dSIan Romanick * \author Ian Romanick <[email protected]> 34a7faac3dSIan Romanick */ 35a7faac3dSIan Romanick 36a7faac3dSIan Romanick #define _GNU_SOURCE 37a7faac3dSIan Romanick 38a7faac3dSIan Romanick #include <stdlib.h> 39a7faac3dSIan Romanick #include <string.h> 40a7faac3dSIan Romanick #include <stdio.h> 41a7faac3dSIan Romanick #include <unistd.h> 42a7faac3dSIan Romanick #include <sys/types.h> 43a7faac3dSIan Romanick #include <sys/stat.h> 44a7faac3dSIan Romanick #include <fcntl.h> 45a7faac3dSIan Romanick #include <sys/mman.h> 46a7faac3dSIan Romanick #include <dirent.h> 47a7faac3dSIan Romanick #include <errno.h> 48a7faac3dSIan Romanick 49a7faac3dSIan Romanick #include "pciaccess.h" 50a7faac3dSIan Romanick #include "pciaccess_private.h" 51a7faac3dSIan Romanick #include "linux_devmem.h" 52a7faac3dSIan Romanick 53a7faac3dSIan Romanick /** 54a7faac3dSIan Romanick * Read a device's expansion ROM using /dev/mem. 55a7faac3dSIan Romanick * 56a7faac3dSIan Romanick * \note 57a7faac3dSIan Romanick * This function could probably be used, as-is, on other platforms that have 58a7faac3dSIan Romanick * a /dev/mem interface. 59a7faac3dSIan Romanick * 60a7faac3dSIan Romanick * \bugs 61a7faac3dSIan Romanick * Before using the VGA special case code, this function should check that 62a7faac3dSIan Romanick * VGA access are routed to the device. Right? 63a7faac3dSIan Romanick */ 64adc46f65SJulien Cristau _pci_hidden int 65adc46f65SJulien Cristau pci_device_linux_devmem_read_rom(struct pci_device *dev, void *buffer) 66a7faac3dSIan Romanick { 67a7faac3dSIan Romanick struct pci_device_private *priv = (struct pci_device_private *) dev; 68a7faac3dSIan Romanick int fd; 69a7faac3dSIan Romanick int err = 0; 70a7faac3dSIan Romanick uint32_t rom_base_tmp; 71a7faac3dSIan Romanick pciaddr_t rom_base; 72a7faac3dSIan Romanick pciaddr_t rom_size; 73a7faac3dSIan Romanick int PCI_ROM; 74a7faac3dSIan Romanick 75a7faac3dSIan Romanick 76a7faac3dSIan Romanick /* Handle some special cases of legacy devices. 77a7faac3dSIan Romanick */ 78a7faac3dSIan Romanick if (priv->base.rom_size == 0) { 79a7faac3dSIan Romanick /* VGA ROMs are supposed to be at 0xC0000. 80a7faac3dSIan Romanick */ 81a7faac3dSIan Romanick if ((priv->base.device_class & 0x00ffff00) == 0x000030000) { 82a7faac3dSIan Romanick rom_base = 0x000C0000; 83a7faac3dSIan Romanick rom_size = 0x00010000; 84a7faac3dSIan Romanick PCI_ROM = 0; 85a7faac3dSIan Romanick } 86a7faac3dSIan Romanick else { 87a7faac3dSIan Romanick /* "Function not implemented." 88a7faac3dSIan Romanick */ 89a7faac3dSIan Romanick return ENOSYS; 90a7faac3dSIan Romanick } 91a7faac3dSIan Romanick } 92a7faac3dSIan Romanick else { 93a7faac3dSIan Romanick rom_base = priv->rom_base; 94a7faac3dSIan Romanick rom_size = priv->base.rom_size; 95a7faac3dSIan Romanick PCI_ROM = 1; 96a7faac3dSIan Romanick } 97a7faac3dSIan Romanick 98a7faac3dSIan Romanick 99a7faac3dSIan Romanick 100a7faac3dSIan Romanick /* Enable the device's ROM. 101a7faac3dSIan Romanick */ 102a7faac3dSIan Romanick if (PCI_ROM) { 103a7faac3dSIan Romanick err = pci_device_cfg_read_u32(& priv->base, & rom_base_tmp, 48); 104a7faac3dSIan Romanick if (err) { 105a7faac3dSIan Romanick return err; 106a7faac3dSIan Romanick } 107a7faac3dSIan Romanick 108a7faac3dSIan Romanick if ((rom_base_tmp & 0x000000001) == 0) { 109a7faac3dSIan Romanick err = pci_device_cfg_write_u32(& priv->base, 110a7faac3dSIan Romanick rom_base_tmp | 1, 48); 111a7faac3dSIan Romanick if (err) { 112a7faac3dSIan Romanick return err; 113a7faac3dSIan Romanick } 114a7faac3dSIan Romanick } 115a7faac3dSIan Romanick } 116a7faac3dSIan Romanick 117a7faac3dSIan Romanick 118a7faac3dSIan Romanick /* Read the portion of /dev/mem that corresponds to the device's ROM. 119a7faac3dSIan Romanick */ 120a7faac3dSIan Romanick fd = open("/dev/mem", O_RDONLY, 0); 121a7faac3dSIan Romanick if (fd < 0) { 122a7faac3dSIan Romanick err = errno; 123a7faac3dSIan Romanick } 124a7faac3dSIan Romanick else { 125a7faac3dSIan Romanick size_t bytes; 126a7faac3dSIan Romanick 127a5c86202SStuart Bennett for (bytes = 0; bytes < rom_size; /* empty */) { 128a7faac3dSIan Romanick const ssize_t got = pread(fd, buffer, rom_size - bytes, 129a7faac3dSIan Romanick rom_base + bytes); 130a7faac3dSIan Romanick if (got == -1) { 131a7faac3dSIan Romanick err = errno; 132a7faac3dSIan Romanick break; 133a7faac3dSIan Romanick } 134a7faac3dSIan Romanick 135a7faac3dSIan Romanick bytes += got; 136a7faac3dSIan Romanick } 137a7faac3dSIan Romanick 138a7faac3dSIan Romanick close(fd); 139a7faac3dSIan Romanick } 140a7faac3dSIan Romanick 141a7faac3dSIan Romanick 142a7faac3dSIan Romanick /* Disable the device's ROM. 143a7faac3dSIan Romanick */ 144a7faac3dSIan Romanick if (PCI_ROM && ((rom_base_tmp & 0x000000001) == 0)) { 145a7faac3dSIan Romanick const int tmp_err = pci_device_cfg_write_u32(& priv->base, 146a7faac3dSIan Romanick rom_base_tmp, 48); 147a7faac3dSIan Romanick 148*d43d21c8SAlan Coopersmith /* Prefer to return the first error that occurred. 149a7faac3dSIan Romanick */ 150a7faac3dSIan Romanick if (err == 0) { 151a7faac3dSIan Romanick err = tmp_err; 152a7faac3dSIan Romanick } 153a7faac3dSIan Romanick } 154a7faac3dSIan Romanick 155a7faac3dSIan Romanick return err; 156a7faac3dSIan Romanick } 157