~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/pseries/pmem.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 /*
  4  * Handles hot and cold plug of persistent memory regions on pseries.
  5  */
  6 
  7 #define pr_fmt(fmt)     "pseries-pmem: " fmt
  8 
  9 #include <linux/kernel.h>
 10 #include <linux/interrupt.h>
 11 #include <linux/delay.h>
 12 #include <linux/sched.h>        /* for idle_task_exit */
 13 #include <linux/sched/hotplug.h>
 14 #include <linux/cpu.h>
 15 #include <linux/of.h>
 16 #include <linux/of_platform.h>
 17 #include <linux/slab.h>
 18 #include <asm/rtas.h>
 19 #include <asm/firmware.h>
 20 #include <asm/machdep.h>
 21 #include <asm/vdso_datapage.h>
 22 #include <asm/plpar_wrappers.h>
 23 #include <asm/topology.h>
 24 
 25 #include "pseries.h"
 26 
 27 static struct device_node *pmem_node;
 28 
 29 static ssize_t pmem_drc_add_node(u32 drc_index)
 30 {
 31         struct device_node *dn;
 32         int rc;
 33 
 34         pr_debug("Attempting to add pmem node, drc index: %x\n", drc_index);
 35 
 36         rc = dlpar_acquire_drc(drc_index);
 37         if (rc) {
 38                 pr_err("Failed to acquire DRC, rc: %d, drc index: %x\n",
 39                         rc, drc_index);
 40                 return -EINVAL;
 41         }
 42 
 43         dn = dlpar_configure_connector(cpu_to_be32(drc_index), pmem_node);
 44         if (!dn) {
 45                 pr_err("configure-connector failed for drc %x\n", drc_index);
 46                 dlpar_release_drc(drc_index);
 47                 return -EINVAL;
 48         }
 49 
 50         /* NB: The of reconfig notifier creates platform device from the node */
 51         rc = dlpar_attach_node(dn, pmem_node);
 52         if (rc) {
 53                 pr_err("Failed to attach node %pOF, rc: %d, drc index: %x\n",
 54                         dn, rc, drc_index);
 55 
 56                 if (dlpar_release_drc(drc_index))
 57                         dlpar_free_cc_nodes(dn);
 58 
 59                 return rc;
 60         }
 61 
 62         pr_info("Successfully added %pOF, drc index: %x\n", dn, drc_index);
 63 
 64         return 0;
 65 }
 66 
 67 static ssize_t pmem_drc_remove_node(u32 drc_index)
 68 {
 69         struct device_node *dn;
 70         uint32_t index;
 71         int rc;
 72 
 73         for_each_child_of_node(pmem_node, dn) {
 74                 if (of_property_read_u32(dn, "ibm,my-drc-index", &index))
 75                         continue;
 76                 if (index == drc_index)
 77                         break;
 78         }
 79 
 80         if (!dn) {
 81                 pr_err("Attempting to remove unused DRC index %x\n", drc_index);
 82                 return -ENODEV;
 83         }
 84 
 85         pr_debug("Attempting to remove %pOF, drc index: %x\n", dn, drc_index);
 86 
 87         /* * NB: tears down the ibm,pmemory device as a side-effect */
 88         rc = dlpar_detach_node(dn);
 89         if (rc)
 90                 return rc;
 91 
 92         rc = dlpar_release_drc(drc_index);
 93         if (rc) {
 94                 pr_err("Failed to release drc (%x) for CPU %pOFn, rc: %d\n",
 95                         drc_index, dn, rc);
 96                 dlpar_attach_node(dn, pmem_node);
 97                 return rc;
 98         }
 99 
100         pr_info("Successfully removed PMEM with drc index: %x\n", drc_index);
101 
102         return 0;
103 }
104 
105 int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog)
106 {
107         u32 drc_index;
108         int rc;
109 
110         /* slim chance, but we might get a hotplug event while booting */
111         if (!pmem_node)
112                 pmem_node = of_find_node_by_type(NULL, "ibm,persistent-memory");
113         if (!pmem_node) {
114                 pr_err("Hotplug event for a pmem device, but none exists\n");
115                 return -ENODEV;
116         }
117 
118         if (hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX) {
119                 pr_err("Unsupported hotplug event type %d\n",
120                                 hp_elog->id_type);
121                 return -EINVAL;
122         }
123 
124         drc_index = hp_elog->_drc_u.drc_index;
125 
126         lock_device_hotplug();
127 
128         if (hp_elog->action == PSERIES_HP_ELOG_ACTION_ADD) {
129                 rc = pmem_drc_add_node(drc_index);
130         } else if (hp_elog->action == PSERIES_HP_ELOG_ACTION_REMOVE) {
131                 rc = pmem_drc_remove_node(drc_index);
132         } else {
133                 pr_err("Unsupported hotplug action (%d)\n", hp_elog->action);
134                 rc = -EINVAL;
135         }
136 
137         unlock_device_hotplug();
138         return rc;
139 }
140 
141 static const struct of_device_id drc_pmem_match[] = {
142         { .type = "ibm,persistent-memory", },
143         {}
144 };
145 
146 static int pseries_pmem_init(void)
147 {
148         /*
149          * Only supported on POWER8 and above.
150          */
151         if (!cpu_has_feature(CPU_FTR_ARCH_207S))
152                 return 0;
153 
154         pmem_node = of_find_node_by_type(NULL, "ibm,persistent-memory");
155         if (!pmem_node)
156                 return 0;
157 
158         /*
159          * The generic OF bus probe/populate handles creating platform devices
160          * from the child (ibm,pmemory) nodes. The generic code registers an of
161          * reconfig notifier to handle the hot-add/remove cases too.
162          */
163         of_platform_bus_probe(pmem_node, drc_pmem_match, NULL);
164 
165         return 0;
166 }
167 machine_arch_initcall(pseries, pseries_pmem_init);
168 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php