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>
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;
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;
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;
pbm->index = pci_num_pbms++;
pbm->portid = portid;
- pbm->parent = p;
pbm->prom_node = dp;
pbm->name = dp->full_name;
/* 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;
}
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;
};
#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;
/* 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;
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;
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);
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.
*/
(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);
}
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;
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;
}
#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)
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);
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. */
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;
#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;
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;
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,
{
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;
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;
goto out_free_iommu;
}
- p->pbm_A.controller_regs = pr_regs[2].phys_addr;
- p->pbm_B.controller_regs = pr_regs[2].phys_addr;
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+ pbm->controller_regs = pr_regs[2].phys_addr;
+ pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
- p->pbm_A.config_space = p->pbm_B.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(&p->pbm_A);
+ psycho_controller_hwinit(pbm);
+ if (!pbm->sibling) {
+ err = psycho_iommu_init(pbm);
+ if (err)
+ goto out_free_iommu;
+ }
- err = psycho_iommu_init(&p->pbm_A);
- if (err)
- goto out_free_iommu;
+ psycho_pbm_init(pbm, op, is_pbm_a);
- is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+ if (pbm->sibling)
+ pbm->sibling->sibling = pbm;
- psycho_pbm_init(p, op, is_pbm_a);
+ 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;
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;
pbm->index = pci_num_pbms++;
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
- pbm->parent = p;
pbm->prom_node = dp;
pci_get_pbm_props(pbm);
{
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;
}
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;
/*
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) {
/*
* 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;
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. */
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;
printk("]\n");
/* Interrogate IOMMU for error status. */
- schizo_check_iommu_error(p, UE_ERR);
+ schizo_check_iommu_error(pbm, UE_ERR);
return IRQ_HANDLED;
}
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;
* 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))
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);
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;
}
}
}
-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;
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;
pbm->index = pci_num_pbms++;
pbm->portid = portid;
- pbm->parent = p;
pbm->prom_node = dp;
pbm->chip_type = 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;
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_A:
- kfree(p->pbm_A.iommu);
+out_free_iommu:
+ kfree(pbm->iommu);
-out_free_controller:
- kfree(p);
+out_free_pbm:
+ kfree(pbm);
out_err:
return err;
};
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)
}
#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;
pbm->index = pci_num_pbms++;
- pbm->parent = p;
pbm->prom_node = dp;
pbm->devhandle = devhandle;
pci_sun4v_scan_bus(pbm, &op->dev);
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
return 0;
}
{
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;
}
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;