]> git.itanic.dy.fi Git - linux-stable/commitdiff
Merge branch 'for-6.3/cxl-rr-emu' into cxl/next
authorDan Williams <dan.j.williams@intel.com>
Wed, 15 Feb 2023 00:06:10 +0000 (16:06 -0800)
committerDan Williams <dan.j.williams@intel.com>
Wed, 15 Feb 2023 00:06:10 +0000 (16:06 -0800)
Pick up the CXL DVSEC range register emulation for v6.3, and resolve
conflicts with the cxl_port_probe() split (from for-6.3/cxl-ram-region)
and event handling (from for-6.3/cxl-events).

1  2 
drivers/cxl/core/hdm.c
drivers/cxl/core/pci.c
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/cxlpci.h
drivers/cxl/port.c
tools/testing/cxl/Kbuild
tools/testing/cxl/test/cxl.c

index 80eccae6ba9e7baa018cefd1ce8cdcfbce5012fa,39e02f28b6a6f7245ef69b53ce2ae7b056d0ce5c..45deda18ed322ef60af2ddb5bdebf8ec6a8b2448
@@@ -119,6 -142,9 +142,9 @@@ struct cxl_hdm *devm_cxl_setup_hdm(stru
        cxlhdm->port = port;
        crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
        if (!crb) {
 -              if (info->mem_enabled)
++              if (info && info->mem_enabled)
+                       return devm_cxl_setup_emulated_hdm(port, info);
                dev_err(dev, "No component registers mapped\n");
                return ERR_PTR(-ENXIO);
        }
@@@ -856,11 -938,9 +952,12 @@@ int devm_cxl_enumerate_decoders(struct 
                        cxld = &cxlsd->cxld;
                }
  
-               rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
+               rc = init_hdm_decoder(port, cxld, target_map, hdm, i,
+                                     &dpa_base, info);
                if (rc) {
 +                      dev_warn(&port->dev,
 +                               "Failed to initialize decoder%d.%d\n",
 +                               port->id, i);
                        put_device(&cxld->dev);
                        return rc;
                }
Simple merge
Simple merge
index 64ede1a06eafb6a34e745c7fd07be61a02024420,187a310780a94368a73683c8bb93c7c936718f1d..c6c560c67a8ad203b4c306425adaa19d2ee41668
@@@ -187,46 -181,6 +187,34 @@@ static inline int cxl_mbox_cmd_rc2errno
   */
  #define CXL_CAPACITY_MULTIPLIER SZ_256M
  
- /**
-  * struct cxl_endpoint_dvsec_info - Cached DVSEC info
-  * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE
-  * @ranges: Number of active HDM ranges this device uses.
-  * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
-  */
- struct cxl_endpoint_dvsec_info {
-       bool mem_enabled;
-       int ranges;
-       struct range dvsec_range[2];
- };
 +/**
 + * Event Interrupt Policy
 + *
 + * CXL rev 3.0 section 8.2.9.2.4; Table 8-52
 + */
 +enum cxl_event_int_mode {
 +      CXL_INT_NONE            = 0x00,
 +      CXL_INT_MSI_MSIX        = 0x01,
 +      CXL_INT_FW              = 0x02
 +};
 +struct cxl_event_interrupt_policy {
 +      u8 info_settings;
 +      u8 warn_settings;
 +      u8 failure_settings;
 +      u8 fatal_settings;
 +} __packed;
 +
 +/**
 + * struct cxl_event_state - Event log driver state
 + *
 + * @event_buf: Buffer to receive event data
 + * @event_log_lock: Serialize event_buf and log use
 + */
 +struct cxl_event_state {
 +      struct cxl_get_event_payload *buf;
 +      struct mutex log_lock;
 +};
 +
  /**
   * struct cxl_dev_state - The driver device state
   *
index a8ea04f536aba3a3c0797f5801821682c424dd3e,430e23345a162e1c5d3133f1488150b491bc71b6..be6a2ef3cce3738a45cc19d8c9cb54aff93af693
@@@ -70,9 -64,7 +70,10 @@@ enum cxl_regloc_type 
  
  int devm_cxl_port_enumerate_dports(struct cxl_port *port);
  struct cxl_dev_state;
- int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm);
+ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+                       struct cxl_endpoint_dvsec_info *info);
  void read_cdat_data(struct cxl_port *port);
 +void cxl_cor_error_detected(struct pci_dev *pdev);
 +pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
 +                                  pci_channel_state_t state);
  #endif /* __CXL_PCI_H__ */
index d6c151dabaa787279a58a2d8bfa0cce241663e19,9f9cc268b5978b840a9e98e204d37942e730c413..1049bb5ea496129177e3db06fae3b64198548483
@@@ -30,98 -30,59 +30,103 @@@ static void schedule_detach(void *cxlmd
        schedule_cxl_memdev_detach(cxlmd);
  }
  
 -static int cxl_port_probe(struct device *dev)
 +static int discover_region(struct device *dev, void *root)
 +{
 +      struct cxl_endpoint_decoder *cxled;
 +      int rc;
 +
 +      if (!is_endpoint_decoder(dev))
 +              return 0;
 +
 +      cxled = to_cxl_endpoint_decoder(dev);
 +      if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
 +              return 0;
 +
 +      if (cxled->state != CXL_DECODER_STATE_AUTO)
 +              return 0;
 +
 +      /*
 +       * Region enumeration is opportunistic, if this add-event fails,
 +       * continue to the next endpoint decoder.
 +       */
 +      rc = cxl_add_to_region(root, cxled);
 +      if (rc)
 +              dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
 +                      cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
 +
 +      return 0;
 +}
 +
 +static int cxl_switch_port_probe(struct cxl_port *port)
  {
-       cxlhdm = devm_cxl_setup_hdm(port);
 +      struct cxl_hdm *cxlhdm;
 +      int rc;
 +
 +      rc = devm_cxl_port_enumerate_dports(port);
 +      if (rc < 0)
 +              return rc;
 +
 +      if (rc == 1)
 +              return devm_cxl_add_passthrough_decoder(port);
 +
-       return devm_cxl_enumerate_decoders(cxlhdm);
++      cxlhdm = devm_cxl_setup_hdm(port, NULL);
 +      if (IS_ERR(cxlhdm))
 +              return PTR_ERR(cxlhdm);
 +
 -      struct cxl_port *port = to_cxl_port(dev);
 -      bool is_ep = is_cxl_endpoint(port);
 -      struct cxl_dev_state *cxlds;
 -      struct cxl_memdev *cxlmd;
++      return devm_cxl_enumerate_decoders(cxlhdm, NULL);
 +}
 +
 +static int cxl_endpoint_port_probe(struct cxl_port *port)
 +{
 +      struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
+       struct cxl_endpoint_dvsec_info info = { 0 };
 +      struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_hdm *cxlhdm;
 +      struct cxl_port *root;
        int rc;
  
-       cxlhdm = devm_cxl_setup_hdm(port);
 -      if (is_ep) {
 -              cxlmd = to_cxl_memdev(port->uport);
 -              cxlds = cxlmd->cxlds;
 -              rc = cxl_dvsec_rr_decode(cxlds->dev, cxlds->cxl_dvsec, &info);
 -              if (rc < 0)
 -                      return rc;
 -      } else {
 -              rc = devm_cxl_port_enumerate_dports(port);
 -              if (rc < 0)
 -                      return rc;
 -              if (rc == 1)
 -                      return devm_cxl_add_passthrough_decoder(port);
 -      }
++      rc = cxl_dvsec_rr_decode(cxlds->dev, cxlds->cxl_dvsec, &info);
++      if (rc < 0)
++              return rc;
+       cxlhdm = devm_cxl_setup_hdm(port, &info);
        if (IS_ERR(cxlhdm))
                return PTR_ERR(cxlhdm);
  
 -      if (is_ep) {
 -              /* Cache the data early to ensure is_visible() works */
 -              read_cdat_data(port);
 +      /* Cache the data early to ensure is_visible() works */
 +      read_cdat_data(port);
  
 -              get_device(&cxlmd->dev);
 -              rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd);
 -              if (rc)
 -                      return rc;
 +      get_device(&cxlmd->dev);
 +      rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
 +      if (rc)
 +              return rc;
  
-       rc = cxl_hdm_decode_init(cxlds, cxlhdm);
 -              rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
 -              if (rc)
 -                      return rc;
++      rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
 +      if (rc)
 +              return rc;
  
 -              rc = cxl_await_media_ready(cxlds);
 -              if (rc) {
 -                      dev_err(dev, "Media not active (%d)\n", rc);
 -                      return rc;
 -              }
 +      rc = cxl_await_media_ready(cxlds);
 +      if (rc) {
 +              dev_err(&port->dev, "Media not active (%d)\n", rc);
 +              return rc;
        }
  
-       rc = devm_cxl_enumerate_decoders(cxlhdm);
+       rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
 -      if (rc) {
 -              dev_err(dev, "Couldn't enumerate decoders (%d)\n", rc);
 +      if (rc)
                return rc;
 -      }
 +
 +      /*
 +       * This can't fail in practice as CXL root exit unregisters all
 +       * descendant ports and that in turn synchronizes with cxl_port_probe()
 +       */
 +      root = find_cxl_root(&cxlmd->dev);
 +
 +      /*
 +       * Now that all endpoint decoders are successfully enumerated, try to
 +       * assemble regions from committed decoders
 +       */
 +      device_for_each_child(&port->dev, root, discover_region);
 +      put_device(&root->dev);
  
        return 0;
  }
Simple merge
index 41c5d735308e1f127cba4c88bee3c5e37e2c39aa,94197abd44aa1e721c7b761a9a744ab4deb2d352..bf00dc52fe96eb6a58de91707a597bc94cfe0999
@@@ -703,143 -702,8 +704,144 @@@ static int mock_decoder_reset(struct cx
        return 0;
  }
  
- static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
 +static void default_mock_decoder(struct cxl_decoder *cxld)
 +{
 +      cxld->hpa_range = (struct range){
 +              .start = 0,
 +              .end = -1,
 +      };
 +
 +      cxld->interleave_ways = 1;
 +      cxld->interleave_granularity = 256;
 +      cxld->target_type = CXL_DECODER_EXPANDER;
 +      cxld->commit = mock_decoder_commit;
 +      cxld->reset = mock_decoder_reset;
 +}
 +
 +static int first_decoder(struct device *dev, void *data)
 +{
 +      struct cxl_decoder *cxld;
 +
 +      if (!is_switch_decoder(dev))
 +              return 0;
 +      cxld = to_cxl_decoder(dev);
 +      if (cxld->id == 0)
 +              return 1;
 +      return 0;
 +}
 +
 +static void mock_init_hdm_decoder(struct cxl_decoder *cxld)
 +{
 +      struct acpi_cedt_cfmws *window = mock_cfmws[0];
 +      struct platform_device *pdev = NULL;
 +      struct cxl_endpoint_decoder *cxled;
 +      struct cxl_switch_decoder *cxlsd;
 +      struct cxl_port *port, *iter;
 +      const int size = SZ_512M;
 +      struct cxl_memdev *cxlmd;
 +      struct cxl_dport *dport;
 +      struct device *dev;
 +      bool hb0 = false;
 +      u64 base;
 +      int i;
 +
 +      if (is_endpoint_decoder(&cxld->dev)) {
 +              cxled = to_cxl_endpoint_decoder(&cxld->dev);
 +              cxlmd = cxled_to_memdev(cxled);
 +              WARN_ON(!dev_is_platform(cxlmd->dev.parent));
 +              pdev = to_platform_device(cxlmd->dev.parent);
 +
 +              /* check is endpoint is attach to host-bridge0 */
 +              port = cxled_to_port(cxled);
 +              do {
 +                      if (port->uport == &cxl_host_bridge[0]->dev) {
 +                              hb0 = true;
 +                              break;
 +                      }
 +                      if (is_cxl_port(port->dev.parent))
 +                              port = to_cxl_port(port->dev.parent);
 +                      else
 +                              port = NULL;
 +              } while (port);
 +              port = cxled_to_port(cxled);
 +      }
 +
 +      /*
 +       * The first decoder on the first 2 devices on the first switch
 +       * attached to host-bridge0 mock a fake / static RAM region. All
 +       * other decoders are default disabled. Given the round robin
 +       * assignment those devices are named cxl_mem.0, and cxl_mem.4.
 +       *
 +       * See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'
 +       */
 +      if (!hb0 || pdev->id % 4 || pdev->id > 4 || cxld->id > 0) {
 +              default_mock_decoder(cxld);
 +              return;
 +      }
 +
 +      base = window->base_hpa;
 +      cxld->hpa_range = (struct range) {
 +              .start = base,
 +              .end = base + size - 1,
 +      };
 +
 +      cxld->interleave_ways = 2;
 +      eig_to_granularity(window->granularity, &cxld->interleave_granularity);
 +      cxld->target_type = CXL_DECODER_EXPANDER;
 +      cxld->flags = CXL_DECODER_F_ENABLE;
 +      cxled->state = CXL_DECODER_STATE_AUTO;
 +      port->commit_end = cxld->id;
 +      devm_cxl_dpa_reserve(cxled, 0, size / cxld->interleave_ways, 0);
 +      cxld->commit = mock_decoder_commit;
 +      cxld->reset = mock_decoder_reset;
 +
 +      /*
 +       * Now that endpoint decoder is set up, walk up the hierarchy
 +       * and setup the switch and root port decoders targeting @cxlmd.
 +       */
 +      iter = port;
 +      for (i = 0; i < 2; i++) {
 +              dport = iter->parent_dport;
 +              iter = dport->port;
 +              dev = device_find_child(&iter->dev, NULL, first_decoder);
 +              /*
 +               * Ancestor ports are guaranteed to be enumerated before
 +               * @port, and all ports have at least one decoder.
 +               */
 +              if (WARN_ON(!dev))
 +                      continue;
 +              cxlsd = to_cxl_switch_decoder(dev);
 +              if (i == 0) {
 +                      /* put cxl_mem.4 second in the decode order */
 +                      if (pdev->id == 4)
 +                              cxlsd->target[1] = dport;
 +                      else
 +                              cxlsd->target[0] = dport;
 +              } else
 +                      cxlsd->target[0] = dport;
 +              cxld = &cxlsd->cxld;
 +              cxld->target_type = CXL_DECODER_EXPANDER;
 +              cxld->flags = CXL_DECODER_F_ENABLE;
 +              iter->commit_end = 0;
 +              /*
 +               * Switch targets 2 endpoints, while host bridge targets
 +               * one root port
 +               */
 +              if (i == 0)
 +                      cxld->interleave_ways = 2;
 +              else
 +                      cxld->interleave_ways = 1;
 +              cxld->interleave_granularity = 256;
 +              cxld->hpa_range = (struct range) {
 +                      .start = base,
 +                      .end = base + size - 1,
 +              };
 +              put_device(dev);
 +      }
 +}
 +
+ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                                      struct cxl_endpoint_dvsec_info *info)
  {
        struct cxl_port *port = cxlhdm->port;
        struct cxl_port *parent_port = to_cxl_port(port->dev.parent);