Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pseries/iommu: Remove DDW on kexec

pseries/iommu: remove DDW on kexec

We currently insert a property in the device-tree when we successfully
configure DDW for a given slot. This was meant to be an optimization to
speed up kexec/kdump, so that we don't need to make the RTAS calls again
to re-configured DDW in the new kernel.

However, we end up tripping a plpar_tce_stuff failure on kexec/kdump
because we unconditionally parse the ibm,dma-window property for the
node at bus/dev setup time. This property contains the 32-bit DMA window
LIOBN, which is distinct from the DDW window's. We pass that LIOBN (via
iommu_table_init -> iommu_table_clear -> tce_free ->
tce_freemulti_pSeriesLP) to plpar_tce_stuff, which fails because that
32-bit window is no longer present after
25ebc45b93452d0bc60271f178237123c4b26808 ("powerpc/pseries/iommu: remove
default window before attempting DDW manipulation").

I believe the simplest, easiest-to-maintain fix is to just change our
initcall to, rather than detecting and updating the new kernel's DDW
knowledge, just remove all DDW configurations. When the drivers
re-initialize, we will set everything back up as it was before.

Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Nishanth Aravamudan and committed by
Benjamin Herrenschmidt
14b6f00f a1dabade

+50 -38
+50 -38
arch/powerpc/platforms/pseries/iommu.c
··· 787 787 return dma_addr; 788 788 } 789 789 790 + static void __restore_default_window(struct eeh_dev *edev, 791 + u32 ddw_restore_token) 792 + { 793 + u32 cfg_addr; 794 + u64 buid; 795 + int ret; 796 + 797 + /* 798 + * Get the config address and phb buid of the PE window. 799 + * Rely on eeh to retrieve this for us. 800 + * Retrieve them from the pci device, not the node with the 801 + * dma-window property 802 + */ 803 + cfg_addr = edev->config_addr; 804 + if (edev->pe_config_addr) 805 + cfg_addr = edev->pe_config_addr; 806 + buid = edev->phb->buid; 807 + 808 + do { 809 + ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr, 810 + BUID_HI(buid), BUID_LO(buid)); 811 + } while (rtas_busy_delay(ret)); 812 + pr_info("ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n", 813 + ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); 814 + } 815 + 790 816 static int find_existing_ddw_windows(void) 791 817 { 792 - int len; 793 818 struct device_node *pdn; 794 - struct direct_window *window; 795 819 const struct dynamic_dma_window_prop *direct64; 820 + const u32 *ddw_extensions; 796 821 797 822 if (!firmware_has_feature(FW_FEATURE_LPAR)) 798 823 return 0; 799 824 800 825 for_each_node_with_property(pdn, DIRECT64_PROPNAME) { 801 - direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); 826 + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, NULL); 802 827 if (!direct64) 803 828 continue; 804 829 805 - window = kzalloc(sizeof(*window), GFP_KERNEL); 806 - if (!window || len < sizeof(struct dynamic_dma_window_prop)) { 807 - kfree(window); 808 - remove_ddw(pdn); 809 - continue; 810 - } 830 + /* 831 + * We need to ensure the IOMMU table is active when we 832 + * return from the IOMMU setup so that the common code 833 + * can clear the table or find the holes. To that end, 834 + * first, remove any existing DDW configuration. 835 + */ 836 + remove_ddw(pdn); 811 837 812 - window->device = pdn; 813 - window->prop = direct64; 814 - spin_lock(&direct_window_list_lock); 815 - list_add(&window->list, &direct_window_list); 816 - spin_unlock(&direct_window_list_lock); 838 + /* 839 + * Second, if we are running on a new enough level of 840 + * firmware where the restore API is present, use it to 841 + * restore the 32-bit window, which was removed in 842 + * create_ddw. 843 + * If the API is not present, then create_ddw couldn't 844 + * have removed the 32-bit window in the first place, so 845 + * removing the DDW configuration should be sufficient. 846 + */ 847 + ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", 848 + NULL); 849 + if (ddw_extensions && ddw_extensions[0] > 0) 850 + __restore_default_window(of_node_to_eeh_dev(pdn), 851 + ddw_extensions[1]); 817 852 } 818 853 819 854 return 0; ··· 921 886 static void restore_default_window(struct pci_dev *dev, 922 887 u32 ddw_restore_token) 923 888 { 924 - struct eeh_dev *edev; 925 - u32 cfg_addr; 926 - u64 buid; 927 - int ret; 928 - 929 - /* 930 - * Get the config address and phb buid of the PE window. 931 - * Rely on eeh to retrieve this for us. 932 - * Retrieve them from the pci device, not the node with the 933 - * dma-window property 934 - */ 935 - edev = pci_dev_to_eeh_dev(dev); 936 - cfg_addr = edev->config_addr; 937 - if (edev->pe_config_addr) 938 - cfg_addr = edev->pe_config_addr; 939 - buid = edev->phb->buid; 940 - 941 - do { 942 - ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr, 943 - BUID_HI(buid), BUID_LO(buid)); 944 - } while (rtas_busy_delay(ret)); 945 - dev_info(&dev->dev, 946 - "ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n", 947 - ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); 889 + __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token); 948 890 } 949 891 950 892 /*