forked from Minki/linux
bba6f6fc68
So I think the right solution is to simply make pci_enable_device just flip enable bits and move the rest of the work someplace else. However a thorough cleanup is a little extreme for this point in the release cycle, so I think a quick hack that makes the code not stomp the irq when msi irq's are enabled should be the first fix. Then we can later make the code not change the irqs at all. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
132 lines
2.9 KiB
C
132 lines
2.9 KiB
C
#include <linux/pci.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/arch/hwregs/intr_vect.h>
|
|
|
|
void __devinit pcibios_fixup_bus(struct pci_bus *b)
|
|
{
|
|
}
|
|
|
|
char * __devinit pcibios_setup(char *str)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void pcibios_set_master(struct pci_dev *dev)
|
|
{
|
|
u8 lat;
|
|
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
|
|
printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
|
|
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
|
|
}
|
|
|
|
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
|
|
enum pci_mmap_state mmap_state, int write_combine)
|
|
{
|
|
unsigned long prot;
|
|
|
|
/* Leave vm_pgoff as-is, the PCI space address is the physical
|
|
* address on this platform.
|
|
*/
|
|
prot = pgprot_val(vma->vm_page_prot);
|
|
vma->vm_page_prot = __pgprot(prot);
|
|
|
|
/* Write-combine setting is ignored, it is changed via the mtrr
|
|
* interfaces on this platform.
|
|
*/
|
|
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
|
|
vma->vm_end - vma->vm_start,
|
|
vma->vm_page_prot))
|
|
return -EAGAIN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
pcibios_align_resource(void *data, struct resource *res,
|
|
resource_size_t size, resource_size_t align)
|
|
{
|
|
if (res->flags & IORESOURCE_IO) {
|
|
resource_size_t start = res->start;
|
|
|
|
if (start & 0x300) {
|
|
start = (start + 0x3ff) & ~0x3ff;
|
|
res->start = start;
|
|
}
|
|
}
|
|
}
|
|
|
|
int pcibios_enable_resources(struct pci_dev *dev, int mask)
|
|
{
|
|
u16 cmd, old_cmd;
|
|
int idx;
|
|
struct resource *r;
|
|
|
|
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", pci_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
if (r->flags & IORESOURCE_IO)
|
|
cmd |= PCI_COMMAND_IO;
|
|
if (r->flags & IORESOURCE_MEM)
|
|
cmd |= PCI_COMMAND_MEMORY;
|
|
}
|
|
if (dev->resource[PCI_ROM_RESOURCE].start)
|
|
cmd |= PCI_COMMAND_MEMORY;
|
|
if (cmd != old_cmd) {
|
|
printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pcibios_enable_irq(struct pci_dev *dev)
|
|
{
|
|
dev->irq = EXT_INTR_VECT;
|
|
return 0;
|
|
}
|
|
|
|
int pcibios_enable_device(struct pci_dev *dev, int mask)
|
|
{
|
|
int err;
|
|
|
|
if ((err = pcibios_enable_resources(dev, mask)) < 0)
|
|
return err;
|
|
|
|
if (!dev->msi_enabled)
|
|
pcibios_enable_irq(dev);
|
|
return 0;
|
|
}
|
|
|
|
int pcibios_assign_resources(void)
|
|
{
|
|
struct pci_dev *dev = NULL;
|
|
int idx;
|
|
struct resource *r;
|
|
|
|
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
|
|
int class = dev->class >> 8;
|
|
|
|
/* Don't touch classless devices and host bridges */
|
|
if (!class || class == PCI_CLASS_BRIDGE_HOST)
|
|
continue;
|
|
|
|
for(idx=0; idx<6; idx++) {
|
|
r = &dev->resource[idx];
|
|
|
|
if (!r->start && r->end)
|
|
pci_assign_resource(dev, idx);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_SYMBOL(pcibios_assign_resources);
|