root/drivers/misc/cxl/of.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_prop_string
  2. read_prop_dword
  3. read_prop64_dword
  4. read_handle
  5. read_phys_addr
  6. read_vpd
  7. cxl_of_read_afu_handle
  8. cxl_of_read_afu_properties
  9. read_adapter_irq_config
  10. cxl_of_read_adapter_handle
  11. cxl_of_read_adapter_properties
  12. cxl_of_remove
  13. cxl_of_shutdown
  14. cxl_of_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2015 IBM Corp.
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/module.h>
   8 #include <linux/platform_device.h>
   9 #include <linux/slab.h>
  10 #include <linux/of_address.h>
  11 #include <linux/of_platform.h>
  12 
  13 #include "cxl.h"
  14 
  15 
  16 static const __be32 *read_prop_string(const struct device_node *np,
  17                                 const char *prop_name)
  18 {
  19         const __be32 *prop;
  20 
  21         prop = of_get_property(np, prop_name, NULL);
  22         if (cxl_verbose && prop)
  23                 pr_info("%s: %s\n", prop_name, (char *) prop);
  24         return prop;
  25 }
  26 
  27 static const __be32 *read_prop_dword(const struct device_node *np,
  28                                 const char *prop_name, u32 *val)
  29 {
  30         const __be32 *prop;
  31 
  32         prop = of_get_property(np, prop_name, NULL);
  33         if (prop)
  34                 *val = be32_to_cpu(prop[0]);
  35         if (cxl_verbose && prop)
  36                 pr_info("%s: %#x (%u)\n", prop_name, *val, *val);
  37         return prop;
  38 }
  39 
  40 static const __be64 *read_prop64_dword(const struct device_node *np,
  41                                 const char *prop_name, u64 *val)
  42 {
  43         const __be64 *prop;
  44 
  45         prop = of_get_property(np, prop_name, NULL);
  46         if (prop)
  47                 *val = be64_to_cpu(prop[0]);
  48         if (cxl_verbose && prop)
  49                 pr_info("%s: %#llx (%llu)\n", prop_name, *val, *val);
  50         return prop;
  51 }
  52 
  53 
  54 static int read_handle(struct device_node *np, u64 *handle)
  55 {
  56         const __be32 *prop;
  57         u64 size;
  58 
  59         /* Get address and size of the node */
  60         prop = of_get_address(np, 0, &size, NULL);
  61         if (size)
  62                 return -EINVAL;
  63 
  64         /* Helper to read a big number; size is in cells (not bytes) */
  65         *handle = of_read_number(prop, of_n_addr_cells(np));
  66         return 0;
  67 }
  68 
  69 static int read_phys_addr(struct device_node *np, char *prop_name,
  70                         struct cxl_afu *afu)
  71 {
  72         int i, len, entry_size, naddr, nsize, type;
  73         u64 addr, size;
  74         const __be32 *prop;
  75 
  76         naddr = of_n_addr_cells(np);
  77         nsize = of_n_size_cells(np);
  78 
  79         prop = of_get_property(np, prop_name, &len);
  80         if (prop) {
  81                 entry_size = naddr + nsize;
  82                 for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {
  83                         type = be32_to_cpu(prop[0]);
  84                         addr = of_read_number(prop, naddr);
  85                         size = of_read_number(&prop[naddr], nsize);
  86                         switch (type) {
  87                         case 0: /* unit address */
  88                                 afu->guest->handle = addr;
  89                                 break;
  90                         case 1: /* p2 area */
  91                                 afu->guest->p2n_phys += addr;
  92                                 afu->guest->p2n_size = size;
  93                                 break;
  94                         case 2: /* problem state area */
  95                                 afu->psn_phys += addr;
  96                                 afu->adapter->ps_size = size;
  97                                 break;
  98                         default:
  99                                 pr_err("Invalid address type %d found in %s property of AFU\n",
 100                                         type, prop_name);
 101                                 return -EINVAL;
 102                         }
 103                         if (cxl_verbose)
 104                                 pr_info("%s: %#x %#llx (size %#llx)\n",
 105                                         prop_name, type, addr, size);
 106                 }
 107         }
 108         return 0;
 109 }
 110 
 111 static int read_vpd(struct cxl *adapter, struct cxl_afu *afu)
 112 {
 113         char vpd[256];
 114         int rc;
 115         size_t len = sizeof(vpd);
 116 
 117         memset(vpd, 0, len);
 118 
 119         if (adapter)
 120                 rc = cxl_guest_read_adapter_vpd(adapter, vpd, len);
 121         else
 122                 rc = cxl_guest_read_afu_vpd(afu, vpd, len);
 123 
 124         if (rc > 0) {
 125                 cxl_dump_debug_buffer(vpd, rc);
 126                 rc = 0;
 127         }
 128         return rc;
 129 }
 130 
 131 int cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np)
 132 {
 133         if (read_handle(afu_np, &afu->guest->handle))
 134                 return -EINVAL;
 135         pr_devel("AFU handle: 0x%.16llx\n", afu->guest->handle);
 136 
 137         return 0;
 138 }
 139 
 140 int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np)
 141 {
 142         int i, len, rc;
 143         char *p;
 144         const __be32 *prop;
 145         u16 device_id, vendor_id;
 146         u32 val = 0, class_code;
 147 
 148         /* Properties are read in the same order as listed in PAPR */
 149 
 150         if (cxl_verbose) {
 151                 pr_info("Dump of the 'ibm,coherent-platform-function' node properties:\n");
 152 
 153                 prop = of_get_property(np, "compatible", &len);
 154                 i = 0;
 155                 while (i < len) {
 156                         p = (char *) prop + i;
 157                         pr_info("compatible: %s\n", p);
 158                         i += strlen(p) + 1;
 159                 }
 160                 read_prop_string(np, "name");
 161         }
 162 
 163         rc = read_phys_addr(np, "reg", afu);
 164         if (rc)
 165                 return rc;
 166 
 167         rc = read_phys_addr(np, "assigned-addresses", afu);
 168         if (rc)
 169                 return rc;
 170 
 171         if (afu->psn_phys == 0)
 172                 afu->psa = false;
 173         else
 174                 afu->psa = true;
 175 
 176         if (cxl_verbose) {
 177                 read_prop_string(np, "ibm,loc-code");
 178                 read_prop_string(np, "device_type");
 179         }
 180 
 181         read_prop_dword(np, "ibm,#processes", &afu->max_procs_virtualised);
 182 
 183         if (cxl_verbose) {
 184                 read_prop_dword(np, "ibm,scratchpad-size", &val);
 185                 read_prop_dword(np, "ibm,programmable", &val);
 186                 read_prop_string(np, "ibm,phandle");
 187                 read_vpd(NULL, afu);
 188         }
 189 
 190         read_prop_dword(np, "ibm,max-ints-per-process", &afu->guest->max_ints);
 191         afu->irqs_max = afu->guest->max_ints;
 192 
 193         prop = read_prop_dword(np, "ibm,min-ints-per-process", &afu->pp_irqs);
 194         if (prop) {
 195                 /* One extra interrupt for the PSL interrupt is already
 196                  * included. Remove it now to keep only AFU interrupts and
 197                  * match the native case.
 198                  */
 199                 afu->pp_irqs--;
 200         }
 201 
 202         if (cxl_verbose) {
 203                 read_prop_dword(np, "ibm,max-ints", &val);
 204                 read_prop_dword(np, "ibm,vpd-size", &val);
 205         }
 206 
 207         read_prop64_dword(np, "ibm,error-buffer-size", &afu->eb_len);
 208         afu->eb_offset = 0;
 209 
 210         if (cxl_verbose)
 211                 read_prop_dword(np, "ibm,config-record-type", &val);
 212 
 213         read_prop64_dword(np, "ibm,config-record-size", &afu->crs_len);
 214         afu->crs_offset = 0;
 215 
 216         read_prop_dword(np, "ibm,#config-records", &afu->crs_num);
 217 
 218         if (cxl_verbose) {
 219                 for (i = 0; i < afu->crs_num; i++) {
 220                         rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID,
 221                                                 &device_id);
 222                         if (!rc)
 223                                 pr_info("record %d - device-id: %#x\n",
 224                                         i, device_id);
 225                         rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID,
 226                                                 &vendor_id);
 227                         if (!rc)
 228                                 pr_info("record %d - vendor-id: %#x\n",
 229                                         i, vendor_id);
 230                         rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION,
 231                                                 &class_code);
 232                         if (!rc) {
 233                                 class_code >>= 8;
 234                                 pr_info("record %d - class-code: %#x\n",
 235                                         i, class_code);
 236                         }
 237                 }
 238 
 239                 read_prop_dword(np, "ibm,function-number", &val);
 240                 read_prop_dword(np, "ibm,privileged-function", &val);
 241                 read_prop_dword(np, "vendor-id", &val);
 242                 read_prop_dword(np, "device-id", &val);
 243                 read_prop_dword(np, "revision-id", &val);
 244                 read_prop_dword(np, "class-code", &val);
 245                 read_prop_dword(np, "subsystem-vendor-id", &val);
 246                 read_prop_dword(np, "subsystem-id", &val);
 247         }
 248         /*
 249          * if "ibm,process-mmio" doesn't exist then per-process mmio is
 250          * not supported
 251          */
 252         val = 0;
 253         prop = read_prop_dword(np, "ibm,process-mmio", &val);
 254         if (prop && val == 1)
 255                 afu->pp_psa = true;
 256         else
 257                 afu->pp_psa = false;
 258 
 259         if (cxl_verbose) {
 260                 read_prop_dword(np, "ibm,supports-aur", &val);
 261                 read_prop_dword(np, "ibm,supports-csrp", &val);
 262                 read_prop_dword(np, "ibm,supports-prr", &val);
 263         }
 264 
 265         prop = read_prop_dword(np, "ibm,function-error-interrupt", &val);
 266         if (prop)
 267                 afu->serr_hwirq = val;
 268 
 269         pr_devel("AFU handle: %#llx\n", afu->guest->handle);
 270         pr_devel("p2n_phys: %#llx (size %#llx)\n",
 271                 afu->guest->p2n_phys, afu->guest->p2n_size);
 272         pr_devel("psn_phys: %#llx (size %#llx)\n",
 273                 afu->psn_phys, afu->adapter->ps_size);
 274         pr_devel("Max number of processes virtualised=%i\n",
 275                 afu->max_procs_virtualised);
 276         pr_devel("Per-process irqs min=%i, max=%i\n", afu->pp_irqs,
 277                  afu->irqs_max);
 278         pr_devel("Slice error interrupt=%#lx\n", afu->serr_hwirq);
 279 
 280         return 0;
 281 }
 282 
 283 static int read_adapter_irq_config(struct cxl *adapter, struct device_node *np)
 284 {
 285         const __be32 *ranges;
 286         int len, nranges, i;
 287         struct irq_avail *cur;
 288 
 289         ranges = of_get_property(np, "interrupt-ranges", &len);
 290         if (ranges == NULL || len < (2 * sizeof(int)))
 291                 return -EINVAL;
 292 
 293         /*
 294          * encoded array of two cells per entry, each cell encoded as
 295          * with encode-int
 296          */
 297         nranges = len / (2 * sizeof(int));
 298         if (nranges == 0 || (nranges * 2 * sizeof(int)) != len)
 299                 return -EINVAL;
 300 
 301         adapter->guest->irq_avail = kcalloc(nranges, sizeof(struct irq_avail),
 302                                             GFP_KERNEL);
 303         if (adapter->guest->irq_avail == NULL)
 304                 return -ENOMEM;
 305 
 306         adapter->guest->irq_base_offset = be32_to_cpu(ranges[0]);
 307         for (i = 0; i < nranges; i++) {
 308                 cur = &adapter->guest->irq_avail[i];
 309                 cur->offset = be32_to_cpu(ranges[i * 2]);
 310                 cur->range  = be32_to_cpu(ranges[i * 2 + 1]);
 311                 cur->bitmap = kcalloc(BITS_TO_LONGS(cur->range),
 312                                 sizeof(*cur->bitmap), GFP_KERNEL);
 313                 if (cur->bitmap == NULL)
 314                         goto err;
 315                 if (cur->offset < adapter->guest->irq_base_offset)
 316                         adapter->guest->irq_base_offset = cur->offset;
 317                 if (cxl_verbose)
 318                         pr_info("available IRQ range: %#lx-%#lx (%lu)\n",
 319                                 cur->offset, cur->offset + cur->range - 1,
 320                                 cur->range);
 321         }
 322         adapter->guest->irq_nranges = nranges;
 323         spin_lock_init(&adapter->guest->irq_alloc_lock);
 324 
 325         return 0;
 326 err:
 327         for (i--; i >= 0; i--) {
 328                 cur = &adapter->guest->irq_avail[i];
 329                 kfree(cur->bitmap);
 330         }
 331         kfree(adapter->guest->irq_avail);
 332         adapter->guest->irq_avail = NULL;
 333         return -ENOMEM;
 334 }
 335 
 336 int cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np)
 337 {
 338         if (read_handle(np, &adapter->guest->handle))
 339                 return -EINVAL;
 340         pr_devel("Adapter handle: 0x%.16llx\n", adapter->guest->handle);
 341 
 342         return 0;
 343 }
 344 
 345 int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
 346 {
 347         int rc, len, naddr, i;
 348         char *p;
 349         const __be32 *prop;
 350         u32 val = 0;
 351 
 352         /* Properties are read in the same order as listed in PAPR */
 353 
 354         naddr = of_n_addr_cells(np);
 355 
 356         if (cxl_verbose) {
 357                 pr_info("Dump of the 'ibm,coherent-platform-facility' node properties:\n");
 358 
 359                 read_prop_dword(np, "#address-cells", &val);
 360                 read_prop_dword(np, "#size-cells", &val);
 361 
 362                 prop = of_get_property(np, "compatible", &len);
 363                 i = 0;
 364                 while (i < len) {
 365                         p = (char *) prop + i;
 366                         pr_info("compatible: %s\n", p);
 367                         i += strlen(p) + 1;
 368                 }
 369                 read_prop_string(np, "name");
 370                 read_prop_string(np, "model");
 371 
 372                 prop = of_get_property(np, "reg", NULL);
 373                 if (prop) {
 374                         pr_info("reg: addr:%#llx size:%#x\n",
 375                                 of_read_number(prop, naddr),
 376                                 be32_to_cpu(prop[naddr]));
 377                 }
 378 
 379                 read_prop_string(np, "ibm,loc-code");
 380         }
 381 
 382         if ((rc = read_adapter_irq_config(adapter, np)))
 383                 return rc;
 384 
 385         if (cxl_verbose) {
 386                 read_prop_string(np, "device_type");
 387                 read_prop_string(np, "ibm,phandle");
 388         }
 389 
 390         prop = read_prop_dword(np, "ibm,caia-version", &val);
 391         if (prop) {
 392                 adapter->caia_major = (val & 0xFF00) >> 8;
 393                 adapter->caia_minor = val & 0xFF;
 394         }
 395 
 396         prop = read_prop_dword(np, "ibm,psl-revision", &val);
 397         if (prop)
 398                 adapter->psl_rev = val;
 399 
 400         prop = read_prop_string(np, "status");
 401         if (prop) {
 402                 adapter->guest->status = kasprintf(GFP_KERNEL, "%s", (char *) prop);
 403                 if (adapter->guest->status == NULL)
 404                         return -ENOMEM;
 405         }
 406 
 407         prop = read_prop_dword(np, "vendor-id", &val);
 408         if (prop)
 409                 adapter->guest->vendor = val;
 410 
 411         prop = read_prop_dword(np, "device-id", &val);
 412         if (prop)
 413                 adapter->guest->device = val;
 414 
 415         if (cxl_verbose) {
 416                 read_prop_dword(np, "ibm,privileged-facility", &val);
 417                 read_prop_dword(np, "revision-id", &val);
 418                 read_prop_dword(np, "class-code", &val);
 419         }
 420 
 421         prop = read_prop_dword(np, "subsystem-vendor-id", &val);
 422         if (prop)
 423                 adapter->guest->subsystem_vendor = val;
 424 
 425         prop = read_prop_dword(np, "subsystem-id", &val);
 426         if (prop)
 427                 adapter->guest->subsystem = val;
 428 
 429         if (cxl_verbose)
 430                 read_vpd(adapter, NULL);
 431 
 432         return 0;
 433 }
 434 
 435 static int cxl_of_remove(struct platform_device *pdev)
 436 {
 437         struct cxl *adapter;
 438         int afu;
 439 
 440         adapter = dev_get_drvdata(&pdev->dev);
 441         for (afu = 0; afu < adapter->slices; afu++)
 442                 cxl_guest_remove_afu(adapter->afu[afu]);
 443 
 444         cxl_guest_remove_adapter(adapter);
 445         return 0;
 446 }
 447 
 448 static void cxl_of_shutdown(struct platform_device *pdev)
 449 {
 450         cxl_of_remove(pdev);
 451 }
 452 
 453 int cxl_of_probe(struct platform_device *pdev)
 454 {
 455         struct device_node *np = NULL;
 456         struct device_node *afu_np = NULL;
 457         struct cxl *adapter = NULL;
 458         int ret;
 459         int slice = 0, slice_ok = 0;
 460 
 461         pr_devel("in %s\n", __func__);
 462 
 463         np = pdev->dev.of_node;
 464         if (np == NULL)
 465                 return -ENODEV;
 466 
 467         /* init adapter */
 468         adapter = cxl_guest_init_adapter(np, pdev);
 469         if (IS_ERR(adapter)) {
 470                 dev_err(&pdev->dev, "guest_init_adapter failed: %li\n", PTR_ERR(adapter));
 471                 return PTR_ERR(adapter);
 472         }
 473 
 474         /* init afu */
 475         for_each_child_of_node(np, afu_np) {
 476                 if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))
 477                         dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",
 478                                 slice, ret);
 479                 else
 480                         slice_ok++;
 481                 slice++;
 482         }
 483 
 484         if (slice_ok == 0) {
 485                 dev_info(&pdev->dev, "No active AFU");
 486                 adapter->slices = 0;
 487         }
 488 
 489         return 0;
 490 }
 491 
 492 static const struct of_device_id cxl_of_match[] = {
 493         { .compatible = "ibm,coherent-platform-facility",},
 494         {},
 495 };
 496 MODULE_DEVICE_TABLE(of, cxl_of_match);
 497 
 498 struct platform_driver cxl_of_driver = {
 499         .driver = {
 500                 .name = "cxl_of",
 501                 .of_match_table = cxl_of_match,
 502                 .owner = THIS_MODULE
 503         },
 504         .probe = cxl_of_probe,
 505         .remove = cxl_of_remove,
 506         .shutdown = cxl_of_shutdown,
 507 };

/* [<][>][^][v][top][bottom][index][help] */