diff options
Diffstat (limited to 'kernel/arch/cris/arch-v32/drivers/pci')
-rw-r--r-- | kernel/arch/cris/arch-v32/drivers/pci/Makefile | 5 | ||||
-rw-r--r-- | kernel/arch/cris/arch-v32/drivers/pci/bios.c | 99 | ||||
-rw-r--r-- | kernel/arch/cris/arch-v32/drivers/pci/dma.c | 50 |
3 files changed, 154 insertions, 0 deletions
diff --git a/kernel/arch/cris/arch-v32/drivers/pci/Makefile b/kernel/arch/cris/arch-v32/drivers/pci/Makefile new file mode 100644 index 000000000..bff7482f2 --- /dev/null +++ b/kernel/arch/cris/arch-v32/drivers/pci/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Etrax cardbus driver +# + +obj-$(CONFIG_ETRAX_CARDBUS) += bios.o dma.o diff --git a/kernel/arch/cris/arch-v32/drivers/pci/bios.c b/kernel/arch/cris/arch-v32/drivers/pci/bios.c new file mode 100644 index 000000000..64a5fb937 --- /dev/null +++ b/kernel/arch/cris/arch-v32/drivers/pci/bios.c @@ -0,0 +1,99 @@ +#include <linux/pci.h> +#include <linux/kernel.h> +#include <arch/hwregs/intr_vect.h> + +void pcibios_fixup_bus(struct pci_bus *b) +{ +} + +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; +} + +resource_size_t +pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + resource_size_t start = res->start; + + if ((res->flags & IORESOURCE_IO) && (start & 0x300)) + start = (start + 0x3ff) & ~0x3ff; + + return 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; +} diff --git a/kernel/arch/cris/arch-v32/drivers/pci/dma.c b/kernel/arch/cris/arch-v32/drivers/pci/dma.c new file mode 100644 index 000000000..ee55578d9 --- /dev/null +++ b/kernel/arch/cris/arch-v32/drivers/pci/dma.c @@ -0,0 +1,50 @@ +/* + * Dynamic DMA mapping support. + * + * On cris there is no hardware dynamic DMA address translation, + * so consistent alloc/free are merely page allocation/freeing. + * The rest of the dynamic DMA mapping interface is implemented + * in asm/pci.h. + * + * Borrowed from i386. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/gfp.h> +#include <asm/io.h> + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + void *ret; + int order = get_order(size); + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) + return ret; + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + + ret = (void *)__get_free_pages(gfp, order); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_phys(ret); + } + return ret; +} + +void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + int order = get_order(size); + + if (!dma_release_from_coherent(dev, order, vaddr)) + free_pages((unsigned long)vaddr, order); +} + |