Skip to content

Commit ec3619a

Browse files
committed
Merge branch 'pci/controller/iommu-map'
- Add host bridge .enable_device() and .disable_device() hooks for bridges that need to configure things like Requester ID to StreamID mapping when enabling devices (Frank Li) - Add imx6 Requester ID to StreamID mapping configuration when enabling devices (Frank Li) - Extend struct pci_ecam_ops with .enable_device() and .disable_device() hooks so drivers that use pci_host_common_probe() instead of their own .probe() have a way to set the .enable_device() callbacks (Marc Zyngier) - Convert pcie-apple StreamID mapping configuration from a bus notifier to the .enable_device() and .disable_device() callbacks (Marc Zyngier) * pci/controller/iommu-map: PCI: apple: Convert to {en,dis}able_device() callbacks PCI: host-generic: Allow {en,dis}able_device() to be provided via pci_ecam_ops PCI: imx6: Add IOMMU and ITS MSI support for i.MX95 PCI: Add enable_device() and disable_device() callbacks for bridges
2 parents 1532594 + d9f6642 commit ec3619a

File tree

6 files changed

+265
-62
lines changed

6 files changed

+265
-62
lines changed

drivers/pci/controller/dwc/pci-imx6.c

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@
5555
#define IMX95_PE0_GEN_CTRL_3 0x1058
5656
#define IMX95_PCIE_LTSSM_EN BIT(0)
5757

58+
#define IMX95_PE0_LUT_ACSCTRL 0x1008
59+
#define IMX95_PEO_LUT_RWA BIT(16)
60+
#define IMX95_PE0_LUT_ENLOC GENMASK(4, 0)
61+
62+
#define IMX95_PE0_LUT_DATA1 0x100c
63+
#define IMX95_PE0_LUT_VLD BIT(31)
64+
#define IMX95_PE0_LUT_DAC_ID GENMASK(10, 8)
65+
#define IMX95_PE0_LUT_STREAM_ID GENMASK(5, 0)
66+
67+
#define IMX95_PE0_LUT_DATA2 0x1010
68+
#define IMX95_PE0_LUT_REQID GENMASK(31, 16)
69+
#define IMX95_PE0_LUT_MASK GENMASK(15, 0)
70+
71+
#define IMX95_SID_MASK GENMASK(5, 0)
72+
#define IMX95_MAX_LUT 32
73+
5874
#define to_imx_pcie(x) dev_get_drvdata((x)->dev)
5975

6076
enum imx_pcie_variants {
@@ -87,6 +103,7 @@ enum imx_pcie_variants {
87103
* workaround suspend resume on some devices which are affected by this errata.
88104
*/
89105
#define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9)
106+
#define IMX_PCIE_FLAG_HAS_LUT BIT(10)
90107

91108
#define imx_check_flag(pci, val) (pci->drvdata->flags & val)
92109

@@ -139,6 +156,9 @@ struct imx_pcie {
139156
struct device *pd_pcie_phy;
140157
struct phy *phy;
141158
const struct imx_pcie_drvdata *drvdata;
159+
160+
/* Ensure that only one device's LUT is configured at any given time */
161+
struct mutex lock;
142162
};
143163

144164
/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
@@ -930,6 +950,184 @@ static void imx_pcie_stop_link(struct dw_pcie *pci)
930950
imx_pcie_ltssm_disable(dev);
931951
}
932952

953+
static int imx_pcie_add_lut(struct imx_pcie *imx_pcie, u16 rid, u8 sid)
954+
{
955+
struct dw_pcie *pci = imx_pcie->pci;
956+
struct device *dev = pci->dev;
957+
u32 data1, data2;
958+
int free = -1;
959+
int i;
960+
961+
if (sid >= 64) {
962+
dev_err(dev, "Invalid SID for index %d\n", sid);
963+
return -EINVAL;
964+
}
965+
966+
guard(mutex)(&imx_pcie->lock);
967+
968+
/*
969+
* Iterate through all LUT entries to check for duplicate RID and
970+
* identify the first available entry. Configure this available entry
971+
* immediately after verification to avoid rescanning it.
972+
*/
973+
for (i = 0; i < IMX95_MAX_LUT; i++) {
974+
regmap_write(imx_pcie->iomuxc_gpr,
975+
IMX95_PE0_LUT_ACSCTRL, IMX95_PEO_LUT_RWA | i);
976+
regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, &data1);
977+
978+
if (!(data1 & IMX95_PE0_LUT_VLD)) {
979+
if (free < 0)
980+
free = i;
981+
continue;
982+
}
983+
984+
regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2);
985+
986+
/* Do not add duplicate RID */
987+
if (rid == FIELD_GET(IMX95_PE0_LUT_REQID, data2)) {
988+
dev_warn(dev, "Existing LUT entry available for RID (%d)", rid);
989+
return 0;
990+
}
991+
}
992+
993+
if (free < 0) {
994+
dev_err(dev, "LUT entry is not available\n");
995+
return -ENOSPC;
996+
}
997+
998+
data1 = FIELD_PREP(IMX95_PE0_LUT_DAC_ID, 0);
999+
data1 |= FIELD_PREP(IMX95_PE0_LUT_STREAM_ID, sid);
1000+
data1 |= IMX95_PE0_LUT_VLD;
1001+
regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, data1);
1002+
1003+
data2 = IMX95_PE0_LUT_MASK; /* Match all bits of RID */
1004+
data2 |= FIELD_PREP(IMX95_PE0_LUT_REQID, rid);
1005+
regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, data2);
1006+
1007+
regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, free);
1008+
1009+
return 0;
1010+
}
1011+
1012+
static void imx_pcie_remove_lut(struct imx_pcie *imx_pcie, u16 rid)
1013+
{
1014+
u32 data2;
1015+
int i;
1016+
1017+
guard(mutex)(&imx_pcie->lock);
1018+
1019+
for (i = 0; i < IMX95_MAX_LUT; i++) {
1020+
regmap_write(imx_pcie->iomuxc_gpr,
1021+
IMX95_PE0_LUT_ACSCTRL, IMX95_PEO_LUT_RWA | i);
1022+
regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2);
1023+
if (FIELD_GET(IMX95_PE0_LUT_REQID, data2) == rid) {
1024+
regmap_write(imx_pcie->iomuxc_gpr,
1025+
IMX95_PE0_LUT_DATA1, 0);
1026+
regmap_write(imx_pcie->iomuxc_gpr,
1027+
IMX95_PE0_LUT_DATA2, 0);
1028+
regmap_write(imx_pcie->iomuxc_gpr,
1029+
IMX95_PE0_LUT_ACSCTRL, i);
1030+
1031+
break;
1032+
}
1033+
}
1034+
}
1035+
1036+
static int imx_pcie_enable_device(struct pci_host_bridge *bridge,
1037+
struct pci_dev *pdev)
1038+
{
1039+
struct imx_pcie *imx_pcie = to_imx_pcie(to_dw_pcie_from_pp(bridge->sysdata));
1040+
u32 sid_i, sid_m, rid = pci_dev_id(pdev);
1041+
struct device_node *target;
1042+
struct device *dev;
1043+
int err_i, err_m;
1044+
u32 sid = 0;
1045+
1046+
dev = imx_pcie->pci->dev;
1047+
1048+
target = NULL;
1049+
err_i = of_map_id(dev->of_node, rid, "iommu-map", "iommu-map-mask",
1050+
&target, &sid_i);
1051+
if (target) {
1052+
of_node_put(target);
1053+
} else {
1054+
/*
1055+
* "target == NULL && err_i == 0" means RID out of map range.
1056+
* Use 1:1 map RID to streamID. Hardware can't support this
1057+
* because the streamID is only 6 bits
1058+
*/
1059+
err_i = -EINVAL;
1060+
}
1061+
1062+
target = NULL;
1063+
err_m = of_map_id(dev->of_node, rid, "msi-map", "msi-map-mask",
1064+
&target, &sid_m);
1065+
1066+
/*
1067+
* err_m target
1068+
* 0 NULL RID out of range. Use 1:1 map RID to
1069+
* streamID, Current hardware can't
1070+
* support it, so return -EINVAL.
1071+
* != 0 NULL msi-map does not exist, use built-in MSI
1072+
* 0 != NULL Get correct streamID from RID
1073+
* != 0 != NULL Invalid combination
1074+
*/
1075+
if (!err_m && !target)
1076+
return -EINVAL;
1077+
else if (target)
1078+
of_node_put(target); /* Find streamID map entry for RID in msi-map */
1079+
1080+
/*
1081+
* msi-map iommu-map
1082+
* N N DWC MSI Ctrl
1083+
* Y Y ITS + SMMU, require the same SID
1084+
* Y N ITS
1085+
* N Y DWC MSI Ctrl + SMMU
1086+
*/
1087+
if (err_i && err_m)
1088+
return 0;
1089+
1090+
if (!err_i && !err_m) {
1091+
/*
1092+
* Glue Layer
1093+
* <==========>
1094+
* ┌─────┐ ┌──────────┐
1095+
* │ LUT │ 6-bit streamID │ │
1096+
* │ │─────────────────►│ MSI │
1097+
* └─────┘ 2-bit ctrl ID │ │
1098+
* ┌───────────►│ │
1099+
* (i.MX95) │ │ │
1100+
* 00 PCIe0 │ │ │
1101+
* 01 ENETC │ │ │
1102+
* 10 PCIe1 │ │ │
1103+
* │ └──────────┘
1104+
* The MSI glue layer auto adds 2 bits controller ID ahead of
1105+
* streamID, so mask these 2 bits to get streamID. The
1106+
* IOMMU glue layer doesn't do that.
1107+
*/
1108+
if (sid_i != (sid_m & IMX95_SID_MASK)) {
1109+
dev_err(dev, "iommu-map and msi-map entries mismatch!\n");
1110+
return -EINVAL;
1111+
}
1112+
}
1113+
1114+
if (!err_i)
1115+
sid = sid_i;
1116+
else if (!err_m)
1117+
sid = sid_m & IMX95_SID_MASK;
1118+
1119+
return imx_pcie_add_lut(imx_pcie, rid, sid);
1120+
}
1121+
1122+
static void imx_pcie_disable_device(struct pci_host_bridge *bridge,
1123+
struct pci_dev *pdev)
1124+
{
1125+
struct imx_pcie *imx_pcie;
1126+
1127+
imx_pcie = to_imx_pcie(to_dw_pcie_from_pp(bridge->sysdata));
1128+
imx_pcie_remove_lut(imx_pcie, pci_dev_id(pdev));
1129+
}
1130+
9331131
static int imx_pcie_host_init(struct dw_pcie_rp *pp)
9341132
{
9351133
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -946,6 +1144,11 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
9461144
}
9471145
}
9481146

1147+
if (pp->bridge && imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) {
1148+
pp->bridge->enable_device = imx_pcie_enable_device;
1149+
pp->bridge->disable_device = imx_pcie_disable_device;
1150+
}
1151+
9491152
imx_pcie_assert_core_reset(imx_pcie);
9501153

9511154
if (imx_pcie->drvdata->init_phy)
@@ -1330,6 +1533,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
13301533
imx_pcie->pci = pci;
13311534
imx_pcie->drvdata = of_device_get_match_data(dev);
13321535

1536+
mutex_init(&imx_pcie->lock);
1537+
13331538
/* Find the PHY if one is defined, only imx7d uses it */
13341539
np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0);
13351540
if (np) {
@@ -1627,7 +1832,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
16271832
},
16281833
[IMX95] = {
16291834
.variant = IMX95,
1630-
.flags = IMX_PCIE_FLAG_HAS_SERDES,
1835+
.flags = IMX_PCIE_FLAG_HAS_SERDES |
1836+
IMX_PCIE_FLAG_HAS_LUT,
16311837
.clk_names = imx8mq_clks,
16321838
.clks_cnt = ARRAY_SIZE(imx8mq_clks),
16331839
.ltssm_off = IMX95_PE0_GEN_CTRL_3,

drivers/pci/controller/pci-host-common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ int pci_host_common_probe(struct platform_device *pdev)
7575

7676
bridge->sysdata = cfg;
7777
bridge->ops = (struct pci_ops *)&ops->pci_ops;
78+
bridge->enable_device = ops->enable_device;
79+
bridge->disable_device = ops->disable_device;
7880
bridge->msi_domain = true;
7981

8082
return pci_host_probe(bridge);

drivers/pci/controller/pcie-apple.c

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <linux/list.h>
2727
#include <linux/module.h>
2828
#include <linux/msi.h>
29-
#include <linux/notifier.h>
3029
#include <linux/of_irq.h>
3130
#include <linux/pci-ecam.h>
3231

@@ -667,12 +666,16 @@ static struct apple_pcie_port *apple_pcie_get_port(struct pci_dev *pdev)
667666
return NULL;
668667
}
669668

670-
static int apple_pcie_add_device(struct apple_pcie_port *port,
671-
struct pci_dev *pdev)
669+
static int apple_pcie_enable_device(struct pci_host_bridge *bridge, struct pci_dev *pdev)
672670
{
673671
u32 sid, rid = pci_dev_id(pdev);
672+
struct apple_pcie_port *port;
674673
int idx, err;
675674

675+
port = apple_pcie_get_port(pdev);
676+
if (!port)
677+
return 0;
678+
676679
dev_dbg(&pdev->dev, "added to bus %s, index %d\n",
677680
pci_name(pdev->bus->self), port->idx);
678681

@@ -698,12 +701,16 @@ static int apple_pcie_add_device(struct apple_pcie_port *port,
698701
return idx >= 0 ? 0 : -ENOSPC;
699702
}
700703

701-
static void apple_pcie_release_device(struct apple_pcie_port *port,
702-
struct pci_dev *pdev)
704+
static void apple_pcie_disable_device(struct pci_host_bridge *bridge, struct pci_dev *pdev)
703705
{
706+
struct apple_pcie_port *port;
704707
u32 rid = pci_dev_id(pdev);
705708
int idx;
706709

710+
port = apple_pcie_get_port(pdev);
711+
if (!port)
712+
return;
713+
707714
mutex_lock(&port->pcie->lock);
708715

709716
for_each_set_bit(idx, port->sid_map, port->sid_map_sz) {
@@ -721,45 +728,6 @@ static void apple_pcie_release_device(struct apple_pcie_port *port,
721728
mutex_unlock(&port->pcie->lock);
722729
}
723730

724-
static int apple_pcie_bus_notifier(struct notifier_block *nb,
725-
unsigned long action,
726-
void *data)
727-
{
728-
struct device *dev = data;
729-
struct pci_dev *pdev = to_pci_dev(dev);
730-
struct apple_pcie_port *port;
731-
int err;
732-
733-
/*
734-
* This is a bit ugly. We assume that if we get notified for
735-
* any PCI device, we must be in charge of it, and that there
736-
* is no other PCI controller in the whole system. It probably
737-
* holds for now, but who knows for how long?
738-
*/
739-
port = apple_pcie_get_port(pdev);
740-
if (!port)
741-
return NOTIFY_DONE;
742-
743-
switch (action) {
744-
case BUS_NOTIFY_ADD_DEVICE:
745-
err = apple_pcie_add_device(port, pdev);
746-
if (err)
747-
return notifier_from_errno(err);
748-
break;
749-
case BUS_NOTIFY_DEL_DEVICE:
750-
apple_pcie_release_device(port, pdev);
751-
break;
752-
default:
753-
return NOTIFY_DONE;
754-
}
755-
756-
return NOTIFY_OK;
757-
}
758-
759-
static struct notifier_block apple_pcie_nb = {
760-
.notifier_call = apple_pcie_bus_notifier,
761-
};
762-
763731
static int apple_pcie_init(struct pci_config_window *cfg)
764732
{
765733
struct device *dev = cfg->parent;
@@ -799,23 +767,10 @@ static int apple_pcie_init(struct pci_config_window *cfg)
799767
return 0;
800768
}
801769

802-
static int apple_pcie_probe(struct platform_device *pdev)
803-
{
804-
int ret;
805-
806-
ret = bus_register_notifier(&pci_bus_type, &apple_pcie_nb);
807-
if (ret)
808-
return ret;
809-
810-
ret = pci_host_common_probe(pdev);
811-
if (ret)
812-
bus_unregister_notifier(&pci_bus_type, &apple_pcie_nb);
813-
814-
return ret;
815-
}
816-
817770
static const struct pci_ecam_ops apple_pcie_cfg_ecam_ops = {
818771
.init = apple_pcie_init,
772+
.enable_device = apple_pcie_enable_device,
773+
.disable_device = apple_pcie_disable_device,
819774
.pci_ops = {
820775
.map_bus = pci_ecam_map_bus,
821776
.read = pci_generic_config_read,
@@ -830,7 +785,7 @@ static const struct of_device_id apple_pcie_of_match[] = {
830785
MODULE_DEVICE_TABLE(of, apple_pcie_of_match);
831786

832787
static struct platform_driver apple_pcie_driver = {
833-
.probe = apple_pcie_probe,
788+
.probe = pci_host_common_probe,
834789
.driver = {
835790
.name = "pcie-apple",
836791
.of_match_table = apple_pcie_of_match,

0 commit comments

Comments
 (0)