1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */
3 
4 #include <linux/platform_device.h>
5 #include <linux/device.h>
6 #include <linux/acpi.h>
7 #include <linux/pci.h>
8 #include <cxl.h>
9 #include "test/mock.h"
10 
to_cxl_host_bridge(struct device * host,struct device * dev)11 struct acpi_device *to_cxl_host_bridge(struct device *host, struct device *dev)
12 {
13 	int index;
14 	struct acpi_device *adev, *found = NULL;
15 	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
16 
17 	if (ops && ops->is_mock_bridge(dev)) {
18 		found = ACPI_COMPANION(dev);
19 		goto out;
20 	}
21 
22 	if (dev->bus == &platform_bus_type)
23 		goto out;
24 
25 	adev = to_acpi_device(dev);
26 	if (!acpi_pci_find_root(adev->handle))
27 		goto out;
28 
29 	if (strcmp(acpi_device_hid(adev), "ACPI0016") == 0) {
30 		found = adev;
31 		dev_dbg(host, "found host bridge %s\n", dev_name(&adev->dev));
32 	}
33 out:
34 	put_cxl_mock_ops(index);
35 	return found;
36 }
37 
match_add_root_port(struct pci_dev * pdev,void * data)38 static int match_add_root_port(struct pci_dev *pdev, void *data)
39 {
40 	struct cxl_walk_context *ctx = data;
41 	struct pci_bus *root_bus = ctx->root;
42 	struct cxl_port *port = ctx->port;
43 	int type = pci_pcie_type(pdev);
44 	struct device *dev = ctx->dev;
45 	u32 lnkcap, port_num;
46 	int rc;
47 
48 	if (pdev->bus != root_bus)
49 		return 0;
50 	if (!pci_is_pcie(pdev))
51 		return 0;
52 	if (type != PCI_EXP_TYPE_ROOT_PORT)
53 		return 0;
54 	if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP,
55 				  &lnkcap) != PCIBIOS_SUCCESSFUL)
56 		return 0;
57 
58 	/* TODO walk DVSEC to find component register base */
59 	port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap);
60 	rc = cxl_add_dport(port, &pdev->dev, port_num, CXL_RESOURCE_NONE);
61 	if (rc) {
62 		dev_err(dev, "failed to add dport: %s (%d)\n",
63 			dev_name(&pdev->dev), rc);
64 		ctx->error = rc;
65 		return rc;
66 	}
67 	ctx->count++;
68 
69 	dev_dbg(dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev));
70 
71 	return 0;
72 }
73 
mock_add_root_port(struct platform_device * pdev,void * data)74 static int mock_add_root_port(struct platform_device *pdev, void *data)
75 {
76 	struct cxl_walk_context *ctx = data;
77 	struct cxl_port *port = ctx->port;
78 	struct device *dev = ctx->dev;
79 	int rc;
80 
81 	rc = cxl_add_dport(port, &pdev->dev, pdev->id, CXL_RESOURCE_NONE);
82 	if (rc) {
83 		dev_err(dev, "failed to add dport: %s (%d)\n",
84 			dev_name(&pdev->dev), rc);
85 		ctx->error = rc;
86 		return rc;
87 	}
88 	ctx->count++;
89 
90 	dev_dbg(dev, "add dport%d: %s\n", pdev->id, dev_name(&pdev->dev));
91 
92 	return 0;
93 }
94 
match_add_root_ports(struct pci_dev * dev,void * data)95 int match_add_root_ports(struct pci_dev *dev, void *data)
96 {
97 	int index, rc;
98 	struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
99 	struct platform_device *pdev = (struct platform_device *) dev;
100 
101 	if (ops && ops->is_mock_port(pdev))
102 		rc = mock_add_root_port(pdev, data);
103 	else
104 		rc = match_add_root_port(dev, data);
105 
106 	put_cxl_mock_ops(index);
107 
108 	return rc;
109 }
110