Advertisement
Guest User

V2 ACS patch

a guest
Apr 11th, 2014
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.61 KB | None | 0 0
  1. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
  2. index 1febe90..b89502f 100644
  3. --- a/drivers/pci/pci.c
  4. +++ b/drivers/pci/pci.c
  5. @@ -2180,21 +2180,18 @@ void pci_request_acs(void)
  6. }
  7.  
  8. /**
  9. - * pci_enable_acs - enable ACS if hardware support it
  10. + * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
  11. * @dev: the PCI device
  12. */
  13. -void pci_enable_acs(struct pci_dev *dev)
  14. +static int pci_std_enable_acs(struct pci_dev *dev)
  15. {
  16. int pos;
  17. u16 cap;
  18. u16 ctrl;
  19.  
  20. - if (!pci_acs_enable)
  21. - return;
  22. -
  23. pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
  24. if (!pos)
  25. - return;
  26. + return -ENODEV;
  27.  
  28. pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
  29. pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
  30. @@ -2212,6 +2209,23 @@ void pci_enable_acs(struct pci_dev *dev)
  31. ctrl |= (cap & PCI_ACS_UF);
  32.  
  33. pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
  34. +
  35. + return 0;
  36. +}
  37. +
  38. +/**
  39. + * pci_enable_acs - enable ACS if hardware support it
  40. + * @dev: the PCI device
  41. + */
  42. +void pci_enable_acs(struct pci_dev *dev)
  43. +{
  44. + if (!pci_acs_enable)
  45. + return;
  46. +
  47. + if (!pci_std_enable_acs(dev))
  48. + return;
  49. +
  50. + pci_dev_specific_enable_acs(dev);
  51. }
  52.  
  53. static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
  54. diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
  55. index 5cb726c..f681fb0 100644
  56. --- a/drivers/pci/quirks.c
  57. +++ b/drivers/pci/quirks.c
  58. @@ -3461,3 +3461,28 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
  59.  
  60. return -ENOTTY;
  61. }
  62. +
  63. +static const struct pci_dev_enable_acs {
  64. + u16 vendor;
  65. + u16 device;
  66. + int (*enable_acs)(struct pci_dev *dev);
  67. +} pci_dev_enable_acs[] = {
  68. + { 0 }
  69. +};
  70. +
  71. +void pci_dev_specific_enable_acs(struct pci_dev *dev)
  72. +{
  73. + const struct pci_dev_enable_acs *i;
  74. + int ret;
  75. +
  76. + for (i = pci_dev_enable_acs; i->enable_acs; i++) {
  77. + if ((i->vendor == dev->vendor ||
  78. + i->vendor == (u16)PCI_ANY_ID) &&
  79. + (i->device == dev->device ||
  80. + i->device == (u16)PCI_ANY_ID)) {
  81. + ret = i->enable_acs(dev);
  82. + if (ret >= 0)
  83. + return;
  84. + }
  85. + }
  86. +}
  87. diff --git a/include/linux/pci.h b/include/linux/pci.h
  88. index fb57c89..f9a47dd 100644
  89. --- a/include/linux/pci.h
  90. +++ b/include/linux/pci.h
  91. @@ -1510,6 +1510,7 @@ enum pci_fixup_pass {
  92. void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
  93. struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
  94. int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
  95. +void pci_dev_specific_enable_acs(struct pci_dev *dev);
  96. #else
  97. static inline void pci_fixup_device(enum pci_fixup_pass pass,
  98. struct pci_dev *dev) { }
  99. @@ -1522,6 +1523,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
  100. {
  101. return -ENOTTY;
  102. }
  103. +static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) {}
  104. #endif
  105.  
  106. void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
  107.  
  108.  
  109.  
  110. diff --git a/include/linux/pci.h b/include/linux/pci.h
  111. index f9a47dd..cb9a109 100644
  112. --- a/include/linux/pci.h
  113. +++ b/include/linux/pci.h
  114. @@ -170,6 +170,8 @@ enum pci_dev_flags {
  115. PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
  116. /* Provide indication device is assigned by a Virtual Machine Manager */
  117. PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
  118. + /* Flag for quirk use to store if quirk specific ACS is enabled */
  119. + PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8,
  120. };
  121.  
  122. enum pci_irq_reroute_variant {
  123.  
  124. }
  125.  
  126.  
  127. diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
  128. index f681fb0..ed2ed86 100644
  129. --- a/drivers/pci/quirks.c
  130. +++ b/drivers/pci/quirks.c
  131. @@ -3423,6 +3423,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
  132. #endif
  133. }
  134.  
  135. +/*
  136. + * Many Intel PCH root ports do provide ACS-like features to disable peer
  137. + * transactions and validate bus numbers in requests, but do not provide an
  138. + * actual PCIe ACS capability. This is the list of device IDs known to fall
  139. + * into that category as provided by Intel in Red Hat bugzilla 1037684.
  140. + */
  141. +static const u16 pci_quirk_intel_pch_acs_ids[] = {
  142. + /* Ibexpeak PCH */
  143. + 0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49,
  144. + 0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51,
  145. + /* Cougarpoint PCH */
  146. + 0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17,
  147. + 0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f,
  148. + /* Pantherpoint PCH */
  149. + 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17,
  150. + 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f,
  151. + /* Lynxpoint-H PCH */
  152. + 0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17,
  153. + 0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f,
  154. + /* Lynxpoint-LP PCH */
  155. + 0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17,
  156. + 0x9c18, 0x9c19, 0x9c1a, 0x9c1b,
  157. + /* Wildcat PCH */
  158. + 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
  159. + 0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
  160. +};
  161. +
  162. +static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
  163. +{
  164. + int i;
  165. +
  166. + /* Filter out a few obvious non-matches first */
  167. + if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
  168. + return false;
  169. +
  170. + for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++)
  171. + if (pci_quirk_intel_pch_acs_ids[i] == dev->device)
  172. + return true;
  173. +
  174. + return false;
  175. +}
  176. +
  177. +#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
  178. +
  179. +static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
  180. +{
  181. + u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
  182. + INTEL_PCH_ACS_FLAGS : 0;
  183. +
  184. + if (!pci_quirk_intel_pch_acs_match(dev))
  185. + return -ENOTTY;
  186. +
  187. + return acs_flags & ~flags ? 0 : 1;
  188. +}
  189. +
  190. static const struct pci_dev_acs_enabled {
  191. u16 vendor;
  192. u16 device;
  193. @@ -3434,6 +3489,7 @@ static const struct pci_dev_acs_enabled {
  194. { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
  195. { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
  196. { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
  197. + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
  198. { 0 }
  199. };
  200.  
  201. @@ -3462,11 +3518,115 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
  202. return -ENOTTY;
  203. }
  204.  
  205. +/* Config space offset of Root Complex Base Address register */
  206. +#define INTEL_LPC_RCBA_REG 0xf0
  207. +/* 31:14 RCBA address */
  208. +#define INTEL_LPC_RCBA_MASK 0xffffc000
  209. +/* RCBA Enable */
  210. +#define INTEL_LPC_RCBA_ENABLE (1 << 0)
  211. +
  212. +/* Backbone Scratch Pad Register */
  213. +#define INTEL_BSPR_REG 0x1104
  214. +/* Backbone Peer Non-Posted Disable */
  215. +#define INTEL_BSPR_REG_BPNPD (1 << 8)
  216. +/* Backbone Peer Posted Disable */
  217. +#define INTEL_BSPR_REG_BPPD (1 << 9)
  218. +
  219. +/* Upstream Peer Decode Configuration Register */
  220. +#define INTEL_UPDCR_REG 0x1114
  221. +/* 5:0 Peer Decode Enable bits */
  222. +#define INTEL_UPDCR_REG_MASK 0x3f
  223. +
  224. +static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev)
  225. +{
  226. + u32 rcba, bspr, updcr;
  227. + void __iomem *rcba_mem;
  228. +
  229. + /*
  230. + * Read the RCBA register from the LPC (D31:F0). PCH root ports
  231. + * are D28:F* and therefore get probed before LPC, thus we can't
  232. + * use pci_get_slot/pci_read_config_dword here.
  233. + */
  234. + pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0),
  235. + INTEL_LPC_RCBA_REG, &rcba);
  236. + if (!(rcba & INTEL_LPC_RCBA_ENABLE))
  237. + return -EINVAL;
  238. +
  239. + rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK,
  240. + PAGE_ALIGN(INTEL_UPDCR_REG));
  241. + if (!rcba_mem)
  242. + return -ENOMEM;
  243. +
  244. + /*
  245. + * The BSPR can disallow peer cycles, but it's set by soft strap and
  246. + * therefore read-only. If both posted and non-posted peer cycles are
  247. + * disallowed, we're ok. If either are allowed, then we need to use
  248. + * the UPDCR to disable peer decodes for each port. This provides the
  249. + * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
  250. + */
  251. + bspr = readl(rcba_mem + INTEL_BSPR_REG);
  252. + bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD;
  253. + if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) {
  254. + updcr = readl(rcba_mem + INTEL_UPDCR_REG);
  255. + if (updcr & INTEL_UPDCR_REG_MASK) {
  256. + dev_info(&dev->dev, "Disabling UPDCR peer decodes\n");
  257. + updcr &= ~INTEL_UPDCR_REG_MASK;
  258. + writel(updcr, rcba_mem + INTEL_UPDCR_REG);
  259. + }
  260. + }
  261. +
  262. + iounmap(rcba_mem);
  263. + return 0;
  264. +}
  265. +
  266. +/* Miscellaneous Port Configuration register */
  267. +#define INTEL_MPC_REG 0xd8
  268. +/* MPC: Invalid Receive Bus Number Check Enable */
  269. +#define INTEL_MPC_REG_IRBNCE (1 << 26)
  270. +
  271. +static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
  272. +{
  273. + u32 mpc;
  274. +
  275. + /*
  276. + * When enabled, the IRBNCE bit of the MPC register enables the
  277. + * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which
  278. + * ensures that requester IDs fall within the bus number range
  279. + * of the bridge. Enable if not already.
  280. + */
  281. + pci_read_config_dword(dev, INTEL_MPC_REG, &mpc);
  282. + if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
  283. + dev_info(&dev->dev, "Enabling MPC IRBNCE\n");
  284. + mpc |= INTEL_MPC_REG_IRBNCE;
  285. + pci_write_config_word(dev, INTEL_MPC_REG, mpc);
  286. + }
  287. +}
  288. +
  289. +static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
  290. +{
  291. + if (!pci_quirk_intel_pch_acs_match(dev))
  292. + return -ENOTTY;
  293. +
  294. + if (pci_quirk_enable_intel_lpc_acs(dev)) {
  295. + dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n");
  296. + return 0;
  297. + }
  298. +
  299. + pci_quirk_enable_intel_rp_mpc_acs(dev);
  300. +
  301. + dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK;
  302. +
  303. + dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n");
  304. +
  305. + return 0;
  306. +}
  307. +
  308. static const struct pci_dev_enable_acs {
  309. u16 vendor;
  310. u16 device;
  311. int (*enable_acs)(struct pci_dev *dev);
  312. } pci_dev_enable_acs[] = {
  313. + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
  314. { 0 }
  315. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement