#include "pci_impl.h"
-unsigned long pci_memspace_mask = 0xffffffffUL;
-
#ifndef CONFIG_PCI
/* A "nop" PCI implementation. */
asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
{ "SUNW,sun4v-pci", sun4v_pci_init },
{ "pciex108e,80f0", fire_pci_init },
};
-#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
- sizeof(pci_controller_table[0]))
+#define PCI_NUM_CONTROLLER_TYPES ARRAY_SIZE(pci_controller_table)
static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
{
return 0;
}
-static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
- if (!strncmp(model_name,
- pci_controller_table[i].model_name,
- namelen)) {
- return 1;
- }
- }
- return 0;
-}
-
static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
{
struct device_node *dp;
return count;
}
-
-/* Is there some PCI controller in the system? */
-int __init pcic_present(void)
-{
- return pci_controller_scan(pci_is_controller);
-}
-
-const struct pci_iommu_ops *pci_iommu_ops;
-EXPORT_SYMBOL(pci_iommu_ops);
-
-extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
- pci_sun4v_iommu_ops;
-
/* Find each controller in the system, attach and initialize
* software state structure for each and link into the
* pci_pbm_root. Setup the controller enough such
*/
static void __init pci_controller_probe(void)
{
- if (tlb_type == hypervisor)
- pci_iommu_ops = &pci_sun4v_iommu_ops;
- else
- pci_iommu_ops = &pci_sun4u_iommu_ops;
-
printk("PCI: Probing for controllers.\n");
pci_controller_scan(pci_controller_init);
sd->host_controller = pbm;
sd->prom_node = node;
sd->op = of_find_device_by_node(node);
- sd->msi_num = 0xffffffff;
+
+ sd = &sd->op->dev.archdata;
+ sd->iommu = pbm->iommu;
+ sd->stc = &pbm->stc;
type = of_get_property(node, "device_type", NULL);
if (type == NULL)
dev->multifunction = 0; /* maybe a lie? */
if (host_controller) {
- dev->vendor = 0x108e;
- dev->device = 0x8000;
- dev->subsystem_vendor = 0x0000;
- dev->subsystem_device = 0x0000;
+ if (tlb_type != hypervisor) {
+ pci_read_config_word(dev, PCI_VENDOR_ID,
+ &dev->vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID,
+ &dev->device);
+ } else {
+ dev->vendor = PCI_VENDOR_ID_SUN;
+ dev->device = 0x80f0;
+ }
dev->cfg_size = 256;
dev->class = PCI_CLASS_BRIDGE_HOST << 8;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
{
struct device_node *child;
const u32 *reg;
- int reglen, devfn;
+ int reglen, devfn, prev_devfn;
struct pci_dev *dev;
if (ofpci_verbose)
node->full_name, bus->number);
child = NULL;
+ prev_devfn = -1;
while ((child = of_get_next_child(node, child)) != NULL) {
if (ofpci_verbose)
printk(" * %s\n", child->full_name);
reg = of_get_property(child, "reg", ®len);
if (reg == NULL || reglen < 20)
continue;
+
devfn = (reg[0] >> 8) & 0xff;
+ /* This is a workaround for some device trees
+ * which list PCI devices twice. On the V100
+ * for example, device number 3 is listed twice.
+ * Once as "pm" and once again as "lomp".
+ */
+ if (devfn == prev_devfn)
+ continue;
+ prev_devfn = devfn;
+
/* create a new pci_dev for this device */
dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
if (!dev)
{
static u8 fake_pci_config[] = {
0x8e, 0x10, /* Vendor: 0x108e (Sun) */
- 0x00, 0x80, /* Device: 0x8000 (PBM) */
+ 0xf0, 0x80, /* Device: 0x80f0 (Fire) */
0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
return 0;
}
-/* Adjust vm_pgoff of VMA such that it is the physical page offset corresponding
- * to the 32-bit pci bus offset for DEV requested by the user.
+/* Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
*
* Basically, the user finds the base address for his device which he wishes
* to mmap. They read the 32-bit value from the config space base register,
*
* Returns negative error code on failure, zero on success.
*/
-static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+static int __pci_mmap_make_offset(struct pci_dev *pdev,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long user32 = user_offset & pci_memspace_mask;
- unsigned long largest_base, this_base, addr32;
- int i;
+ unsigned long user_paddr, user_size;
+ int i, err;
+
+ /* First compute the physical address in vma->vm_pgoff,
+ * making sure the user offset is within range in the
+ * appropriate PCI space.
+ */
+ err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
+ if (err)
+ return err;
+
+ /* If this is a mapping on a host bridge, any address
+ * is OK.
+ */
+ if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ return err;
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
- return __pci_mmap_make_offset_bus(dev, vma, mmap_state);
+ /* Otherwise make sure it's in the range for one of the
+ * device's resources.
+ */
+ user_paddr = vma->vm_pgoff << PAGE_SHIFT;
+ user_size = vma->vm_end - vma->vm_start;
- /* Figure out which base address this is for. */
- largest_base = 0UL;
for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &dev->resource[i];
+ struct resource *rp = &pdev->resource[i];
/* Active? */
if (!rp->flags)
continue;
}
- this_base = rp->start;
-
- addr32 = (this_base & PAGE_MASK) & pci_memspace_mask;
-
- if (mmap_state == pci_mmap_io)
- addr32 &= 0xffffff;
-
- if (addr32 <= user32 && this_base > largest_base)
- largest_base = this_base;
+ if ((rp->start <= user_paddr) &&
+ (user_paddr + user_size) <= (rp->end + 1UL))
+ break;
}
- if (largest_base == 0UL)
+ if (i > PCI_ROM_RESOURCE)
return -EINVAL;
- /* Now construct the final physical address. */
- if (mmap_state == pci_mmap_io)
- vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT);
- else
- vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT);
-
return 0;
}
}
EXPORT_SYMBOL(pci_device_to_OF_node);
+static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
+{
+ struct pci_dev *ali_isa_bridge;
+ u8 val;
+
+ /* ALI sound chips generate 31-bits of DMA, a special register
+ * determines what bit 31 is emitted as.
+ */
+ ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
+ PCI_DEVICE_ID_AL_M1533,
+ NULL);
+
+ pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
+ if (set_bit)
+ val |= 0x01;
+ else
+ val &= ~0x01;
+ pci_write_config_byte(ali_isa_bridge, 0x7e, val);
+ pci_dev_put(ali_isa_bridge);
+}
+
+int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
+{
+ u64 dma_addr_mask;
+
+ if (pdev == NULL) {
+ dma_addr_mask = 0xffffffff;
+ } else {
+ struct iommu *iommu = pdev->dev.archdata.iommu;
+
+ dma_addr_mask = iommu->dma_addr_mask;
+
+ if (pdev->vendor == PCI_VENDOR_ID_AL &&
+ pdev->device == PCI_DEVICE_ID_AL_M5451 &&
+ device_mask == 0x7fffffff) {
+ ali_sound_dma_hack(pdev,
+ (dma_addr_mask & 0x80000000) != 0);
+ return 1;
+ }
+ }
+
+ if (device_mask >= (1UL << 32UL))
+ return 0;
+
+ return (device_mask & dma_addr_mask) == dma_addr_mask;
+}
+
+void pci_resource_to_user(const struct pci_dev *pdev, int bar,
+ const struct resource *rp, resource_size_t *start,
+ resource_size_t *end)
+{
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+ unsigned long offset;
+
+ if (rp->flags & IORESOURCE_IO)
+ offset = pbm->io_space.start;
+ else
+ offset = pbm->mem_space.start;
+
+ *start = rp->start - offset;
+ *end = rp->end - offset;
+}
+
#endif /* !(CONFIG_PCI) */