Guest User

Untitled

a guest
Nov 17th, 2018
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.35 KB | None | 0 0
  1. ---
  2. hw/pci/pcie.c | 7 ++++---
  3. hw/vfio/pci.c | 3 ++-
  4. include/hw/pci/pcie_regs.h | 23 +++++++++++++++++++++--
  5. 3 files changed, 27 insertions(+), 6 deletions(-)
  6.  
  7. diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
  8. index 6c91bd44a0a5..914a5261a79b 100644
  9. --- a/hw/pci/pcie.c
  10. +++ b/hw/pci/pcie.c
  11. @@ -68,11 +68,12 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
  12. pci_set_long(exp_cap + PCI_EXP_LNKCAP,
  13. (port << PCI_EXP_LNKCAP_PN_SHIFT) |
  14. PCI_EXP_LNKCAP_ASPMS_0S |
  15. - PCI_EXP_LNK_MLW_1 |
  16. - PCI_EXP_LNK_LS_25);
  17. + QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
  18. + QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
  19.  
  20. pci_set_word(exp_cap + PCI_EXP_LNKSTA,
  21. - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
  22. + QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
  23. + QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));
  24.  
  25. if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
  26. pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
  27. diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
  28. index 866f0deeb7eb..08aab328b442 100644
  29. --- a/hw/vfio/pci.c
  30. +++ b/hw/vfio/pci.c
  31. @@ -1895,7 +1895,8 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
  32. PCI_EXP_TYPE_ENDPOINT << 4,
  33. PCI_EXP_FLAGS_TYPE);
  34. vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
  35. - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
  36. + QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
  37. + QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
  38. vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
  39. }
  40.  
  41. diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
  42. index a95522a13b04..ad4e7808b8ac 100644
  43. --- a/include/hw/pci/pcie_regs.h
  44. +++ b/include/hw/pci/pcie_regs.h
  45. @@ -34,10 +34,29 @@
  46.  
  47. /* PCI_EXP_LINK{CAP, STA} */
  48. /* link speed */
  49. -#define PCI_EXP_LNK_LS_25 1
  50. +typedef enum PCIExpLinkSpeed {
  51. + QEMU_PCI_EXP_LNK_2_5GT = 1,
  52. + QEMU_PCI_EXP_LNK_5GT,
  53. + QEMU_PCI_EXP_LNK_8GT,
  54. + QEMU_PCI_EXP_LNK_16GT,
  55. +} PCIExpLinkSpeed;
  56. +
  57. +#define QEMU_PCI_EXP_LNKCAP_MLS(speed) (speed)
  58. +#define QEMU_PCI_EXP_LNKSTA_CLS QEMU_PCI_EXP_LNKCAP_MLS
  59. +
  60. +typedef enum PCIExpLinkWidth {
  61. + QEMU_PCI_EXP_LNK_X1 = 1,
  62. + QEMU_PCI_EXP_LNK_X2 = 2,
  63. + QEMU_PCI_EXP_LNK_X4 = 4,
  64. + QEMU_PCI_EXP_LNK_X8 = 8,
  65. + QEMU_PCI_EXP_LNK_X12 = 12,
  66. + QEMU_PCI_EXP_LNK_X16 = 16,
  67. + QEMU_PCI_EXP_LNK_X32 = 32,
  68. +} PCIExpLinkWidth;
  69.  
  70. #define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW)
  71. -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
  72. +#define QEMU_PCI_EXP_LNKCAP_MLW(width) (width << PCI_EXP_LNK_MLW_SHIFT)
  73. +#define QEMU_PCI_EXP_LNKSTA_NLW QEMU_PCI_EXP_LNKCAP_MLW
  74.  
  75. /* PCI_EXP_LINKCAP */
  76. #define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS)
  77.  
  78.  
  79. ---
  80. hw/pci/pci.c | 4 ++++
  81. hw/pci/pcie.c | 39 +++++++++++++++++++++++++++++++++++++++
  82. include/hw/pci/pci.h | 13 +++++++++++++
  83. include/hw/pci/pcie.h | 1 +
  84. 4 files changed, 57 insertions(+)
  85.  
  86. diff --git a/hw/pci/pci.c b/hw/pci/pci.c
  87. index b937f0dc0af4..576c85f376b6 100644
  88. --- a/hw/pci/pci.c
  89. +++ b/hw/pci/pci.c
  90. @@ -1353,6 +1353,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
  91. {
  92. uint32_t val = 0;
  93.  
  94. + if (pci_is_express_downstream_port(d) &&
  95. + ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) {
  96. + pcie_sync_bridge_lnk(d);
  97. + }
  98. memcpy(&val, d->config + address, len);
  99. return le32_to_cpu(val);
  100. }
  101. diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
  102. index 914a5261a79b..61b7b96c52cd 100644
  103. --- a/hw/pci/pcie.c
  104. +++ b/hw/pci/pcie.c
  105. @@ -729,6 +729,45 @@ void pcie_add_capability(PCIDevice *dev,
  106. memset(dev->cmask + offset, 0xFF, size);
  107. }
  108.  
  109. +/*
  110. + * Sync the PCIe Link Status negotiated speed and width of a bridge with the
  111. + * downstream device. If downstream device is not present, re-write with the
  112. + * Link Capability fields. Limit width and speed to bridge capabilities for
  113. + * compatibility. Use config_read to access the downstream device since it
  114. + * could be an assigned device with volatile link information.
  115. + */
  116. +void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
  117. +{
  118. + PCIBridge *br = PCI_BRIDGE(bridge_dev);
  119. + PCIBus *bus = pci_bridge_get_sec_bus(br);
  120. + PCIDevice *target = bus->devices[0];
  121. + uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
  122. + uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);
  123. +
  124. + if (!target || !target->exp.exp_cap) {
  125. + lnksta = lnkcap;
  126. + } else {
  127. + lnksta = target->config_read(target,
  128. + target->exp.exp_cap + PCI_EXP_LNKSTA,
  129. + sizeof(lnksta));
  130. +
  131. + if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
  132. + lnksta &= ~PCI_EXP_LNKSTA_NLW;
  133. + lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
  134. + }
  135. +
  136. + if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
  137. + lnksta &= ~PCI_EXP_LNKSTA_CLS;
  138. + lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
  139. + }
  140. + }
  141. +
  142. + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
  143. + PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
  144. + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
  145. + (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
  146. +}
  147. +
  148. /**************************************************************************
  149. * pci express extended capability helper functions
  150. */
  151. diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
  152. index e6514bba23aa..eb12fa112ed2 100644
  153. --- a/include/hw/pci/pci.h
  154. +++ b/include/hw/pci/pci.h
  155. @@ -737,6 +737,19 @@ static inline int pci_is_express(const PCIDevice *d)
  156. return d->cap_present & QEMU_PCI_CAP_EXPRESS;
  157. }
  158.  
  159. +static inline int pci_is_express_downstream_port(const PCIDevice *d)
  160. +{
  161. + uint8_t type;
  162. +
  163. + if (!pci_is_express(d) || !d->exp.exp_cap) {
  164. + return 0;
  165. + }
  166. +
  167. + type = pcie_cap_get_type(d);
  168. +
  169. + return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
  170. +}
  171. +
  172. static inline uint32_t pci_config_size(const PCIDevice *d)
  173. {
  174. return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
  175. diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
  176. index b71e36970345..1976909ab4c8 100644
  177. --- a/include/hw/pci/pcie.h
  178. +++ b/include/hw/pci/pcie.h
  179. @@ -126,6 +126,7 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
  180. void pcie_add_capability(PCIDevice *dev,
  181. uint16_t cap_id, uint8_t cap_ver,
  182. uint16_t offset, uint16_t size);
  183. +void pcie_sync_bridge_lnk(PCIDevice *dev);
  184.  
  185. void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
  186. void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
  187.  
  188.  
  189. ---
  190. hw/core/qdev-properties.c | 178 ++++++++++++++++++++++++++++++++++++++++++
  191. include/hw/qdev-properties.h | 8 ++
  192. qapi/common.json | 42 ++++++++++
  193. 3 files changed, 228 insertions(+)
  194.  
  195. diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
  196. index 35072dec1ecf..f5ca5b821a79 100644
  197. --- a/hw/core/qdev-properties.c
  198. +++ b/hw/core/qdev-properties.c
  199. @@ -1327,3 +1327,181 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
  200. .set = set_enum,
  201. .set_default_value = set_default_value_enum,
  202. };
  203. +
  204. +/* --- PCIELinkSpeed 2_5/5/8/16 -- */
  205. +
  206. +static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
  207. + void *opaque, Error **errp)
  208. +{
  209. + DeviceState *dev = DEVICE(obj);
  210. + Property *prop = opaque;
  211. + PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
  212. + PCIELinkSpeed speed;
  213. +
  214. + switch (*p) {
  215. + case QEMU_PCI_EXP_LNK_2_5GT:
  216. + speed = PCIE_LINK_SPEED_2_5;
  217. + break;
  218. + case QEMU_PCI_EXP_LNK_5GT:
  219. + speed = PCIE_LINK_SPEED_5;
  220. + break;
  221. + case QEMU_PCI_EXP_LNK_8GT:
  222. + speed = PCIE_LINK_SPEED_8;
  223. + break;
  224. + case QEMU_PCI_EXP_LNK_16GT:
  225. + speed = PCIE_LINK_SPEED_16;
  226. + break;
  227. + default:
  228. + /* Unreachable */
  229. + abort();
  230. + }
  231. +
  232. + visit_type_enum(v, prop->name, (int *)&speed, prop->info->enum_table, errp);
  233. +}
  234. +
  235. +static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
  236. + void *opaque, Error **errp)
  237. +{
  238. + DeviceState *dev = DEVICE(obj);
  239. + Property *prop = opaque;
  240. + PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
  241. + PCIELinkSpeed speed;
  242. + Error *local_err = NULL;
  243. +
  244. + if (dev->realized) {
  245. + qdev_prop_set_after_realize(dev, name, errp);
  246. + return;
  247. + }
  248. +
  249. + visit_type_enum(v, prop->name, (int *)&speed,
  250. + prop->info->enum_table, &local_err);
  251. + if (local_err) {
  252. + error_propagate(errp, local_err);
  253. + return;
  254. + }
  255. +
  256. + switch (speed) {
  257. + case PCIE_LINK_SPEED_2_5:
  258. + *p = QEMU_PCI_EXP_LNK_2_5GT;
  259. + break;
  260. + case PCIE_LINK_SPEED_5:
  261. + *p = QEMU_PCI_EXP_LNK_5GT;
  262. + break;
  263. + case PCIE_LINK_SPEED_8:
  264. + *p = QEMU_PCI_EXP_LNK_8GT;
  265. + break;
  266. + case PCIE_LINK_SPEED_16:
  267. + *p = QEMU_PCI_EXP_LNK_16GT;
  268. + break;
  269. + default:
  270. + /* Unreachable */
  271. + abort();
  272. + }
  273. +}
  274. +
  275. +const PropertyInfo qdev_prop_pcie_link_speed = {
  276. + .name = "PCIELinkSpeed",
  277. + .description = "2_5/5/8/16",
  278. + .enum_table = &PCIELinkSpeed_lookup,
  279. + .get = get_prop_pcielinkspeed,
  280. + .set = set_prop_pcielinkspeed,
  281. + .set_default_value = set_default_value_enum,
  282. +};
  283. +
  284. +/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
  285. +
  286. +static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
  287. + void *opaque, Error **errp)
  288. +{
  289. + DeviceState *dev = DEVICE(obj);
  290. + Property *prop = opaque;
  291. + PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
  292. + PCIELinkWidth width;
  293. +
  294. + switch (*p) {
  295. + case QEMU_PCI_EXP_LNK_X1:
  296. + width = PCIE_LINK_WIDTH_1;
  297. + break;
  298. + case QEMU_PCI_EXP_LNK_X2:
  299. + width = PCIE_LINK_WIDTH_2;
  300. + break;
  301. + case QEMU_PCI_EXP_LNK_X4:
  302. + width = PCIE_LINK_WIDTH_4;
  303. + break;
  304. + case QEMU_PCI_EXP_LNK_X8:
  305. + width = PCIE_LINK_WIDTH_8;
  306. + break;
  307. + case QEMU_PCI_EXP_LNK_X12:
  308. + width = PCIE_LINK_WIDTH_12;
  309. + break;
  310. + case QEMU_PCI_EXP_LNK_X16:
  311. + width = PCIE_LINK_WIDTH_16;
  312. + break;
  313. + case QEMU_PCI_EXP_LNK_X32:
  314. + width = PCIE_LINK_WIDTH_32;
  315. + break;
  316. + default:
  317. + /* Unreachable */
  318. + abort();
  319. + }
  320. +
  321. + visit_type_enum(v, prop->name, (int *)&width, prop->info->enum_table, errp);
  322. +}
  323. +
  324. +static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
  325. + void *opaque, Error **errp)
  326. +{
  327. + DeviceState *dev = DEVICE(obj);
  328. + Property *prop = opaque;
  329. + PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
  330. + PCIELinkWidth width;
  331. + Error *local_err = NULL;
  332. +
  333. + if (dev->realized) {
  334. + qdev_prop_set_after_realize(dev, name, errp);
  335. + return;
  336. + }
  337. +
  338. + visit_type_enum(v, prop->name, (int *)&width,
  339. + prop->info->enum_table, &local_err);
  340. + if (local_err) {
  341. + error_propagate(errp, local_err);
  342. + return;
  343. + }
  344. +
  345. + switch (width) {
  346. + case PCIE_LINK_WIDTH_1:
  347. + *p = QEMU_PCI_EXP_LNK_X1;
  348. + break;
  349. + case PCIE_LINK_WIDTH_2:
  350. + *p = QEMU_PCI_EXP_LNK_X2;
  351. + break;
  352. + case PCIE_LINK_WIDTH_4:
  353. + *p = QEMU_PCI_EXP_LNK_X4;
  354. + break;
  355. + case PCIE_LINK_WIDTH_8:
  356. + *p = QEMU_PCI_EXP_LNK_X8;
  357. + break;
  358. + case PCIE_LINK_WIDTH_12:
  359. + *p = QEMU_PCI_EXP_LNK_X12;
  360. + break;
  361. + case PCIE_LINK_WIDTH_16:
  362. + *p = QEMU_PCI_EXP_LNK_X16;
  363. + break;
  364. + case PCIE_LINK_WIDTH_32:
  365. + *p = QEMU_PCI_EXP_LNK_X32;
  366. + break;
  367. + default:
  368. + /* Unreachable */
  369. + abort();
  370. + }
  371. +}
  372. +
  373. +const PropertyInfo qdev_prop_pcie_link_width = {
  374. + .name = "PCIELinkWidth",
  375. + .description = "1/2/4/8/12/16/32",
  376. + .enum_table = &PCIELinkWidth_lookup,
  377. + .get = get_prop_pcielinkwidth,
  378. + .set = set_prop_pcielinkwidth,
  379. + .set_default_value = set_default_value_enum,
  380. +};
  381. diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
  382. index 4f60cc88f325..6a13a284c48c 100644
  383. --- a/include/hw/qdev-properties.h
  384. +++ b/include/hw/qdev-properties.h
  385. @@ -36,6 +36,8 @@ extern const PropertyInfo qdev_prop_uuid;
  386. extern const PropertyInfo qdev_prop_arraylen;
  387. extern const PropertyInfo qdev_prop_link;
  388. extern const PropertyInfo qdev_prop_off_auto_pcibar;
  389. +extern const PropertyInfo qdev_prop_pcie_link_speed;
  390. +extern const PropertyInfo qdev_prop_pcie_link_width;
  391.  
  392. #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
  393. .name = (_name), \
  394. @@ -217,6 +219,12 @@ extern const PropertyInfo qdev_prop_off_auto_pcibar;
  395. #define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \
  396. DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \
  397. OffAutoPCIBAR)
  398. +#define DEFINE_PROP_PCIE_LINK_SPEED(_n, _s, _f, _d) \
  399. + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_speed, \
  400. + PCIExpLinkSpeed)
  401. +#define DEFINE_PROP_PCIE_LINK_WIDTH(_n, _s, _f, _d) \
  402. + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_width, \
  403. + PCIExpLinkWidth)
  404.  
  405. #define DEFINE_PROP_UUID(_name, _state, _field) { \
  406. .name = (_name), \
  407. diff --git a/qapi/common.json b/qapi/common.json
  408. index 021174f04ea4..b6f3cca35c7e 100644
  409. --- a/qapi/common.json
  410. +++ b/qapi/common.json
  411. @@ -127,6 +127,48 @@
  412. { 'enum': 'OffAutoPCIBAR',
  413. 'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] }
  414.  
  415. +##
  416. +# @PCIELinkSpeed:
  417. +#
  418. +# An enumeration of PCIe link speeds in units of GT/s
  419. +#
  420. +# @2_5: 2.5GT/s
  421. +#
  422. +# @5: 5.0GT/s
  423. +#
  424. +# @8: 8.0GT/s
  425. +#
  426. +# @16: 16.0GT/s
  427. +#
  428. +# Since: 3.2
  429. +##
  430. +{ 'enum': 'PCIELinkSpeed',
  431. + 'data': [ '2_5', '5', '8', '16' ] }
  432. +
  433. +##
  434. +# @PCIELinkWidth:
  435. +#
  436. +# An enumeration of PCIe link width
  437. +#
  438. +# @1: x1
  439. +#
  440. +# @2: x2
  441. +#
  442. +# @4: x4
  443. +#
  444. +# @8: x8
  445. +#
  446. +# @12: x12
  447. +#
  448. +# @16: x16
  449. +#
  450. +# @32: x32
  451. +#
  452. +# Since: 3.2
  453. +##
  454. +{ 'enum': 'PCIELinkWidth',
  455. + 'data': [ '1', '2', '4', '8', '12', '16', '32' ] }
  456. +
  457. ##
  458. # @SysEmuTarget:
  459. #
  460.  
  461.  
  462. ---
  463. hw/pci-bridge/pcie_root_port.c | 14 ++++++++++++++
  464. include/hw/pci/pcie_port.h | 4 ++++
  465. 2 files changed, 18 insertions(+)
  466.  
  467. diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
  468. index 45f9e8cd4a36..34ad76743c44 100644
  469. --- a/hw/pci-bridge/pcie_root_port.c
  470. +++ b/hw/pci-bridge/pcie_root_port.c
  471. @@ -140,6 +140,19 @@ static Property rp_props[] = {
  472. DEFINE_PROP_END_OF_LIST()
  473. };
  474.  
  475. +static void rp_instance_post_init(Object *obj)
  476. +{
  477. + PCIESlot *s = PCIE_SLOT(obj);
  478. +
  479. + if (!s->speed) {
  480. + s->speed = QEMU_PCI_EXP_LNK_2_5GT;
  481. + }
  482. +
  483. + if (!s->width) {
  484. + s->width = QEMU_PCI_EXP_LNK_X1;
  485. + }
  486. +}
  487. +
  488. static void rp_class_init(ObjectClass *klass, void *data)
  489. {
  490. DeviceClass *dc = DEVICE_CLASS(klass);
  491. @@ -157,6 +170,7 @@ static void rp_class_init(ObjectClass *klass, void *data)
  492. static const TypeInfo rp_info = {
  493. .name = TYPE_PCIE_ROOT_PORT,
  494. .parent = TYPE_PCIE_SLOT,
  495. + .instance_post_init = rp_instance_post_init,
  496. .class_init = rp_class_init,
  497. .abstract = true,
  498. .class_size = sizeof(PCIERootPortClass),
  499. diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
  500. index 0736014bfdb4..df242a0cafff 100644
  501. --- a/include/hw/pci/pcie_port.h
  502. +++ b/include/hw/pci/pcie_port.h
  503. @@ -49,6 +49,10 @@ struct PCIESlot {
  504. /* pci express switch port with slot */
  505. uint8_t chassis;
  506. uint16_t slot;
  507. +
  508. + PCIExpLinkSpeed speed;
  509. + PCIExpLinkWidth width;
  510. +
  511. QLIST_ENTRY(PCIESlot) next;
  512. };
  513.  
  514.  
  515.  
  516. ---
  517. hw/pci/pcie.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  518. 1 file changed, 72 insertions(+)
  519.  
  520. diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
  521. index 61b7b96c52cd..556ec19925b9 100644
  522. --- a/hw/pci/pcie.c
  523. +++ b/hw/pci/pcie.c
  524. @@ -27,6 +27,7 @@
  525. #include "hw/pci/msi.h"
  526. #include "hw/pci/pci_bus.h"
  527. #include "hw/pci/pcie_regs.h"
  528. +#include "hw/pci/pcie_port.h"
  529. #include "qemu/range.h"
  530.  
  531. //#define DEBUG_PCIE
  532. @@ -87,6 +88,74 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
  533. pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
  534. }
  535.  
  536. +static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
  537. +{
  538. + PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
  539. + uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
  540. +
  541. + /* Skip anything that isn't a PCIESlot */
  542. + if (!s) {
  543. + return;
  544. + }
  545. +
  546. + /* Clear and fill LNKCAP from what was configured above */
  547. + pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
  548. + PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
  549. + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
  550. + QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
  551. + QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
  552. +
  553. + /*
  554. + * Link bandwidth notification is required for all root ports and
  555. + * downstream ports supporting links wider than x1.
  556. + */
  557. + if (s->width > QEMU_PCI_EXP_LNK_X1) {
  558. + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
  559. + PCI_EXP_LNKCAP_LBNC);
  560. + }
  561. +
  562. + if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
  563. + /*
  564. + * Hot-plug capable downstream ports and downstream ports supporting
  565. + * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
  566. + * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
  567. + * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
  568. + * technically implement this, but it's not done here for compatibility.
  569. + */
  570. + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
  571. + PCI_EXP_LNKCAP_DLLLARC);
  572. + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
  573. + PCI_EXP_LNKSTA_DLLLA);
  574. +
  575. + /*
  576. + * Target Link Speed defaults to the highest link speed supported by
  577. + * the component. 2.5GT/s devices are permitted to hardwire to zero.
  578. + */
  579. + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
  580. + PCI_EXP_LNKCTL2_TLS);
  581. + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
  582. + QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
  583. + PCI_EXP_LNKCTL2_TLS);
  584. + }
  585. +
  586. + /*
  587. + * 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
  588. + * actually a reference to the highest bit supported in this register.
  589. + * We assume the device supports all link speeds.
  590. + */
  591. + if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
  592. + pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
  593. + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
  594. + PCI_EXP_LNKCAP2_SLS_2_5GB |
  595. + PCI_EXP_LNKCAP2_SLS_5_0GB |
  596. + PCI_EXP_LNKCAP2_SLS_8_0GB);
  597. + if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
  598. + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
  599. + PCI_EXP_LNKCAP2_SLS_16_0GB);
  600. + }
  601. + }
  602. +}
  603. +
  604. int pcie_cap_init(PCIDevice *dev, uint8_t offset,
  605. uint8_t type, uint8_t port,
  606. Error **errp)
  607. @@ -108,6 +177,9 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
  608. /* Filling values common with v1 */
  609. pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
  610.  
  611. + /* Fill link speed and width options */
  612. + pcie_cap_fill_slot_lnk(dev);
  613. +
  614. /* Filling v2 specific values */
  615. pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
  616. PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
  617.  
  618.  
  619. ---
  620. hw/pci-bridge/gen_pcie_root_port.c | 2 ++
  621. 1 file changed, 2 insertions(+)
  622.  
  623. diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
  624. index 299de429ec1e..e3bba2ab68ef 100644
  625. --- a/hw/pci-bridge/gen_pcie_root_port.c
  626. +++ b/hw/pci-bridge/gen_pcie_root_port.c
  627. @@ -123,6 +123,8 @@ static Property gen_rp_props[] = {
  628. DEFINE_PROP_SIZE("mem-reserve", GenPCIERootPort, mem_reserve, -1),
  629. DEFINE_PROP_SIZE("pref32-reserve", GenPCIERootPort, pref32_reserve, -1),
  630. DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort, pref64_reserve, -1),
  631. + DEFINE_PROP_PCIE_LINK_SPEED("speed", PCIESlot, speed, PCIE_LINK_SPEED_2_5),
  632. + DEFINE_PROP_PCIE_LINK_WIDTH("width", PCIESlot, width, PCIE_LINK_WIDTH_1),
  633. DEFINE_PROP_END_OF_LIST()
  634. };
  635.  
  636.  
  637.  
  638. ---
  639. hw/vfio/pci.c | 6 ------
  640. 1 file changed, 6 deletions(-)
  641.  
  642. diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
  643. index 08aab328b442..0d1dd4666fd1 100644
  644. --- a/hw/vfio/pci.c
  645. +++ b/hw/vfio/pci.c
  646. @@ -1899,12 +1899,6 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
  647. QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
  648. vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
  649. }
  650. -
  651. - /* Mark the Link Status bits as emulated to allow virtual negotiation */
  652. - vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
  653. - pci_get_word(vdev->pdev.config + pos +
  654. - PCI_EXP_LNKSTA),
  655. - PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
  656. }
  657.  
  658. /*
Add Comment
Please, Sign In to add comment