2005-04-17 02:20:36 +04:00
/*
* drivers / pci / rom . c
*
* ( C ) Copyright 2004 Jon Smirl < jonsmirl @ yahoo . com >
* ( C ) Copyright 2004 Silicon Graphics , Inc . Jesse Barnes < jbarnes @ sgi . com >
*
* PCI ROM access routines
*/
# include <linux/kernel.h>
2011-05-27 17:37:25 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/pci.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include "pci.h"
/**
* pci_enable_rom - enable ROM decoding for a PCI device
2005-05-01 19:59:26 +04:00
* @ pdev : PCI device to enable
2005-04-17 02:20:36 +04:00
*
* Enable ROM decoding on @ dev . This involves simply turning on the last
* bit of the PCI ROM BAR . Note that some cards may share address decoders
* between the ROM and other resources , so enabling it may disable access
* to MMIO registers or other card memory .
*/
2008-09-23 20:25:10 +04:00
int pci_enable_rom ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2016-03-03 17:53:47 +03:00
struct resource * res = & pdev - > resource [ PCI_ROM_RESOURCE ] ;
2005-08-31 08:16:53 +04:00
struct pci_bus_region region ;
2005-04-17 02:20:36 +04:00
u32 rom_addr ;
2005-08-31 08:16:53 +04:00
if ( ! res - > flags )
return - 1 ;
2016-03-03 17:53:47 +03:00
/* Nothing to enable if we're using a shadow copy in RAM */
if ( res - > flags & IORESOURCE_ROM_SHADOW )
return 0 ;
2016-11-29 01:17:41 +03:00
/*
* Ideally pci_update_resource ( ) would update the ROM BAR address ,
* and we would only set the enable bit here . But apparently some
* devices have buggy ROM BARs that read as zero when disabled .
*/
PCI: Convert pcibios_resource_to_bus() to take a pci_bus, not a pci_dev
These interfaces:
pcibios_resource_to_bus(struct pci_dev *dev, *bus_region, *resource)
pcibios_bus_to_resource(struct pci_dev *dev, *resource, *bus_region)
took a pci_dev, but they really depend only on the pci_bus. And we want to
use them in resource allocation paths where we have the bus but not a
device, so this patch converts them to take the pci_bus instead of the
pci_dev:
pcibios_resource_to_bus(struct pci_bus *bus, *bus_region, *resource)
pcibios_bus_to_resource(struct pci_bus *bus, *resource, *bus_region)
In fact, with standard PCI-PCI bridges, they only depend on the host
bridge, because that's the only place address translation occurs, but
we aren't going that far yet.
[bhelgaas: changelog]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2013-12-10 10:54:40 +04:00
pcibios_resource_to_bus ( pdev - > bus , & region , res ) ;
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( pdev , pdev - > rom_base_reg , & rom_addr ) ;
2005-08-31 08:16:53 +04:00
rom_addr & = ~ PCI_ROM_ADDRESS_MASK ;
rom_addr | = region . start | PCI_ROM_ADDRESS_ENABLE ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( pdev , pdev - > rom_base_reg , rom_addr ) ;
2005-08-31 08:16:53 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2014-04-26 00:32:25 +04:00
EXPORT_SYMBOL_GPL ( pci_enable_rom ) ;
2005-04-17 02:20:36 +04:00
/**
* pci_disable_rom - disable ROM decoding for a PCI device
2005-05-01 19:59:26 +04:00
* @ pdev : PCI device to disable
2005-04-17 02:20:36 +04:00
*
* Disable ROM decoding on a PCI device by turning off the last bit in the
* ROM BAR .
*/
2008-09-23 20:25:10 +04:00
void pci_disable_rom ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2016-03-03 17:53:47 +03:00
struct resource * res = & pdev - > resource [ PCI_ROM_RESOURCE ] ;
2005-04-17 02:20:36 +04:00
u32 rom_addr ;
2016-03-03 17:53:47 +03:00
if ( res - > flags & IORESOURCE_ROM_SHADOW )
return ;
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( pdev , pdev - > rom_base_reg , & rom_addr ) ;
rom_addr & = ~ PCI_ROM_ADDRESS_ENABLE ;
pci_write_config_dword ( pdev , pdev - > rom_base_reg , rom_addr ) ;
}
2014-04-26 00:32:25 +04:00
EXPORT_SYMBOL_GPL ( pci_disable_rom ) ;
2005-04-17 02:20:36 +04:00
2007-07-09 22:42:24 +04:00
/**
* pci_get_rom_size - obtain the actual size of the ROM image
2009-02-09 20:31:20 +03:00
* @ pdev : target PCI device
2007-07-09 22:42:24 +04:00
* @ rom : kernel virtual pointer to image of ROM
* @ size : size of PCI window
* return : size of actual ROM image
*
* Determine the actual length of the ROM image .
* The PCI window size could be much larger than the
* actual image size .
*/
2009-01-29 22:12:47 +03:00
size_t pci_get_rom_size ( struct pci_dev * pdev , void __iomem * rom , size_t size )
2007-07-09 22:42:24 +04:00
{
void __iomem * image ;
int last_image ;
2015-01-19 11:53:20 +03:00
unsigned length ;
2007-07-09 22:42:24 +04:00
image = rom ;
do {
void __iomem * pds ;
/* Standard PCI ROMs start out with these bytes 55 AA */
2015-11-27 20:20:06 +03:00
if ( readw ( image ) ! = 0xAA55 ) {
dev_err ( & pdev - > dev , " Invalid PCI ROM header signature: expecting 0xaa55, got %#06x \n " ,
readw ( image ) ) ;
2007-07-09 22:42:24 +04:00
break ;
2009-01-29 22:12:47 +03:00
}
2015-11-27 20:20:06 +03:00
/* get the PCI data structure and check its "PCIR" signature */
2007-07-09 22:42:24 +04:00
pds = image + readw ( image + 24 ) ;
2015-11-27 20:20:06 +03:00
if ( readl ( pds ) ! = 0x52494350 ) {
dev_err ( & pdev - > dev , " Invalid PCI ROM data signature: expecting 0x52494350, got %#010x \n " ,
readl ( pds ) ) ;
2007-07-09 22:42:24 +04:00
break ;
2015-11-27 20:20:06 +03:00
}
2007-07-09 22:42:24 +04:00
last_image = readb ( pds + 21 ) & 0x80 ;
2015-01-19 11:53:20 +03:00
length = readw ( pds + 16 ) ;
image + = length * 512 ;
2016-01-08 21:16:04 +03:00
/* Avoid iterating through memory outside the resource window */
if ( image > rom + size )
break ;
2015-01-19 11:53:20 +03:00
} while ( length & & ! last_image ) ;
2007-07-09 22:42:24 +04:00
/* never return a size larger than the PCI resource window */
/* there are known ROMs that get the size wrong */
return min ( ( size_t ) ( image - rom ) , size ) ;
}
2005-04-17 02:20:36 +04:00
/**
* pci_map_rom - map a PCI ROM to kernel space
2005-05-01 19:59:26 +04:00
* @ pdev : pointer to pci device struct
2005-04-17 02:20:36 +04:00
* @ size : pointer to receive size of pci window over ROM
2008-10-30 08:35:12 +03:00
*
* Return : kernel virtual pointer to image of ROM
2005-04-17 02:20:36 +04:00
*
* Map a PCI ROM into kernel space . If ROM is boot video ROM ,
* the shadow BIOS copy will be returned instead of the
* actual ROM .
*/
void __iomem * pci_map_rom ( struct pci_dev * pdev , size_t * size )
{
struct resource * res = & pdev - > resource [ PCI_ROM_RESOURCE ] ;
2013-03-27 01:25:54 +04:00
loff_t start ;
2005-04-17 02:20:36 +04:00
void __iomem * rom ;
2016-03-01 20:13:30 +03:00
/* assign the ROM an address if it doesn't have one */
if ( res - > parent = = NULL & & pci_assign_resource ( pdev , PCI_ROM_RESOURCE ) )
return NULL ;
start = pci_resource_start ( pdev , PCI_ROM_RESOURCE ) ;
* size = pci_resource_len ( pdev , PCI_ROM_RESOURCE ) ;
if ( * size = = 0 )
return NULL ;
/* Enable ROM space decodes */
if ( pci_enable_rom ( pdev ) )
return NULL ;
2013-03-20 01:26:57 +04:00
2005-04-17 02:20:36 +04:00
rom = ioremap ( start , * size ) ;
if ( ! rom ) {
/* restore enable if ioremap fails */
2016-03-03 06:46:50 +03:00
if ( ! ( res - > flags & IORESOURCE_ROM_ENABLE ) )
2005-04-17 02:20:36 +04:00
pci_disable_rom ( pdev ) ;
return NULL ;
}
/*
* Try to find the true size of the ROM since sometimes the PCI window
* size is much larger than the actual size of the ROM .
* True size is important if the ROM is going to be copied .
*/
2009-01-29 22:12:47 +03:00
* size = pci_get_rom_size ( pdev , rom , * size ) ;
2005-04-17 02:20:36 +04:00
return rom ;
}
2014-04-26 00:32:25 +04:00
EXPORT_SYMBOL ( pci_map_rom ) ;
2005-04-17 02:20:36 +04:00
/**
* pci_unmap_rom - unmap the ROM from kernel space
2005-05-01 19:59:26 +04:00
* @ pdev : pointer to pci device struct
2005-04-17 02:20:36 +04:00
* @ rom : virtual address of the previous mapping
*
* Remove a mapping of a previously mapped ROM
*/
void pci_unmap_rom ( struct pci_dev * pdev , void __iomem * rom )
{
struct resource * res = & pdev - > resource [ PCI_ROM_RESOURCE ] ;
2013-03-27 01:25:54 +04:00
iounmap ( rom ) ;
2005-04-17 02:20:36 +04:00
2016-03-03 17:53:47 +03:00
/* Disable again before continuing */
if ( ! ( res - > flags & IORESOURCE_ROM_ENABLE ) )
2005-04-17 02:20:36 +04:00
pci_disable_rom ( pdev ) ;
}
2014-04-26 00:32:25 +04:00
EXPORT_SYMBOL ( pci_unmap_rom ) ;
2005-04-17 02:20:36 +04:00
2013-03-27 01:25:54 +04:00
/**
* pci_platform_rom - provides a pointer to any ROM image provided by the
* platform
* @ pdev : pointer to pci device struct
* @ size : pointer to receive size of pci window over ROM
*/
void __iomem * pci_platform_rom ( struct pci_dev * pdev , size_t * size )
{
if ( pdev - > rom & & pdev - > romlen ) {
* size = pdev - > romlen ;
return phys_to_virt ( ( phys_addr_t ) pdev - > rom ) ;
}
return NULL ;
}
EXPORT_SYMBOL ( pci_platform_rom ) ;