1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * OPAL Runtime Diagnostics interface driver 4 * Supported on POWERNV platform 5 * 6 * Copyright IBM Corporation 2015 7 */ 8 9 #define pr_fmt(fmt) "opal-prd: " fmt 10 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/platform_device.h> 14 #include <linux/miscdevice.h> 15 #include <linux/fs.h> 16 #include <linux/of.h> 17 #include <linux/of_address.h> 18 #include <linux/poll.h> 19 #include <linux/mm.h> 20 #include <linux/slab.h> 21 #include <asm/opal-prd.h> 22 #include <asm/opal.h> 23 #include <asm/io.h> 24 #include <linux/uaccess.h> 25 26 27 struct opal_prd_msg { 28 union { 29 struct opal_prd_msg_header header; 30 DECLARE_FLEX_ARRAY(u8, data); 31 }; 32 }; 33 34 /* 35 * The msg member must be at the end of the struct, as it's followed by the 36 * message data. 37 */ 38 struct opal_prd_msg_queue_item { 39 struct list_head list; 40 struct opal_prd_msg msg; 41 }; 42 43 static struct device_node *prd_node; 44 static LIST_HEAD(opal_prd_msg_queue); 45 static DEFINE_SPINLOCK(opal_prd_msg_queue_lock); 46 static DECLARE_WAIT_QUEUE_HEAD(opal_prd_msg_wait); 47 static atomic_t prd_usage; 48 49 static bool opal_prd_range_is_valid(uint64_t addr, uint64_t size) 50 { 51 struct device_node *parent, *node; 52 bool found; 53 54 if (addr + size < addr) 55 return false; 56 57 parent = of_find_node_by_path("/reserved-memory"); 58 if (!parent) 59 return false; 60 61 found = false; 62 63 for_each_child_of_node(parent, node) { 64 uint64_t range_addr, range_size, range_end; 65 const __be32 *addrp; 66 const char *label; 67 68 addrp = of_get_address(node, 0, &range_size, NULL); 69 70 range_addr = of_read_number(addrp, 2); 71 range_end = range_addr + range_size; 72 73 label = of_get_property(node, "ibm,prd-label", NULL); 74 75 /* PRD ranges need a label */ 76 if (!label) 77 continue; 78 79 if (range_end <= range_addr) 80 continue; 81 82 if (addr >= range_addr && addr + size <= range_end) { 83 found = true; 84 of_node_put(node); 85 break; 86 } 87 } 88 89 of_node_put(parent); 90 return found; 91 } 92 93 static int opal_prd_open(struct inode *inode, struct file *file) 94 { 95 /* 96 * Prevent multiple (separate) processes from concurrent interactions 97 * with the FW PRD channel 98 */ 99 if (atomic_xchg(&prd_usage, 1) == 1) 100 return -EBUSY; 101 102 return 0; 103 } 104 105 /* 106 * opal_prd_mmap - maps firmware-provided ranges into userspace 107 * @file: file structure for the device 108 * @vma: VMA to map the registers into 109 */ 110 111 static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma) 112 { 113 size_t addr, size; 114 pgprot_t page_prot; 115 116 pr_devel("opal_prd_mmap(0x%016lx, 0x%016lx, 0x%lx, 0x%lx)\n", 117 vma->vm_start, vma->vm_end, vma->vm_pgoff, 118 vma->vm_flags); 119 120 addr = vma->vm_pgoff << PAGE_SHIFT; 121 size = vma->vm_end - vma->vm_start; 122 123 /* ensure we're mapping within one of the allowable ranges */ 124 if (!opal_prd_range_is_valid(addr, size)) 125 return -EINVAL; 126 127 page_prot = phys_mem_access_prot(file, vma->vm_pgoff, 128 size, vma->vm_page_prot); 129 130 return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, 131 page_prot); 132 } 133 134 static bool opal_msg_queue_empty(void) 135 { 136 unsigned long flags; 137 bool ret; 138 139 spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); 140 ret = list_empty(&opal_prd_msg_queue); 141 spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags); 142 143 return ret; 144 } 145 146 static __poll_t opal_prd_poll(struct file *file, 147 struct poll_table_struct *wait) 148 { 149 poll_wait(file, &opal_prd_msg_wait, wait); 150 151 if (!opal_msg_queue_empty()) 152 return EPOLLIN | EPOLLRDNORM; 153 154 return 0; 155 } 156 157 static ssize_t opal_prd_read(struct file *file, char __user *buf, 158 size_t count, loff_t *ppos) 159 { 160 struct opal_prd_msg_queue_item *item; 161 unsigned long flags; 162 ssize_t size, err; 163 int rc; 164 165 /* we need at least a header's worth of data */ 166 if (count < sizeof(item->msg.header)) 167 return -EINVAL; 168 169 if (*ppos) 170 return -ESPIPE; 171 172 item = NULL; 173 174 for (;;) { 175 176 spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); 177 if (!list_empty(&opal_prd_msg_queue)) { 178 item = list_first_entry(&opal_prd_msg_queue, 179 struct opal_prd_msg_queue_item, list); 180 list_del(&item->list); 181 } 182 spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags); 183 184 if (item) 185 break; 186 187 if (file->f_flags & O_NONBLOCK) 188 return -EAGAIN; 189 190 rc = wait_event_interruptible(opal_prd_msg_wait, 191 !opal_msg_queue_empty()); 192 if (rc) 193 return -EINTR; 194 } 195 196 size = be16_to_cpu(item->msg.header.size); 197 if (size > count) { 198 err = -EINVAL; 199 goto err_requeue; 200 } 201 202 rc = copy_to_user(buf, &item->msg, size); 203 if (rc) { 204 err = -EFAULT; 205 goto err_requeue; 206 } 207 208 kfree(item); 209 210 return size; 211 212 err_requeue: 213 /* eep! re-queue at the head of the list */ 214 spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); 215 list_add(&item->list, &opal_prd_msg_queue); 216 spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags); 217 return err; 218 } 219 220 static ssize_t opal_prd_write(struct file *file, const char __user *buf, 221 size_t count, loff_t *ppos) 222 { 223 struct opal_prd_msg_header hdr; 224 struct opal_prd_msg *msg; 225 ssize_t size; 226 int rc; 227 228 size = sizeof(hdr); 229 230 if (count < size) 231 return -EINVAL; 232 233 /* grab the header */ 234 rc = copy_from_user(&hdr, buf, sizeof(hdr)); 235 if (rc) 236 return -EFAULT; 237 238 size = be16_to_cpu(hdr.size); 239 240 msg = memdup_user(buf, size); 241 if (IS_ERR(msg)) 242 return PTR_ERR(msg); 243 244 rc = opal_prd_msg(msg); 245 if (rc) { 246 pr_warn("write: opal_prd_msg returned %d\n", rc); 247 size = -EIO; 248 } 249 250 kfree(msg); 251 252 return size; 253 } 254 255 static int opal_prd_release(struct inode *inode, struct file *file) 256 { 257 struct opal_prd_msg msg; 258 259 msg.header.size = cpu_to_be16(sizeof(msg)); 260 msg.header.type = OPAL_PRD_MSG_TYPE_FINI; 261 262 opal_prd_msg(&msg); 263 264 atomic_xchg(&prd_usage, 0); 265 266 return 0; 267 } 268 269 static long opal_prd_ioctl(struct file *file, unsigned int cmd, 270 unsigned long param) 271 { 272 struct opal_prd_info info; 273 struct opal_prd_scom scom; 274 int rc = 0; 275 276 switch (cmd) { 277 case OPAL_PRD_GET_INFO: 278 memset(&info, 0, sizeof(info)); 279 info.version = OPAL_PRD_KERNEL_VERSION; 280 rc = copy_to_user((void __user *)param, &info, sizeof(info)); 281 if (rc) 282 return -EFAULT; 283 break; 284 285 case OPAL_PRD_SCOM_READ: 286 rc = copy_from_user(&scom, (void __user *)param, sizeof(scom)); 287 if (rc) 288 return -EFAULT; 289 290 scom.rc = opal_xscom_read(scom.chip, scom.addr, 291 (__be64 *)&scom.data); 292 scom.data = be64_to_cpu(scom.data); 293 pr_devel("ioctl SCOM_READ: chip %llx addr %016llx data %016llx rc %lld\n", 294 scom.chip, scom.addr, scom.data, scom.rc); 295 296 rc = copy_to_user((void __user *)param, &scom, sizeof(scom)); 297 if (rc) 298 return -EFAULT; 299 break; 300 301 case OPAL_PRD_SCOM_WRITE: 302 rc = copy_from_user(&scom, (void __user *)param, sizeof(scom)); 303 if (rc) 304 return -EFAULT; 305 306 scom.rc = opal_xscom_write(scom.chip, scom.addr, scom.data); 307 pr_devel("ioctl SCOM_WRITE: chip %llx addr %016llx data %016llx rc %lld\n", 308 scom.chip, scom.addr, scom.data, scom.rc); 309 310 rc = copy_to_user((void __user *)param, &scom, sizeof(scom)); 311 if (rc) 312 return -EFAULT; 313 break; 314 315 default: 316 rc = -EINVAL; 317 } 318 319 return rc; 320 } 321 322 static const struct file_operations opal_prd_fops = { 323 .open = opal_prd_open, 324 .mmap = opal_prd_mmap, 325 .poll = opal_prd_poll, 326 .read = opal_prd_read, 327 .write = opal_prd_write, 328 .unlocked_ioctl = opal_prd_ioctl, 329 .release = opal_prd_release, 330 .owner = THIS_MODULE, 331 }; 332 333 static struct miscdevice opal_prd_dev = { 334 .minor = MISC_DYNAMIC_MINOR, 335 .name = "opal-prd", 336 .fops = &opal_prd_fops, 337 }; 338 339 /* opal interface */ 340 static int opal_prd_msg_notifier(struct notifier_block *nb, 341 unsigned long msg_type, void *_msg) 342 { 343 struct opal_prd_msg_queue_item *item; 344 struct opal_prd_msg_header *hdr; 345 struct opal_msg *msg = _msg; 346 int msg_size, item_size; 347 unsigned long flags; 348 349 if (msg_type != OPAL_MSG_PRD && msg_type != OPAL_MSG_PRD2) 350 return 0; 351 352 /* Calculate total size of the message and item we need to store. The 353 * 'size' field in the header includes the header itself. */ 354 hdr = (void *)msg->params; 355 msg_size = be16_to_cpu(hdr->size); 356 item_size = msg_size + sizeof(*item) - sizeof(item->msg); 357 358 item = kzalloc(item_size, GFP_ATOMIC); 359 if (!item) 360 return -ENOMEM; 361 362 memcpy(&item->msg.data, msg->params, msg_size); 363 364 spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); 365 list_add_tail(&item->list, &opal_prd_msg_queue); 366 spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags); 367 368 wake_up_interruptible(&opal_prd_msg_wait); 369 370 return 0; 371 } 372 373 static struct notifier_block opal_prd_event_nb = { 374 .notifier_call = opal_prd_msg_notifier, 375 .next = NULL, 376 .priority = 0, 377 }; 378 379 static struct notifier_block opal_prd_event_nb2 = { 380 .notifier_call = opal_prd_msg_notifier, 381 .next = NULL, 382 .priority = 0, 383 }; 384 385 static int opal_prd_probe(struct platform_device *pdev) 386 { 387 int rc; 388 389 if (!pdev || !pdev->dev.of_node) 390 return -ENODEV; 391 392 /* We should only have one prd driver instance per machine; ensure 393 * that we only get a valid probe on a single OF node. 394 */ 395 if (prd_node) 396 return -EBUSY; 397 398 prd_node = pdev->dev.of_node; 399 400 rc = opal_message_notifier_register(OPAL_MSG_PRD, &opal_prd_event_nb); 401 if (rc) { 402 pr_err("Couldn't register event notifier\n"); 403 return rc; 404 } 405 406 rc = opal_message_notifier_register(OPAL_MSG_PRD2, &opal_prd_event_nb2); 407 if (rc) { 408 pr_err("Couldn't register PRD2 event notifier\n"); 409 opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb); 410 return rc; 411 } 412 413 rc = misc_register(&opal_prd_dev); 414 if (rc) { 415 pr_err("failed to register miscdev\n"); 416 opal_message_notifier_unregister(OPAL_MSG_PRD, 417 &opal_prd_event_nb); 418 opal_message_notifier_unregister(OPAL_MSG_PRD2, 419 &opal_prd_event_nb2); 420 return rc; 421 } 422 423 return 0; 424 } 425 426 static int opal_prd_remove(struct platform_device *pdev) 427 { 428 misc_deregister(&opal_prd_dev); 429 opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb); 430 opal_message_notifier_unregister(OPAL_MSG_PRD2, &opal_prd_event_nb2); 431 return 0; 432 } 433 434 static const struct of_device_id opal_prd_match[] = { 435 { .compatible = "ibm,opal-prd" }, 436 { }, 437 }; 438 439 static struct platform_driver opal_prd_driver = { 440 .driver = { 441 .name = "opal-prd", 442 .of_match_table = opal_prd_match, 443 }, 444 .probe = opal_prd_probe, 445 .remove = opal_prd_remove, 446 }; 447 448 module_platform_driver(opal_prd_driver); 449 450 MODULE_DEVICE_TABLE(of, opal_prd_match); 451 MODULE_DESCRIPTION("PowerNV OPAL runtime diagnostic driver"); 452 MODULE_LICENSE("GPL"); 453