Commit e47901f9 authored by Jens Axboe's avatar Jens Axboe Committed by Jens Axboe

[PATCH] PCI individual resource handling

This merges the changes from 2.4-ac that allow drivers to enable (and
mark as used) only a subset of PCI resources, for those drivers that
need it (at this point apparently only the i845 IDE controller).
parent ac9c060c
......@@ -199,11 +199,11 @@ unsigned int pcibios_assign_all_busses(void)
return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
}
int pcibios_enable_device(struct pci_dev *dev)
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
int err;
if ((err = pcibios_enable_resources(dev)) < 0)
if ((err = pcibios_enable_resources(dev, mask)) < 0)
return err;
return pcibios_enable_irq(dev);
......
......@@ -243,7 +243,7 @@ void __init pcibios_resource_survey(void)
pcibios_assign_resources();
}
int pcibios_enable_resources(struct pci_dev *dev)
int pcibios_enable_resources(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
int idx;
......@@ -252,6 +252,10 @@ int pcibios_enable_resources(struct pci_dev *dev)
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx<6; idx++) {
/* Only set up the requested stuff */
if (!(mask & (1<<idx)))
continue;
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
......
......@@ -31,7 +31,7 @@ extern unsigned int pci_probe;
extern unsigned int pcibios_max_latency;
void pcibios_resource_survey(void);
int pcibios_enable_resources(struct pci_dev *);
int pcibios_enable_resources(struct pci_dev *, int);
/* pci-pc.c */
......
......@@ -131,9 +131,9 @@ char * __init pcibios_setup(char *str)
return str;
}
int pcibios_enable_device(struct pci_dev *dev)
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pcibios_enable_resources(dev);
return pcibios_enable_resources(dev, mask);
}
void __init pcibios_penalize_isa_irq(irq)
......
......@@ -240,24 +240,40 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer)
}
/**
* pci_enable_device - Initialize device before it's used by a driver.
* pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
* @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
* to enable I/O and memory. Wake up the device if it was suspended.
* Beware, this function can fail.
* to enable selected I/O and memory resources. Wake up the device if it
* was suspended. Beware, this function can fail.
*/
int
pci_enable_device(struct pci_dev *dev)
pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
pci_set_power_state(dev, 0);
if ((err = pcibios_enable_device(dev)) < 0)
if ((err = pcibios_enable_device(dev, bars)) < 0)
return err;
return 0;
}
/**
* pci_enable_device - Initialize device before it's used by a driver.
* @dev: PCI device to be initialized
*
* Initialize device before it's used by a driver. Ask low-level code
* to enable I/O and memory. Wake up the device if it was suspended.
* Beware, this function can fail.
*/
int
pci_enable_device(struct pci_dev *dev)
{
return pci_enable_device_bars(dev, 0x3F);
}
/**
* pci_disable_device - Disable PCI device after use
* @dev: PCI device to be disabled
......@@ -344,6 +360,69 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
return pin;
}
/**
* pci_release_region - Release a PCI bar
* @pdev: PCI device whose resources were previously reserved by pci_request_region
* @bar: BAR to release
*
* Releases the PCI I/O and memory resources previously reserved by a
* successful call to pci_request_region. Call this function only
* after all use of the PCI regions has ceased.
*/
void pci_release_region(struct pci_dev *pdev, int bar)
{
if (pci_resource_len(pdev, bar) == 0)
return;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
release_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
}
/**
* pci_request_region - Reserved PCI I/O and memory resource
* @pdev: PCI device whose resources are to be reserved
* @bar: BAR to be reserved
* @res_name: Name to be associated with resource.
*
* Mark the PCI region associated with PCI device @pdev BR @bar as
* being reserved by owner @res_name. Do not access any
* address inside the PCI regions unless this call returns
* successfully.
*
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
{
if (pci_resource_len(pdev, bar) == 0)
return 0;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
if (!request_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
if (!request_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
return 0;
err_out:
printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
bar + 1, /* PCI BAR # */
pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
pdev->slot_name);
return -EBUSY;
}
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
* @pdev: PCI device whose resources were previously reserved by pci_request_regions
......@@ -352,22 +431,13 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
* successful call to pci_request_regions. Call this function only
* after all use of the PCI regions has ceased.
*/
void pci_release_regions(struct pci_dev *pdev)
{
int i;
for (i = 0; i < 6; i++) {
if (pci_resource_len(pdev, i) == 0)
continue;
if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
release_region(pci_resource_start(pdev, i),
pci_resource_len(pdev, i));
else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, i),
pci_resource_len(pdev, i));
}
for (i = 0; i < 6; i++)
pci_release_region(pdev, i);
}
/**
......@@ -387,23 +457,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name)
{
int i;
for (i = 0; i < 6; i++) {
if (pci_resource_len(pdev, i) == 0)
continue;
if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
if (!request_region(pci_resource_start(pdev, i),
pci_resource_len(pdev, i), res_name))
goto err_out;
}
else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
if (!request_mem_region(pci_resource_start(pdev, i),
pci_resource_len(pdev, i), res_name))
goto err_out;
}
}
for (i = 0; i < 6; i++)
if(pci_request_region(pdev, i, res_name))
goto err_out;
return 0;
err_out:
......@@ -412,7 +468,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name)
i + 1, /* PCI BAR # */
pci_resource_len(pdev, i), pci_resource_start(pdev, i),
pdev->slot_name);
pci_release_regions(pdev);
while(--i >= 0)
pci_release_region(pdev, i);
return -EBUSY;
}
......@@ -589,6 +647,8 @@ EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
......
......@@ -507,7 +507,7 @@ struct pci_driver {
for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
void pcibios_fixup_bus(struct pci_bus *);
int pcibios_enable_device(struct pci_dev *);
int pcibios_enable_device(struct pci_dev *, int mask);
char *pcibios_setup (char *str);
/* Used only when drivers/pci/setup.c is used */
......@@ -600,6 +600,7 @@ static int inline pci_write_config_dword(struct pci_dev *dev, int where, u32 val
extern spinlock_t pci_lock;
int pci_enable_device(struct pci_dev *dev);
int pci_enable_device_bars(struct pci_dev *dev, int mask);
void pci_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI
......@@ -623,9 +624,11 @@ void pdev_enable_device(struct pci_dev *);
void pdev_sort_resources(struct pci_dev *, struct resource_list *);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(struct pci_dev *, u8, u8));
#define HAVE_PCI_REQ_REGIONS
#define HAVE_PCI_REQ_REGIONS 2
int pci_request_regions(struct pci_dev *, char *);
void pci_release_regions(struct pci_dev *);
int pci_request_region(struct pci_dev *, int, char *);
void pci_release_region(struct pci_dev *, int);
/* New-style probing supporting hot-pluggable devices */
int pci_register_driver(struct pci_driver *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment