ibm_nmi_register_token = rtas_function_token(RTAS_FN_IBM_NMI_REGISTER); if (ibm_nmi_register_token == RTAS_UNKNOWN_SERVICE) return;
ibm_nmi_interlock_token = rtas_function_token(RTAS_FN_IBM_NMI_INTERLOCK); if (WARN_ON(ibm_nmi_interlock_token == RTAS_UNKNOWN_SERVICE)) return;
/* If the kernel's not linked at zero we point the firmware at low
* addresses anyway, and use a trampoline to get to the real code. */
system_reset_addr = __pa(system_reset_fwnmi) - PHYSICAL_START;
machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START;
#ifdef CONFIG_PPC_64S_HASH_MMU if (!radix_enabled()) { /* Allocate per cpu area to save old slb contents during MCE */
size = sizeof(struct slb_entry) * mmu_slb_size * nr_cpus;
slb_ptr = memblock_alloc_try_nid_raw(size, sizeof(struct slb_entry), MEMBLOCK_LOW_LIMIT,
ppc64_rma_size, NUMA_NO_NODE); if (!slb_ptr)
panic("Failed to allocate %zu bytes below %pa for slb area\n",
size, &ppc64_rma_size);
for_each_node_by_type(np, "interrupt-controller") { if (of_device_is_compatible(np, "chrp,iic")) {
found = np; break;
}
}
if (found == NULL) {
printk(KERN_DEBUG "pic: no ISA interrupt controller\n"); return;
}
cascade = irq_of_parse_and_map(found, 0); if (!cascade) {
printk(KERN_ERR "pic: failed to map cascade interrupt"); return;
}
pr_debug("pic: cascade mapped to irq %d\n", cascade);
for (old = of_node_get(found); old != NULL ; old = np) {
np = of_get_parent(old);
of_node_put(old); if (np == NULL) break; if (!of_node_name_eq(np, "pci")) continue;
addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL); if (addrp == NULL) continue;
naddr = of_n_addr_cells(np);
intack = addrp[naddr-1]; if (naddr > 1)
intack |= ((unsignedlong)addrp[naddr-2]) << 32;
} if (intack)
printk(KERN_DEBUG "pic: PCI 8259 intack at 0x%016lx\n", intack);
i8259_init(found, intack);
of_node_put(found);
irq_set_chained_handler(cascade, pseries_8259_cascade);
}
staticvoid __init pseries_init_irq(void)
{ /* Try using a XIVE if available, otherwise use a XICS */ if (!xive_spapr_init()) {
xics_init();
pseries_setup_i8259_cascade();
}
}
void pseries_disable_reloc_on_exc(void)
{ long rc;
while (1) {
rc = disable_reloc_on_exceptions(); if (!H_IS_LONG_BUSY(rc)) break;
mdelay(get_longbusy_msecs(rc));
} if (rc == H_SUCCESS)
pseries_reloc_on_exception_enabled = false; else
pr_warn("Warning: Failed to disable relocation on exceptions: %ld\n",
rc);
}
EXPORT_SYMBOL(pseries_disable_reloc_on_exc);
#ifdef __LITTLE_ENDIAN__ void pseries_big_endian_exceptions(void)
{ long rc;
while (1) {
rc = enable_big_endian_exceptions(); if (!H_IS_LONG_BUSY(rc)) break;
mdelay(get_longbusy_msecs(rc));
}
/* *Atthispointitisunlikelypanic()willgetanything *outtotheuser,sincethisiscalledverylateinkexec *butatleastthiswillstopusfromcontinuingonfurther *andcreatinganevenmoredifficulttodebugsituation. * *Thereisaknownproblemwhenkdump'ing,ifcpusareoffline *theabovecallwillfail.Ratherthanpanickingagain,keep *goingandhopethekdumpkernelisalsolittleendian,which *itusuallyis.
*/ if (rc && !kdump_in_progress())
panic("Could not enable big endian exceptions");
}
void __init pseries_little_endian_exceptions(void)
{ long rc;
while (1) {
rc = enable_little_endian_exceptions(); if (!H_IS_LONG_BUSY(rc)) break;
mdelay(get_longbusy_msecs(rc));
} if (rc) {
ppc_md.progress("H_SET_MODE LE exception fail", 0);
panic("Could not enable little endian exceptions");
}
} #endif
#ifdef CONFIG_PCI_IOV enum rtas_iov_fw_value_map {
NUM_RES_PROPERTY = 0, /* Number of Resources */
LOW_INT = 1, /* Lowest 32 bits of Address */
START_OF_ENTRIES = 2, /* Always start of entry */
APERTURE_PROPERTY = 2, /* Start of entry+ to Aperture Size */
WDW_SIZE_PROPERTY = 4, /* Start of entry+ to Window Size */
NEXT_ENTRY = 7/* Go to next entry on array */
};
enum get_iov_fw_value_index {
BAR_ADDRS = 1, /* Get Bar Address */
APERTURE_SIZE = 2, /* Get Aperture Size */
WDW_SIZE = 3/* Get Window Size */
};
static resource_size_t pseries_get_iov_fw_value(struct pci_dev *dev, int resno, enum get_iov_fw_value_index value)
{ constint *indexes; struct device_node *dn = pci_device_to_OF_node(dev); int i, num_res, ret = 0;
indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL); if (!indexes) return0;
/* *FirstelementinthearrayisthenumberofBars *returned.Searchthroughthelisttofindthematching *bar
*/
num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1); if (resno >= num_res) return0; /* or an error */
i = START_OF_ENTRIES + NEXT_ENTRY * resno; switch (value) { case BAR_ADDRS:
ret = of_read_number(&indexes[i], 2); break; case APERTURE_SIZE:
ret = of_read_number(&indexes[i + APERTURE_PROPERTY], 2); break; case WDW_SIZE:
ret = of_read_number(&indexes[i + WDW_SIZE_PROPERTY], 2); break;
}
return ret;
}
staticvoid of_pci_set_vf_bar_size(struct pci_dev *dev, constint *indexes)
{ struct resource *res;
resource_size_t base, size; int i, r, num_res;
num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
num_res = min_t(int, num_res, PCI_SRIOV_NUM_BARS); for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
i += NEXT_ENTRY, r++) {
res = &dev->resource[r + PCI_IOV_RESOURCES];
base = of_read_number(&indexes[i], 2);
size = of_read_number(&indexes[i + APERTURE_PROPERTY], 2);
res->flags = pci_parse_of_flags(of_read_number
(&indexes[i + LOW_INT], 1), 0);
res->flags |= (IORESOURCE_MEM_64 | IORESOURCE_PCI_FIXED);
res->name = pci_name(dev);
res->start = base;
res->end = base + size - 1;
}
}
staticvoid of_pci_parse_iov_addrs(struct pci_dev *dev, constint *indexes)
{ struct resource *res, *root, *conflict;
resource_size_t base, size; int i, r, num_res;
/* *FirstelementinthearrayisthenumberofBars *returned.Searchthroughthelisttofindthematching *barsassignthemfromfirmwareintoresourcesstructure.
*/
num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1); for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
i += NEXT_ENTRY, r++) {
res = &dev->resource[r + PCI_IOV_RESOURCES];
base = of_read_number(&indexes[i], 2);
size = of_read_number(&indexes[i + WDW_SIZE_PROPERTY], 2);
res->name = pci_name(dev);
res->start = base;
res->end = base + size - 1;
root = &iomem_resource;
dev_dbg(&dev->dev, "pSeries IOV BAR %d: trying firmware assignment %pR\n",
r + PCI_IOV_RESOURCES, res);
conflict = request_resource_conflict(root, res); if (conflict) {
dev_info(&dev->dev, "BAR %d: %pR conflicts with %s %pR\n",
r + PCI_IOV_RESOURCES, res,
conflict->name, conflict);
res->flags |= IORESOURCE_UNSET;
}
}
}
staticvoid pseries_disable_sriov_resources(struct pci_dev *pdev)
{ int i;
pci_warn(pdev, "No hypervisor support for SR-IOV on this device, IOV BARs disabled.\n"); for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
pdev->resource[i + PCI_IOV_RESOURCES].flags = 0;
}
/*Firmware must support open sriov otherwise dont configure*/
indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL); if (indexes)
of_pci_set_vf_bar_size(pdev, indexes); else
pseries_disable_sriov_resources(pdev);
}
if (!pdev->is_physfn) return; /*Firmware must support open sriov otherwise don't configure*/
indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL); if (indexes)
of_pci_parse_iov_addrs(pdev, indexes); else
pseries_disable_sriov_resources(pdev);
}
/*Firmware must support open sriov otherwise report regular alignment*/
reg = of_get_property(dn, "ibm,is-open-sriov-pf", NULL); if (!reg) return pci_iov_resource_size(pdev, resno);
/* Discover PIC type and setup ppc_md accordingly */
smp_init_pseries();
// Setup CPU hotplug callbacks
pseries_cpu_hotplug_init();
if (radix_enabled() && !mmu_has_feature(MMU_FTR_GTSE)) if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE))
panic("BUG: Radix support requires either GTSE or RPT_INVALIDATE\n");
/* openpic global configuration register (64-bit format). */ /* openpic Interrupt Source Unit pointer (64-bit format). */ /* python0 facility area (mmio) (64-bit format) REAL address. */
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000;
fwnmi_init();
pseries_setup_security_mitigations(); if (!radix_enabled())
pseries_lpar_read_hblkrm_characteristics();
/* By default, only probe PCI (can be overridden by rtas_pci) */
pci_add_flags(PCI_PROBE_ONLY);
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
of_reconfig_notifier_register(&pci_dn_reconfig_nb);
pSeries_nvram_init();
if (firmware_has_feature(FW_FEATURE_LPAR)) {
vpa_init(boot_cpuid);
if (lppaca_shared_proc()) {
static_branch_enable(&shared_processor);
pv_spinlocks_init(); #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
static_key_slow_inc(¶virt_steal_enabled); if (steal_acc)
static_key_slow_inc(¶virt_steal_rq_enabled); #endif
}
staticint pseries_set_xdabr(unsignedlong dabr, unsignedlong dabrx)
{ /* Have to set at least one bit in the DABRX according to PAPR */ if (dabrx == 0 && dabr == 0)
dabrx = DABRX_USER; /* PAPR says we can only set kernel and user bits */
dabrx &= DABRX_KERNEL | DABRX_USER;
if (papr_sysparm_get(PAPR_SYSPARM_COOP_MEM_OVERCOMMIT_ATTRS, &buf)) {
pr_debug("CMO not available\n");
pr_debug(" <- fw_cmo_feature_init()\n"); return;
}
end = &buf.val[CMO_MAXLENGTH];
ptr = &buf.val[0];
key = value = ptr;
while (*ptr && (ptr <= end)) { /* Separate the key and value by replacing '=' with '\0' and *pointthevalueatthestringafterthe'='
*/ if (ptr[0] == '=') {
ptr[0] = '\0';
value = ptr + 1;
} elseif (ptr[0] == '\0' || ptr[0] == ',') { /* Terminate the string containing the key/value pair */
ptr[0] = '\0';
if (key == value) {
pr_debug("Malformed key/value pair\n"); /* Never found a '=', end processing */ break;
}
/* Page size is returned as the power of 2 of the page size, *converttothepagesizeinbytesbeforereturning
*/
CMO_PageSize = 1 << page_order;
pr_debug("CMO_PageSize = %lu\n", CMO_PageSize);
/* Cell blades firmware claims to be chrp while it's not. Until this *isfixed,weneedtoavoidthosehere.
*/ if (of_machine_is_compatible("IBM,CPBW-1.0") ||
of_machine_is_compatible("IBM,CBEA")) return0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.