@@ -946,30 +946,67 @@ void pci_request_acs(void)
946
946
}
947
947
948
948
static const char * disable_acs_redir_param ;
949
+ static const char * config_acs_param ;
949
950
950
- /**
951
- * pci_disable_acs_redir - disable ACS redirect capabilities
952
- * @dev: the PCI device
953
- *
954
- * For only devices specified in the disable_acs_redir parameter.
955
- */
956
- static void pci_disable_acs_redir (struct pci_dev * dev )
951
+ struct pci_acs {
952
+ u16 cap ;
953
+ u16 ctrl ;
954
+ u16 fw_ctrl ;
955
+ };
956
+
957
+ static void __pci_config_acs (struct pci_dev * dev , struct pci_acs * caps ,
958
+ const char * p , u16 mask , u16 flags )
957
959
{
960
+ char * delimit ;
958
961
int ret = 0 ;
959
- const char * p ;
960
- int pos ;
961
- u16 ctrl ;
962
962
963
- if (!disable_acs_redir_param )
963
+ if (!p )
964
964
return ;
965
965
966
- p = disable_acs_redir_param ;
967
966
while (* p ) {
967
+ if (!mask ) {
968
+ /* Check for ACS flags */
969
+ delimit = strstr (p , "@" );
970
+ if (delimit ) {
971
+ int end ;
972
+ u32 shift = 0 ;
973
+
974
+ end = delimit - p - 1 ;
975
+
976
+ while (end > -1 ) {
977
+ if (* (p + end ) == '0' ) {
978
+ mask |= 1 << shift ;
979
+ shift ++ ;
980
+ end -- ;
981
+ } else if (* (p + end ) == '1' ) {
982
+ mask |= 1 << shift ;
983
+ flags |= 1 << shift ;
984
+ shift ++ ;
985
+ end -- ;
986
+ } else if ((* (p + end ) == 'x' ) || (* (p + end ) == 'X' )) {
987
+ shift ++ ;
988
+ end -- ;
989
+ } else {
990
+ pci_err (dev , "Invalid ACS flags... Ignoring\n" );
991
+ return ;
992
+ }
993
+ }
994
+ p = delimit + 1 ;
995
+ } else {
996
+ pci_err (dev , "ACS Flags missing\n" );
997
+ return ;
998
+ }
999
+ }
1000
+
1001
+ if (mask & ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | PCI_ACS_CR |
1002
+ PCI_ACS_UF | PCI_ACS_EC | PCI_ACS_DT )) {
1003
+ pci_err (dev , "Invalid ACS flags specified\n" );
1004
+ return ;
1005
+ }
1006
+
968
1007
ret = pci_dev_str_match (dev , p , & p );
969
1008
if (ret < 0 ) {
970
- pr_info_once ("PCI: Can't parse disable_acs_redir parameter: %s\n" ,
971
- disable_acs_redir_param );
972
-
1009
+ pr_info_once ("PCI: Can't parse ACS command line parameter\n" );
973
1010
break ;
974
1011
} else if (ret == 1 ) {
975
1012
/* Found a match */
@@ -989,56 +1026,38 @@ static void pci_disable_acs_redir(struct pci_dev *dev)
989
1026
if (!pci_dev_specific_disable_acs_redir (dev ))
990
1027
return ;
991
1028
992
- pos = dev -> acs_cap ;
993
- if (!pos ) {
994
- pci_warn (dev , "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n" );
995
- return ;
996
- }
997
-
998
- pci_read_config_word (dev , pos + PCI_ACS_CTRL , & ctrl );
1029
+ pci_dbg (dev , "ACS mask = %#06x\n" , mask );
1030
+ pci_dbg (dev , "ACS flags = %#06x\n" , flags );
999
1031
1000
- /* P2P Request & Completion Redirect */
1001
- ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC );
1032
+ /* If mask is 0 then we copy the bit from the firmware setting. */
1033
+ caps -> ctrl = (caps -> ctrl & ~mask ) | (caps -> fw_ctrl & mask );
1034
+ caps -> ctrl |= flags ;
1002
1035
1003
- pci_write_config_word (dev , pos + PCI_ACS_CTRL , ctrl );
1004
-
1005
- pci_info (dev , "disabled ACS redirect\n" );
1036
+ pci_info (dev , "Configured ACS to %#06x\n" , caps -> ctrl );
1006
1037
}
1007
1038
1008
1039
/**
1009
1040
* pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
1010
1041
* @dev: the PCI device
1042
+ * @caps: default ACS controls
1011
1043
*/
1012
- static void pci_std_enable_acs (struct pci_dev * dev )
1044
+ static void pci_std_enable_acs (struct pci_dev * dev , struct pci_acs * caps )
1013
1045
{
1014
- int pos ;
1015
- u16 cap ;
1016
- u16 ctrl ;
1017
-
1018
- pos = dev -> acs_cap ;
1019
- if (!pos )
1020
- return ;
1021
-
1022
- pci_read_config_word (dev , pos + PCI_ACS_CAP , & cap );
1023
- pci_read_config_word (dev , pos + PCI_ACS_CTRL , & ctrl );
1024
-
1025
1046
/* Source Validation */
1026
- ctrl |= (cap & PCI_ACS_SV );
1047
+ caps -> ctrl |= (caps -> cap & PCI_ACS_SV );
1027
1048
1028
1049
/* P2P Request Redirect */
1029
- ctrl |= (cap & PCI_ACS_RR );
1050
+ caps -> ctrl |= (caps -> cap & PCI_ACS_RR );
1030
1051
1031
1052
/* P2P Completion Redirect */
1032
- ctrl |= (cap & PCI_ACS_CR );
1053
+ caps -> ctrl |= (caps -> cap & PCI_ACS_CR );
1033
1054
1034
1055
/* Upstream Forwarding */
1035
- ctrl |= (cap & PCI_ACS_UF );
1056
+ caps -> ctrl |= (caps -> cap & PCI_ACS_UF );
1036
1057
1037
1058
/* Enable Translation Blocking for external devices and noats */
1038
1059
if (pci_ats_disabled () || dev -> external_facing || dev -> untrusted )
1039
- ctrl |= (cap & PCI_ACS_TB );
1040
-
1041
- pci_write_config_word (dev , pos + PCI_ACS_CTRL , ctrl );
1060
+ caps -> ctrl |= (caps -> cap & PCI_ACS_TB );
1042
1061
}
1043
1062
1044
1063
/**
@@ -1047,23 +1066,33 @@ static void pci_std_enable_acs(struct pci_dev *dev)
1047
1066
*/
1048
1067
static void pci_enable_acs (struct pci_dev * dev )
1049
1068
{
1050
- if (!pci_acs_enable )
1051
- goto disable_acs_redir ;
1069
+ struct pci_acs caps ;
1070
+ int pos ;
1071
+
1072
+ pos = dev -> acs_cap ;
1073
+ if (!pos )
1074
+ return ;
1052
1075
1053
- if (!pci_dev_specific_enable_acs (dev ))
1054
- goto disable_acs_redir ;
1076
+ pci_read_config_word (dev , pos + PCI_ACS_CAP , & caps .cap );
1077
+ pci_read_config_word (dev , pos + PCI_ACS_CTRL , & caps .ctrl );
1078
+ caps .fw_ctrl = caps .ctrl ;
1055
1079
1056
- pci_std_enable_acs (dev );
1080
+ /* If an iommu is present we start with kernel default caps */
1081
+ if (pci_acs_enable ) {
1082
+ if (pci_dev_specific_enable_acs (dev ))
1083
+ pci_std_enable_acs (dev , & caps );
1084
+ }
1057
1085
1058
- disable_acs_redir :
1059
1086
/*
1060
- * Note: pci_disable_acs_redir() must be called even if ACS was not
1061
- * enabled by the kernel because it may have been enabled by
1062
- * platform firmware. So if we are told to disable it, we should
1063
- * always disable it after setting the kernel's default
1064
- * preferences.
1087
+ * Always apply caps from the command line, even if there is no iommu.
1088
+ * Trust that the admin has a reason to change the ACS settings.
1065
1089
*/
1066
- pci_disable_acs_redir (dev );
1090
+ __pci_config_acs (dev , & caps , disable_acs_redir_param ,
1091
+ PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC ,
1092
+ ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC ));
1093
+ __pci_config_acs (dev , & caps , config_acs_param , 0 , 0 );
1094
+
1095
+ pci_write_config_word (dev , pos + PCI_ACS_CTRL , caps .ctrl );
1067
1096
}
1068
1097
1069
1098
/**
@@ -6874,6 +6903,8 @@ static int __init pci_setup(char *str)
6874
6903
pci_add_flags (PCI_SCAN_ALL_PCIE_DEVS );
6875
6904
} else if (!strncmp (str , "disable_acs_redir=" , 18 )) {
6876
6905
disable_acs_redir_param = str + 18 ;
6906
+ } else if (!strncmp (str , "config_acs=" , 11 )) {
6907
+ config_acs_param = str + 11 ;
6877
6908
} else {
6878
6909
pr_err ("PCI: Unknown option `%s'\n" , str );
6879
6910
}
@@ -6898,6 +6929,7 @@ static int __init pci_realloc_setup_params(void)
6898
6929
resource_alignment_param = kstrdup (resource_alignment_param ,
6899
6930
GFP_KERNEL );
6900
6931
disable_acs_redir_param = kstrdup (disable_acs_redir_param , GFP_KERNEL );
6932
+ config_acs_param = kstrdup (config_acs_param , GFP_KERNEL );
6901
6933
6902
6934
return 0 ;
6903
6935
}
0 commit comments