diff options
Diffstat (limited to 'drivers/parisc')
-rw-r--r-- | drivers/parisc/iosapic.c | 38 | ||||
-rw-r--r-- | drivers/parisc/lba_pci.c | 56 |
2 files changed, 83 insertions, 11 deletions
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index e79e006eb9a..9ee04b4b68b 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) return pcidev->irq; } -static struct iosapic_info *first_isi = NULL; +static struct iosapic_info *iosapic_list; #ifdef CONFIG_64BIT -int iosapic_serial_irq(int num) +int iosapic_serial_irq(struct parisc_device *dev) { - struct iosapic_info *isi = first_isi; - struct irt_entry *irte = NULL; /* only used if PAT PDC */ + struct iosapic_info *isi; + struct irt_entry *irte; struct vector_info *vi; - int isi_line; /* line used by device */ + int cnt; + int intin; + + intin = (dev->mod_info >> 24) & 15; /* lookup IRT entry for isi/slot/pin set */ - irte = &irt_cell[num]; + for (cnt = 0; cnt < irt_num_entry; cnt++) { + irte = &irt_cell[cnt]; + if (COMPARE_IRTE_ADDR(irte, dev->mod0) && + irte->dest_iosapic_intin == intin) + break; + } + if (cnt >= irt_num_entry) + return 0; /* no irq found, force polling */ DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", irte, @@ -834,11 +844,17 @@ int iosapic_serial_irq(int num) irte->src_seg_id, irte->dest_iosapic_intin, (u32) irte->dest_iosapic_addr); - isi_line = irte->dest_iosapic_intin; + + /* search for iosapic */ + for (isi = iosapic_list; isi; isi = isi->isi_next) + if (isi->isi_hpa == dev->mod0) + break; + if (!isi) + return 0; /* no iosapic found, force polling */ /* get vector info for this input line */ - vi = isi->isi_vector + isi_line; - DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi); + vi = isi->isi_vector + intin; + DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi); /* If this IRQ line has already been setup, skip it */ if (vi->irte) @@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa) vip->irqline = (unsigned char) cnt; vip->iosapic = isi; } - if (!first_isi) - first_isi = isi; + isi->isi_next = iosapic_list; + iosapic_list = isi; return isi; } diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 1f05913ae67..19f6f70c67d 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -613,6 +613,54 @@ truncate_pat_collision(struct resource *root, struct resource *new) return 0; /* truncation successful */ } +/* + * extend_lmmio_len: extend lmmio range to maximum length + * + * This is needed at least on C8000 systems to get the ATI FireGL card + * working. On other systems we will currently not extend the lmmio space. + */ +static unsigned long +extend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len) +{ + struct resource *tmp; + + pr_debug("LMMIO mismatch: PAT length = 0x%lx, MASK register = 0x%lx\n", + end - start, lba_len); + + lba_len = min(lba_len+1, 256UL*1024*1024); /* limit to 256 MB */ + + pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - original\n", start, end); + + if (boot_cpu_data.cpu_type < mako) { + pr_info("LBA: Not a C8000 system - not extending LMMIO range.\n"); + return end; + } + + end += lba_len; + if (end < start) /* fix overflow */ + end = -1ULL; + + pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - current\n", start, end); + + /* first overlap */ + for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) { + pr_debug("LBA: testing %pR\n", tmp); + if (tmp->start == start) + continue; /* ignore ourself */ + if (tmp->end < start) + continue; + if (tmp->start > end) + continue; + if (end >= tmp->start) + end = tmp->start - 1; + } + + pr_info("LBA: lmmio_space [0x%lx-0x%lx] - new\n", start, end); + + /* return new end */ + return end; +} + #else #define truncate_pat_collision(r,n) (0) #endif @@ -994,6 +1042,14 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) case PAT_LMMIO: /* used to fix up pre-initialized MEM BARs */ if (!lba_dev->hba.lmmio_space.flags) { + unsigned long lba_len; + + lba_len = ~READ_REG32(lba_dev->hba.base_addr + + LBA_LMMIO_MASK); + if ((p->end - p->start) != lba_len) + p->end = extend_lmmio_len(p->start, + p->end, lba_len); + sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO", (int)lba_dev->hba.bus_num.start); |