Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1635317f authored by Paul Mackerras's avatar Paul Mackerras
Browse files

[PATCH] Separate pci bits out of struct device_node



This patch pulls the PCI-related junk out of struct device_node and
puts it in a separate structure, struct pci_dn.  The device_node now
just has a void * pointer in it, which points to a struct pci_dn for
nodes that represent PCI devices.  It could potentially be used in
future for device-specific data for other sorts of devices, such as
virtual I/O devices.

Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent b28d2582
Loading
Loading
Loading
Loading
+32 −23
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
static void __pci_addr_cache_insert_device(struct pci_dev *dev)
{
	struct device_node *dn;
	struct pci_dn *pdn;
	int i;
	int inserted = 0;

@@ -265,8 +266,9 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev)
	}

	/* Skip any devices for which EEH is not enabled. */
	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
	    dn->eeh_mode & EEH_MODE_NOCHECK) {
	pdn = dn->data;
	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
#ifdef DEBUG
		printk(KERN_INFO "PCI: skip building address cache for=%s\n",
		       pci_name(dev));
@@ -415,6 +417,7 @@ int eeh_unregister_notifier(struct notifier_block *nb)
static int read_slot_reset_state(struct device_node *dn, int rets[])
{
	int token, outputs;
	struct pci_dn *pdn = dn->data;

	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
		token = ibm_read_slot_reset_state2;
@@ -424,8 +427,8 @@ static int read_slot_reset_state(struct device_node *dn, int rets[])
		outputs = 3;
	}

	return rtas_call(token, 3, outputs, rets, dn->eeh_config_addr,
			 BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
	return rtas_call(token, 3, outputs, rets, pdn->eeh_config_addr,
			 BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
}

/**
@@ -534,6 +537,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
	unsigned long flags;
	int rc, reset_state;
	struct eeh_event  *event;
	struct pci_dn *pdn;

	__get_cpu_var(total_mmio_ffs)++;

@@ -542,14 +546,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)

	if (!dn)
		return 0;
	pdn = dn->data;

	/* Access to IO BARs might get this far and still not want checking. */
	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
	    dn->eeh_mode & EEH_MODE_NOCHECK) {
	if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
		return 0;
	}

	if (!dn->eeh_config_addr) {
	if (!pdn->eeh_config_addr) {
		return 0;
	}

@@ -557,7 +562,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
	 * If we already have a pending isolation event for this
	 * slot, we know it's bad already, we don't need to check...
	 */
	if (dn->eeh_mode & EEH_MODE_ISOLATED) {
	if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
		atomic_inc(&eeh_fail_count);
		if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) {
			/* re-read the slot reset state */
@@ -582,7 +587,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
	}

	/* prevent repeated reports of this failure */
	dn->eeh_mode |= EEH_MODE_ISOLATED;
	pdn->eeh_mode |= EEH_MODE_ISOLATED;

	reset_state = rets[0];

@@ -590,9 +595,9 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
	memset(slot_errbuf, 0, eeh_error_buf_size);

	rc = rtas_call(ibm_slot_error_detail,
	               8, 1, NULL, dn->eeh_config_addr,
	               BUID_HI(dn->phb->buid),
	               BUID_LO(dn->phb->buid), NULL, 0,
	               8, 1, NULL, pdn->eeh_config_addr,
	               BUID_HI(pdn->phb->buid),
	               BUID_LO(pdn->phb->buid), NULL, 0,
	               virt_to_phys(slot_errbuf),
	               eeh_error_buf_size,
	               1 /* Temporary Error */);
@@ -679,8 +684,9 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
	u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);
	u32 *regs;
	int enable;
	struct pci_dn *pdn = dn->data;

	dn->eeh_mode = 0;
	pdn->eeh_mode = 0;

	if (status && strcmp(status, "ok") != 0)
		return NULL;	/* ignore devices with bad status */
@@ -691,7 +697,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)

	/* There is nothing to check on PCI to ISA bridges */
	if (dn->type && !strcmp(dn->type, "isa")) {
		dn->eeh_mode |= EEH_MODE_NOCHECK;
		pdn->eeh_mode |= EEH_MODE_NOCHECK;
		return NULL;
	}

@@ -708,7 +714,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
		enable = 0;

	if (!enable)
		dn->eeh_mode |= EEH_MODE_NOCHECK;
		pdn->eeh_mode |= EEH_MODE_NOCHECK;

	/* Ok... see if this device supports EEH.  Some do, some don't,
	 * and the only way to find out is to check each and every one. */
@@ -721,8 +727,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
				EEH_ENABLE);
		if (ret == 0) {
			eeh_subsystem_enabled = 1;
			dn->eeh_mode |= EEH_MODE_SUPPORTED;
			dn->eeh_config_addr = regs[0];
			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
			pdn->eeh_config_addr = regs[0];
#ifdef DEBUG
			printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name);
#endif
@@ -730,10 +736,11 @@ static void *early_enable_eeh(struct device_node *dn, void *data)

			/* This device doesn't support EEH, but it may have an
			 * EEH parent, in which case we mark it as supported. */
			if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
			if (dn->parent && dn->parent->data
			    && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
				/* Parent supports EEH. */
				dn->eeh_mode |= EEH_MODE_SUPPORTED;
				dn->eeh_config_addr = dn->parent->eeh_config_addr;
				pdn->eeh_mode |= EEH_MODE_SUPPORTED;
				pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;
				return NULL;
			}
		}
@@ -790,11 +797,13 @@ void __init eeh_init(void)
	for (phb = of_find_node_by_name(NULL, "pci"); phb;
	     phb = of_find_node_by_name(phb, "pci")) {
		unsigned long buid;
		struct pci_dn *pci;

		buid = get_phb_buid(phb);
		if (buid == 0)
		if (buid == 0 || phb->data == NULL)
			continue;

		pci = phb->data;
		info.buid_lo = BUID_LO(buid);
		info.buid_hi = BUID_HI(buid);
		traverse_pci_devices(phb, early_enable_eeh, &info);
@@ -823,9 +832,9 @@ void eeh_add_device_early(struct device_node *dn)
	struct pci_controller *phb;
	struct eeh_early_enable_info info;

	if (!dn)
	if (!dn || !dn->data)
		return;
	phb = dn->phb;
	phb = PCI_DN(dn)->phb;
	if (NULL == phb || 0 == phb->buid) {
		printk(KERN_WARNING "EEH: Expected buid but found none\n");
		return;
+2 −1
Original line number Diff line number Diff line
@@ -438,7 +438,8 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl)

void iommu_free_table(struct device_node *dn)
{
	struct iommu_table *tbl = dn->iommu_table;
	struct pci_dn *pdn = dn->data;
	struct iommu_table *tbl = pdn->iommu_table;
	unsigned long bitmap_sz, i;
	unsigned int order;

+2 −2
Original line number Diff line number Diff line
@@ -447,9 +447,9 @@ void __init maple_pci_init(void)
	 */
	if (u3_agp) {
		struct device_node *np = u3_agp->arch_data;
		np->busno = 0xf0;
		PCI_DN(np)->busno = 0xf0;
		for (np = np->child; np; np = np->sibling)
			np->busno = 0xf0;
			PCI_DN(np)->busno = 0xf0;
	}

	/* Tell pci.c to use the common resource allocation mecanism */
+41 −31
Original line number Diff line number Diff line
@@ -295,7 +295,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
				      struct iommu_table *tbl,
				      unsigned int *dma_window)
{
	tbl->it_busno  = dn->bussubno;
	tbl->it_busno  = PCI_DN(dn)->bussubno;

	/* TODO: Parse field size properties properly. */
	tbl->it_size   = (((unsigned long)dma_window[4] << 32) |
@@ -311,6 +311,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
static void iommu_bus_setup_pSeries(struct pci_bus *bus)
{
	struct device_node *dn, *pdn;
	struct pci_dn *pci;
	struct iommu_table *tbl;

	DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);
@@ -325,6 +326,7 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
	 */

	dn = pci_bus_to_OF_node(bus);
	pci = dn->data;

	if (!bus->self) {
		/* Root bus */
@@ -341,18 +343,18 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
				 * alltogether. This leaves 768MB for the window.
				 */
				DBG("PHB has io-hole, reserving 256MB\n");
				dn->phb->dma_window_size = 3 << 28;
				dn->phb->dma_window_base_cur = 1 << 28;
				pci->phb->dma_window_size = 3 << 28;
				pci->phb->dma_window_base_cur = 1 << 28;
			} else {
				/* 1GB window by default */
				dn->phb->dma_window_size = 1 << 30;
				dn->phb->dma_window_base_cur = 0;
				pci->phb->dma_window_size = 1 << 30;
				pci->phb->dma_window_base_cur = 0;
			}

			tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);

			iommu_table_setparms(dn->phb, dn, tbl);
			dn->iommu_table = iommu_init_table(tbl);
			iommu_table_setparms(pci->phb, dn, tbl);
			pci->iommu_table = iommu_init_table(tbl);
		} else {
			/* Do a 128MB table at root. This is used for the IDE
			 * controller on some SMP-mode POWER4 machines. It
@@ -363,16 +365,16 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
			 * Allocate at offset 128MB to avoid having to deal
			 * with ISA holes; 128MB table for IDE is plenty.
			 */
			dn->phb->dma_window_size = 1 << 27;
			dn->phb->dma_window_base_cur = 1 << 27;
			pci->phb->dma_window_size = 1 << 27;
			pci->phb->dma_window_base_cur = 1 << 27;

			tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);

			iommu_table_setparms(dn->phb, dn, tbl);
			dn->iommu_table = iommu_init_table(tbl);
			iommu_table_setparms(pci->phb, dn, tbl);
			pci->iommu_table = iommu_init_table(tbl);

			/* All child buses have 256MB tables */
			dn->phb->dma_window_size = 1 << 28;
			pci->phb->dma_window_size = 1 << 28;
		}
	} else {
		pdn = pci_bus_to_OF_node(bus->parent);
@@ -386,12 +388,12 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)

			tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);

			iommu_table_setparms(dn->phb, dn, tbl);
			iommu_table_setparms(pci->phb, dn, tbl);

			dn->iommu_table = iommu_init_table(tbl);
			pci->iommu_table = iommu_init_table(tbl);
		} else {
			/* Lower than first child or under python, use parent table */
			dn->iommu_table = pdn->iommu_table;
			pci->iommu_table = PCI_DN(pdn)->iommu_table;
		}
	}
}
@@ -401,6 +403,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
{
	struct iommu_table *tbl;
	struct device_node *dn, *pdn;
	struct pci_dn *ppci;
	unsigned int *dma_window = NULL;

	DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
@@ -419,22 +422,24 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
		return;
	}

	if (!pdn->iommu_table) {
	ppci = pdn->data;
	if (!ppci->iommu_table) {
		/* Bussubno hasn't been copied yet.
		 * Do it now because iommu_table_setparms_lpar needs it.
		 */
		pdn->bussubno = bus->number;

		ppci->bussubno = bus->number;

		tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
						    GFP_KERNEL);
	
		iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
		iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);

		pdn->iommu_table = iommu_init_table(tbl);
		ppci->iommu_table = iommu_init_table(tbl);
	}

	if (pdn != dn)
		dn->iommu_table = pdn->iommu_table;
		PCI_DN(dn)->iommu_table = ppci->iommu_table;
}


@@ -449,11 +454,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
	 */
	mydn = dn = pci_device_to_OF_node(dev);

	while (dn && dn->iommu_table == NULL)
	while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)
		dn = dn->parent;

	if (dn) {
		mydn->iommu_table = dn->iommu_table;
	if (dn && dn->data) {
		PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
	} else {
		DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name);
	}
@@ -463,10 +468,11 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
{
	int err = NOTIFY_OK;
	struct device_node *np = node;
	struct pci_dn *pci = np->data;

	switch (action) {
	case PSERIES_RECONFIG_REMOVE:
		if (np->iommu_table &&
		if (pci->iommu_table &&
		    get_property(np, "ibm,dma-window", NULL))
			iommu_free_table(np);
		break;
@@ -486,6 +492,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
	struct device_node *pdn, *dn;
	struct iommu_table *tbl;
	int *dma_window = NULL;
	struct pci_dn *pci;

	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);

@@ -497,8 +504,10 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
	 */
	dn = pci_device_to_OF_node(dev);

	for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) {
		dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
	for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;
	     pdn = pdn->parent) {
		dma_window = (unsigned int *)
			get_property(pdn, "ibm,dma-window", NULL);
		if (dma_window)
			break;
	}
@@ -515,20 +524,21 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
		DBG("Found DMA window, allocating table\n");
	}

	if (!pdn->iommu_table) {
	pci = pdn->data;
	if (!pci->iommu_table) {
		/* iommu_table_setparms_lpar needs bussubno. */
		pdn->bussubno = pdn->phb->bus->number;
		pci->bussubno = pci->phb->bus->number;

		tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
						    GFP_KERNEL);

		iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
		iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);

		pdn->iommu_table = iommu_init_table(tbl);
		pci->iommu_table = iommu_init_table(tbl);
	}

	if (pdn != dn)
		dn->iommu_table = pdn->iommu_table;
		PCI_DN(dn)->iommu_table = pci->iommu_table;
}

static void iommu_bus_setup_null(struct pci_bus *b) { }
+4 −2
Original line number Diff line number Diff line
@@ -837,9 +837,11 @@ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn)
        * device tree.  If they are then we need to scan all the
        * functions of this slot.
        */
       for (dn = busdn->child; dn; dn = dn->sibling)
               if ((dn->devfn >> 3) == (devfn >> 3))
       for (dn = busdn->child; dn; dn = dn->sibling) {
	       struct pci_dn *pdn = dn->data;
	       if (pdn && (pdn->devfn >> 3) == (devfn >> 3))
                       return 1;
       }

       return 0;
}
Loading