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) ...@@ -199,11 +199,11 @@ unsigned int pcibios_assign_all_busses(void)
return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 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; int err;
if ((err = pcibios_enable_resources(dev)) < 0) if ((err = pcibios_enable_resources(dev, mask)) < 0)
return err; return err;
return pcibios_enable_irq(dev); return pcibios_enable_irq(dev);
......
...@@ -243,7 +243,7 @@ void __init pcibios_resource_survey(void) ...@@ -243,7 +243,7 @@ void __init pcibios_resource_survey(void)
pcibios_assign_resources(); 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; u16 cmd, old_cmd;
int idx; int idx;
...@@ -252,6 +252,10 @@ int pcibios_enable_resources(struct pci_dev *dev) ...@@ -252,6 +252,10 @@ int pcibios_enable_resources(struct pci_dev *dev)
pci_read_config_word(dev, PCI_COMMAND, &cmd); pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd; old_cmd = cmd;
for(idx=0; idx<6; idx++) { for(idx=0; idx<6; idx++) {
/* Only set up the requested stuff */
if (!(mask & (1<<idx)))
continue;
r = &dev->resource[idx]; r = &dev->resource[idx];
if (!r->start && r->end) { if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); 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; ...@@ -31,7 +31,7 @@ extern unsigned int pci_probe;
extern unsigned int pcibios_max_latency; extern unsigned int pcibios_max_latency;
void pcibios_resource_survey(void); void pcibios_resource_survey(void);
int pcibios_enable_resources(struct pci_dev *); int pcibios_enable_resources(struct pci_dev *, int);
/* pci-pc.c */ /* pci-pc.c */
......
...@@ -131,9 +131,9 @@ char * __init pcibios_setup(char *str) ...@@ -131,9 +131,9 @@ char * __init pcibios_setup(char *str)
return 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) void __init pcibios_penalize_isa_irq(irq)
......
...@@ -240,24 +240,40 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) ...@@ -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 * @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 * 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. * to enable selected I/O and memory resources. Wake up the device if it
* Beware, this function can fail. * was suspended. Beware, this function can fail.
*/ */
int int
pci_enable_device(struct pci_dev *dev) pci_enable_device_bars(struct pci_dev *dev, int bars)
{ {
int err; int err;
pci_set_power_state(dev, 0); pci_set_power_state(dev, 0);
if ((err = pcibios_enable_device(dev)) < 0) if ((err = pcibios_enable_device(dev, bars)) < 0)
return err; return err;
return 0; 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 * pci_disable_device - Disable PCI device after use
* @dev: PCI device to be disabled * @dev: PCI device to be disabled
...@@ -344,6 +360,69 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) ...@@ -344,6 +360,69 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
return pin; 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 * pci_release_regions - Release reserved PCI I/O and memory resources
* @pdev: PCI device whose resources were previously reserved by pci_request_regions * @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) ...@@ -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 * successful call to pci_request_regions. Call this function only
* after all use of the PCI regions has ceased. * after all use of the PCI regions has ceased.
*/ */
void pci_release_regions(struct pci_dev *pdev) void pci_release_regions(struct pci_dev *pdev)
{ {
int i; int i;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++)
if (pci_resource_len(pdev, i) == 0) pci_release_region(pdev, i);
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));
}
} }
/** /**
...@@ -387,23 +457,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name) ...@@ -387,23 +457,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name)
{ {
int i; int i;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++)
if (pci_resource_len(pdev, i) == 0) if(pci_request_region(pdev, i, res_name))
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; goto err_out;
}
}
return 0; return 0;
err_out: err_out:
...@@ -412,7 +468,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name) ...@@ -412,7 +468,9 @@ int pci_request_regions(struct pci_dev *pdev, char *res_name)
i + 1, /* PCI BAR # */ i + 1, /* PCI BAR # */
pci_resource_len(pdev, i), pci_resource_start(pdev, i), pci_resource_len(pdev, i), pci_resource_start(pdev, i),
pdev->slot_name); pdev->slot_name);
pci_release_regions(pdev); while(--i >= 0)
pci_release_region(pdev, i);
return -EBUSY; return -EBUSY;
} }
...@@ -589,6 +647,8 @@ EXPORT_SYMBOL(pci_disable_device); ...@@ -589,6 +647,8 @@ EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_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_master);
EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi); EXPORT_SYMBOL(pci_clear_mwi);
......
...@@ -507,7 +507,7 @@ struct pci_driver { ...@@ -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)) 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 *); 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); char *pcibios_setup (char *str);
/* Used only when drivers/pci/setup.c is used */ /* 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 ...@@ -600,6 +600,7 @@ static int inline pci_write_config_dword(struct pci_dev *dev, int where, u32 val
extern spinlock_t pci_lock; extern spinlock_t pci_lock;
int pci_enable_device(struct pci_dev *dev); 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_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI #define HAVE_PCI_SET_MWI
...@@ -623,9 +624,11 @@ void pdev_enable_device(struct pci_dev *); ...@@ -623,9 +624,11 @@ void pdev_enable_device(struct pci_dev *);
void pdev_sort_resources(struct pci_dev *, struct resource_list *); void pdev_sort_resources(struct pci_dev *, struct resource_list *);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(struct pci_dev *, u8, 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 *); int pci_request_regions(struct pci_dev *, char *);
void pci_release_regions(struct pci_dev *); 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 */ /* New-style probing supporting hot-pluggable devices */
int pci_register_driver(struct pci_driver *); 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