sparc64: Get rid of pci_controller_info.
It is just used as a parent to encapsulate two PBM objects. But that layout is only really relevant and necessary for psycho PCI controllers, which unlike all the others share a single IOMMU instance between sibling PCI busses. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ab138c031f
commit
d3ae4b5bc7
8 changed files with 184 additions and 244 deletions
|
@ -48,6 +48,9 @@ struct strbuf {
|
|||
unsigned long strbuf_control;
|
||||
unsigned long strbuf_pflush;
|
||||
unsigned long strbuf_fsync;
|
||||
unsigned long strbuf_err_stat;
|
||||
unsigned long strbuf_tag_diag;
|
||||
unsigned long strbuf_line_diag;
|
||||
unsigned long strbuf_ctxflush;
|
||||
unsigned long strbuf_ctxmatch_base;
|
||||
unsigned long strbuf_flushflag_pa;
|
||||
|
|
|
@ -977,14 +977,14 @@ int pcibus_to_node(struct pci_bus *pbus)
|
|||
EXPORT_SYMBOL(pcibus_to_node);
|
||||
#endif
|
||||
|
||||
/* Return the domain nuber for this pci bus */
|
||||
/* Return the domain number for this pci bus */
|
||||
|
||||
int pci_domain_nr(struct pci_bus *pbus)
|
||||
{
|
||||
struct pci_pbm_info *pbm = pbus->sysdata;
|
||||
int ret;
|
||||
|
||||
if (pbm == NULL || pbm->parent == NULL) {
|
||||
if (!pbm) {
|
||||
ret = -ENXIO;
|
||||
} else {
|
||||
ret = pbm->index;
|
||||
|
|
|
@ -431,22 +431,13 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
|
|||
fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
|
||||
}
|
||||
|
||||
static int __init pci_fire_pbm_init(struct pci_controller_info *p,
|
||||
static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
|
||||
struct of_device *op, u32 portid)
|
||||
{
|
||||
const struct linux_prom64_registers *regs;
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_pbm_info *pbm;
|
||||
int err;
|
||||
|
||||
if ((portid & 1) == 0)
|
||||
pbm = &p->pbm_A;
|
||||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->numa_node = -1;
|
||||
|
||||
pbm->pci_ops = &sun4u_pci_ops;
|
||||
|
@ -455,7 +446,6 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p,
|
|||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->portid = portid;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
pbm->name = dp->full_name;
|
||||
|
||||
|
@ -481,13 +471,9 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
/* XXX register error interrupt handlers XXX */
|
||||
|
||||
return 0;
|
||||
}
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
static inline int portid_compare(u32 x, u32 y)
|
||||
{
|
||||
if (x == (y ^ 1))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -495,48 +481,41 @@ static int __devinit fire_probe(struct of_device *op,
|
|||
const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
u32 portid;
|
||||
int err;
|
||||
|
||||
portid = of_getintprop_default(dp, "portid", 0xff);
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (portid_compare(pbm->portid, portid))
|
||||
return pci_fire_pbm_init(pbm->parent, op, portid);
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
|
||||
if (!p) {
|
||||
printk(KERN_ERR PFX "Cannot allocate controller info.\n");
|
||||
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
||||
if (!pbm) {
|
||||
printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
||||
goto out_free_controller;
|
||||
}
|
||||
|
||||
p->pbm_A.iommu = iommu;
|
||||
pbm->iommu = iommu;
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
|
||||
goto out_free_iommu_A;
|
||||
}
|
||||
err = pci_fire_pbm_init(pbm, op, portid);
|
||||
if (err)
|
||||
goto out_free_iommu;
|
||||
|
||||
p->pbm_B.iommu = iommu;
|
||||
dev_set_drvdata(&op->dev, pbm);
|
||||
|
||||
return pci_fire_pbm_init(p, op, portid);
|
||||
return 0;
|
||||
|
||||
out_free_iommu_A:
|
||||
kfree(p->pbm_A.iommu);
|
||||
out_free_iommu:
|
||||
kfree(pbm->iommu);
|
||||
|
||||
out_free_controller:
|
||||
kfree(p);
|
||||
kfree(pbm);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
|
|
|
@ -56,15 +56,11 @@ struct sparc64_msiq_cookie {
|
|||
};
|
||||
#endif
|
||||
|
||||
struct pci_controller_info;
|
||||
|
||||
struct pci_pbm_info {
|
||||
struct pci_pbm_info *next;
|
||||
struct pci_pbm_info *sibling;
|
||||
int index;
|
||||
|
||||
/* PCI controller we sit under. */
|
||||
struct pci_controller_info *parent;
|
||||
|
||||
/* Physical address base of controller registers. */
|
||||
unsigned long controller_regs;
|
||||
|
||||
|
@ -107,6 +103,10 @@ struct pci_pbm_info {
|
|||
/* This will be 12 on PCI-E controllers, 8 elsewhere. */
|
||||
unsigned long config_space_reg_bits;
|
||||
|
||||
unsigned long pci_afsr;
|
||||
unsigned long pci_afar;
|
||||
unsigned long pci_csr;
|
||||
|
||||
/* State of 66MHz capabilities on this PBM. */
|
||||
int is_66mhz_capable;
|
||||
int all_devs_66mhz;
|
||||
|
@ -151,12 +151,6 @@ struct pci_pbm_info {
|
|||
int numa_node;
|
||||
};
|
||||
|
||||
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 int pci_num_pbms;
|
||||
|
|
|
@ -146,24 +146,16 @@ 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_pbm_info *pbm,
|
||||
int is_pbm_a)
|
||||
static void psycho_check_stc_error(struct pci_pbm_info *pbm)
|
||||
{
|
||||
struct strbuf *strbuf = &pbm->stc;
|
||||
unsigned long regbase = pbm->controller_regs;
|
||||
unsigned long err_base, tag_base, line_base;
|
||||
u64 control;
|
||||
int i;
|
||||
|
||||
if (is_pbm_a) {
|
||||
err_base = regbase + PSYCHO_STC_ERR_A;
|
||||
tag_base = regbase + PSYCHO_STC_TAG_A;
|
||||
line_base = regbase + PSYCHO_STC_LINE_A;
|
||||
} else {
|
||||
err_base = regbase + PSYCHO_STC_ERR_B;
|
||||
tag_base = regbase + PSYCHO_STC_TAG_B;
|
||||
line_base = regbase + PSYCHO_STC_LINE_B;
|
||||
}
|
||||
err_base = strbuf->strbuf_err_stat;
|
||||
tag_base = strbuf->strbuf_tag_diag;
|
||||
line_base = strbuf->strbuf_line_diag;
|
||||
|
||||
spin_lock(&stc_buf_lock);
|
||||
|
||||
|
@ -239,15 +231,6 @@ static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
|
|||
spin_unlock(&stc_buf_lock);
|
||||
}
|
||||
|
||||
static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
|
||||
unsigned long afsr,
|
||||
unsigned long afar,
|
||||
enum psycho_error_type type)
|
||||
{
|
||||
__psycho_check_one_stc(pbm,
|
||||
(pbm == &pbm->parent->pbm_A));
|
||||
}
|
||||
|
||||
/* When an Uncorrectable Error or a PCI Error happens, we
|
||||
* interrogate the IOMMU state to see if it is the cause.
|
||||
*/
|
||||
|
@ -386,7 +369,7 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
|
|||
(data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
__psycho_check_stc_error(pbm, afsr, afar, type);
|
||||
psycho_check_stc_error(pbm);
|
||||
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -412,7 +395,6 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
|
|||
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
||||
{
|
||||
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;
|
||||
|
@ -465,8 +447,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|||
printk("]\n");
|
||||
|
||||
/* 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);
|
||||
psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
|
||||
if (pbm->sibling)
|
||||
psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -573,23 +556,18 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
|
|||
#define PSYCHO_PCI_AFAR_A 0x2018UL
|
||||
#define PSYCHO_PCI_AFAR_B 0x4018UL
|
||||
|
||||
static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
|
||||
static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
|
||||
{
|
||||
unsigned long csr_reg, csr, csr_error_bits;
|
||||
unsigned long csr, csr_error_bits;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u16 stat;
|
||||
|
||||
if (is_pbm_a) {
|
||||
csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
|
||||
} else {
|
||||
csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
|
||||
}
|
||||
csr = psycho_read(csr_reg);
|
||||
csr = psycho_read(pbm->pci_csr);
|
||||
csr_error_bits =
|
||||
csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
|
||||
if (csr_error_bits) {
|
||||
/* Clear the errors. */
|
||||
psycho_write(csr_reg, csr);
|
||||
psycho_write(pbm->pci_csr, csr);
|
||||
|
||||
/* Log 'em. */
|
||||
if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
|
||||
|
@ -616,19 +594,12 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
|
|||
static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
unsigned long afsr_reg, afar_reg;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int is_pbm_a, reported;
|
||||
int reported;
|
||||
|
||||
is_pbm_a = (pbm == &pbm->parent->pbm_A);
|
||||
if (is_pbm_a) {
|
||||
afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
|
||||
afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
|
||||
} else {
|
||||
afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
|
||||
afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
|
||||
}
|
||||
afsr_reg = pbm->pci_afsr;
|
||||
afar_reg = pbm->pci_afar;
|
||||
|
||||
/* Latch error status. */
|
||||
afar = psycho_read(afar_reg);
|
||||
|
@ -641,7 +612,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|||
PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
|
||||
PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
|
||||
if (!error_bits)
|
||||
return psycho_pcierr_intr_other(pbm, is_pbm_a);
|
||||
return psycho_pcierr_intr_other(pbm);
|
||||
psycho_write(afsr_reg, error_bits);
|
||||
|
||||
/* Log the error. */
|
||||
|
@ -923,10 +894,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
|
|||
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
|
||||
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
|
||||
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A;
|
||||
pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
|
||||
pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
|
||||
pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
|
||||
} else {
|
||||
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B;
|
||||
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
|
||||
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
|
||||
pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
|
||||
pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
|
||||
pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
|
||||
}
|
||||
/* PSYCHO's streaming buffer lacks ctx flushing. */
|
||||
pbm->stc.strbuf_ctxflush = 0;
|
||||
|
@ -971,16 +948,10 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
|
|||
#define PSYCHO_MEMSPACE_B 0x180000000UL
|
||||
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
|
||||
|
||||
static void __init psycho_pbm_init(struct pci_controller_info *p,
|
||||
static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
|
||||
struct of_device *op, int is_pbm_a)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
if (is_pbm_a)
|
||||
pbm = &p->pbm_A;
|
||||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
@ -996,7 +967,6 @@ static void __init psycho_pbm_init(struct pci_controller_info *p,
|
|||
pbm->chip_version = of_getintprop_default(dp, "version#", 0);
|
||||
pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
|
||||
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
pbm->name = dp->full_name;
|
||||
|
||||
|
@ -1013,6 +983,17 @@ static void __init psycho_pbm_init(struct pci_controller_info *p,
|
|||
psycho_scan_bus(pbm, &op->dev);
|
||||
}
|
||||
|
||||
static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (pbm->portid == upa_portid)
|
||||
return pbm;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define PSYCHO_CONFIGSPACE 0x001000000UL
|
||||
|
||||
static int __devinit psycho_probe(struct of_device *op,
|
||||
|
@ -1020,7 +1001,6 @@ static int __devinit psycho_probe(struct of_device *op,
|
|||
{
|
||||
const struct linux_prom64_registers *pr_regs;
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
int is_pbm_a, err;
|
||||
|
@ -1028,33 +1008,26 @@ static int __devinit psycho_probe(struct of_device *op,
|
|||
|
||||
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
|
||||
|
||||
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, op, is_pbm_a);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
|
||||
if (!p) {
|
||||
printk(KERN_ERR PFX "Cannot allocate controller info.\n");
|
||||
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
||||
if (!pbm) {
|
||||
printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
||||
goto out_free_controller;
|
||||
pbm->sibling = psycho_find_sibling(upa_portid);
|
||||
if (pbm->sibling) {
|
||||
iommu = pbm->sibling->iommu;
|
||||
} else {
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
||||
goto out_free_controller;
|
||||
}
|
||||
}
|
||||
|
||||
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
|
||||
|
||||
p->pbm_A.portid = upa_portid;
|
||||
p->pbm_B.portid = upa_portid;
|
||||
pbm->iommu = iommu;
|
||||
pbm->portid = upa_portid;
|
||||
|
||||
pr_regs = of_get_property(dp, "reg", NULL);
|
||||
err = -ENODEV;
|
||||
|
@ -1063,29 +1036,43 @@ static int __devinit psycho_probe(struct of_device *op,
|
|||
goto out_free_iommu;
|
||||
}
|
||||
|
||||
p->pbm_A.controller_regs = pr_regs[2].phys_addr;
|
||||
p->pbm_B.controller_regs = pr_regs[2].phys_addr;
|
||||
|
||||
p->pbm_A.config_space = p->pbm_B.config_space =
|
||||
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
|
||||
|
||||
psycho_controller_hwinit(&p->pbm_A);
|
||||
|
||||
err = psycho_iommu_init(&p->pbm_A);
|
||||
if (err)
|
||||
goto out_free_iommu;
|
||||
|
||||
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
|
||||
|
||||
psycho_pbm_init(p, op, is_pbm_a);
|
||||
pbm->controller_regs = pr_regs[2].phys_addr;
|
||||
pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
|
||||
|
||||
if (is_pbm_a) {
|
||||
pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
|
||||
pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
|
||||
pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIA_CTRL;
|
||||
} else {
|
||||
pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
|
||||
pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
|
||||
pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIB_CTRL;
|
||||
}
|
||||
|
||||
psycho_controller_hwinit(pbm);
|
||||
if (!pbm->sibling) {
|
||||
err = psycho_iommu_init(pbm);
|
||||
if (err)
|
||||
goto out_free_iommu;
|
||||
}
|
||||
|
||||
psycho_pbm_init(pbm, op, is_pbm_a);
|
||||
|
||||
if (pbm->sibling)
|
||||
pbm->sibling->sibling = pbm;
|
||||
|
||||
dev_set_drvdata(&op->dev, pbm);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_iommu:
|
||||
kfree(p->pbm_A.iommu);
|
||||
if (!pbm->sibling)
|
||||
kfree(pbm->iommu);
|
||||
|
||||
out_free_controller:
|
||||
kfree(p);
|
||||
kfree(pbm);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
|
|
|
@ -734,8 +734,8 @@ static int sabre_iommu_init(struct pci_pbm_info *pbm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __init sabre_pbm_init(struct pci_controller_info *p,
|
||||
struct pci_pbm_info *pbm, struct of_device *op)
|
||||
static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
|
||||
struct of_device *op)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
|
||||
|
@ -750,7 +750,6 @@ static void __init sabre_pbm_init(struct pci_controller_info *p,
|
|||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
pci_get_pbm_props(pbm);
|
||||
|
||||
|
@ -764,7 +763,6 @@ static int __devinit sabre_probe(struct of_device *op,
|
|||
{
|
||||
const struct linux_prom64_registers *pr_regs;
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
u32 upa_portid, dma_mask;
|
||||
struct iommu *iommu;
|
||||
|
@ -786,26 +784,22 @@ static int __devinit sabre_probe(struct of_device *op,
|
|||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
p = kzalloc(sizeof(*p), GFP_ATOMIC);
|
||||
if (!p) {
|
||||
printk(KERN_ERR PFX "Cannot allocate controller info.\n");
|
||||
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
||||
if (!pbm) {
|
||||
printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
|
||||
iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
||||
goto out_free_controller;
|
||||
}
|
||||
|
||||
pbm = &p->pbm_A;
|
||||
pbm->iommu = iommu;
|
||||
|
||||
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->portid = upa_portid;
|
||||
|
||||
/*
|
||||
|
@ -840,8 +834,7 @@ static int __devinit sabre_probe(struct of_device *op,
|
|||
SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
|
||||
|
||||
/* Now map in PCI config space for entire SABRE. */
|
||||
pbm->config_space =
|
||||
(pbm->controller_regs + SABRE_CONFIGSPACE);
|
||||
pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE;
|
||||
|
||||
vdma = of_get_property(dp, "virtual-dma", NULL);
|
||||
if (!vdma) {
|
||||
|
@ -876,14 +869,20 @@ static int __devinit sabre_probe(struct of_device *op,
|
|||
/*
|
||||
* Look for APB underneath.
|
||||
*/
|
||||
sabre_pbm_init(p, pbm, op);
|
||||
sabre_pbm_init(pbm, op);
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
dev_set_drvdata(&op->dev, pbm);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_iommu:
|
||||
kfree(p->pbm_A.iommu);
|
||||
kfree(pbm->iommu);
|
||||
|
||||
out_free_controller:
|
||||
kfree(p);
|
||||
kfree(pbm);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
|
|
|
@ -358,11 +358,12 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
|
|||
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
}
|
||||
|
||||
static void schizo_check_iommu_error(struct pci_controller_info *p,
|
||||
static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
|
||||
enum schizo_error_type type)
|
||||
{
|
||||
schizo_check_iommu_error_pbm(&p->pbm_A, type);
|
||||
schizo_check_iommu_error_pbm(&p->pbm_B, type);
|
||||
schizo_check_iommu_error_pbm(pbm, type);
|
||||
if (pbm->sibling)
|
||||
schizo_check_iommu_error_pbm(pbm->sibling, type);
|
||||
}
|
||||
|
||||
/* Uncorrectable ECC error status gathering. */
|
||||
|
@ -387,7 +388,6 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
|
|||
static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
|
||||
{
|
||||
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;
|
||||
|
@ -450,7 +450,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
|
|||
printk("]\n");
|
||||
|
||||
/* Interrogate IOMMU for error status. */
|
||||
schizo_check_iommu_error(p, UE_ERR);
|
||||
schizo_check_iommu_error(pbm, UE_ERR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -651,7 +651,6 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
|
|||
static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
unsigned long afsr_reg, afar_reg, base;
|
||||
unsigned long afsr, afar, error_bits;
|
||||
int reported;
|
||||
|
@ -745,7 +744,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
|||
* a bug in the IOMMU support code or a PCI device driver.
|
||||
*/
|
||||
if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
|
||||
schizo_check_iommu_error(p, PCI_ERR);
|
||||
schizo_check_iommu_error(pbm, PCI_ERR);
|
||||
pci_scan_for_target_abort(pbm, pbm->pci_bus);
|
||||
}
|
||||
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
|
||||
|
@ -806,7 +805,6 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
|
|||
static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct pci_pbm_info *pbm = dev_id;
|
||||
struct pci_controller_info *p = pbm->parent;
|
||||
u64 errlog;
|
||||
|
||||
errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
|
||||
|
@ -822,7 +820,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
|
|||
|
||||
printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
|
||||
pbm->name);
|
||||
schizo_check_iommu_error(p, SAFARI_ERR);
|
||||
schizo_check_iommu_error(pbm, SAFARI_ERR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1329,13 +1327,12 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
|
|||
}
|
||||
}
|
||||
|
||||
static int __devinit schizo_pbm_init(struct pci_controller_info *p,
|
||||
static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
|
||||
struct of_device *op, u32 portid,
|
||||
int chip_type)
|
||||
{
|
||||
const struct linux_prom64_registers *regs;
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_pbm_info *pbm;
|
||||
const char *chipset_name;
|
||||
int is_pbm_a, err;
|
||||
|
||||
|
@ -1368,10 +1365,6 @@ static int __devinit schizo_pbm_init(struct pci_controller_info *p,
|
|||
regs = of_get_property(dp, "reg", NULL);
|
||||
|
||||
is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
|
||||
if (is_pbm_a)
|
||||
pbm = &p->pbm_A;
|
||||
else
|
||||
pbm = &p->pbm_B;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
@ -1384,7 +1377,6 @@ static int __devinit schizo_pbm_init(struct pci_controller_info *p,
|
|||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->portid = portid;
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
|
||||
pbm->chip_type = chip_type;
|
||||
|
@ -1430,10 +1422,21 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
|
|||
return (x == y);
|
||||
}
|
||||
|
||||
static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
|
||||
int chip_type)
|
||||
{
|
||||
struct pci_pbm_info *pbm;
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (portid_compare(pbm->portid, portid, chip_type))
|
||||
return pbm;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct iommu *iommu;
|
||||
u32 portid;
|
||||
|
@ -1442,50 +1445,37 @@ static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type
|
|||
portid = of_getintprop_default(dp, "portid", 0xff);
|
||||
|
||||
err = -ENOMEM;
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (portid_compare(pbm->portid, portid, chip_type)) {
|
||||
if (schizo_pbm_init(pbm->parent, op,
|
||||
portid, chip_type))
|
||||
goto out_err;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
|
||||
if (!p) {
|
||||
printk(KERN_ERR PFX "Cannot allocate controller info.\n");
|
||||
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
||||
if (!pbm) {
|
||||
printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
pbm->sibling = schizo_find_sibling(portid, chip_type);
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
|
||||
goto out_free_controller;
|
||||
goto out_free_pbm;
|
||||
}
|
||||
|
||||
p->pbm_A.iommu = iommu;
|
||||
pbm->iommu = iommu;
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Cannot allocate PBM B iommu.\n");
|
||||
goto out_free_iommu_A;
|
||||
}
|
||||
if (schizo_pbm_init(pbm, op, portid, chip_type))
|
||||
goto out_free_iommu;
|
||||
|
||||
p->pbm_B.iommu = iommu;
|
||||
if (pbm->sibling)
|
||||
pbm->sibling->sibling = pbm;
|
||||
|
||||
if (schizo_pbm_init(p, op, portid, chip_type))
|
||||
goto out_free_iommu_B;
|
||||
dev_set_drvdata(&op->dev, pbm);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_iommu_B:
|
||||
kfree(p->pbm_B.iommu);
|
||||
out_free_iommu:
|
||||
kfree(pbm->iommu);
|
||||
|
||||
out_free_iommu_A:
|
||||
kfree(p->pbm_A.iommu);
|
||||
|
||||
out_free_controller:
|
||||
kfree(p);
|
||||
out_free_pbm:
|
||||
kfree(pbm);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
|
|
|
@ -42,6 +42,7 @@ struct iommu_batch {
|
|||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
|
||||
static int iommu_batch_initialized;
|
||||
|
||||
/* Interrupts must be disabled. */
|
||||
static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
|
||||
|
@ -887,21 +888,12 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
|
|||
}
|
||||
#endif /* !(CONFIG_PCI_MSI) */
|
||||
|
||||
static int __init pci_sun4v_pbm_init(struct pci_controller_info *p,
|
||||
static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
|
||||
struct of_device *op, u32 devhandle)
|
||||
{
|
||||
struct device_node *dp = op->node;
|
||||
struct pci_pbm_info *pbm;
|
||||
int err;
|
||||
|
||||
if (devhandle & 0x40)
|
||||
pbm = &p->pbm_B;
|
||||
else
|
||||
pbm = &p->pbm_A;
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
pbm->numa_node = of_node_to_nid(dp);
|
||||
|
||||
pbm->pci_ops = &sun4v_pci_ops;
|
||||
|
@ -909,7 +901,6 @@ static int __init pci_sun4v_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
pbm->index = pci_num_pbms++;
|
||||
|
||||
pbm->parent = p;
|
||||
pbm->prom_node = dp;
|
||||
|
||||
pbm->devhandle = devhandle;
|
||||
|
@ -931,6 +922,9 @@ static int __init pci_sun4v_pbm_init(struct pci_controller_info *p,
|
|||
|
||||
pci_sun4v_scan_bus(pbm, &op->dev);
|
||||
|
||||
pbm->next = pci_pbm_root;
|
||||
pci_pbm_root = pbm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -939,7 +933,6 @@ static int __devinit pci_sun4v_probe(struct of_device *op,
|
|||
{
|
||||
const struct linux_prom64_registers *regs;
|
||||
static int hvapi_negotiated = 0;
|
||||
struct pci_controller_info *p;
|
||||
struct pci_pbm_info *pbm;
|
||||
struct device_node *dp;
|
||||
struct iommu *iommu;
|
||||
|
@ -972,51 +965,46 @@ static int __devinit pci_sun4v_probe(struct of_device *op,
|
|||
}
|
||||
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
|
||||
|
||||
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
||||
if (pbm->devhandle == (devhandle ^ 0x40)) {
|
||||
return pci_sun4v_pbm_init(pbm->parent, op, devhandle);
|
||||
}
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
for_each_possible_cpu(i) {
|
||||
unsigned long page = get_zeroed_page(GFP_ATOMIC);
|
||||
if (!iommu_batch_initialized) {
|
||||
for_each_possible_cpu(i) {
|
||||
unsigned long page = get_zeroed_page(GFP_KERNEL);
|
||||
|
||||
if (!page)
|
||||
goto out_err;
|
||||
if (!page)
|
||||
goto out_err;
|
||||
|
||||
per_cpu(iommu_batch, i).pglist = (u64 *) page;
|
||||
per_cpu(iommu_batch, i).pglist = (u64 *) page;
|
||||
}
|
||||
iommu_batch_initialized = 1;
|
||||
}
|
||||
|
||||
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
|
||||
if (!p) {
|
||||
printk(KERN_ERR PFX "Could not allocate pci_controller_info\n");
|
||||
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
||||
if (!pbm) {
|
||||
printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Could not allocate pbm A iommu\n");
|
||||
printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
|
||||
goto out_free_controller;
|
||||
}
|
||||
|
||||
p->pbm_A.iommu = iommu;
|
||||
pbm->iommu = iommu;
|
||||
|
||||
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
||||
if (!iommu) {
|
||||
printk(KERN_ERR PFX "Could not allocate pbm B iommu\n");
|
||||
goto out_free_iommu_A;
|
||||
}
|
||||
err = pci_sun4v_pbm_init(pbm, op, devhandle);
|
||||
if (err)
|
||||
goto out_free_iommu;
|
||||
|
||||
p->pbm_B.iommu = iommu;
|
||||
dev_set_drvdata(&op->dev, pbm);
|
||||
|
||||
return pci_sun4v_pbm_init(p, op, devhandle);
|
||||
return 0;
|
||||
|
||||
out_free_iommu_A:
|
||||
kfree(p->pbm_A.iommu);
|
||||
out_free_iommu:
|
||||
kfree(pbm->iommu);
|
||||
|
||||
out_free_controller:
|
||||
kfree(p);
|
||||
kfree(pbm);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
|
|
Loading…
Reference in a new issue