Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: [SPARC64]: Optimize fault kprobe handling just like powerpc. [SPARC]: Wire up utimensat syscall. [SPARC64]: Fix request_irq() ignored result warnings in PCI controller code. [SPARC64]: Kill asm-sparc64/pbm.h [ATYFB]: Fix sparc includes. [QLA2XXX]: Fix build on sparc. [SPARC64]: Removal of trivial pci_controller_info uses. [SPARC64]: Move index info pci_pbm_info. [SPARC64]: Move {setup,teardown}_msi_irq into pci_pbm_info. [SPARC64]: Move pci_ops into pci_pbm_info. [SPARC64] SBUS: Error interrupt registry cleanups. [SPARC64] PCI: Use root list of pbm's instead of pci_controller_info's [SPARC64] PCI: Kill PROM_PCIRNG_MAX and PROM_PCIIMAP_MAX. [SPARC64] PCI: Use common routine to fetch PBM properties.
This commit is contained in:
commit
0c23664ee8
|
@ -80,6 +80,7 @@ sys_call_table:
|
|||
/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
|
||||
/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
|
||||
/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
|
||||
/*310*/ .long sys_utimensat
|
||||
|
||||
#ifdef CONFIG_SUNOS_EMUL
|
||||
/* Now the SunOS syscall table. */
|
||||
|
@ -196,5 +197,6 @@ sunos_sys_table:
|
|||
.long sunos_nosys, sunos_nosys, sunos_nosys
|
||||
.long sunos_nosys, sunos_nosys, sunos_nosys
|
||||
.long sunos_nosys
|
||||
/*310*/ .long sunos_nosys
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,16 +13,17 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/ebus.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/bpp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* EBUS dma library. */
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ out:
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||
int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||
{
|
||||
struct kprobe *cur = kprobe_running();
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
@ -403,15 +403,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
|||
if (post_kprobe_handler(args->regs))
|
||||
ret = NOTIFY_STOP;
|
||||
break;
|
||||
case DIE_GPF:
|
||||
case DIE_PAGE_FAULT:
|
||||
/* kprobe_running() needs smp_processor_id() */
|
||||
preempt_disable();
|
||||
if (kprobe_running() &&
|
||||
kprobe_fault_handler(args->regs, args->trapnr))
|
||||
ret = NOTIFY_STOP;
|
||||
preempt_enable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/ebus.h>
|
||||
|
@ -48,10 +48,10 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
|
|||
#else
|
||||
|
||||
/* List of all PCI controllers found in the system. */
|
||||
struct pci_controller_info *pci_controller_root = NULL;
|
||||
struct pci_pbm_info *pci_pbm_root = NULL;
|
||||
|
||||
/* Each PCI controller found gets a unique index. */
|
||||
int pci_num_controllers = 0;
|
||||
/* Each PBM found gets a unique index. */
|
||||
int pci_num_pbms = 0;
|
||||
|
||||
volatile int pci_poke_in_progress;
|
||||
volatile int pci_poke_cpu = -1;
|
||||
|
@ -291,7 +291,7 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
|
|||
|
||||
/* Find each controller in the system, attach and initialize
|
||||
* software state structure for each and link into the
|
||||
* pci_controller_root. Setup the controller enough such
|
||||
* pci_pbm_root. Setup the controller enough such
|
||||
* that bus scanning can be done.
|
||||
*/
|
||||
static void __init pci_controller_probe(void)
|
||||
|
@ -743,7 +743,6 @@ int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
|
|||
|
||||
struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
struct device_node *node = pbm->prom_node;
|
||||
struct pci_dev *host_pdev;
|
||||
struct pci_bus *bus;
|
||||
|
@ -751,7 +750,7 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
|||
printk("PCI: Scanning PBM %s\n", node->full_name);
|
||||
|
||||
/* XXX parent device? XXX */
|
||||
bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
|
||||
bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
|
||||
if (!bus) {
|
||||
printk(KERN_ERR "Failed to create bus for %s\n",
|
||||
node->full_name);
|
||||
|
@ -776,10 +775,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
|||
|
||||
static void __init pci_scan_each_controller_bus(void)
|
||||
{
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
for (p = pci_controller_root; p; p = p->next)
|
||||
p->scan_bus(p);
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
|
||||
pbm->scan_bus(pbm);
|
||||
}
|
||||
|
||||
extern void power_init(void);
|
||||
|
@ -787,7 +786,7 @@ extern void power_init(void);
|
|||
static int __init pcibios_init(void)
|
||||
{
|
||||
pci_controller_probe();
|
||||
if (pci_controller_root == NULL)
|
||||
if (pci_pbm_root == NULL)
|
||||
return 0;
|
||||
|
||||
pci_scan_each_controller_bus();
|
||||
|
@ -922,10 +921,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
|
|||
enum pci_mmap_state mmap_state)
|
||||
{
|
||||
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
|
||||
struct pci_controller_info *p;
|
||||
unsigned long space_size, user_offset, user_size;
|
||||
|
||||
p = pbm->parent;
|
||||
if (mmap_state == pci_mmap_io) {
|
||||
space_size = (pbm->io_space.end -
|
||||
pbm->io_space.start) + 1;
|
||||
|
@ -1078,11 +1075,7 @@ int pci_domain_nr(struct pci_bus *pbus)
|
|||
if (pbm == NULL || pbm->parent == NULL) {
|
||||
ret = -ENXIO;
|
||||
} else {
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
|
||||
ret = p->index;
|
||||
ret = ((ret << 1) +
|
||||
((pbm == &pbm->parent->pbm_B) ? 1 : 0));
|
||||
ret = pbm->index;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1093,17 +1086,12 @@ EXPORT_SYMBOL(pci_domain_nr);
|
|||
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
|
||||
{
|
||||
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
int virt_irq, err;
|
||||
int virt_irq;
|
||||
|
||||
if (!pbm->msi_num || !p->setup_msi_irq)
|
||||
if (!pbm->setup_msi_irq)
|
||||
return -EINVAL;
|
||||
|
||||
err = p->setup_msi_irq(&virt_irq, pdev, desc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return pbm->setup_msi_irq(&virt_irq, pdev, desc);
|
||||
}
|
||||
|
||||
void arch_teardown_msi_irq(unsigned int virt_irq)
|
||||
|
@ -1111,12 +1099,11 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
|
|||
struct msi_desc *entry = get_irq_msi(virt_irq);
|
||||
struct pci_dev *pdev = entry->dev;
|
||||
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
|
||||
if (!pbm->msi_num || !p->setup_msi_irq)
|
||||
if (!pbm->teardown_msi_irq)
|
||||
return;
|
||||
|
||||
return p->teardown_msi_irq(virt_irq, pdev);
|
||||
return pbm->teardown_msi_irq(virt_irq, pdev);
|
||||
}
|
||||
#endif /* !(CONFIG_PCI_MSI) */
|
||||
|
||||
|
|
|
@ -9,12 +9,26 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/oplib.h>
|
||||
|
||||
#include "pci_impl.h"
|
||||
|
||||
void pci_get_pbm_props(struct pci_pbm_info *pbm)
|
||||
{
|
||||
const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
|
||||
|
||||
pbm->pci_first_busno = val[0];
|
||||
pbm->pci_last_busno = val[1];
|
||||
|
||||
val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
|
||||
if (val) {
|
||||
pbm->ino_bitmap = (((u64)val[1] << 32UL) |
|
||||
((u64)val[0] << 0UL));
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_register_legacy_regions(struct resource *io_res,
|
||||
struct resource *mem_res)
|
||||
{
|
||||
|
@ -149,8 +163,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
|
|||
}
|
||||
|
||||
/* Generic helper routines for PCI error reporting. */
|
||||
void pci_scan_for_target_abort(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
void pci_scan_for_target_abort(struct pci_pbm_info *pbm,
|
||||
struct pci_bus *pbus)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
@ -165,18 +178,16 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
|
|||
PCI_STATUS_REC_TARGET_ABORT));
|
||||
if (error_bits) {
|
||||
pci_write_config_word(pdev, PCI_STATUS, error_bits);
|
||||
printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
|
||||
p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
|
||||
pci_name(pdev), status);
|
||||
printk("%s: Device %s saw Target Abort [%016x]\n",
|
||||
pbm->name, pci_name(pdev), status);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(bus, &pbus->children, node)
|
||||
pci_scan_for_target_abort(p, pbm, bus);
|
||||
pci_scan_for_target_abort(pbm, bus);
|
||||
}
|
||||
|
||||
void pci_scan_for_master_abort(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
void pci_scan_for_master_abort(struct pci_pbm_info *pbm,
|
||||
struct pci_bus *pbus)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
@ -190,18 +201,16 @@ void pci_scan_for_master_abort(struct pci_controller_info *p,
|
|||
(status & (PCI_STATUS_REC_MASTER_ABORT));
|
||||
if (error_bits) {
|
||||
pci_write_config_word(pdev, PCI_STATUS, error_bits);
|
||||
printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
|
||||
p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
|
||||
pci_name(pdev), status);
|
||||
printk("%s: Device %s received Master Abort [%016x]\n",
|
||||
pbm->name, pci_name(pdev), status);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(bus, &pbus->children, node)
|
||||
pci_scan_for_master_abort(p, pbm, bus);
|
||||
pci_scan_for_master_abort(pbm, bus);
|
||||
}
|
||||
|
||||
void pci_scan_for_parity_error(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
void pci_scan_for_parity_error(struct pci_pbm_info *pbm,
|
||||
struct pci_bus *pbus)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
@ -216,12 +225,11 @@ void pci_scan_for_parity_error(struct pci_controller_info *p,
|
|||
PCI_STATUS_DETECTED_PARITY));
|
||||
if (error_bits) {
|
||||
pci_write_config_word(pdev, PCI_STATUS, error_bits);
|
||||
printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
|
||||
p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
|
||||
pci_name(pdev), status);
|
||||
printk("%s: Device %s saw Parity Error [%016x]\n",
|
||||
pbm->name, pci_name(pdev), status);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(bus, &pbus->children, node)
|
||||
pci_scan_for_parity_error(p, pbm, bus);
|
||||
pci_scan_for_parity_error(pbm, bus);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
|
@ -160,21 +159,9 @@ static struct pci_ops pci_fire_ops = {
|
|||
.write = fire_write_pci_cfg,
|
||||
};
|
||||
|
||||
static void pbm_scan_bus(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm)
|
||||
static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
|
||||
{
|
||||
pbm->pci_bus = pci_scan_one_pbm(pbm);
|
||||
}
|
||||
|
||||
static void pci_fire_scan_bus(struct pci_controller_info *p)
|
||||
{
|
||||
struct device_node *dp;
|
||||
|
||||
if ((dp = p->pbm_A.prom_node) != NULL)
|
||||
pbm_scan_bus(p, &p->pbm_A);
|
||||
|
||||
if ((dp = p->pbm_B.prom_node) != NULL)
|
||||
pbm_scan_bus(p, &p->pbm_B);
|
||||
|
||||
/* XXX register error interrupt handlers XXX */
|
||||
}
|
||||
|
@ -313,18 +300,24 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
|
|||
}
|
||||
|
||||
static void pci_fire_pbm_init(struct pci_controller_info *p,
|
||||
struct device_node *dp, u32 portid)
|
||||
struct device_node *dp, u32 portid)
|
||||
{
|
||||
const struct linux_prom64_registers *regs;
|
||||
struct pci_pbm_info *pbm;
|
||||
const u32 *ino_bitmap;
|
||||
const unsigned int *busrange;
|
||||
|
||||
if ((portid & 1) == 0)
|
||||
pbm = &p->pbm_A;
|
||||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->scan_bus = pci_fire_scan_bus;
|
||||
pbm->pci_ops = &pci_fire_ops;
|
||||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->portid = portid;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
|
@ -338,13 +331,7 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
pci_determine_mem_io_space(pbm);
|
||||
|
||||
ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
|
||||
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
|
||||
((u64)ino_bitmap[0] << 0UL));
|
||||
|
||||
busrange = of_get_property(dp, "bus-range", NULL);
|
||||
pbm->pci_first_busno = busrange[0];
|
||||
pbm->pci_last_busno = busrange[1];
|
||||
pci_get_pbm_props(pbm);
|
||||
|
||||
pci_fire_hw_init(pbm);
|
||||
pci_fire_pbm_iommu_init(pbm);
|
||||
|
@ -362,19 +349,11 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
|
|||
struct pci_controller_info *p;
|
||||
u32 portid = of_getintprop_default(dp, "portid", 0xff);
|
||||
struct iommu *iommu;
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
for (p = pci_controller_root; p; p = p->next) {
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
|
||||
continue;
|
||||
|
||||
pbm = (p->pbm_A.prom_node ?
|
||||
&p->pbm_A :
|
||||
&p->pbm_B);
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (portid_compare(pbm->portid, portid)) {
|
||||
pci_fire_pbm_init(p, dp, portid);
|
||||
pci_fire_pbm_init(pbm->parent, dp, portid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -395,14 +374,7 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
|
|||
|
||||
p->pbm_B.iommu = iommu;
|
||||
|
||||
p->next = pci_controller_root;
|
||||
pci_controller_root = p;
|
||||
|
||||
p->index = pci_num_controllers++;
|
||||
|
||||
p->scan_bus = pci_fire_scan_bus;
|
||||
/* XXX MSI support XXX */
|
||||
p->pci_ops = &pci_fire_ops;
|
||||
|
||||
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
|
||||
* for memory space.
|
||||
|
|
|
@ -8,15 +8,129 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/iommu.h>
|
||||
|
||||
extern struct pci_controller_info *pci_controller_root;
|
||||
/* The abstraction used here is that there are PCI controllers,
|
||||
* each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
|
||||
* underneath. Each PCI bus module uses an IOMMU (shared by both
|
||||
* PBMs of a controller, or per-PBM), and if a streaming buffer
|
||||
* is present, each PCI bus module has it's own. (ie. the IOMMU
|
||||
* might be shared between PBMs, the STC is never shared)
|
||||
* Furthermore, each PCI bus module controls it's own autonomous
|
||||
* PCI bus.
|
||||
*/
|
||||
|
||||
#define PCI_STC_FLUSHFLAG_INIT(STC) \
|
||||
(*((STC)->strbuf_flushflag) = 0UL)
|
||||
#define PCI_STC_FLUSHFLAG_SET(STC) \
|
||||
(*((STC)->strbuf_flushflag) != 0UL)
|
||||
|
||||
struct pci_controller_info;
|
||||
|
||||
struct pci_pbm_info {
|
||||
struct pci_pbm_info *next;
|
||||
int index;
|
||||
|
||||
/* PCI controller we sit under. */
|
||||
struct pci_controller_info *parent;
|
||||
|
||||
/* Physical address base of controller registers. */
|
||||
unsigned long controller_regs;
|
||||
|
||||
/* Physical address base of PBM registers. */
|
||||
unsigned long pbm_regs;
|
||||
|
||||
/* Physical address of DMA sync register, if any. */
|
||||
unsigned long sync_reg;
|
||||
|
||||
/* Opaque 32-bit system bus Port ID. */
|
||||
u32 portid;
|
||||
|
||||
/* Opaque 32-bit handle used for hypervisor calls. */
|
||||
u32 devhandle;
|
||||
|
||||
/* Chipset version information. */
|
||||
int chip_type;
|
||||
#define PBM_CHIP_TYPE_SABRE 1
|
||||
#define PBM_CHIP_TYPE_PSYCHO 2
|
||||
#define PBM_CHIP_TYPE_SCHIZO 3
|
||||
#define PBM_CHIP_TYPE_SCHIZO_PLUS 4
|
||||
#define PBM_CHIP_TYPE_TOMATILLO 5
|
||||
int chip_version;
|
||||
int chip_revision;
|
||||
|
||||
/* Name used for top-level resources. */
|
||||
char *name;
|
||||
|
||||
/* OBP specific information. */
|
||||
struct device_node *prom_node;
|
||||
u64 ino_bitmap;
|
||||
|
||||
/* PBM I/O and Memory space resources. */
|
||||
struct resource io_space;
|
||||
struct resource mem_space;
|
||||
|
||||
/* Base of PCI Config space, can be per-PBM or shared. */
|
||||
unsigned long config_space;
|
||||
|
||||
/* State of 66MHz capabilities on this PBM. */
|
||||
int is_66mhz_capable;
|
||||
int all_devs_66mhz;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
/* MSI info. */
|
||||
u32 msiq_num;
|
||||
u32 msiq_ent_count;
|
||||
u32 msiq_first;
|
||||
u32 msiq_first_devino;
|
||||
u32 msi_num;
|
||||
u32 msi_first;
|
||||
u32 msi_data_mask;
|
||||
u32 msix_data_width;
|
||||
u64 msi32_start;
|
||||
u64 msi64_start;
|
||||
u32 msi32_len;
|
||||
u32 msi64_len;
|
||||
void *msi_queues;
|
||||
unsigned long *msi_bitmap;
|
||||
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
|
||||
struct msi_desc *entry);
|
||||
void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
|
||||
#endif /* !(CONFIG_PCI_MSI) */
|
||||
|
||||
/* This PBM's streaming buffer. */
|
||||
struct strbuf stc;
|
||||
|
||||
/* IOMMU state, potentially shared by both PBM segments. */
|
||||
struct iommu *iommu;
|
||||
|
||||
/* Now things for the actual PCI bus probes. */
|
||||
unsigned int pci_first_busno;
|
||||
unsigned int pci_last_busno;
|
||||
struct pci_bus *pci_bus;
|
||||
void (*scan_bus)(struct pci_pbm_info *);
|
||||
struct pci_ops *pci_ops;
|
||||
};
|
||||
|
||||
struct pci_controller_info {
|
||||
/* The PCI bus modules controlled by us. */
|
||||
struct pci_pbm_info pbm_A;
|
||||
struct pci_pbm_info pbm_B;
|
||||
};
|
||||
|
||||
extern struct pci_pbm_info *pci_pbm_root;
|
||||
extern unsigned long pci_memspace_mask;
|
||||
|
||||
extern int pci_num_controllers;
|
||||
extern int pci_num_pbms;
|
||||
|
||||
/* PCI bus scanning and fixup support. */
|
||||
extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize,
|
||||
u32 dma_offset, u32 dma_addr_mask);
|
||||
extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
|
||||
extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
|
||||
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
|
||||
|
||||
|
@ -30,9 +144,9 @@ extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
|
|||
u32 value);
|
||||
|
||||
/* Error reporting support. */
|
||||
extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
||||
extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
||||
extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
||||
extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
|
||||
extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);
|
||||
extern void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *);
|
||||
|
||||
/* Configuration space access. */
|
||||
extern void pci_config_read8(u8 *addr, u8 *ret);
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/oplib.h>
|
||||
|
||||
#include "iommu_common.h"
|
||||
#include "pci_impl.h"
|
||||
|
||||
#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
|
||||
((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/starfire.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/oplib.h>
|
||||
|
||||
#include "pci_impl.h"
|
||||
#include "iommu_common.h"
|
||||
|
@ -98,13 +98,8 @@ static int psycho_out_of_range(struct pci_pbm_info *pbm,
|
|||
unsigned char bus,
|
||||
unsigned char devfn)
|
||||
{
|
||||
return ((pbm->parent == 0) ||
|
||||
((pbm == &pbm->parent->pbm_B) &&
|
||||
(bus == pbm->pci_first_busno) &&
|
||||
PCI_SLOT(devfn) > 8) ||
|
||||
((pbm == &pbm->parent->pbm_A) &&
|
||||
(bus == pbm->pci_first_busno) &&
|
||||
PCI_SLOT(devfn) > 8));
|
||||
return ((bus == pbm->pci_first_busno) &&
|
||||
PCI_SLOT(devfn) > 8);
|
||||
}
|
||||
|
||||
/* PSYCHO PCI configuration space accessors. */
|
||||
|
@ -265,12 +260,11 @@ static unsigned long stc_error_buf[128];
|
|||
static unsigned long stc_tag_buf[16];
|
||||
static unsigned long stc_line_buf[16];
|
||||
|
||||
static void __psycho_check_one_stc(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
|
||||
int is_pbm_a)
|
||||
{
|
||||
struct strbuf *strbuf = &pbm->stc;
|
||||
unsigned long regbase = p->pbm_A.controller_regs;
|
||||
unsigned long regbase = pbm->controller_regs;
|
||||
unsigned long err_base, tag_base, line_base;
|
||||
u64 control;
|
||||
int i;
|
||||
|
@ -326,9 +320,8 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
|
|||
unsigned long errval = stc_error_buf[j];
|
||||
if (errval != 0) {
|
||||
saw_error++;
|
||||
printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n",
|
||||
p->index,
|
||||
(is_pbm_a ? 'A' : 'B'),
|
||||
printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
|
||||
pbm->name,
|
||||
j,
|
||||
(errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
|
||||
(errval & PSYCHO_STCERR_READ) ? 1 : 0);
|
||||
|
@ -337,18 +330,16 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
|
|||
if (saw_error != 0) {
|
||||
unsigned long tagval = stc_tag_buf[i];
|
||||
unsigned long lineval = stc_line_buf[i];
|
||||
printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
|
||||
p->index,
|
||||
(is_pbm_a ? 'A' : 'B'),
|
||||
printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
|
||||
pbm->name,
|
||||
i,
|
||||
((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
|
||||
(tagval & PSYCHO_STCTAG_VPN),
|
||||
((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
|
||||
((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
|
||||
printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
|
||||
printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
|
||||
"V(%d)FOFN(%d)]\n",
|
||||
p->index,
|
||||
(is_pbm_a ? 'A' : 'B'),
|
||||
pbm->name,
|
||||
i,
|
||||
((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
|
||||
((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
|
||||
|
@ -362,20 +353,13 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
|
|||
spin_unlock(&stc_buf_lock);
|
||||
}
|
||||
|
||||
static void __psycho_check_stc_error(struct pci_controller_info *p,
|
||||
static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
|
||||
unsigned long afsr,
|
||||
unsigned long afar,
|
||||
enum psycho_error_type type)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
pbm = &p->pbm_A;
|
||||
if (pbm->stc.strbuf_enabled)
|
||||
__psycho_check_one_stc(p, pbm, 1);
|
||||
|
||||
pbm = &p->pbm_B;
|
||||
if (pbm->stc.strbuf_enabled)
|
||||
__psycho_check_one_stc(p, pbm, 0);
|
||||
__psycho_check_one_stc(pbm,
|
||||
(pbm == &pbm->parent->pbm_A));
|
||||
}
|
||||
|
||||
/* When an Uncorrectable Error or a PCI Error happens, we
|
||||
|
@ -413,12 +397,12 @@ static void __psycho_check_stc_error(struct pci_controller_info *p,
|
|||
#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
|
||||
#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
|
||||
#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
|
||||
static void psycho_check_iommu_error(struct pci_controller_info *p,
|
||||
static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
|
||||
unsigned long afsr,
|
||||
unsigned long afar,
|
||||
enum psycho_error_type type)
|
||||
{
|
||||
struct iommu *iommu = p->pbm_A.iommu;
|
||||
struct iommu *iommu = pbm->iommu;
|
||||
unsigned long iommu_tag[16];
|
||||
unsigned long iommu_data[16];
|
||||
unsigned long flags;
|
||||
|
@ -449,8 +433,8 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
|
|||
type_string = "ECC Error";
|
||||
break;
|
||||
};
|
||||
printk("PSYCHO%d: IOMMU Error, type[%s]\n",
|
||||
p->index, type_string);
|
||||
printk("%s: IOMMU Error, type[%s]\n",
|
||||
pbm->name, type_string);
|
||||
|
||||
/* Put the IOMMU into diagnostic mode and probe
|
||||
* it's TLB for entries with error status.
|
||||
|
@ -465,7 +449,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
|
|||
psycho_write(iommu->iommu_control,
|
||||
control | PSYCHO_IOMMU_CTRL_DENAB);
|
||||
for (i = 0; i < 16; i++) {
|
||||
unsigned long base = p->pbm_A.controller_regs;
|
||||
unsigned long base = pbm->controller_regs;
|
||||
|
||||
iommu_tag[i] =
|
||||
psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
|
||||
|
@ -503,20 +487,20 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
|
|||
type_string = "ECC Error";
|
||||
break;
|
||||
};
|
||||
printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
|
||||
p->index, i, type_string,
|
||||
printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
|
||||
pbm->name, i, type_string,
|
||||
((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
|
||||
((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
|
||||
((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
|
||||
(tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
|
||||
printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
|
||||
p->index, i,
|
||||
printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
|
||||
pbm->name, i,
|
||||
((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
|
||||
((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
|
||||
(data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
__psycho_check_stc_error(p, afsr, afar, type);
|
||||
__psycho_check_stc_error(pbm, afsr, afar, type);
|
||||
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -541,9 +525,10 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
|
|||
|
||||
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
||||
|
@ -560,22 +545,22 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|||
psycho_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: Uncorrectable Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & PSYCHO_UEAFSR_PPIO) ?
|
||||
"PIO" :
|
||||
((error_bits & PSYCHO_UEAFSR_PDRD) ?
|
||||
"DMA Read" :
|
||||
((error_bits & PSYCHO_UEAFSR_PDWR) ?
|
||||
"DMA Write" : "???")))));
|
||||
printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
|
||||
p->index,
|
||||
printk("%s: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
|
||||
pbm->name,
|
||||
(afsr & PSYCHO_UEAFSR_BMSK) >> 32UL,
|
||||
(afsr & PSYCHO_UEAFSR_DOFF) >> 29UL,
|
||||
(afsr & PSYCHO_UEAFSR_MID) >> 24UL,
|
||||
((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0));
|
||||
printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("PSYCHO%d: UE Secondary errors [", p->index);
|
||||
printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: UE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & PSYCHO_UEAFSR_SPIO) {
|
||||
reported++;
|
||||
|
@ -593,8 +578,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|||
printk("(none)");
|
||||
printk("]\n");
|
||||
|
||||
/* Interrogate IOMMU for error status. */
|
||||
psycho_check_iommu_error(p, afsr, afar, UE_ERR);
|
||||
/* Interrogate both IOMMUs for error status. */
|
||||
psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
|
||||
psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -618,9 +604,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|||
|
||||
static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
||||
|
@ -637,8 +623,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
|
|||
psycho_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: Correctable Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & PSYCHO_CEAFSR_PPIO) ?
|
||||
"PIO" :
|
||||
((error_bits & PSYCHO_CEAFSR_PDRD) ?
|
||||
|
@ -649,16 +635,16 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
|
|||
/* XXX Use syndrome and afar to print out module string just like
|
||||
* XXX UDB CE trap handler does... -DaveM
|
||||
*/
|
||||
printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
|
||||
printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
|
||||
"UPA_MID[%02lx] was_block(%d)\n",
|
||||
p->index,
|
||||
pbm->name,
|
||||
(afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,
|
||||
(afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,
|
||||
(afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,
|
||||
(afsr & PSYCHO_CEAFSR_MID) >> 24UL,
|
||||
((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));
|
||||
printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("PSYCHO%d: CE Secondary errors [", p->index);
|
||||
printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: CE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & PSYCHO_CEAFSR_SPIO) {
|
||||
reported++;
|
||||
|
@ -773,8 +759,8 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
psycho_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",
|
||||
p->index, (is_pbm_a ? 'A' : 'B'),
|
||||
printk("%s: PCI Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & PSYCHO_PCIAFSR_PMA) ?
|
||||
"Master Abort" :
|
||||
((error_bits & PSYCHO_PCIAFSR_PTA) ?
|
||||
|
@ -783,15 +769,13 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
"Excessive Retries" :
|
||||
((error_bits & PSYCHO_PCIAFSR_PPERR) ?
|
||||
"Parity Error" : "???"))))));
|
||||
printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
|
||||
p->index, (is_pbm_a ? 'A' : 'B'),
|
||||
printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
|
||||
pbm->name,
|
||||
(afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
|
||||
(afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
|
||||
(afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
|
||||
printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",
|
||||
p->index, (is_pbm_a ? 'A' : 'B'), afar);
|
||||
printk("PSYCHO%d(PBM%c): PCI Secondary errors [",
|
||||
p->index, (is_pbm_a ? 'A' : 'B'));
|
||||
printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: PCI Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & PSYCHO_PCIAFSR_SMA) {
|
||||
reported++;
|
||||
|
@ -823,11 +807,11 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
* a bug in the IOMMU support code or a PCI device driver.
|
||||
*/
|
||||
if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
|
||||
psycho_check_iommu_error(p, afsr, afar, PCI_ERR);
|
||||
pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
|
||||
psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
|
||||
pci_scan_for_target_abort(pbm, pbm->pci_bus);
|
||||
}
|
||||
if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
|
||||
pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
|
||||
pci_scan_for_master_abort(pbm, pbm->pci_bus);
|
||||
|
||||
/* For excessive retries, PSYCHO/PBM will abort the device
|
||||
* and there is no way to specifically check for excessive
|
||||
|
@ -837,7 +821,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
*/
|
||||
|
||||
if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
|
||||
pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
|
||||
pci_scan_for_parity_error(pbm, pbm->pci_bus);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -847,34 +831,49 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */
|
||||
#define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */
|
||||
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
|
||||
static void psycho_register_error_handlers(struct pci_controller_info *p)
|
||||
static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
|
||||
struct of_device *op = of_find_device_by_node(pbm->prom_node);
|
||||
unsigned long base = p->pbm_A.controller_regs;
|
||||
unsigned long base = pbm->controller_regs;
|
||||
u64 tmp;
|
||||
int err;
|
||||
|
||||
if (!op)
|
||||
return;
|
||||
|
||||
/* Psycho interrupt property order is:
|
||||
* 0: PCIERR PBM B INO
|
||||
* 0: PCIERR INO for this PBM
|
||||
* 1: UE ERR
|
||||
* 2: CE ERR
|
||||
* 3: POWER FAIL
|
||||
* 4: SPARE HARDWARE
|
||||
* 5: PCIERR PBM A INO
|
||||
* 5: POWER MANAGEMENT
|
||||
*/
|
||||
|
||||
if (op->num_irqs < 6)
|
||||
return;
|
||||
|
||||
request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
|
||||
request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
|
||||
request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
|
||||
"PSYCHO PCIERR-A", &p->pbm_A);
|
||||
request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
|
||||
"PSYCHO PCIERR-B", &p->pbm_B);
|
||||
/* We really mean to ignore the return result here. Two
|
||||
* PCI controller share the same interrupt numbers and
|
||||
* drive the same front-end hardware. Whichever of the
|
||||
* two get in here first will register the IRQ handler
|
||||
* the second will just error out since we do not pass in
|
||||
* IRQF_SHARED.
|
||||
*/
|
||||
err = request_irq(op->irqs[1], psycho_ue_intr, 0,
|
||||
"PSYCHO_UE", pbm);
|
||||
err = request_irq(op->irqs[2], psycho_ce_intr, 0,
|
||||
"PSYCHO_CE", pbm);
|
||||
|
||||
/* This one, however, ought not to fail. We can just warn
|
||||
* about it since the system can still operate properly even
|
||||
* if this fails.
|
||||
*/
|
||||
err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
|
||||
"PSYCHO_PCIERR", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register PCIERR, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
|
||||
/* Enable UE and CE interrupts for controller. */
|
||||
psycho_write(base + PSYCHO_ECC_CTRL,
|
||||
|
@ -918,54 +917,45 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
|
|||
pci_config_write8(addr, 64);
|
||||
}
|
||||
|
||||
static void pbm_scan_bus(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm)
|
||||
static void psycho_scan_bus(struct pci_pbm_info *pbm)
|
||||
{
|
||||
pbm_config_busmastering(pbm);
|
||||
pbm->is_66mhz_capable = 0;
|
||||
pbm->pci_bus = pci_scan_one_pbm(pbm);
|
||||
}
|
||||
|
||||
static void psycho_scan_bus(struct pci_controller_info *p)
|
||||
{
|
||||
pbm_config_busmastering(&p->pbm_B);
|
||||
p->pbm_B.is_66mhz_capable = 0;
|
||||
pbm_config_busmastering(&p->pbm_A);
|
||||
p->pbm_A.is_66mhz_capable = 1;
|
||||
pbm_scan_bus(p, &p->pbm_B);
|
||||
pbm_scan_bus(p, &p->pbm_A);
|
||||
|
||||
/* After the PCI bus scan is complete, we can register
|
||||
* the error interrupt handlers.
|
||||
*/
|
||||
psycho_register_error_handlers(p);
|
||||
psycho_register_error_handlers(pbm);
|
||||
}
|
||||
|
||||
static void psycho_iommu_init(struct pci_controller_info *p)
|
||||
static void psycho_iommu_init(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct iommu *iommu = p->pbm_A.iommu;
|
||||
struct iommu *iommu = pbm->iommu;
|
||||
unsigned long i;
|
||||
u64 control;
|
||||
|
||||
/* Register addresses. */
|
||||
iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
|
||||
iommu->iommu_tsbbase = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE;
|
||||
iommu->iommu_flush = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH;
|
||||
iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
|
||||
iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
|
||||
iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
|
||||
/* PSYCHO's IOMMU lacks ctx flushing. */
|
||||
iommu->iommu_ctxflush = 0;
|
||||
|
||||
/* We use the main control register of PSYCHO as the write
|
||||
* completion register.
|
||||
*/
|
||||
iommu->write_complete_reg = p->pbm_A.controller_regs + PSYCHO_CONTROL;
|
||||
iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
|
||||
|
||||
/*
|
||||
* Invalidate TLB Entries.
|
||||
*/
|
||||
control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
|
||||
control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
|
||||
control |= PSYCHO_IOMMU_CTRL_DENAB;
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
|
||||
for(i = 0; i < 16; i++) {
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
|
||||
}
|
||||
|
||||
/* Leave diag mode enabled for full-flushing done
|
||||
|
@ -973,17 +963,17 @@ static void psycho_iommu_init(struct pci_controller_info *p)
|
|||
*/
|
||||
pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
|
||||
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE,
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
|
||||
__pa(iommu->page_table));
|
||||
|
||||
control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
|
||||
control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
|
||||
control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
|
||||
control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
|
||||
|
||||
/* If necessary, hook us up for starfire IRQ translations. */
|
||||
if (this_is_starfire)
|
||||
starfire_hookup(p->pbm_A.portid);
|
||||
starfire_hookup(pbm->portid);
|
||||
}
|
||||
|
||||
#define PSYCHO_IRQ_RETRY 0x1a00UL
|
||||
|
@ -998,36 +988,35 @@ static void psycho_iommu_init(struct pci_controller_info *p)
|
|||
#define PSYCHO_PCIDIAG_IPAPAR 0x0000000000000002UL /* Invert PIO address parity */
|
||||
#define PSYCHO_PCIDIAG_LPBACK 0x0000000000000001UL /* Enable loopback mode */
|
||||
|
||||
static void psycho_controller_hwinit(struct pci_controller_info *p)
|
||||
static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
|
||||
{
|
||||
u64 tmp;
|
||||
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
|
||||
|
||||
/* Enable arbiter for all PCI slots. */
|
||||
tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
|
||||
tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
|
||||
tmp |= PSYCHO_PCICTRL_AEN;
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
|
||||
|
||||
tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL);
|
||||
tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
|
||||
tmp |= PSYCHO_PCICTRL_AEN;
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
|
||||
|
||||
/* Disable DMA write / PIO read synchronization on
|
||||
* both PCI bus segments.
|
||||
* [ U2P Erratum 1243770, STP2223BGA data sheet ]
|
||||
*/
|
||||
tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG);
|
||||
tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
|
||||
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
|
||||
|
||||
tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG);
|
||||
tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
|
||||
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
|
||||
psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
|
||||
psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
|
||||
}
|
||||
|
||||
static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm,
|
||||
static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
|
||||
int is_pbm_a)
|
||||
{
|
||||
unsigned long base = pbm->controller_regs;
|
||||
|
@ -1088,7 +1077,6 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
|
|||
static void psycho_pbm_init(struct pci_controller_info *p,
|
||||
struct device_node *dp, int is_pbm_a)
|
||||
{
|
||||
unsigned int *busrange;
|
||||
struct property *prop;
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
|
@ -1097,6 +1085,14 @@ static void psycho_pbm_init(struct pci_controller_info *p,
|
|||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->scan_bus = psycho_scan_bus;
|
||||
pbm->pci_ops = &psycho_ops;
|
||||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
|
||||
pbm->chip_version = 0;
|
||||
prop = of_find_property(dp, "version#", NULL);
|
||||
|
@ -1117,12 +1113,9 @@ static void psycho_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
pci_determine_mem_io_space(pbm);
|
||||
|
||||
prop = of_find_property(dp, "bus-range", NULL);
|
||||
busrange = prop->value;
|
||||
pbm->pci_first_busno = busrange[0];
|
||||
pbm->pci_last_busno = busrange[1];
|
||||
pci_get_pbm_props(pbm);
|
||||
|
||||
psycho_pbm_strbuf_init(p, pbm, is_pbm_a);
|
||||
psycho_pbm_strbuf_init(pbm, is_pbm_a);
|
||||
}
|
||||
|
||||
#define PSYCHO_CONFIGSPACE 0x001000000UL
|
||||
|
@ -1131,6 +1124,7 @@ void psycho_init(struct device_node *dp, char *model_name)
|
|||
{
|
||||
struct linux_prom64_registers *pr_regs;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
struct property *prop;
|
||||
u32 upa_portid;
|
||||
|
@ -1141,7 +1135,9 @@ void psycho_init(struct device_node *dp, char *model_name)
|
|||
if (prop)
|
||||
upa_portid = *(u32 *) prop->value;
|
||||
|
||||
for(p = pci_controller_root; p; p = p->next) {
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
|
||||
if (p->pbm_A.portid == upa_portid) {
|
||||
is_pbm_a = (p->pbm_A.prom_node == NULL);
|
||||
psycho_pbm_init(p, dp, is_pbm_a);
|
||||
|
@ -1161,14 +1157,8 @@ void psycho_init(struct device_node *dp, char *model_name)
|
|||
}
|
||||
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
|
||||
|
||||
p->next = pci_controller_root;
|
||||
pci_controller_root = p;
|
||||
|
||||
p->pbm_A.portid = upa_portid;
|
||||
p->pbm_B.portid = upa_portid;
|
||||
p->index = pci_num_controllers++;
|
||||
p->scan_bus = psycho_scan_bus;
|
||||
p->pci_ops = &psycho_ops;
|
||||
|
||||
prop = of_find_property(dp, "reg", NULL);
|
||||
pr_regs = prop->value;
|
||||
|
@ -1185,9 +1175,9 @@ void psycho_init(struct device_node *dp, char *model_name)
|
|||
*/
|
||||
pci_memspace_mask = 0x7fffffffUL;
|
||||
|
||||
psycho_controller_hwinit(p);
|
||||
psycho_controller_hwinit(&p->pbm_A);
|
||||
|
||||
psycho_iommu_init(p);
|
||||
psycho_iommu_init(&p->pbm_A);
|
||||
|
||||
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
|
||||
psycho_pbm_init(p, dp, is_pbm_a);
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/apb.h>
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
|
||||
#include "pci_impl.h"
|
||||
#include "iommu_common.h"
|
||||
|
@ -494,11 +494,11 @@ static struct pci_ops sabre_ops = {
|
|||
};
|
||||
|
||||
/* SABRE error handling support. */
|
||||
static void sabre_check_iommu_error(struct pci_controller_info *p,
|
||||
static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
|
||||
unsigned long afsr,
|
||||
unsigned long afar)
|
||||
{
|
||||
struct iommu *iommu = p->pbm_A.iommu;
|
||||
struct iommu *iommu = pbm->iommu;
|
||||
unsigned long iommu_tag[16];
|
||||
unsigned long iommu_data[16];
|
||||
unsigned long flags;
|
||||
|
@ -526,8 +526,8 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
|
|||
type_string = "Unknown";
|
||||
break;
|
||||
};
|
||||
printk("SABRE%d: IOMMU Error, type[%s]\n",
|
||||
p->index, type_string);
|
||||
printk("%s: IOMMU Error, type[%s]\n",
|
||||
pbm->name, type_string);
|
||||
|
||||
/* Enter diagnostic mode and probe for error'd
|
||||
* entries in the IOTLB.
|
||||
|
@ -536,7 +536,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
|
|||
sabre_write(iommu->iommu_control,
|
||||
(control | SABRE_IOMMUCTRL_DENAB));
|
||||
for (i = 0; i < 16; i++) {
|
||||
unsigned long base = p->pbm_A.controller_regs;
|
||||
unsigned long base = pbm->controller_regs;
|
||||
|
||||
iommu_tag[i] =
|
||||
sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
|
||||
|
@ -566,13 +566,13 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
|
|||
type_string = "Unknown";
|
||||
break;
|
||||
};
|
||||
printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
|
||||
p->index, i, tag, type_string,
|
||||
printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
|
||||
pbm->name, i, tag, type_string,
|
||||
((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
|
||||
((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
|
||||
((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
|
||||
printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
|
||||
p->index, i, data,
|
||||
printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
|
||||
pbm->name, i, data,
|
||||
((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
|
||||
((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
|
||||
((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
|
||||
|
@ -584,9 +584,9 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
|
|||
|
||||
static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
||||
|
@ -604,21 +604,21 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
|
|||
sabre_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",
|
||||
p->index,
|
||||
printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
|
||||
pbm->name,
|
||||
((error_bits & SABRE_UEAFSR_PDRD) ?
|
||||
"DMA Read" :
|
||||
((error_bits & SABRE_UEAFSR_PDWR) ?
|
||||
"DMA Write" : "???")),
|
||||
((error_bits & SABRE_UEAFSR_PDTE) ?
|
||||
":Translation Error" : ""));
|
||||
printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
|
||||
p->index,
|
||||
printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
|
||||
pbm->name,
|
||||
(afsr & SABRE_UEAFSR_BMSK) >> 32UL,
|
||||
(afsr & SABRE_UEAFSR_OFF) >> 29UL,
|
||||
((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));
|
||||
printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("SABRE%d: UE Secondary errors [", p->index);
|
||||
printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: UE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & SABRE_UEAFSR_SDRD) {
|
||||
reported++;
|
||||
|
@ -637,16 +637,16 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
|
|||
printk("]\n");
|
||||
|
||||
/* Interrogate IOMMU for error status. */
|
||||
sabre_check_iommu_error(p, afsr, afar);
|
||||
sabre_check_iommu_error(pbm, afsr, afar);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
||||
|
@ -663,8 +663,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
|
|||
sabre_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("SABRE%d: Correctable Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: Correctable Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
((error_bits & SABRE_CEAFSR_PDRD) ?
|
||||
"DMA Read" :
|
||||
((error_bits & SABRE_CEAFSR_PDWR) ?
|
||||
|
@ -673,15 +673,15 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
|
|||
/* XXX Use syndrome and afar to print out module string just like
|
||||
* XXX UDB CE trap handler does... -DaveM
|
||||
*/
|
||||
printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
|
||||
printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
|
||||
"was_block(%d)\n",
|
||||
p->index,
|
||||
pbm->name,
|
||||
(afsr & SABRE_CEAFSR_ESYND) >> 48UL,
|
||||
(afsr & SABRE_CEAFSR_BMSK) >> 32UL,
|
||||
(afsr & SABRE_CEAFSR_OFF) >> 29UL,
|
||||
((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));
|
||||
printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("SABRE%d: CE Secondary errors [", p->index);
|
||||
printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: CE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & SABRE_CEAFSR_SDRD) {
|
||||
reported++;
|
||||
|
@ -698,13 +698,13 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
|
||||
static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
|
||||
{
|
||||
unsigned long csr_reg, csr, csr_error_bits;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u16 stat;
|
||||
|
||||
csr_reg = p->pbm_A.controller_regs + SABRE_PCICTRL;
|
||||
csr_reg = pbm->controller_regs + SABRE_PCICTRL;
|
||||
csr = sabre_read(csr_reg);
|
||||
csr_error_bits =
|
||||
csr & SABRE_PCICTRL_SERR;
|
||||
|
@ -714,8 +714,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
|
|||
|
||||
/* Log 'em. */
|
||||
if (csr_error_bits & SABRE_PCICTRL_SERR)
|
||||
printk("SABRE%d: PCI SERR signal asserted.\n",
|
||||
p->index);
|
||||
printk("%s: PCI SERR signal asserted.\n",
|
||||
pbm->name);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
pci_bus_read_config_word(sabre_root_bus, 0,
|
||||
|
@ -725,8 +725,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
|
|||
PCI_STATUS_REC_TARGET_ABORT |
|
||||
PCI_STATUS_REC_MASTER_ABORT |
|
||||
PCI_STATUS_SIG_SYSTEM_ERROR)) {
|
||||
printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
|
||||
p->index, stat);
|
||||
printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
|
||||
pbm->name, stat);
|
||||
pci_bus_write_config_word(sabre_root_bus, 0,
|
||||
PCI_STATUS, 0xffff);
|
||||
ret = IRQ_HANDLED;
|
||||
|
@ -736,13 +736,13 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
|
|||
|
||||
static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
unsigned long afsr_reg, afar_reg;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
||||
afsr_reg = p->pbm_A.controller_regs + SABRE_PIOAFSR;
|
||||
afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR;
|
||||
afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
|
||||
afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
|
||||
|
||||
/* Latch error status. */
|
||||
afar = sabre_read(afar_reg);
|
||||
|
@ -755,12 +755,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
|
|||
SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
|
||||
SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
|
||||
if (!error_bits)
|
||||
return sabre_pcierr_intr_other(p);
|
||||
return sabre_pcierr_intr_other(pbm);
|
||||
sabre_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("SABRE%d: PCI Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: PCI Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & SABRE_PIOAFSR_PMA) ?
|
||||
"Master Abort" :
|
||||
((error_bits & SABRE_PIOAFSR_PTA) ?
|
||||
|
@ -769,12 +769,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
|
|||
"Excessive Retries" :
|
||||
((error_bits & SABRE_PIOAFSR_PPERR) ?
|
||||
"Parity Error" : "???"))))));
|
||||
printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",
|
||||
p->index,
|
||||
printk("%s: bytemask[%04lx] was_block(%d)\n",
|
||||
pbm->name,
|
||||
(afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
|
||||
(afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
|
||||
printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);
|
||||
printk("SABRE%d: PCI Secondary errors [", p->index);
|
||||
printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: PCI Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & SABRE_PIOAFSR_SMA) {
|
||||
reported++;
|
||||
|
@ -806,11 +806,11 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
|
|||
* a bug in the IOMMU support code or a PCI device driver.
|
||||
*/
|
||||
if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
|
||||
sabre_check_iommu_error(p, afsr, afar);
|
||||
pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
|
||||
sabre_check_iommu_error(pbm, afsr, afar);
|
||||
pci_scan_for_target_abort(pbm, pbm->pci_bus);
|
||||
}
|
||||
if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
|
||||
pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
|
||||
pci_scan_for_master_abort(pbm, pbm->pci_bus);
|
||||
|
||||
/* For excessive retries, SABRE/PBM will abort the device
|
||||
* and there is no way to specifically check for excessive
|
||||
|
@ -820,18 +820,18 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
|
|||
*/
|
||||
|
||||
if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
|
||||
pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
|
||||
pci_scan_for_parity_error(pbm, pbm->pci_bus);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void sabre_register_error_handlers(struct pci_controller_info *p)
|
||||
static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
|
||||
struct device_node *dp = pbm->prom_node;
|
||||
struct of_device *op;
|
||||
unsigned long base = pbm->controller_regs;
|
||||
u64 tmp;
|
||||
int err;
|
||||
|
||||
if (pbm->chip_type == PBM_CHIP_TYPE_SABRE)
|
||||
dp = dp->parent;
|
||||
|
@ -858,22 +858,31 @@ static void sabre_register_error_handlers(struct pci_controller_info *p)
|
|||
SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
|
||||
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
|
||||
|
||||
request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p);
|
||||
err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
|
||||
pbm->name, err);
|
||||
|
||||
sabre_write(base + SABRE_CE_AFSR,
|
||||
(SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
|
||||
SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
|
||||
|
||||
request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p);
|
||||
request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED,
|
||||
"SABRE PCIERR", p);
|
||||
err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
|
||||
pbm->name, err);
|
||||
err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
|
||||
"SABRE_PCIERR", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
|
||||
pbm->name, err);
|
||||
|
||||
tmp = sabre_read(base + SABRE_PCICTRL);
|
||||
tmp |= SABRE_PCICTRL_ERREN;
|
||||
sabre_write(base + SABRE_PCICTRL, tmp);
|
||||
}
|
||||
|
||||
static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
|
||||
static void apb_init(struct pci_bus *sabre_bus)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
||||
|
@ -909,7 +918,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
|
|||
}
|
||||
}
|
||||
|
||||
static void sabre_scan_bus(struct pci_controller_info *p)
|
||||
static void sabre_scan_bus(struct pci_pbm_info *pbm)
|
||||
{
|
||||
static int once;
|
||||
struct pci_bus *pbus;
|
||||
|
@ -918,7 +927,7 @@ static void sabre_scan_bus(struct pci_controller_info *p)
|
|||
* at 66Mhz, but the front side of APB runs at 33Mhz
|
||||
* for both segments.
|
||||
*/
|
||||
p->pbm_A.is_66mhz_capable = 0;
|
||||
pbm->is_66mhz_capable = 0;
|
||||
|
||||
/* This driver has not been verified to handle
|
||||
* multiple SABREs yet, so trap this.
|
||||
|
@ -932,41 +941,41 @@ static void sabre_scan_bus(struct pci_controller_info *p)
|
|||
}
|
||||
once++;
|
||||
|
||||
pbus = pci_scan_one_pbm(&p->pbm_A);
|
||||
pbus = pci_scan_one_pbm(pbm);
|
||||
if (!pbus)
|
||||
return;
|
||||
|
||||
sabre_root_bus = pbus;
|
||||
|
||||
apb_init(p, pbus);
|
||||
apb_init(pbus);
|
||||
|
||||
sabre_register_error_handlers(p);
|
||||
sabre_register_error_handlers(pbm);
|
||||
}
|
||||
|
||||
static void sabre_iommu_init(struct pci_controller_info *p,
|
||||
static void sabre_iommu_init(struct pci_pbm_info *pbm,
|
||||
int tsbsize, unsigned long dvma_offset,
|
||||
u32 dma_mask)
|
||||
{
|
||||
struct iommu *iommu = p->pbm_A.iommu;
|
||||
struct iommu *iommu = pbm->iommu;
|
||||
unsigned long i;
|
||||
u64 control;
|
||||
|
||||
/* Register addresses. */
|
||||
iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
|
||||
iommu->iommu_tsbbase = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE;
|
||||
iommu->iommu_flush = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH;
|
||||
iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC;
|
||||
iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL;
|
||||
iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
|
||||
iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH;
|
||||
iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
|
||||
/* Sabre's IOMMU lacks ctx flushing. */
|
||||
iommu->iommu_ctxflush = 0;
|
||||
|
||||
/* Invalidate TLB Entries. */
|
||||
control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
|
||||
control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
|
||||
control |= SABRE_IOMMUCTRL_DENAB;
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
|
||||
sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
|
||||
|
||||
for(i = 0; i < 16; i++) {
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
|
||||
sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
|
||||
sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
|
||||
}
|
||||
|
||||
/* Leave diag mode enabled for full-flushing done
|
||||
|
@ -974,10 +983,10 @@ static void sabre_iommu_init(struct pci_controller_info *p,
|
|||
*/
|
||||
pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
|
||||
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE,
|
||||
sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
|
||||
__pa(iommu->page_table));
|
||||
|
||||
control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
|
||||
control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
|
||||
control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
|
||||
control |= SABRE_IOMMUCTRL_ENAB;
|
||||
switch(tsbsize) {
|
||||
|
@ -992,22 +1001,23 @@ static void sabre_iommu_init(struct pci_controller_info *p,
|
|||
prom_halt();
|
||||
break;
|
||||
}
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
|
||||
sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
|
||||
}
|
||||
|
||||
static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
|
||||
static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
pbm = &p->pbm_A;
|
||||
pbm->name = dp->full_name;
|
||||
printk("%s: SABRE PCI Bus Module\n", pbm->name);
|
||||
|
||||
pbm->scan_bus = sabre_scan_bus;
|
||||
pbm->pci_ops = &sabre_ops;
|
||||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
pbm->pci_first_busno = p->pci_first_busno;
|
||||
pbm->pci_last_busno = p->pci_last_busno;
|
||||
pci_get_pbm_props(pbm);
|
||||
|
||||
pci_determine_mem_io_space(pbm);
|
||||
}
|
||||
|
@ -1016,9 +1026,9 @@ void sabre_init(struct device_node *dp, char *model_name)
|
|||
{
|
||||
const struct linux_prom64_registers *pr_regs;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
int tsbsize;
|
||||
const u32 *busrange;
|
||||
const u32 *vdma;
|
||||
u32 upa_portid, dma_mask;
|
||||
u64 clear_irq;
|
||||
|
@ -1053,17 +1063,15 @@ void sabre_init(struct device_node *dp, char *model_name)
|
|||
prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
|
||||
prom_halt();
|
||||
}
|
||||
p->pbm_A.iommu = iommu;
|
||||
pbm = &p->pbm_A;
|
||||
pbm->iommu = iommu;
|
||||
|
||||
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
|
||||
|
||||
p->next = pci_controller_root;
|
||||
pci_controller_root = p;
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
p->pbm_A.portid = upa_portid;
|
||||
p->index = pci_num_controllers++;
|
||||
p->scan_bus = sabre_scan_bus;
|
||||
p->pci_ops = &sabre_ops;
|
||||
pbm->portid = upa_portid;
|
||||
|
||||
/*
|
||||
* Map in SABRE register set and report the presence of this SABRE.
|
||||
|
@ -1074,26 +1082,26 @@ void sabre_init(struct device_node *dp, char *model_name)
|
|||
/*
|
||||
* First REG in property is base of entire SABRE register space.
|
||||
*/
|
||||
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
|
||||
pbm->controller_regs = pr_regs[0].phys_addr;
|
||||
|
||||
/* Clear interrupts */
|
||||
|
||||
/* PCI first */
|
||||
for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
|
||||
sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
|
||||
sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
|
||||
|
||||
/* Then OBIO */
|
||||
for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
|
||||
sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
|
||||
sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
|
||||
|
||||
/* Error interrupts are enabled later after the bus scan. */
|
||||
sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL,
|
||||
sabre_write(pbm->controller_regs + SABRE_PCICTRL,
|
||||
(SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
|
||||
SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
|
||||
|
||||
/* Now map in PCI config space for entire SABRE. */
|
||||
p->pbm_A.config_space =
|
||||
(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
|
||||
pbm->config_space =
|
||||
(pbm->controller_regs + SABRE_CONFIGSPACE);
|
||||
|
||||
vdma = of_get_property(dp, "virtual-dma", NULL);
|
||||
|
||||
|
@ -1117,14 +1125,10 @@ void sabre_init(struct device_node *dp, char *model_name)
|
|||
prom_halt();
|
||||
}
|
||||
|
||||
sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
|
||||
|
||||
busrange = of_get_property(dp, "bus-range", NULL);
|
||||
p->pci_first_busno = busrange[0];
|
||||
p->pci_last_busno = busrange[1];
|
||||
sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
|
||||
|
||||
/*
|
||||
* Look for APB underneath.
|
||||
*/
|
||||
sabre_pbm_init(p, dp);
|
||||
sabre_pbm_init(p, pbm, dp);
|
||||
}
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/upa.h>
|
||||
#include <asm/pstate.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/oplib.h>
|
||||
|
||||
#include "pci_impl.h"
|
||||
#include "iommu_common.h"
|
||||
|
@ -238,25 +239,6 @@ static unsigned long stc_line_buf[16];
|
|||
#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */
|
||||
#define SCHIZO_SERR_INO 0x34 /* Safari interface error */
|
||||
|
||||
struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
|
||||
{
|
||||
ino &= IMAP_INO;
|
||||
if (p->pbm_A.ino_bitmap & (1UL << ino))
|
||||
return &p->pbm_A;
|
||||
if (p->pbm_B.ino_bitmap & (1UL << ino))
|
||||
return &p->pbm_B;
|
||||
|
||||
printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
|
||||
"PBM_A[%016lx] PBM_B[%016lx]",
|
||||
p->index, ino,
|
||||
p->pbm_A.ino_bitmap,
|
||||
p->pbm_B.ino_bitmap);
|
||||
printk("PCI%d: Using PBM_A, report this problem immediately.\n",
|
||||
p->index);
|
||||
|
||||
return &p->pbm_A;
|
||||
}
|
||||
|
||||
#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
|
||||
#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
|
||||
#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */
|
||||
|
@ -522,9 +504,10 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
|
|||
|
||||
static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported, limit;
|
||||
|
||||
|
@ -549,28 +532,28 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
|
|||
schizo_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: Uncorrectable Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & SCHIZO_UEAFSR_PPIO) ?
|
||||
"PIO" :
|
||||
((error_bits & SCHIZO_UEAFSR_PDRD) ?
|
||||
"DMA Read" :
|
||||
((error_bits & SCHIZO_UEAFSR_PDWR) ?
|
||||
"DMA Write" : "???")))));
|
||||
printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
|
||||
p->index,
|
||||
printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
|
||||
pbm->name,
|
||||
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
|
||||
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
|
||||
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
|
||||
printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
|
||||
p->index,
|
||||
printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
|
||||
pbm->name,
|
||||
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
|
||||
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
|
||||
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
|
||||
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
|
||||
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
|
||||
printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("PCI%d: UE Secondary errors [", p->index);
|
||||
printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: UE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & SCHIZO_UEAFSR_SPIO) {
|
||||
reported++;
|
||||
|
@ -610,9 +593,9 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
|
|||
|
||||
static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
|
||||
unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
unsigned long afsr_reg = pbm->controller_regs + SCHIZO_CE_AFSR;
|
||||
unsigned long afar_reg = pbm->controller_regs + SCHIZO_CE_AFAR;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported, limit;
|
||||
|
||||
|
@ -637,8 +620,8 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
|
|||
schizo_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
printk("PCI%d: Correctable Error, primary error type[%s]\n",
|
||||
p->index,
|
||||
printk("%s: Correctable Error, primary error type[%s]\n",
|
||||
pbm->name,
|
||||
(((error_bits & SCHIZO_CEAFSR_PPIO) ?
|
||||
"PIO" :
|
||||
((error_bits & SCHIZO_CEAFSR_PDRD) ?
|
||||
|
@ -649,20 +632,20 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
|
|||
/* XXX Use syndrome and afar to print out module string just like
|
||||
* XXX UDB CE trap handler does... -DaveM
|
||||
*/
|
||||
printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
|
||||
p->index,
|
||||
printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
|
||||
pbm->name,
|
||||
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
|
||||
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
|
||||
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
|
||||
printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
|
||||
p->index,
|
||||
printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
|
||||
pbm->name,
|
||||
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
|
||||
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
|
||||
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
|
||||
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
|
||||
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
|
||||
printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
|
||||
printk("PCI%d: CE Secondary errors [", p->index);
|
||||
printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
|
||||
printk("%s: CE Secondary errors [", pbm->name);
|
||||
reported = 0;
|
||||
if (afsr & SCHIZO_CEAFSR_SPIO) {
|
||||
reported++;
|
||||
|
@ -881,10 +864,10 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
|||
*/
|
||||
if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
|
||||
schizo_check_iommu_error(p, PCI_ERR);
|
||||
pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
|
||||
pci_scan_for_target_abort(pbm, pbm->pci_bus);
|
||||
}
|
||||
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
|
||||
pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
|
||||
pci_scan_for_master_abort(pbm, pbm->pci_bus);
|
||||
|
||||
/* For excessive retries, PSYCHO/PBM will abort the device
|
||||
* and there is no way to specifically check for excessive
|
||||
|
@ -894,7 +877,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
|||
*/
|
||||
|
||||
if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
|
||||
pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
|
||||
pci_scan_for_parity_error(pbm, pbm->pci_bus);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -940,22 +923,23 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
|||
*/
|
||||
static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_controller_info *p = dev_id;
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
u64 errlog;
|
||||
|
||||
errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
|
||||
schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
|
||||
errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
|
||||
schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
|
||||
errlog & ~(SAFARI_ERRLOG_ERROUT));
|
||||
|
||||
if (!(errlog & BUS_ERROR_UNMAP)) {
|
||||
printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
|
||||
p->index, errlog);
|
||||
printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
|
||||
pbm->name, errlog);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
|
||||
p->index);
|
||||
printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
|
||||
pbm->name);
|
||||
schizo_check_iommu_error(p, SAFARI_ERR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -972,6 +956,16 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
|
|||
#define SCHIZO_SAFARI_IRQCTRL 0x10010UL
|
||||
#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL
|
||||
|
||||
static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
|
||||
{
|
||||
ino &= IMAP_INO;
|
||||
|
||||
if (pbm->ino_bitmap & (1UL << ino))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* How the Tomatillo IRQs are routed around is pure guesswork here.
|
||||
*
|
||||
* All the Tomatillo devices I see in prtconf dumps seem to have only
|
||||
|
@ -986,11 +980,11 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
|
|||
* PCI bus units of the same Tomatillo. I still have not really
|
||||
* figured this out...
|
||||
*/
|
||||
static void tomatillo_register_error_handlers(struct pci_controller_info *p)
|
||||
static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
struct of_device *op;
|
||||
struct of_device *op = of_find_device_by_node(pbm->prom_node);
|
||||
u64 tmp, err_mask, err_no_mask;
|
||||
int err;
|
||||
|
||||
/* Tomatillo IRQ property layout is:
|
||||
* 0: PCIERR
|
||||
|
@ -1000,44 +994,42 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
|
|||
* 4: POWER FAIL?
|
||||
*/
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_UE_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
|
||||
"TOMATILLO_UE", p);
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
|
||||
err = request_irq(op->irqs[1], schizo_ue_intr, 0,
|
||||
"TOMATILLO_UE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register UE, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
|
||||
err = request_irq(op->irqs[2], schizo_ce_intr, 0,
|
||||
"TOMATILLO_CE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register CE, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
err = 0;
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
|
||||
err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
|
||||
"TOMATILLO_PCIERR", pbm);
|
||||
} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
|
||||
err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
|
||||
"TOMATILLO_PCIERR", pbm);
|
||||
}
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register PCIERR, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_CE_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
|
||||
"TOMATILLO CE", p);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
|
||||
"TOMATILLO PCIERR-A", pbm);
|
||||
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
|
||||
"TOMATILLO PCIERR-B", pbm);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
|
||||
"TOMATILLO SERR", p);
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
|
||||
err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
|
||||
"TOMATILLO_SERR", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register SERR, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
|
||||
/* Enable UE and CE interrupts for controller. */
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
|
||||
(SCHIZO_ECCCTRL_EE |
|
||||
SCHIZO_ECCCTRL_UE |
|
||||
SCHIZO_ECCCTRL_CE));
|
||||
|
||||
schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
|
||||
schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
|
||||
(SCHIZO_ECCCTRL_EE |
|
||||
SCHIZO_ECCCTRL_UE |
|
||||
SCHIZO_ECCCTRL_CE));
|
||||
|
@ -1053,15 +1045,10 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
|
|||
|
||||
err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
|
||||
|
||||
tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp |= err_mask;
|
||||
tmp &= ~err_no_mask;
|
||||
schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
|
||||
tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp |= err_mask;
|
||||
tmp &= ~err_no_mask;
|
||||
schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
|
||||
err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
|
||||
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
|
||||
|
@ -1070,8 +1057,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
|
|||
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
|
||||
SCHIZO_PCIAFSR_STTO);
|
||||
|
||||
schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
|
||||
schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
|
||||
schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
|
||||
|
||||
err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
|
||||
BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
|
||||
|
@ -1083,22 +1069,18 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
|
|||
BUS_ERROR_APERR | BUS_ERROR_UNMAP |
|
||||
BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
|
||||
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
|
||||
(SCHIZO_SAFERRCTRL_EN | err_mask));
|
||||
schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
|
||||
schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
|
||||
(SCHIZO_SAFERRCTRL_EN | err_mask));
|
||||
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
|
||||
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
|
||||
schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
|
||||
schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
|
||||
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
|
||||
}
|
||||
|
||||
static void schizo_register_error_handlers(struct pci_controller_info *p)
|
||||
static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
struct of_device *op;
|
||||
struct of_device *op = of_find_device_by_node(pbm->prom_node);
|
||||
u64 tmp, err_mask, err_no_mask;
|
||||
int err;
|
||||
|
||||
/* Schizo IRQ property layout is:
|
||||
* 0: PCIERR
|
||||
|
@ -1108,39 +1090,42 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
|
|||
* 4: POWER FAIL?
|
||||
*/
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_UE_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
|
||||
"SCHIZO_UE", p);
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
|
||||
err = request_irq(op->irqs[1], schizo_ue_intr, 0,
|
||||
"SCHIZO_UE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register UE, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
|
||||
err = request_irq(op->irqs[2], schizo_ce_intr, 0,
|
||||
"SCHIZO_CE", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register CE, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
err = 0;
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
|
||||
err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
|
||||
"SCHIZO_PCIERR", pbm);
|
||||
} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
|
||||
err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
|
||||
"SCHIZO_PCIERR", pbm);
|
||||
}
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register PCIERR, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_CE_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
|
||||
"SCHIZO CE", p);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
|
||||
"SCHIZO PCIERR-A", pbm);
|
||||
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
|
||||
"SCHIZO PCIERR-B", pbm);
|
||||
|
||||
pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
|
||||
op = of_find_device_by_node(pbm->prom_node);
|
||||
if (op)
|
||||
request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
|
||||
"SCHIZO SERR", p);
|
||||
if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
|
||||
err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
|
||||
"SCHIZO_SERR", pbm);
|
||||
if (err)
|
||||
printk(KERN_WARNING "%s: Could not register SERR, "
|
||||
"err=%d\n", pbm->name, err);
|
||||
}
|
||||
|
||||
/* Enable UE and CE interrupts for controller. */
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
|
||||
schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
|
||||
(SCHIZO_ECCCTRL_EE |
|
||||
SCHIZO_ECCCTRL_UE |
|
||||
SCHIZO_ECCCTRL_CE));
|
||||
|
@ -1159,25 +1144,12 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
|
|||
/* Enable PCI Error interrupts and clear error
|
||||
* bits for each PBM.
|
||||
*/
|
||||
tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp |= err_mask;
|
||||
tmp &= ~err_no_mask;
|
||||
schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
|
||||
schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR,
|
||||
(SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
|
||||
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
|
||||
SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
|
||||
SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
|
||||
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
|
||||
SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
|
||||
|
||||
tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
|
||||
tmp |= err_mask;
|
||||
tmp &= ~err_no_mask;
|
||||
schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
|
||||
|
||||
schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
|
||||
schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
|
||||
(SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
|
||||
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
|
||||
SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
|
||||
|
@ -1210,11 +1182,8 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
|
|||
BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
|
||||
#endif
|
||||
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
|
||||
schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
|
||||
(SCHIZO_SAFERRCTRL_EN | err_mask));
|
||||
|
||||
schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
|
||||
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
|
||||
}
|
||||
|
||||
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
|
||||
|
@ -1234,27 +1203,19 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
|
|||
pci_config_write8(addr, 64);
|
||||
}
|
||||
|
||||
static void schizo_scan_bus(struct pci_controller_info *p)
|
||||
static void schizo_scan_bus(struct pci_pbm_info *pbm)
|
||||
{
|
||||
pbm_config_busmastering(&p->pbm_B);
|
||||
p->pbm_B.is_66mhz_capable =
|
||||
(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
|
||||
!= NULL);
|
||||
pbm_config_busmastering(&p->pbm_A);
|
||||
p->pbm_A.is_66mhz_capable =
|
||||
(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
|
||||
pbm_config_busmastering(pbm);
|
||||
pbm->is_66mhz_capable =
|
||||
(of_find_property(pbm->prom_node, "66mhz-capable", NULL)
|
||||
!= NULL);
|
||||
|
||||
p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
|
||||
p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
|
||||
pbm->pci_bus = pci_scan_one_pbm(pbm);
|
||||
|
||||
/* After the PCI bus scan is complete, we can register
|
||||
* the error interrupt handlers.
|
||||
*/
|
||||
if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
|
||||
tomatillo_register_error_handlers(p);
|
||||
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
|
||||
tomatillo_register_error_handlers(pbm);
|
||||
else
|
||||
schizo_register_error_handlers(p);
|
||||
schizo_register_error_handlers(pbm);
|
||||
}
|
||||
|
||||
#define SCHIZO_STRBUF_CONTROL (0x02800UL)
|
||||
|
@ -1491,10 +1452,8 @@ static void schizo_pbm_init(struct pci_controller_info *p,
|
|||
int chip_type)
|
||||
{
|
||||
const struct linux_prom64_registers *regs;
|
||||
const unsigned int *busrange;
|
||||
struct pci_pbm_info *pbm;
|
||||
const char *chipset_name;
|
||||
const u32 *ino_bitmap;
|
||||
int is_pbm_a;
|
||||
|
||||
switch (chip_type) {
|
||||
|
@ -1531,6 +1490,14 @@ static void schizo_pbm_init(struct pci_controller_info *p,
|
|||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->scan_bus = schizo_scan_bus;
|
||||
pbm->pci_ops = &schizo_ops;
|
||||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->portid = portid;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
|
@ -1555,13 +1522,7 @@ static void schizo_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
pci_determine_mem_io_space(pbm);
|
||||
|
||||
ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
|
||||
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
|
||||
((u64)ino_bitmap[0] << 0UL));
|
||||
|
||||
busrange = of_get_property(dp, "bus-range", NULL);
|
||||
pbm->pci_first_busno = busrange[0];
|
||||
pbm->pci_last_busno = busrange[1];
|
||||
pci_get_pbm_props(pbm);
|
||||
|
||||
schizo_pbm_iommu_init(pbm);
|
||||
schizo_pbm_strbuf_init(pbm);
|
||||
|
@ -1580,23 +1541,15 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
|
|||
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
|
||||
{
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
u32 portid;
|
||||
|
||||
portid = of_getintprop_default(dp, "portid", 0xff);
|
||||
|
||||
for (p = pci_controller_root; p; p = p->next) {
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
|
||||
continue;
|
||||
|
||||
pbm = (p->pbm_A.prom_node ?
|
||||
&p->pbm_A :
|
||||
&p->pbm_B);
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (portid_compare(pbm->portid, portid, chip_type)) {
|
||||
schizo_pbm_init(p, dp, portid, chip_type);
|
||||
schizo_pbm_init(pbm->parent, dp, portid, chip_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1617,13 +1570,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
|
|||
|
||||
p->pbm_B.iommu = iommu;
|
||||
|
||||
p->next = pci_controller_root;
|
||||
pci_controller_root = p;
|
||||
|
||||
p->index = pci_num_controllers++;
|
||||
p->scan_bus = schizo_scan_bus;
|
||||
p->pci_ops = &schizo_ops;
|
||||
|
||||
/* Like PSYCHO we have a 2GB aligned area for memory space. */
|
||||
pci_memspace_mask = 0x7fffffffUL;
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/msi.h>
|
||||
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/upa.h>
|
||||
|
@ -677,29 +676,15 @@ static struct pci_ops pci_sun4v_ops = {
|
|||
};
|
||||
|
||||
|
||||
static void pbm_scan_bus(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm)
|
||||
{
|
||||
pbm->pci_bus = pci_scan_one_pbm(pbm);
|
||||
}
|
||||
|
||||
static void pci_sun4v_scan_bus(struct pci_controller_info *p)
|
||||
static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct property *prop;
|
||||
struct device_node *dp;
|
||||
|
||||
if ((dp = p->pbm_A.prom_node) != NULL) {
|
||||
prop = of_find_property(dp, "66mhz-capable", NULL);
|
||||
p->pbm_A.is_66mhz_capable = (prop != NULL);
|
||||
|
||||
pbm_scan_bus(p, &p->pbm_A);
|
||||
}
|
||||
if ((dp = p->pbm_B.prom_node) != NULL) {
|
||||
prop = of_find_property(dp, "66mhz-capable", NULL);
|
||||
p->pbm_B.is_66mhz_capable = (prop != NULL);
|
||||
|
||||
pbm_scan_bus(p, &p->pbm_B);
|
||||
}
|
||||
dp = pbm->prom_node;
|
||||
prop = of_find_property(dp, "66mhz-capable", NULL);
|
||||
pbm->is_66mhz_capable = (prop != NULL);
|
||||
pbm->pci_bus = pci_scan_one_pbm(pbm);
|
||||
|
||||
/* XXX register error interrupt handlers XXX */
|
||||
}
|
||||
|
@ -802,20 +787,6 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
|
|||
pbm->name, sz);
|
||||
}
|
||||
|
||||
static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct property *prop;
|
||||
unsigned int *busrange;
|
||||
|
||||
prop = of_find_property(pbm->prom_node, "bus-range", NULL);
|
||||
|
||||
busrange = prop->value;
|
||||
|
||||
pbm->pci_first_busno = busrange[0];
|
||||
pbm->pci_last_busno = busrange[1];
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
struct pci_sun4v_msiq_entry {
|
||||
u64 version_type;
|
||||
|
@ -1019,114 +990,6 @@ h_error:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
|
||||
{
|
||||
const u32 *val;
|
||||
int len;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msiq_num = *val;
|
||||
if (pbm->msiq_num) {
|
||||
const struct msiq_prop {
|
||||
u32 first_msiq;
|
||||
u32 num_msiq;
|
||||
u32 first_devino;
|
||||
} *mqp;
|
||||
const struct msi_range_prop {
|
||||
u32 first_msi;
|
||||
u32 num_msi;
|
||||
} *mrng;
|
||||
const struct addr_range_prop {
|
||||
u32 msi32_high;
|
||||
u32 msi32_low;
|
||||
u32 msi32_len;
|
||||
u32 msi64_high;
|
||||
u32 msi64_low;
|
||||
u32 msi64_len;
|
||||
} *arng;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
|
||||
pbm->msiq_ent_count = *val;
|
||||
|
||||
mqp = of_get_property(pbm->prom_node,
|
||||
"msi-eq-to-devino", &len);
|
||||
if (!mqp || len != sizeof(struct msiq_prop))
|
||||
goto no_msi;
|
||||
|
||||
pbm->msiq_first = mqp->first_msiq;
|
||||
pbm->msiq_first_devino = mqp->first_devino;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "#msi", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msi_num = *val;
|
||||
|
||||
mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
|
||||
if (!mrng || len != sizeof(struct msi_range_prop))
|
||||
goto no_msi;
|
||||
pbm->msi_first = mrng->first_msi;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msi_data_mask = *val;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msix-data-width", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msix_data_width = *val;
|
||||
|
||||
arng = of_get_property(pbm->prom_node, "msi-address-ranges",
|
||||
&len);
|
||||
if (!arng || len != sizeof(struct addr_range_prop))
|
||||
goto no_msi;
|
||||
pbm->msi32_start = ((u64)arng->msi32_high << 32) |
|
||||
(u64) arng->msi32_low;
|
||||
pbm->msi64_start = ((u64)arng->msi64_high << 32) |
|
||||
(u64) arng->msi64_low;
|
||||
pbm->msi32_len = arng->msi32_len;
|
||||
pbm->msi64_len = arng->msi64_len;
|
||||
|
||||
if (msi_bitmap_alloc(pbm))
|
||||
goto no_msi;
|
||||
|
||||
if (msi_queue_alloc(pbm)) {
|
||||
msi_bitmap_free(pbm);
|
||||
goto no_msi;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
|
||||
"devino[0x%x]\n",
|
||||
pbm->name,
|
||||
pbm->msiq_first, pbm->msiq_num,
|
||||
pbm->msiq_ent_count,
|
||||
pbm->msiq_first_devino);
|
||||
printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
|
||||
"width[%u]\n",
|
||||
pbm->name,
|
||||
pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
|
||||
pbm->msix_data_width);
|
||||
printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
|
||||
"addr64[0x%lx:0x%x]\n",
|
||||
pbm->name,
|
||||
pbm->msi32_start, pbm->msi32_len,
|
||||
pbm->msi64_start, pbm->msi64_len);
|
||||
printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
|
||||
pbm->name,
|
||||
pbm->msi_queues);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
no_msi:
|
||||
pbm->msiq_num = 0;
|
||||
printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
|
||||
}
|
||||
|
||||
static int alloc_msi(struct pci_pbm_info *pbm)
|
||||
{
|
||||
|
@ -1245,6 +1108,117 @@ static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
|
|||
*/
|
||||
sun4v_destroy_msi(virt_irq);
|
||||
}
|
||||
|
||||
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
|
||||
{
|
||||
const u32 *val;
|
||||
int len;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msiq_num = *val;
|
||||
if (pbm->msiq_num) {
|
||||
const struct msiq_prop {
|
||||
u32 first_msiq;
|
||||
u32 num_msiq;
|
||||
u32 first_devino;
|
||||
} *mqp;
|
||||
const struct msi_range_prop {
|
||||
u32 first_msi;
|
||||
u32 num_msi;
|
||||
} *mrng;
|
||||
const struct addr_range_prop {
|
||||
u32 msi32_high;
|
||||
u32 msi32_low;
|
||||
u32 msi32_len;
|
||||
u32 msi64_high;
|
||||
u32 msi64_low;
|
||||
u32 msi64_len;
|
||||
} *arng;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
|
||||
pbm->msiq_ent_count = *val;
|
||||
|
||||
mqp = of_get_property(pbm->prom_node,
|
||||
"msi-eq-to-devino", &len);
|
||||
if (!mqp || len != sizeof(struct msiq_prop))
|
||||
goto no_msi;
|
||||
|
||||
pbm->msiq_first = mqp->first_msiq;
|
||||
pbm->msiq_first_devino = mqp->first_devino;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "#msi", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msi_num = *val;
|
||||
|
||||
mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
|
||||
if (!mrng || len != sizeof(struct msi_range_prop))
|
||||
goto no_msi;
|
||||
pbm->msi_first = mrng->first_msi;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msi_data_mask = *val;
|
||||
|
||||
val = of_get_property(pbm->prom_node, "msix-data-width", &len);
|
||||
if (!val || len != 4)
|
||||
goto no_msi;
|
||||
pbm->msix_data_width = *val;
|
||||
|
||||
arng = of_get_property(pbm->prom_node, "msi-address-ranges",
|
||||
&len);
|
||||
if (!arng || len != sizeof(struct addr_range_prop))
|
||||
goto no_msi;
|
||||
pbm->msi32_start = ((u64)arng->msi32_high << 32) |
|
||||
(u64) arng->msi32_low;
|
||||
pbm->msi64_start = ((u64)arng->msi64_high << 32) |
|
||||
(u64) arng->msi64_low;
|
||||
pbm->msi32_len = arng->msi32_len;
|
||||
pbm->msi64_len = arng->msi64_len;
|
||||
|
||||
if (msi_bitmap_alloc(pbm))
|
||||
goto no_msi;
|
||||
|
||||
if (msi_queue_alloc(pbm)) {
|
||||
msi_bitmap_free(pbm);
|
||||
goto no_msi;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
|
||||
"devino[0x%x]\n",
|
||||
pbm->name,
|
||||
pbm->msiq_first, pbm->msiq_num,
|
||||
pbm->msiq_ent_count,
|
||||
pbm->msiq_first_devino);
|
||||
printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
|
||||
"width[%u]\n",
|
||||
pbm->name,
|
||||
pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
|
||||
pbm->msix_data_width);
|
||||
printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
|
||||
"addr64[0x%lx:0x%x]\n",
|
||||
pbm->name,
|
||||
pbm->msi32_start, pbm->msi32_len,
|
||||
pbm->msi64_start, pbm->msi64_len);
|
||||
printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
|
||||
pbm->name,
|
||||
pbm->msi_queues);
|
||||
}
|
||||
pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
|
||||
pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
|
||||
|
||||
return;
|
||||
|
||||
no_msi:
|
||||
pbm->msiq_num = 0;
|
||||
printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
|
||||
}
|
||||
#else /* CONFIG_PCI_MSI */
|
||||
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
|
||||
{
|
||||
|
@ -1260,6 +1234,14 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
|
|||
else
|
||||
pbm = &p->pbm_A;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->scan_bus = pci_sun4v_scan_bus;
|
||||
pbm->pci_ops = &pci_sun4v_ops;
|
||||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
|
||||
|
@ -1271,7 +1253,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
|
|||
|
||||
pci_determine_mem_io_space(pbm);
|
||||
|
||||
pci_sun4v_get_bus_range(pbm);
|
||||
pci_get_pbm_props(pbm);
|
||||
pci_sun4v_iommu_init(pbm);
|
||||
pci_sun4v_msi_init(pbm);
|
||||
}
|
||||
|
@ -1279,6 +1261,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
|
|||
void sun4v_pci_init(struct device_node *dp, char *model_name)
|
||||
{
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
struct property *prop;
|
||||
struct linux_prom64_registers *regs;
|
||||
|
@ -1290,18 +1273,9 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
|
|||
|
||||
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
|
||||
|
||||
for (p = pci_controller_root; p; p = p->next) {
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
|
||||
continue;
|
||||
|
||||
pbm = (p->pbm_A.prom_node ?
|
||||
&p->pbm_A :
|
||||
&p->pbm_B);
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (pbm->devhandle == (devhandle ^ 0x40)) {
|
||||
pci_sun4v_pbm_init(p, dp, devhandle);
|
||||
pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1331,18 +1305,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
|
|||
|
||||
p->pbm_B.iommu = iommu;
|
||||
|
||||
p->next = pci_controller_root;
|
||||
pci_controller_root = p;
|
||||
|
||||
p->index = pci_num_controllers++;
|
||||
|
||||
p->scan_bus = pci_sun4v_scan_bus;
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
p->setup_msi_irq = pci_sun4v_setup_msi_irq;
|
||||
p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
|
||||
#endif
|
||||
p->pci_ops = &pci_sun4v_ops;
|
||||
|
||||
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
|
||||
* for memory space.
|
||||
*/
|
||||
|
|
|
@ -1002,24 +1002,24 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
|
|||
u64 control;
|
||||
|
||||
irq = sbus_build_irq(sbus, SYSIO_UE_INO);
|
||||
if (request_irq(irq, sysio_ue_handler,
|
||||
IRQF_SHARED, "SYSIO UE", sbus) < 0) {
|
||||
if (request_irq(irq, sysio_ue_handler, 0,
|
||||
"SYSIO_UE", sbus) < 0) {
|
||||
prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
|
||||
sbus->portid);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
irq = sbus_build_irq(sbus, SYSIO_CE_INO);
|
||||
if (request_irq(irq, sysio_ce_handler,
|
||||
IRQF_SHARED, "SYSIO CE", sbus) < 0) {
|
||||
if (request_irq(irq, sysio_ce_handler, 0,
|
||||
"SYSIO_CE", sbus) < 0) {
|
||||
prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
|
||||
sbus->portid);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
|
||||
if (request_irq(irq, sysio_sbus_error_handler,
|
||||
IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) {
|
||||
if (request_irq(irq, sysio_sbus_error_handler, 0,
|
||||
"SYSIO_SBERR", sbus) < 0) {
|
||||
prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
|
||||
sbus->portid);
|
||||
prom_halt();
|
||||
|
|
|
@ -793,7 +793,7 @@ asmlinkage long sys32_utimes(char __user *filename,
|
|||
tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
|
||||
}
|
||||
|
||||
return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL);
|
||||
return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
|
||||
}
|
||||
|
||||
/* These are here just in case some old sparc32 binary calls it. */
|
||||
|
|
|
@ -81,6 +81,7 @@ sys_call_table32:
|
|||
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
|
||||
/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
|
||||
.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
|
||||
/*310*/ .word compat_sys_utimensat
|
||||
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
|
@ -152,6 +153,7 @@ sys_call_table:
|
|||
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
|
||||
/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
|
||||
.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
|
||||
/*310*/ .word sys_utimensat
|
||||
|
||||
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
|
||||
defined(CONFIG_SOLARIS_EMUL_MODULE)
|
||||
|
@ -269,5 +271,6 @@ sunos_sys_table:
|
|||
.word sunos_nosys, sunos_nosys, sunos_nosys
|
||||
.word sunos_nosys, sunos_nosys, sunos_nosys
|
||||
.word sunos_nosys
|
||||
/*310*/ .long sunos_nosys
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,36 +32,23 @@
|
|||
#include <asm/mmu_context.h>
|
||||
|
||||
#ifdef CONFIG_KPROBES
|
||||
ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
|
||||
|
||||
/* Hook to register for page fault notifications */
|
||||
int register_page_fault_notifier(struct notifier_block *nb)
|
||||
static inline int notify_page_fault(struct pt_regs *regs)
|
||||
{
|
||||
return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
int unregister_page_fault_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
|
||||
}
|
||||
|
||||
static inline int notify_page_fault(enum die_val val, const char *str,
|
||||
struct pt_regs *regs, long err, int trap, int sig)
|
||||
{
|
||||
struct die_args args = {
|
||||
.regs = regs,
|
||||
.str = str,
|
||||
.err = err,
|
||||
.trapnr = trap,
|
||||
.signr = sig
|
||||
};
|
||||
return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args);
|
||||
/* kprobe_running() needs smp_processor_id() */
|
||||
if (!user_mode(regs)) {
|
||||
preempt_disable();
|
||||
if (kprobe_running() && kprobe_fault_handler(regs, 0))
|
||||
ret = 1;
|
||||
preempt_enable();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline int notify_page_fault(enum die_val val, const char *str,
|
||||
struct pt_regs *regs, long err, int trap, int sig)
|
||||
static inline int notify_page_fault(struct pt_regs *regs)
|
||||
{
|
||||
return NOTIFY_DONE;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -120,9 +107,6 @@ static void __kprobes unhandled_fault(unsigned long address,
|
|||
printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
|
||||
(tsk->mm ? (unsigned long) tsk->mm->pgd :
|
||||
(unsigned long) tsk->active_mm->pgd));
|
||||
if (notify_die(DIE_GPF, "general protection fault", regs,
|
||||
0, 0, SIGSEGV) == NOTIFY_STOP)
|
||||
return;
|
||||
die_if_kernel("Oops", regs);
|
||||
}
|
||||
|
||||
|
@ -299,8 +283,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
|
|||
|
||||
fault_code = get_thread_fault_code();
|
||||
|
||||
if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
|
||||
fault_code, 0, SIGSEGV) == NOTIFY_STOP)
|
||||
if (notify_page_fault(regs))
|
||||
return;
|
||||
|
||||
si_code = SEGV_MAPERR;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#ifdef CONFIG_SPARC
|
||||
#include <asm/prom.h>
|
||||
#include <asm/pbm.h>
|
||||
#endif
|
||||
|
||||
/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
|
||||
|
@ -1397,9 +1396,8 @@ static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
|
|||
{
|
||||
#ifdef CONFIG_SPARC
|
||||
struct pci_dev *pdev = ha->pdev;
|
||||
struct pcidev_cookie *pcp = pdev->sysdata;
|
||||
struct device_node *dp = pcp->prom_node;
|
||||
u8 *val;
|
||||
struct device_node *dp = pci_device_to_OF_node(pdev);
|
||||
const u8 *val;
|
||||
int len;
|
||||
|
||||
val = of_get_property(dp, "port-wwn", &len);
|
||||
|
@ -3370,9 +3368,8 @@ static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *n
|
|||
{
|
||||
#ifdef CONFIG_SPARC
|
||||
struct pci_dev *pdev = ha->pdev;
|
||||
struct pcidev_cookie *pcp = pdev->sysdata;
|
||||
struct device_node *dp = pcp->prom_node;
|
||||
u8 *val;
|
||||
struct device_node *dp = pci_device_to_OF_node(pdev);
|
||||
const u8 *val;
|
||||
int len;
|
||||
|
||||
val = of_get_property(dp, "port-wwn", &len);
|
||||
|
|
|
@ -80,8 +80,9 @@
|
|||
#include "../macmodes.h"
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/fbio.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADB_PMU
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <asm/uaccess.h>
|
||||
|
||||
#ifdef __sparc__
|
||||
#include <asm/pbm.h>
|
||||
#include <asm/fbio.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -326,8 +326,9 @@
|
|||
#define __NR_move_pages 307
|
||||
#define __NR_getcpu 308
|
||||
#define __NR_epoll_pwait 309
|
||||
#define __NR_utimensat 310
|
||||
|
||||
#define NR_SYSCALLS 310
|
||||
#define NR_SYSCALLS 311
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define __ARCH_WANT_IPC_PARSE_VERSION
|
||||
|
|
|
@ -7,8 +7,19 @@
|
|||
|
||||
struct pt_regs;
|
||||
|
||||
extern int register_page_fault_notifier(struct notifier_block *);
|
||||
extern int unregister_page_fault_notifier(struct notifier_block *);
|
||||
/*
|
||||
* These are only here because kprobes.c wants them to implement a
|
||||
* blatant layering violation. Will hopefully go away soon once all
|
||||
* architectures are updated.
|
||||
*/
|
||||
static inline int register_page_fault_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int unregister_page_fault_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void bad_trap(struct pt_regs *, long);
|
||||
|
||||
|
@ -20,7 +31,6 @@ enum die_val {
|
|||
DIE_DIE,
|
||||
DIE_TRAP,
|
||||
DIE_TRAP_TL1,
|
||||
DIE_GPF,
|
||||
DIE_CALL,
|
||||
DIE_PAGE_FAULT,
|
||||
};
|
||||
|
|
|
@ -43,4 +43,5 @@ struct kprobe_ctlblk {
|
|||
|
||||
extern int kprobe_exceptions_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data);
|
||||
extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
|
||||
#endif /* _SPARC64_KPROBES_H */
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/* pbm.h: UltraSparc PCI controller software state.
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#ifndef __SPARC64_PBM_H
|
||||
#define __SPARC64_PBM_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/msi.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/iommu.h>
|
||||
|
||||
/* The abstraction used here is that there are PCI controllers,
|
||||
* each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
|
||||
* underneath. Each PCI bus module uses an IOMMU (shared by both
|
||||
* PBMs of a controller, or per-PBM), and if a streaming buffer
|
||||
* is present, each PCI bus module has it's own. (ie. the IOMMU
|
||||
* might be shared between PBMs, the STC is never shared)
|
||||
* Furthermore, each PCI bus module controls it's own autonomous
|
||||
* PCI bus.
|
||||
*/
|
||||
|
||||
extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
|
||||
|
||||
#define PCI_STC_FLUSHFLAG_INIT(STC) \
|
||||
(*((STC)->strbuf_flushflag) = 0UL)
|
||||
#define PCI_STC_FLUSHFLAG_SET(STC) \
|
||||
(*((STC)->strbuf_flushflag) != 0UL)
|
||||
|
||||
/* There can be quite a few ranges and interrupt maps on a PCI
|
||||
* segment. Thus...
|
||||
*/
|
||||
#define PROM_PCIRNG_MAX 64
|
||||
#define PROM_PCIIMAP_MAX 64
|
||||
|
||||
struct pci_controller_info;
|
||||
|
||||
struct pci_pbm_info {
|
||||
/* PCI controller we sit under. */
|
||||
struct pci_controller_info *parent;
|
||||
|
||||
/* Physical address base of controller registers. */
|
||||
unsigned long controller_regs;
|
||||
|
||||
/* Physical address base of PBM registers. */
|
||||
unsigned long pbm_regs;
|
||||
|
||||
/* Physical address of DMA sync register, if any. */
|
||||
unsigned long sync_reg;
|
||||
|
||||
/* Opaque 32-bit system bus Port ID. */
|
||||
u32 portid;
|
||||
|
||||
/* Opaque 32-bit handle used for hypervisor calls. */
|
||||
u32 devhandle;
|
||||
|
||||
/* Chipset version information. */
|
||||
int chip_type;
|
||||
#define PBM_CHIP_TYPE_SABRE 1
|
||||
#define PBM_CHIP_TYPE_PSYCHO 2
|
||||
#define PBM_CHIP_TYPE_SCHIZO 3
|
||||
#define PBM_CHIP_TYPE_SCHIZO_PLUS 4
|
||||
#define PBM_CHIP_TYPE_TOMATILLO 5
|
||||
int chip_version;
|
||||
int chip_revision;
|
||||
|
||||
/* Name used for top-level resources. */
|
||||
char *name;
|
||||
|
||||
/* OBP specific information. */
|
||||
struct device_node *prom_node;
|
||||
u64 ino_bitmap;
|
||||
|
||||
/* PBM I/O and Memory space resources. */
|
||||
struct resource io_space;
|
||||
struct resource mem_space;
|
||||
|
||||
/* Base of PCI Config space, can be per-PBM or shared. */
|
||||
unsigned long config_space;
|
||||
|
||||
/* State of 66MHz capabilities on this PBM. */
|
||||
int is_66mhz_capable;
|
||||
int all_devs_66mhz;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
/* MSI info. */
|
||||
u32 msiq_num;
|
||||
u32 msiq_ent_count;
|
||||
u32 msiq_first;
|
||||
u32 msiq_first_devino;
|
||||
u32 msi_num;
|
||||
u32 msi_first;
|
||||
u32 msi_data_mask;
|
||||
u32 msix_data_width;
|
||||
u64 msi32_start;
|
||||
u64 msi64_start;
|
||||
u32 msi32_len;
|
||||
u32 msi64_len;
|
||||
void *msi_queues;
|
||||
unsigned long *msi_bitmap;
|
||||
#endif /* !(CONFIG_PCI_MSI) */
|
||||
|
||||
/* This PBM's streaming buffer. */
|
||||
struct strbuf stc;
|
||||
|
||||
/* IOMMU state, potentially shared by both PBM segments. */
|
||||
struct iommu *iommu;
|
||||
|
||||
/* Now things for the actual PCI bus probes. */
|
||||
unsigned int pci_first_busno;
|
||||
unsigned int pci_last_busno;
|
||||
struct pci_bus *pci_bus;
|
||||
};
|
||||
|
||||
struct pci_controller_info {
|
||||
/* List of all PCI controllers. */
|
||||
struct pci_controller_info *next;
|
||||
|
||||
/* Each controller gets a unique index, used mostly for
|
||||
* error logging purposes.
|
||||
*/
|
||||
int index;
|
||||
|
||||
/* The PCI bus modules controlled by us. */
|
||||
struct pci_pbm_info pbm_A;
|
||||
struct pci_pbm_info pbm_B;
|
||||
|
||||
/* Operations which are controller specific. */
|
||||
void (*scan_bus)(struct pci_controller_info *);
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
|
||||
struct msi_desc *entry);
|
||||
void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
|
||||
#endif
|
||||
|
||||
/* Now things for the actual PCI bus probes. */
|
||||
struct pci_ops *pci_ops;
|
||||
unsigned int pci_first_busno;
|
||||
unsigned int pci_last_busno;
|
||||
};
|
||||
|
||||
#endif /* !(__SPARC64_PBM_H) */
|
|
@ -328,8 +328,9 @@
|
|||
#define __NR_move_pages 307
|
||||
#define __NR_getcpu 308
|
||||
#define __NR_epoll_pwait 309
|
||||
#define __NR_utimensat 310
|
||||
|
||||
#define NR_SYSCALLS 310
|
||||
#define NR_SYSCALLS 311
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/* sysconf options, for SunOS compatibility */
|
||||
|
|
Loading…
Reference in a new issue