}
static void *
-sn_default_pci_bus_fixup(struct pcibus_bussoft *soft)
+sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller)
{
return NULL;
}
provider_soft = NULL;
if (provider->bus_fixup)
- provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr);
+ provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller);
if (provider_soft == NULL)
return; /* fixup failed or not applicable */
SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
&(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
+ /*
+ * If the node information we obtained during the fixup phase is invalid
+ * then set controller->node to -1 (undetermined)
+ */
+ if (controller->node >= num_online_nodes()) {
+ struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
+
+ printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu"
+ "L_IO=%lx L_MEM=%lx BASE=%lx\n",
+ b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
+ b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
+ printk(KERN_WARNING "on node %d but only %d nodes online."
+ "Association set to undetermined.\n",
+ controller->node, num_online_nodes());
+ controller->node = -1;
+ }
return;
error_return:
{
void *cpuaddr;
unsigned long phys_addr;
+ int node;
struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
/*
* Allocate the memory.
- * FIXME: We should be doing alloc_pages_node for the node closest
- * to the PCI device.
*/
- if (!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size))))
+ node = pcibus_to_node(pdev->bus);
+ if (likely(node >=0)) {
+ struct page *p = alloc_pages_node(node, GFP_ATOMIC, get_order(size));
+
+ if (likely(p))
+ cpuaddr = page_address(p);
+ else
+ return NULL;
+ } else
+ cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+
+ if (unlikely(!cpuaddr))
return NULL;
memset(cpuaddr, 0x0, size);
}
void *
-pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft)
+pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
{
int nasid, cnode, j;
struct hubdev_info *hubdev_info;
memset(soft->pbi_int_ate_resource.ate, 0,
(soft->pbi_int_ate_size * sizeof(uint64_t)));
+ if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP)
+ /*
+ * TIO PCI Bridge with no closest node information.
+ * FIXME: Find another way to determine the closest node
+ */
+ controller->node = -1;
+ else
+ controller->node = cnode;
return soft;
}
* the caller.
*/
static void *
-tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft)
+tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
{
struct tioca_common *tioca_common;
struct tioca_kernel *tioca_kern;
__FUNCTION__, SGI_TIOCA_ERROR,
(int)tioca_common->ca_common.bs_persist_busnum);
+ /* Setup locality information */
+ controller->node = tioca_kern->ca_closest_node;
return tioca_common;
}
#define pcibr_unlock(pcibus_info, flag) spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag)
extern int pcibr_init_provider(void);
-extern void *pcibr_bus_fixup(struct pcibus_bussoft *);
+extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *);
extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t);
extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t);
extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
struct xwidget_info *bs_xwidget_info;
};
+struct pci_controller;
/*
* SN pci bus indirection
*/
dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t);
dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
void (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
- void * (*bus_fixup)(struct pcibus_bussoft *);
+ void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
};
extern struct sn_pcibus_provider *sn_pci_provider[];