powerpc fixes for 6.8 #5

- Fix IOMMU table initialisation when doing kdump over SR-IOV.
 
  - Fix incorrect RTAS function name for resetting TCE tables.
 
  - Fix fpu_signal selftest failures since a recent change.
 
 Thanks to: Gaurav Batra, Nathan Lynch.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAmXkauwTHG1wZUBlbGxl
 cm1hbi5pZC5hdQAKCRBR6+o8yOGlgLTSD/4/boNe5MtrGgk6RtxnyWJv/p9KCMcC
 rRTa5pSR6HFVK3m89V17O0onL8aKyIljO5P3rDS8X4SUhr41Z9b9/FUoHv277E7a
 f7hgX4/901DYiMLJEt9jkfmM30IxTYkPmlft0Uus/NiesNdTcdQOO4UScSysnZac
 0HM1POp32KSC2HQRc/i+WIshRnaZcC+f0PPTU/qfS/u7/pwK4eekWdayLNvvvSvH
 TfjV5Hu4JVDF7hBLsoY4PdqVQGVD3t3d1D5+UrhHuYzPx+Afc8rIDfJx/+o339W6
 ZTXrRPOfiticfhHQvMX1AgsYr3/A0BbZj/wCvv+pPsCjZPfox9XsW6CgiMKUxVDf
 ifrBhvNx0fICMf+cEjH9q2dcGwMba7dZTX5HBlSXR4xLeNitUI8pt6bYCaqw7UjH
 ohwl9aAI7Rl1hcW6qBaviKaIDqhbmj3N4B4ZdgMAKj2gnovbF9gUSG3ARLwEjsqB
 qfd0c3x6UUThj4vYfGC/iI1z1LCXC8myqof6EGArLTc13R9vFv+ycx5FwERvAxtY
 ALNBh6LMIkKI5z8ZrGWULoXHoS2QrE1SXpQ5ooH2g9n+vLibd37JdJNcrEMf/TJZ
 PluhRCJcEWkw98aUSzIoRFIFpZ2wMg/uzg3KZePhRus3GhgttTqFTbrcKHhyONBO
 pq/EDB8FizZ9/A==
 =MSDF
 -----END PGP SIGNATURE-----

Merge tag 'powerpc-6.8-5' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Michael Ellerman:

 - Fix IOMMU table initialisation when doing kdump over SR-IOV

 - Fix incorrect RTAS function name for resetting TCE tables

 - Fix fpu_signal selftest failures since a recent change

Thanks to Gaurav Batra and Nathan Lynch.

* tag 'powerpc-6.8-5' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  selftests/powerpc: Fix fpu_signal failures
  powerpc/rtas: use correct function name for resetting TCE tables
  powerpc/pseries/iommu: IOMMU table is not initialized for kdump over SR-IOV
This commit is contained in:
Linus Torvalds 2024-03-03 09:47:19 -08:00
commit e4f7900095
4 changed files with 120 additions and 65 deletions

View File

@ -69,7 +69,7 @@ enum rtas_function_index {
RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE,
RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2,
RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW,
RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS,
RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW,
RTAS_FNIDX__IBM_SCAN_LOG_DUMP,
RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR,
RTAS_FNIDX__IBM_SET_EEH_OPTION,
@ -164,7 +164,7 @@ typedef struct {
#define RTAS_FN_IBM_READ_SLOT_RESET_STATE rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE)
#define RTAS_FN_IBM_READ_SLOT_RESET_STATE2 rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2)
#define RTAS_FN_IBM_REMOVE_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW)
#define RTAS_FN_IBM_RESET_PE_DMA_WINDOWS rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS)
#define RTAS_FN_IBM_RESET_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW)
#define RTAS_FN_IBM_SCAN_LOG_DUMP rtas_fn_handle(RTAS_FNIDX__IBM_SCAN_LOG_DUMP)
#define RTAS_FN_IBM_SET_DYNAMIC_INDICATOR rtas_fn_handle(RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR)
#define RTAS_FN_IBM_SET_EEH_OPTION rtas_fn_handle(RTAS_FNIDX__IBM_SET_EEH_OPTION)

View File

@ -375,8 +375,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = {
[RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW] = {
.name = "ibm,remove-pe-dma-window",
},
[RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS] = {
.name = "ibm,reset-pe-dma-windows",
[RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW] = {
/*
* Note: PAPR+ v2.13 7.3.31.4.1 spells this as
* "ibm,reset-pe-dma-windows" (plural), but RTAS
* implementations use the singular form in practice.
*/
.name = "ibm,reset-pe-dma-window",
},
[RTAS_FNIDX__IBM_SCAN_LOG_DUMP] = {
.name = "ibm,scan-log-dump",

View File

@ -574,29 +574,6 @@ static void iommu_table_setparms(struct pci_controller *phb,
struct iommu_table_ops iommu_table_lpar_multi_ops;
/*
* iommu_table_setparms_lpar
*
* Function: On pSeries LPAR systems, return TCE table info, given a pci bus.
*/
static void iommu_table_setparms_lpar(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl,
struct iommu_table_group *table_group,
const __be32 *dma_window)
{
unsigned long offset, size, liobn;
of_parse_dma_window(dn, dma_window, &liobn, &offset, &size);
iommu_table_setparms_common(tbl, phb->bus->number, liobn, offset, size, IOMMU_PAGE_SHIFT_4K, NULL,
&iommu_table_lpar_multi_ops);
table_group->tce32_start = offset;
table_group->tce32_size = size;
}
struct iommu_table_ops iommu_table_pseries_ops = {
.set = tce_build_pSeries,
.clear = tce_free_pSeries,
@ -724,26 +701,71 @@ struct iommu_table_ops iommu_table_lpar_multi_ops = {
* dynamic 64bit DMA window, walking up the device tree.
*/
static struct device_node *pci_dma_find(struct device_node *dn,
const __be32 **dma_window)
struct dynamic_dma_window_prop *prop)
{
const __be32 *dw = NULL;
const __be32 *default_prop = NULL;
const __be32 *ddw_prop = NULL;
struct device_node *rdn = NULL;
bool default_win = false, ddw_win = false;
for ( ; dn && PCI_DN(dn); dn = dn->parent) {
dw = of_get_property(dn, "ibm,dma-window", NULL);
if (dw) {
if (dma_window)
*dma_window = dw;
return dn;
default_prop = of_get_property(dn, "ibm,dma-window", NULL);
if (default_prop) {
rdn = dn;
default_win = true;
}
dw = of_get_property(dn, DIRECT64_PROPNAME, NULL);
if (dw)
return dn;
dw = of_get_property(dn, DMA64_PROPNAME, NULL);
if (dw)
return dn;
ddw_prop = of_get_property(dn, DIRECT64_PROPNAME, NULL);
if (ddw_prop) {
rdn = dn;
ddw_win = true;
break;
}
ddw_prop = of_get_property(dn, DMA64_PROPNAME, NULL);
if (ddw_prop) {
rdn = dn;
ddw_win = true;
break;
}
/* At least found default window, which is the case for normal boot */
if (default_win)
break;
}
return NULL;
/* For PCI devices there will always be a DMA window, either on the device
* or parent bus
*/
WARN_ON(!(default_win | ddw_win));
/* caller doesn't want to get DMA window property */
if (!prop)
return rdn;
/* parse DMA window property. During normal system boot, only default
* DMA window is passed in OF. But, for kdump, a dedicated adapter might
* have both default and DDW in FDT. In this scenario, DDW takes precedence
* over default window.
*/
if (ddw_win) {
struct dynamic_dma_window_prop *p;
p = (struct dynamic_dma_window_prop *)ddw_prop;
prop->liobn = p->liobn;
prop->dma_base = p->dma_base;
prop->tce_shift = p->tce_shift;
prop->window_shift = p->window_shift;
} else if (default_win) {
unsigned long offset, size, liobn;
of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size);
prop->liobn = cpu_to_be32((u32)liobn);
prop->dma_base = cpu_to_be64(offset);
prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K);
prop->window_shift = cpu_to_be32(order_base_2(size));
}
return rdn;
}
static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
@ -751,17 +773,20 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
struct iommu_table *tbl;
struct device_node *dn, *pdn;
struct pci_dn *ppci;
const __be32 *dma_window = NULL;
struct dynamic_dma_window_prop prop;
dn = pci_bus_to_OF_node(bus);
pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %pOF\n",
dn);
pdn = pci_dma_find(dn, &dma_window);
pdn = pci_dma_find(dn, &prop);
if (dma_window == NULL)
pr_debug(" no ibm,dma-window property !\n");
/* In PPC architecture, there will always be DMA window on bus or one of the
* parent bus. During reboot, there will be ibm,dma-window property to
* define DMA window. For kdump, there will at least be default window or DDW
* or both.
*/
ppci = PCI_DN(pdn);
@ -771,13 +796,24 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
if (!ppci->table_group) {
ppci->table_group = iommu_pseries_alloc_group(ppci->phb->node);
tbl = ppci->table_group->tables[0];
if (dma_window) {
iommu_table_setparms_lpar(ppci->phb, pdn, tbl,
ppci->table_group, dma_window);
if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
panic("Failed to initialize iommu table");
}
iommu_table_setparms_common(tbl, ppci->phb->bus->number,
be32_to_cpu(prop.liobn),
be64_to_cpu(prop.dma_base),
1ULL << be32_to_cpu(prop.window_shift),
be32_to_cpu(prop.tce_shift), NULL,
&iommu_table_lpar_multi_ops);
/* Only for normal boot with default window. Doesn't matter even
* if we set these with DDW which is 64bit during kdump, since
* these will not be used during kdump.
*/
ppci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
ppci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);
if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
panic("Failed to initialize iommu table");
iommu_register_group(ppci->table_group,
pci_domain_nr(bus), 0);
pr_debug(" created table: %p\n", ppci->table_group);
@ -968,6 +1004,12 @@ static void find_existing_ddw_windows_named(const char *name)
continue;
}
/* If at the time of system initialization, there are DDWs in OF,
* it means this is during kexec. DDW could be direct or dynamic.
* We will just mark DDWs as "dynamic" since this is kdump path,
* no need to worry about perforance. ddw_list_new_entry() will
* set window->direct = false.
*/
window = ddw_list_new_entry(pdn, dma64);
if (!window) {
of_node_put(pdn);
@ -1524,8 +1566,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
struct iommu_table *tbl;
const __be32 *dma_window = NULL;
struct pci_dn *pci;
struct dynamic_dma_window_prop prop;
pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
@ -1538,7 +1580,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
dn = pci_device_to_OF_node(dev);
pr_debug(" node is %pOF\n", dn);
pdn = pci_dma_find(dn, &dma_window);
pdn = pci_dma_find(dn, &prop);
if (!pdn || !PCI_DN(pdn)) {
printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: "
"no DMA window found for pci dev=%s dn=%pOF\n",
@ -1551,8 +1593,20 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
if (!pci->table_group) {
pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
tbl = pci->table_group->tables[0];
iommu_table_setparms_lpar(pci->phb, pdn, tbl,
pci->table_group, dma_window);
iommu_table_setparms_common(tbl, pci->phb->bus->number,
be32_to_cpu(prop.liobn),
be64_to_cpu(prop.dma_base),
1ULL << be32_to_cpu(prop.window_shift),
be32_to_cpu(prop.tce_shift), NULL,
&iommu_table_lpar_multi_ops);
/* Only for normal boot with default window. Doesn't matter even
* if we set these with DDW which is 64bit during kdump, since
* these will not be used during kdump.
*/
pci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
pci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);
iommu_init_table(tbl, pci->phb->node, 0, 0);
iommu_register_group(pci->table_group,

View File

@ -18,6 +18,7 @@
#include <pthread.h>
#include "utils.h"
#include "fpu.h"
/* Number of times each thread should receive the signal */
#define ITERATIONS 10
@ -27,9 +28,7 @@
*/
#define THREAD_FACTOR 8
__thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
2.1};
__thread double darray[32];
bool bad_context;
int threads_starting;
@ -43,9 +42,9 @@ void signal_fpu_sig(int sig, siginfo_t *info, void *context)
ucontext_t *uc = context;
mcontext_t *mc = &uc->uc_mcontext;
/* Only the non volatiles were loaded up */
for (i = 14; i < 32; i++) {
if (mc->fp_regs[i] != darray[i - 14]) {
// Don't check f30/f31, they're used as scratches in check_all_fprs()
for (i = 0; i < 30; i++) {
if (mc->fp_regs[i] != darray[i]) {
bad_context = true;
break;
}
@ -54,7 +53,6 @@ void signal_fpu_sig(int sig, siginfo_t *info, void *context)
void *signal_fpu_c(void *p)
{
int i;
long rc;
struct sigaction act;
act.sa_sigaction = signal_fpu_sig;
@ -64,9 +62,7 @@ void *signal_fpu_c(void *p)
return p;
srand(pthread_self());
for (i = 0; i < 21; i++)
darray[i] = rand();
randomise_darray(darray, ARRAY_SIZE(darray));
rc = preempt_fpu(darray, &threads_starting, &running);
return (void *) rc;