|
@@ -41,11 +41,18 @@
|
|
#include <asm/ppc-pci.h>
|
|
#include <asm/ppc-pci.h>
|
|
#include <asm/eeh.h>
|
|
#include <asm/eeh.h>
|
|
|
|
|
|
|
|
+/* hose_spinlock protects accesses to the the phb_bitmap. */
|
|
static DEFINE_SPINLOCK(hose_spinlock);
|
|
static DEFINE_SPINLOCK(hose_spinlock);
|
|
LIST_HEAD(hose_list);
|
|
LIST_HEAD(hose_list);
|
|
|
|
|
|
-/* XXX kill that some day ... */
|
|
|
|
-static int global_phb_number; /* Global phb counter */
|
|
|
|
|
|
+/* For dynamic PHB numbering on get_phb_number(): max number of PHBs. */
|
|
|
|
+#define MAX_PHBS 0x10000
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * For dynamic PHB numbering: used/free PHBs tracking bitmap.
|
|
|
|
+ * Accesses to this bitmap should be protected by hose_spinlock.
|
|
|
|
+ */
|
|
|
|
+static DECLARE_BITMAP(phb_bitmap, MAX_PHBS);
|
|
|
|
|
|
/* ISA Memory physical address */
|
|
/* ISA Memory physical address */
|
|
resource_size_t isa_mem_base;
|
|
resource_size_t isa_mem_base;
|
|
@@ -64,6 +71,42 @@ struct dma_map_ops *get_pci_dma_ops(void)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(get_pci_dma_ops);
|
|
EXPORT_SYMBOL(get_pci_dma_ops);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * This function should run under locking protection, specifically
|
|
|
|
+ * hose_spinlock.
|
|
|
|
+ */
|
|
|
|
+static int get_phb_number(struct device_node *dn)
|
|
|
|
+{
|
|
|
|
+ int ret, phb_id = -1;
|
|
|
|
+ u64 prop;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Try fixed PHB numbering first, by checking archs and reading
|
|
|
|
+ * the respective device-tree properties. Firstly, try powernv by
|
|
|
|
+ * reading "ibm,opal-phbid", only present in OPAL environment.
|
|
|
|
+ */
|
|
|
|
+ ret = of_property_read_u64(dn, "ibm,opal-phbid", &prop);
|
|
|
|
+ if (ret)
|
|
|
|
+ ret = of_property_read_u32_index(dn, "reg", 1, (u32 *)&prop);
|
|
|
|
+
|
|
|
|
+ if (!ret)
|
|
|
|
+ phb_id = (int)(prop & (MAX_PHBS - 1));
|
|
|
|
+
|
|
|
|
+ /* We need to be sure to not use the same PHB number twice. */
|
|
|
|
+ if ((phb_id >= 0) && !test_and_set_bit(phb_id, phb_bitmap))
|
|
|
|
+ return phb_id;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If not pseries nor powernv, or if fixed PHB numbering tried to add
|
|
|
|
+ * the same PHB number twice, then fallback to dynamic PHB numbering.
|
|
|
|
+ */
|
|
|
|
+ phb_id = find_first_zero_bit(phb_bitmap, MAX_PHBS);
|
|
|
|
+ BUG_ON(phb_id >= MAX_PHBS);
|
|
|
|
+ set_bit(phb_id, phb_bitmap);
|
|
|
|
+
|
|
|
|
+ return phb_id;
|
|
|
|
+}
|
|
|
|
+
|
|
struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
|
|
struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
|
|
{
|
|
{
|
|
struct pci_controller *phb;
|
|
struct pci_controller *phb;
|
|
@@ -72,7 +115,7 @@ struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
|
|
if (phb == NULL)
|
|
if (phb == NULL)
|
|
return NULL;
|
|
return NULL;
|
|
spin_lock(&hose_spinlock);
|
|
spin_lock(&hose_spinlock);
|
|
- phb->global_number = global_phb_number++;
|
|
|
|
|
|
+ phb->global_number = get_phb_number(dev);
|
|
list_add_tail(&phb->list_node, &hose_list);
|
|
list_add_tail(&phb->list_node, &hose_list);
|
|
spin_unlock(&hose_spinlock);
|
|
spin_unlock(&hose_spinlock);
|
|
phb->dn = dev;
|
|
phb->dn = dev;
|
|
@@ -94,6 +137,11 @@ EXPORT_SYMBOL_GPL(pcibios_alloc_controller);
|
|
void pcibios_free_controller(struct pci_controller *phb)
|
|
void pcibios_free_controller(struct pci_controller *phb)
|
|
{
|
|
{
|
|
spin_lock(&hose_spinlock);
|
|
spin_lock(&hose_spinlock);
|
|
|
|
+
|
|
|
|
+ /* Clear bit of phb_bitmap to allow reuse of this PHB number. */
|
|
|
|
+ if (phb->global_number < MAX_PHBS)
|
|
|
|
+ clear_bit(phb->global_number, phb_bitmap);
|
|
|
|
+
|
|
list_del(&phb->list_node);
|
|
list_del(&phb->list_node);
|
|
spin_unlock(&hose_spinlock);
|
|
spin_unlock(&hose_spinlock);
|
|
|
|
|