@@ -946,30 +946,67 @@ void pci_request_acs(void)
946946}
947947
948948static const char * disable_acs_redir_param ;
949+ static const char * config_acs_param ;
949950
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 )
957959{
960+ char * delimit ;
958961 int ret = 0 ;
959- const char * p ;
960- int pos ;
961- u16 ctrl ;
962962
963- if (!disable_acs_redir_param )
963+ if (!p )
964964 return ;
965965
966- p = disable_acs_redir_param ;
967966 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+
9681007 ret = pci_dev_str_match (dev , p , & p );
9691008 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" );
9731010 break ;
9741011 } else if (ret == 1 ) {
9751012 /* Found a match */
@@ -989,56 +1026,38 @@ static void pci_disable_acs_redir(struct pci_dev *dev)
9891026 if (!pci_dev_specific_disable_acs_redir (dev ))
9901027 return ;
9911028
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 );
9991031
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 ;
10021035
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 );
10061037}
10071038
10081039/**
10091040 * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
10101041 * @dev: the PCI device
1042+ * @caps: default ACS controls
10111043 */
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 )
10131045{
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-
10251046 /* Source Validation */
1026- ctrl |= (cap & PCI_ACS_SV );
1047+ caps -> ctrl |= (caps -> cap & PCI_ACS_SV );
10271048
10281049 /* P2P Request Redirect */
1029- ctrl |= (cap & PCI_ACS_RR );
1050+ caps -> ctrl |= (caps -> cap & PCI_ACS_RR );
10301051
10311052 /* P2P Completion Redirect */
1032- ctrl |= (cap & PCI_ACS_CR );
1053+ caps -> ctrl |= (caps -> cap & PCI_ACS_CR );
10331054
10341055 /* Upstream Forwarding */
1035- ctrl |= (cap & PCI_ACS_UF );
1056+ caps -> ctrl |= (caps -> cap & PCI_ACS_UF );
10361057
10371058 /* Enable Translation Blocking for external devices and noats */
10381059 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 );
10421061}
10431062
10441063/**
@@ -1047,23 +1066,33 @@ static void pci_std_enable_acs(struct pci_dev *dev)
10471066 */
10481067static void pci_enable_acs (struct pci_dev * dev )
10491068{
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 ;
10521075
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 ;
10551079
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+ }
10571085
1058- disable_acs_redir :
10591086 /*
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.
10651089 */
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 );
10671096}
10681097
10691098/**
@@ -6840,6 +6869,8 @@ static int __init pci_setup(char *str)
68406869 pci_add_flags (PCI_SCAN_ALL_PCIE_DEVS );
68416870 } else if (!strncmp (str , "disable_acs_redir=" , 18 )) {
68426871 disable_acs_redir_param = str + 18 ;
6872+ } else if (!strncmp (str , "config_acs=" , 11 )) {
6873+ config_acs_param = str + 11 ;
68436874 } else {
68446875 pr_err ("PCI: Unknown option `%s'\n" , str );
68456876 }
@@ -6864,6 +6895,7 @@ static int __init pci_realloc_setup_params(void)
68646895 resource_alignment_param = kstrdup (resource_alignment_param ,
68656896 GFP_KERNEL );
68666897 disable_acs_redir_param = kstrdup (disable_acs_redir_param , GFP_KERNEL );
6898+ config_acs_param = kstrdup (config_acs_param , GFP_KERNEL );
68676899
68686900 return 0 ;
68696901}
0 commit comments