xref: /openbmc/qemu/hw/pci/pcie.c (revision 91b2cb9a78ae3b0487497e004c660016bc7b7b44)
1315a1350SMichael S. Tsirkin /*
2315a1350SMichael S. Tsirkin  * pcie.c
3315a1350SMichael S. Tsirkin  *
4315a1350SMichael S. Tsirkin  * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
5315a1350SMichael S. Tsirkin  *                    VA Linux Systems Japan K.K.
6315a1350SMichael S. Tsirkin  *
7315a1350SMichael S. Tsirkin  * This program is free software; you can redistribute it and/or modify
8315a1350SMichael S. Tsirkin  * it under the terms of the GNU General Public License as published by
9315a1350SMichael S. Tsirkin  * the Free Software Foundation; either version 2 of the License, or
10315a1350SMichael S. Tsirkin  * (at your option) any later version.
11315a1350SMichael S. Tsirkin  *
12315a1350SMichael S. Tsirkin  * This program is distributed in the hope that it will be useful,
13315a1350SMichael S. Tsirkin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14315a1350SMichael S. Tsirkin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15315a1350SMichael S. Tsirkin  * GNU General Public License for more details.
16315a1350SMichael S. Tsirkin  *
17315a1350SMichael S. Tsirkin  * You should have received a copy of the GNU General Public License along
18315a1350SMichael S. Tsirkin  * with this program; if not, see <http://www.gnu.org/licenses/>.
19315a1350SMichael S. Tsirkin  */
20315a1350SMichael S. Tsirkin 
2197d5408fSPeter Maydell #include "qemu/osdep.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
23c759b24fSMichael S. Tsirkin #include "hw/pci/pci_bridge.h"
24c759b24fSMichael S. Tsirkin #include "hw/pci/pcie.h"
25c759b24fSMichael S. Tsirkin #include "hw/pci/msix.h"
26c759b24fSMichael S. Tsirkin #include "hw/pci/msi.h"
2706aac7bdSMichael S. Tsirkin #include "hw/pci/pci_bus.h"
28c759b24fSMichael S. Tsirkin #include "hw/pci/pcie_regs.h"
293d67447fSAlex Williamson #include "hw/pci/pcie_port.h"
301de7afc9SPaolo Bonzini #include "qemu/range.h"
3186f0aa1dSVladimir Sementsov-Ogievskiy #include "trace.h"
32315a1350SMichael S. Tsirkin 
33315a1350SMichael S. Tsirkin //#define DEBUG_PCIE
34315a1350SMichael S. Tsirkin #ifdef DEBUG_PCIE
35315a1350SMichael S. Tsirkin # define PCIE_DPRINTF(fmt, ...)                                         \
36315a1350SMichael S. Tsirkin     fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
37315a1350SMichael S. Tsirkin #else
38315a1350SMichael S. Tsirkin # define PCIE_DPRINTF(fmt, ...) do {} while (0)
39315a1350SMichael S. Tsirkin #endif
40315a1350SMichael S. Tsirkin #define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
41315a1350SMichael S. Tsirkin     PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
42315a1350SMichael S. Tsirkin 
pcie_sltctl_powered_off(uint16_t sltctl)435aaed9caSVladimir Sementsov-Ogievskiy static bool pcie_sltctl_powered_off(uint16_t sltctl)
445aaed9caSVladimir Sementsov-Ogievskiy {
455aaed9caSVladimir Sementsov-Ogievskiy     return (sltctl & PCI_EXP_SLTCTL_PCC) == PCI_EXP_SLTCTL_PWR_OFF
465aaed9caSVladimir Sementsov-Ogievskiy         && (sltctl & PCI_EXP_SLTCTL_PIC) == PCI_EXP_SLTCTL_PWR_IND_OFF;
475aaed9caSVladimir Sementsov-Ogievskiy }
48315a1350SMichael S. Tsirkin 
pcie_led_state_to_str(uint16_t value)4986f0aa1dSVladimir Sementsov-Ogievskiy static const char *pcie_led_state_to_str(uint16_t value)
5086f0aa1dSVladimir Sementsov-Ogievskiy {
5186f0aa1dSVladimir Sementsov-Ogievskiy     switch (value) {
5286f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_PWR_IND_ON:
5386f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_ATTN_IND_ON:
5486f0aa1dSVladimir Sementsov-Ogievskiy         return "on";
5586f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_PWR_IND_BLINK:
5686f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_ATTN_IND_BLINK:
5786f0aa1dSVladimir Sementsov-Ogievskiy         return "blink";
5886f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_PWR_IND_OFF:
5986f0aa1dSVladimir Sementsov-Ogievskiy     case PCI_EXP_SLTCTL_ATTN_IND_OFF:
6086f0aa1dSVladimir Sementsov-Ogievskiy         return "off";
6186f0aa1dSVladimir Sementsov-Ogievskiy     default:
6286f0aa1dSVladimir Sementsov-Ogievskiy         return "invalid";
6386f0aa1dSVladimir Sementsov-Ogievskiy     }
6486f0aa1dSVladimir Sementsov-Ogievskiy }
6586f0aa1dSVladimir Sementsov-Ogievskiy 
66315a1350SMichael S. Tsirkin /***************************************************************************
67315a1350SMichael S. Tsirkin  * pci express capability helper functions
68315a1350SMichael S. Tsirkin  */
696383292aSDmitry Fleytman 
706383292aSDmitry Fleytman static void
pcie_cap_v1_fill(PCIDevice * dev,uint8_t port,uint8_t type,uint8_t version)716b449540SMichael S. Tsirkin pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
72315a1350SMichael S. Tsirkin {
736b449540SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
746b449540SMichael S. Tsirkin     uint8_t *cmask = dev->cmask + dev->exp.exp_cap;
756b449540SMichael S. Tsirkin 
76315a1350SMichael S. Tsirkin     /* capability register
77315a1350SMichael S. Tsirkin     interrupt message number defaults to 0 */
78315a1350SMichael S. Tsirkin     pci_set_word(exp_cap + PCI_EXP_FLAGS,
79315a1350SMichael S. Tsirkin                  ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
806383292aSDmitry Fleytman                  version);
81315a1350SMichael S. Tsirkin 
82315a1350SMichael S. Tsirkin     /* device capability register
83315a1350SMichael S. Tsirkin      * table 7-12:
84315a1350SMichael S. Tsirkin      * roll based error reporting bit must be set by all
85315a1350SMichael S. Tsirkin      * Functions conforming to the ECN, PCI Express Base
86315a1350SMichael S. Tsirkin      * Specification, Revision 1.1., or subsequent PCI Express Base
87315a1350SMichael S. Tsirkin      * Specification revisions.
88315a1350SMichael S. Tsirkin      */
89449dca6aSMarcin Juszkiewicz     uint32_t devcap = PCI_EXP_DEVCAP_RBER;
90449dca6aSMarcin Juszkiewicz 
91449dca6aSMarcin Juszkiewicz     if (dev->cap_present & QEMU_PCIE_EXT_TAG) {
92449dca6aSMarcin Juszkiewicz         devcap = PCI_EXP_DEVCAP_RBER | PCI_EXP_DEVCAP_EXT_TAG;
93449dca6aSMarcin Juszkiewicz     }
94449dca6aSMarcin Juszkiewicz 
95449dca6aSMarcin Juszkiewicz     pci_set_long(exp_cap + PCI_EXP_DEVCAP, devcap);
96315a1350SMichael S. Tsirkin 
97315a1350SMichael S. Tsirkin     pci_set_long(exp_cap + PCI_EXP_LNKCAP,
98315a1350SMichael S. Tsirkin                  (port << PCI_EXP_LNKCAP_PN_SHIFT) |
99315a1350SMichael S. Tsirkin                  PCI_EXP_LNKCAP_ASPMS_0S |
100d96a0ac7SAlex Williamson                  QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
101d96a0ac7SAlex Williamson                  QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
102315a1350SMichael S. Tsirkin 
103315a1350SMichael S. Tsirkin     pci_set_word(exp_cap + PCI_EXP_LNKSTA,
104d96a0ac7SAlex Williamson                  QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
105d96a0ac7SAlex Williamson                  QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));
1066b449540SMichael S. Tsirkin 
1076b449540SMichael S. Tsirkin     /* We changed link status bits over time, and changing them across
1086b449540SMichael S. Tsirkin      * migrations is generally fine as hardware changes them too.
1096b449540SMichael S. Tsirkin      * Let's not bother checking.
1106b449540SMichael S. Tsirkin      */
1116b449540SMichael S. Tsirkin     pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
1126383292aSDmitry Fleytman }
113315a1350SMichael S. Tsirkin 
1146d1bda91SJonathan Cameron /* Includes setting the target speed default */
pcie_cap_fill_lnk(uint8_t * exp_cap,PCIExpLinkWidth width,PCIExpLinkSpeed speed)1156d1bda91SJonathan Cameron static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
1166d1bda91SJonathan Cameron                               PCIExpLinkSpeed speed)
1176d1bda91SJonathan Cameron {
1186d1bda91SJonathan Cameron     /* Clear and fill LNKCAP from what was configured above */
1196d1bda91SJonathan Cameron     pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
1206d1bda91SJonathan Cameron                                  PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
1216d1bda91SJonathan Cameron     pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
1226d1bda91SJonathan Cameron                                QEMU_PCI_EXP_LNKCAP_MLW(width) |
1236d1bda91SJonathan Cameron                                QEMU_PCI_EXP_LNKCAP_MLS(speed));
1246d1bda91SJonathan Cameron 
1256d1bda91SJonathan Cameron     if (speed > QEMU_PCI_EXP_LNK_2_5GT) {
1266d1bda91SJonathan Cameron         /*
1276d1bda91SJonathan Cameron          * Target Link Speed defaults to the highest link speed supported by
1286d1bda91SJonathan Cameron          * the component.  2.5GT/s devices are permitted to hardwire to zero.
1296d1bda91SJonathan Cameron          */
1306d1bda91SJonathan Cameron         pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
1316d1bda91SJonathan Cameron                                      PCI_EXP_LNKCTL2_TLS);
1326d1bda91SJonathan Cameron         pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
1336d1bda91SJonathan Cameron                                    QEMU_PCI_EXP_LNKCAP_MLS(speed) &
1346d1bda91SJonathan Cameron                                    PCI_EXP_LNKCTL2_TLS);
1356d1bda91SJonathan Cameron     }
1366d1bda91SJonathan Cameron 
1376d1bda91SJonathan Cameron     /*
1386d1bda91SJonathan Cameron      * 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
1396d1bda91SJonathan Cameron      * actually a reference to the highest bit supported in this register.
1406d1bda91SJonathan Cameron      * We assume the device supports all link speeds.
1416d1bda91SJonathan Cameron      */
1426d1bda91SJonathan Cameron     if (speed > QEMU_PCI_EXP_LNK_5GT) {
1436d1bda91SJonathan Cameron         pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
1446d1bda91SJonathan Cameron         pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
1456d1bda91SJonathan Cameron                                    PCI_EXP_LNKCAP2_SLS_2_5GB |
1466d1bda91SJonathan Cameron                                    PCI_EXP_LNKCAP2_SLS_5_0GB |
1476d1bda91SJonathan Cameron                                    PCI_EXP_LNKCAP2_SLS_8_0GB);
1486d1bda91SJonathan Cameron         if (speed > QEMU_PCI_EXP_LNK_8GT) {
1496d1bda91SJonathan Cameron             pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
1506d1bda91SJonathan Cameron                                        PCI_EXP_LNKCAP2_SLS_16_0GB);
1516d1bda91SJonathan Cameron         }
1526d1bda91SJonathan Cameron         if (speed > QEMU_PCI_EXP_LNK_16GT) {
1536d1bda91SJonathan Cameron             pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
1546d1bda91SJonathan Cameron                                        PCI_EXP_LNKCAP2_SLS_32_0GB);
1556d1bda91SJonathan Cameron         }
1566d1bda91SJonathan Cameron         if (speed > QEMU_PCI_EXP_LNK_32GT) {
1576d1bda91SJonathan Cameron             pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
1586d1bda91SJonathan Cameron                                        PCI_EXP_LNKCAP2_SLS_64_0GB);
1596d1bda91SJonathan Cameron         }
1606d1bda91SJonathan Cameron     }
1616d1bda91SJonathan Cameron }
1626d1bda91SJonathan Cameron 
pcie_cap_fill_link_ep_usp(PCIDevice * dev,PCIExpLinkWidth width,PCIExpLinkSpeed speed)163ea3f0ebcSJonathan Cameron void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
164ea3f0ebcSJonathan Cameron                                PCIExpLinkSpeed speed)
165ea3f0ebcSJonathan Cameron {
166ea3f0ebcSJonathan Cameron     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
167ea3f0ebcSJonathan Cameron 
168ea3f0ebcSJonathan Cameron     /*
169ea3f0ebcSJonathan Cameron      * For an end point or USP need to set the current status as well
170ea3f0ebcSJonathan Cameron      * as the capabilities.
171ea3f0ebcSJonathan Cameron      */
172ea3f0ebcSJonathan Cameron     pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
173ea3f0ebcSJonathan Cameron                                  PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
174ea3f0ebcSJonathan Cameron     pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
175ea3f0ebcSJonathan Cameron                                QEMU_PCI_EXP_LNKSTA_NLW(width) |
176ea3f0ebcSJonathan Cameron                                QEMU_PCI_EXP_LNKSTA_CLS(speed));
177ea3f0ebcSJonathan Cameron 
178ea3f0ebcSJonathan Cameron     pcie_cap_fill_lnk(exp_cap, width, speed);
179ea3f0ebcSJonathan Cameron }
180ea3f0ebcSJonathan Cameron 
pcie_cap_fill_slot_lnk(PCIDevice * dev)1813d67447fSAlex Williamson static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
1823d67447fSAlex Williamson {
1833d67447fSAlex Williamson     PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
1843d67447fSAlex Williamson     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
1853d67447fSAlex Williamson 
1863d67447fSAlex Williamson     /* Skip anything that isn't a PCIESlot */
1873d67447fSAlex Williamson     if (!s) {
1883d67447fSAlex Williamson         return;
1893d67447fSAlex Williamson     }
1903d67447fSAlex Williamson 
1913d67447fSAlex Williamson     /*
1923d67447fSAlex Williamson      * Link bandwidth notification is required for all root ports and
1933d67447fSAlex Williamson      * downstream ports supporting links wider than x1 or multiple link
1943d67447fSAlex Williamson      * speeds.
1953d67447fSAlex Williamson      */
1963d67447fSAlex Williamson     if (s->width > QEMU_PCI_EXP_LNK_X1 ||
1973d67447fSAlex Williamson         s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
1983d67447fSAlex Williamson         pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
1993d67447fSAlex Williamson                                    PCI_EXP_LNKCAP_LBNC);
2003d67447fSAlex Williamson     }
2013d67447fSAlex Williamson 
2023d67447fSAlex Williamson     if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
2033d67447fSAlex Williamson         /*
2043d67447fSAlex Williamson          * Hot-plug capable downstream ports and downstream ports supporting
2053d67447fSAlex Williamson          * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
2063d67447fSAlex Williamson          * to 1b.  PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
2073d67447fSAlex Williamson          * we also hardwire to 1b here.  2.5GT/s hot-plug slots should also
2083d67447fSAlex Williamson          * technically implement this, but it's not done here for compatibility.
2093d67447fSAlex Williamson          */
2103d67447fSAlex Williamson         pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
2113d67447fSAlex Williamson                                    PCI_EXP_LNKCAP_DLLLARC);
212df72184eSLaurent Vivier         /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
2133d67447fSAlex Williamson     }
2143d67447fSAlex Williamson 
2156d1bda91SJonathan Cameron     pcie_cap_fill_lnk(exp_cap, s->width, s->speed);
2163d67447fSAlex Williamson }
2173d67447fSAlex Williamson 
pcie_cap_init(PCIDevice * dev,uint8_t offset,uint8_t type,uint8_t port,Error ** errp)218f8cd1b02SMao Zhongyi int pcie_cap_init(PCIDevice *dev, uint8_t offset,
219f8cd1b02SMao Zhongyi                   uint8_t type, uint8_t port,
220f8cd1b02SMao Zhongyi                   Error **errp)
2216383292aSDmitry Fleytman {
2226383292aSDmitry Fleytman     /* PCIe cap v2 init */
2236383292aSDmitry Fleytman     int pos;
2246383292aSDmitry Fleytman     uint8_t *exp_cap;
2256383292aSDmitry Fleytman 
2266383292aSDmitry Fleytman     assert(pci_is_express(dev));
2276383292aSDmitry Fleytman 
2289a7c2a59SMao Zhongyi     pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
229f8cd1b02SMao Zhongyi                              PCI_EXP_VER2_SIZEOF, errp);
2306383292aSDmitry Fleytman     if (pos < 0) {
2316383292aSDmitry Fleytman         return pos;
2326383292aSDmitry Fleytman     }
2336383292aSDmitry Fleytman     dev->exp.exp_cap = pos;
2346383292aSDmitry Fleytman     exp_cap = dev->config + pos;
2356383292aSDmitry Fleytman 
2366383292aSDmitry Fleytman     /* Filling values common with v1 */
2376b449540SMichael S. Tsirkin     pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
2386383292aSDmitry Fleytman 
2393d67447fSAlex Williamson     /* Fill link speed and width options */
2403d67447fSAlex Williamson     pcie_cap_fill_slot_lnk(dev);
2413d67447fSAlex Williamson 
2426383292aSDmitry Fleytman     /* Filling v2 specific values */
243315a1350SMichael S. Tsirkin     pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
244315a1350SMichael S. Tsirkin                  PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
245315a1350SMichael S. Tsirkin 
24630b04f87SChen Fan     pci_set_word(dev->wmask + pos + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_EETLPPB);
247f03d8ea3SMarcel Apfelbaum 
248f03d8ea3SMarcel Apfelbaum     if (dev->cap_present & QEMU_PCIE_EXTCAP_INIT) {
249f03d8ea3SMarcel Apfelbaum         /* read-only to behave like a 'NULL' Extended Capability Header */
250f03d8ea3SMarcel Apfelbaum         pci_set_long(dev->wmask + PCI_CONFIG_SPACE_SIZE, 0);
251f03d8ea3SMarcel Apfelbaum     }
252f03d8ea3SMarcel Apfelbaum 
253315a1350SMichael S. Tsirkin     return pos;
254315a1350SMichael S. Tsirkin }
255315a1350SMichael S. Tsirkin 
pcie_cap_v1_init(PCIDevice * dev,uint8_t offset,uint8_t type,uint8_t port)2566383292aSDmitry Fleytman int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
2576383292aSDmitry Fleytman                      uint8_t port)
2586383292aSDmitry Fleytman {
2596383292aSDmitry Fleytman     /* PCIe cap v1 init */
2606383292aSDmitry Fleytman     int pos;
2619a7c2a59SMao Zhongyi     Error *local_err = NULL;
2626383292aSDmitry Fleytman 
2636383292aSDmitry Fleytman     assert(pci_is_express(dev));
2646383292aSDmitry Fleytman 
2659a7c2a59SMao Zhongyi     pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
2669a7c2a59SMao Zhongyi                              PCI_EXP_VER1_SIZEOF, &local_err);
2676383292aSDmitry Fleytman     if (pos < 0) {
2689a7c2a59SMao Zhongyi         error_report_err(local_err);
2696383292aSDmitry Fleytman         return pos;
2706383292aSDmitry Fleytman     }
2716383292aSDmitry Fleytman     dev->exp.exp_cap = pos;
2726383292aSDmitry Fleytman 
2736b449540SMichael S. Tsirkin     pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER1);
2746383292aSDmitry Fleytman 
2756383292aSDmitry Fleytman     return pos;
2766383292aSDmitry Fleytman }
2776383292aSDmitry Fleytman 
2786383292aSDmitry Fleytman static int
pcie_endpoint_cap_common_init(PCIDevice * dev,uint8_t offset,uint8_t cap_size)2796383292aSDmitry Fleytman pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size)
2806214e73cSAlex Williamson {
2816214e73cSAlex Williamson     uint8_t type = PCI_EXP_TYPE_ENDPOINT;
282f8cd1b02SMao Zhongyi     Error *local_err = NULL;
283f8cd1b02SMao Zhongyi     int ret;
2846214e73cSAlex Williamson 
2856214e73cSAlex Williamson     /*
2866214e73cSAlex Williamson      * Windows guests will report Code 10, device cannot start, if
2876214e73cSAlex Williamson      * a regular Endpoint type is exposed on a root complex.  These
2886214e73cSAlex Williamson      * should instead be Root Complex Integrated Endpoints.
2896214e73cSAlex Williamson      */
290fd56e061SDavid Gibson     if (pci_bus_is_express(pci_get_bus(dev))
291fd56e061SDavid Gibson         && pci_bus_is_root(pci_get_bus(dev))) {
2926214e73cSAlex Williamson         type = PCI_EXP_TYPE_RC_END;
2936214e73cSAlex Williamson     }
2946214e73cSAlex Williamson 
295f8cd1b02SMao Zhongyi     if (cap_size == PCI_EXP_VER1_SIZEOF) {
296f8cd1b02SMao Zhongyi         return pcie_cap_v1_init(dev, offset, type, 0);
297f8cd1b02SMao Zhongyi     } else {
298f8cd1b02SMao Zhongyi         ret = pcie_cap_init(dev, offset, type, 0, &local_err);
299f8cd1b02SMao Zhongyi 
300f8cd1b02SMao Zhongyi         if (ret < 0) {
301f8cd1b02SMao Zhongyi             error_report_err(local_err);
302f8cd1b02SMao Zhongyi         }
303f8cd1b02SMao Zhongyi 
304f8cd1b02SMao Zhongyi         return ret;
305f8cd1b02SMao Zhongyi     }
3066383292aSDmitry Fleytman }
3076383292aSDmitry Fleytman 
pcie_endpoint_cap_init(PCIDevice * dev,uint8_t offset)3086383292aSDmitry Fleytman int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
3096383292aSDmitry Fleytman {
3106383292aSDmitry Fleytman     return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER2_SIZEOF);
3116383292aSDmitry Fleytman }
3126383292aSDmitry Fleytman 
pcie_endpoint_cap_v1_init(PCIDevice * dev,uint8_t offset)3136383292aSDmitry Fleytman int pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset)
3146383292aSDmitry Fleytman {
3156383292aSDmitry Fleytman     return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER1_SIZEOF);
3166214e73cSAlex Williamson }
3176214e73cSAlex Williamson 
pcie_cap_exit(PCIDevice * dev)318315a1350SMichael S. Tsirkin void pcie_cap_exit(PCIDevice *dev)
319315a1350SMichael S. Tsirkin {
320315a1350SMichael S. Tsirkin     pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
321315a1350SMichael S. Tsirkin }
322315a1350SMichael S. Tsirkin 
pcie_cap_v1_exit(PCIDevice * dev)3236383292aSDmitry Fleytman void pcie_cap_v1_exit(PCIDevice *dev)
3246383292aSDmitry Fleytman {
3256383292aSDmitry Fleytman     pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER1_SIZEOF);
3266383292aSDmitry Fleytman }
3276383292aSDmitry Fleytman 
pcie_cap_get_type(const PCIDevice * dev)328315a1350SMichael S. Tsirkin uint8_t pcie_cap_get_type(const PCIDevice *dev)
329315a1350SMichael S. Tsirkin {
330315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
331315a1350SMichael S. Tsirkin     assert(pos > 0);
332315a1350SMichael S. Tsirkin     return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
333315a1350SMichael S. Tsirkin             PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
334315a1350SMichael S. Tsirkin }
335315a1350SMichael S. Tsirkin 
pcie_cap_get_version(const PCIDevice * dev)336cf2916f6SAlex Williamson uint8_t pcie_cap_get_version(const PCIDevice *dev)
337cf2916f6SAlex Williamson {
338cf2916f6SAlex Williamson     uint32_t pos = dev->exp.exp_cap;
339cf2916f6SAlex Williamson     assert(pos > 0);
340cf2916f6SAlex Williamson     return pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & PCI_EXP_FLAGS_VERS;
341cf2916f6SAlex Williamson }
342cf2916f6SAlex Williamson 
343315a1350SMichael S. Tsirkin /* MSI/MSI-X */
344315a1350SMichael S. Tsirkin /* pci express interrupt message number */
345315a1350SMichael S. Tsirkin /* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
pcie_cap_flags_set_vector(PCIDevice * dev,uint8_t vector)346315a1350SMichael S. Tsirkin void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
347315a1350SMichael S. Tsirkin {
348315a1350SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
349315a1350SMichael S. Tsirkin     assert(vector < 32);
350315a1350SMichael S. Tsirkin     pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
351315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
352315a1350SMichael S. Tsirkin                                vector << PCI_EXP_FLAGS_IRQ_SHIFT);
353315a1350SMichael S. Tsirkin }
354315a1350SMichael S. Tsirkin 
pcie_cap_flags_get_vector(PCIDevice * dev)355315a1350SMichael S. Tsirkin uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
356315a1350SMichael S. Tsirkin {
357315a1350SMichael S. Tsirkin     return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
358315a1350SMichael S. Tsirkin             PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
359315a1350SMichael S. Tsirkin }
360315a1350SMichael S. Tsirkin 
pcie_cap_deverr_init(PCIDevice * dev)361315a1350SMichael S. Tsirkin void pcie_cap_deverr_init(PCIDevice *dev)
362315a1350SMichael S. Tsirkin {
363315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
364315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
365315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCAP_RBER);
366315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
367315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
368315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
369315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
370315a1350SMichael S. Tsirkin                                PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
3718e815eeeSGonglei                                PCI_EXP_DEVSTA_FED | PCI_EXP_DEVSTA_URD);
372315a1350SMichael S. Tsirkin }
373315a1350SMichael S. Tsirkin 
pcie_cap_deverr_reset(PCIDevice * dev)374315a1350SMichael S. Tsirkin void pcie_cap_deverr_reset(PCIDevice *dev)
375315a1350SMichael S. Tsirkin {
376315a1350SMichael S. Tsirkin     uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
377315a1350SMichael S. Tsirkin     pci_long_test_and_clear_mask(devctl,
378315a1350SMichael S. Tsirkin                                  PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
379315a1350SMichael S. Tsirkin                                  PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
380315a1350SMichael S. Tsirkin }
381315a1350SMichael S. Tsirkin 
pcie_cap_lnkctl_init(PCIDevice * dev)382d584f1b9SMarcel Apfelbaum void pcie_cap_lnkctl_init(PCIDevice *dev)
383d584f1b9SMarcel Apfelbaum {
384d584f1b9SMarcel Apfelbaum     uint32_t pos = dev->exp.exp_cap;
385d584f1b9SMarcel Apfelbaum     pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_LNKCTL,
386d584f1b9SMarcel Apfelbaum                                PCI_EXP_LNKCTL_CCC | PCI_EXP_LNKCTL_ES);
387d584f1b9SMarcel Apfelbaum }
388d584f1b9SMarcel Apfelbaum 
pcie_cap_lnkctl_reset(PCIDevice * dev)389d584f1b9SMarcel Apfelbaum void pcie_cap_lnkctl_reset(PCIDevice *dev)
390d584f1b9SMarcel Apfelbaum {
391d584f1b9SMarcel Apfelbaum     uint8_t *lnkctl = dev->config + dev->exp.exp_cap + PCI_EXP_LNKCTL;
392d584f1b9SMarcel Apfelbaum     pci_long_test_and_clear_mask(lnkctl,
393d584f1b9SMarcel Apfelbaum                                  PCI_EXP_LNKCTL_CCC | PCI_EXP_LNKCTL_ES);
394d584f1b9SMarcel Apfelbaum }
395d584f1b9SMarcel Apfelbaum 
hotplug_event_update_event_status(PCIDevice * dev)396315a1350SMichael S. Tsirkin static void hotplug_event_update_event_status(PCIDevice *dev)
397315a1350SMichael S. Tsirkin {
398315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
399315a1350SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + pos;
400315a1350SMichael S. Tsirkin     uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
401315a1350SMichael S. Tsirkin     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
402315a1350SMichael S. Tsirkin 
403315a1350SMichael S. Tsirkin     dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
404315a1350SMichael S. Tsirkin         (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
405315a1350SMichael S. Tsirkin }
406315a1350SMichael S. Tsirkin 
hotplug_event_notify(PCIDevice * dev)407315a1350SMichael S. Tsirkin static void hotplug_event_notify(PCIDevice *dev)
408315a1350SMichael S. Tsirkin {
409315a1350SMichael S. Tsirkin     bool prev = dev->exp.hpev_notified;
410315a1350SMichael S. Tsirkin 
411315a1350SMichael S. Tsirkin     hotplug_event_update_event_status(dev);
412315a1350SMichael S. Tsirkin 
413315a1350SMichael S. Tsirkin     if (prev == dev->exp.hpev_notified) {
414315a1350SMichael S. Tsirkin         return;
415315a1350SMichael S. Tsirkin     }
416315a1350SMichael S. Tsirkin 
417315a1350SMichael S. Tsirkin     /* Note: the logic above does not take into account whether interrupts
418315a1350SMichael S. Tsirkin      * are masked. The result is that interrupt will be sent when it is
419315a1350SMichael S. Tsirkin      * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
420315a1350SMichael S. Tsirkin      * The Port may optionally send an MSI when there are hot-plug events that
421315a1350SMichael S. Tsirkin      * occur while interrupt generation is disabled, and interrupt generation is
422315a1350SMichael S. Tsirkin      * subsequently enabled. */
423315a1350SMichael S. Tsirkin     if (msix_enabled(dev)) {
424315a1350SMichael S. Tsirkin         msix_notify(dev, pcie_cap_flags_get_vector(dev));
425315a1350SMichael S. Tsirkin     } else if (msi_enabled(dev)) {
426315a1350SMichael S. Tsirkin         msi_notify(dev, pcie_cap_flags_get_vector(dev));
4272e865671SFrederic Barrat     } else if (pci_intx(dev) != -1) {
4285a03e708SMarcel Apfelbaum         pci_set_irq(dev, dev->exp.hpev_notified);
429315a1350SMichael S. Tsirkin     }
430315a1350SMichael S. Tsirkin }
431315a1350SMichael S. Tsirkin 
hotplug_event_clear(PCIDevice * dev)432315a1350SMichael S. Tsirkin static void hotplug_event_clear(PCIDevice *dev)
433315a1350SMichael S. Tsirkin {
434315a1350SMichael S. Tsirkin     hotplug_event_update_event_status(dev);
4352e865671SFrederic Barrat     if (!msix_enabled(dev) && !msi_enabled(dev) && pci_intx(dev) != -1 &&
4362e865671SFrederic Barrat         !dev->exp.hpev_notified) {
4375a03e708SMarcel Apfelbaum         pci_irq_deassert(dev);
438315a1350SMichael S. Tsirkin     }
439315a1350SMichael S. Tsirkin }
440315a1350SMichael S. Tsirkin 
pcie_cap_slot_enable_power(PCIDevice * dev)4416b0969f1SIgor Mammedov void pcie_cap_slot_enable_power(PCIDevice *dev)
4426b0969f1SIgor Mammedov {
4436b0969f1SIgor Mammedov     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
4446b0969f1SIgor Mammedov     uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP);
4456b0969f1SIgor Mammedov 
4466b0969f1SIgor Mammedov     if (sltcap & PCI_EXP_SLTCAP_PCP) {
447f90d9320SVladimir Sementsov-Ogievskiy         pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
448f90d9320SVladimir Sementsov-Ogievskiy                                      PCI_EXP_SLTCTL_PCC);
4496b0969f1SIgor Mammedov     }
4506b0969f1SIgor Mammedov }
4516b0969f1SIgor Mammedov 
pcie_set_power_device(PCIBus * bus,PCIDevice * dev,void * opaque)452d5daff7dSGerd Hoffmann static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque)
453d5daff7dSGerd Hoffmann {
454d5daff7dSGerd Hoffmann     bool *power = opaque;
455d5daff7dSGerd Hoffmann 
456d5daff7dSGerd Hoffmann     pci_set_power(dev, *power);
457d5daff7dSGerd Hoffmann }
458d5daff7dSGerd Hoffmann 
pcie_cap_update_power(PCIDevice * hotplug_dev)459d5daff7dSGerd Hoffmann static void pcie_cap_update_power(PCIDevice *hotplug_dev)
460d5daff7dSGerd Hoffmann {
461d5daff7dSGerd Hoffmann     uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
462d5daff7dSGerd Hoffmann     PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(hotplug_dev));
463d5daff7dSGerd Hoffmann     uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP);
464d5daff7dSGerd Hoffmann     uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
465d5daff7dSGerd Hoffmann     bool power = true;
466d5daff7dSGerd Hoffmann 
467d5daff7dSGerd Hoffmann     if (sltcap & PCI_EXP_SLTCAP_PCP) {
468d5daff7dSGerd Hoffmann         power = (sltctl & PCI_EXP_SLTCTL_PCC) == PCI_EXP_SLTCTL_PWR_ON;
4695aaed9caSVladimir Sementsov-Ogievskiy         /* Don't we need to check also (sltctl & PCI_EXP_SLTCTL_PIC) ? */
470d5daff7dSGerd Hoffmann     }
471d5daff7dSGerd Hoffmann 
472d5daff7dSGerd Hoffmann     pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
473d5daff7dSGerd Hoffmann                         pcie_set_power_device, &power);
474d5daff7dSGerd Hoffmann }
475d5daff7dSGerd Hoffmann 
476315a1350SMichael S. Tsirkin /*
477315a1350SMichael S. Tsirkin  * A PCI Express Hot-Plug Event has occurred, so update slot status register
478315a1350SMichael S. Tsirkin  * and notify OS of the event if necessary.
479315a1350SMichael S. Tsirkin  *
480315a1350SMichael S. Tsirkin  * 6.7.3 PCI Express Hot-Plug Events
481315a1350SMichael S. Tsirkin  * 6.7.3.4 Software Notification of Hot-Plug Events
482315a1350SMichael S. Tsirkin  */
pcie_cap_slot_event(PCIDevice * dev,PCIExpressHotPlugEvent event)483315a1350SMichael S. Tsirkin static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
484315a1350SMichael S. Tsirkin {
485315a1350SMichael S. Tsirkin     /* Minor optimization: if nothing changed - no event is needed. */
486315a1350SMichael S. Tsirkin     if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
487861dc735SMichael S. Tsirkin                                    PCI_EXP_SLTSTA, event) == event) {
488315a1350SMichael S. Tsirkin         return;
489315a1350SMichael S. Tsirkin     }
490315a1350SMichael S. Tsirkin     hotplug_event_notify(dev);
491315a1350SMichael S. Tsirkin }
492315a1350SMichael S. Tsirkin 
pcie_cap_slot_plug_common(PCIDevice * hotplug_dev,DeviceState * dev,Error ** errp)4935571727aSDavid Hildenbrand static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
494b9731850SDavid Hildenbrand                                       Error **errp)
495315a1350SMichael S. Tsirkin {
496b9731850SDavid Hildenbrand     uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
497b9731850SDavid Hildenbrand     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
498315a1350SMichael S. Tsirkin 
499e4bcd27cSMarcel Apfelbaum     PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta);
500315a1350SMichael S. Tsirkin     if (sltsta & PCI_EXP_SLTSTA_EIS) {
501315a1350SMichael S. Tsirkin         /* the slot is electromechanically locked.
502315a1350SMichael S. Tsirkin          * This error is propagated up to qdev and then to HMP/QMP.
503315a1350SMichael S. Tsirkin          */
5046c150fbdSGonglei         error_setg_errno(errp, EBUSY, "slot is electromechanically locked");
505315a1350SMichael S. Tsirkin     }
506a66e657eSIgor Mammedov }
507315a1350SMichael S. Tsirkin 
pcie_cap_slot_pre_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)508b9731850SDavid Hildenbrand void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
509b9731850SDavid Hildenbrand                                Error **errp)
510b9731850SDavid Hildenbrand {
5110dabc0f6SJulia Suvorova     PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
5120dabc0f6SJulia Suvorova     uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
5130dabc0f6SJulia Suvorova     uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
5140dabc0f6SJulia Suvorova 
5150dabc0f6SJulia Suvorova     /* Check if hot-plug is disabled on the slot */
5160dabc0f6SJulia Suvorova     if (dev->hotplugged && (sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
5170dabc0f6SJulia Suvorova         error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'",
5180dabc0f6SJulia Suvorova                          DEVICE(hotplug_pdev)->id);
5190dabc0f6SJulia Suvorova         return;
5200dabc0f6SJulia Suvorova     }
5210dabc0f6SJulia Suvorova 
522b9731850SDavid Hildenbrand     pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp);
523b9731850SDavid Hildenbrand }
524b9731850SDavid Hildenbrand 
pcie_cap_slot_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)5255571727aSDavid Hildenbrand void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
526a66e657eSIgor Mammedov                            Error **errp)
527a66e657eSIgor Mammedov {
528b9731850SDavid Hildenbrand     PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
529b9731850SDavid Hildenbrand     uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
5306e1f0a55SIgor Mammedov     PCIDevice *pci_dev = PCI_DEVICE(dev);
531df72184eSLaurent Vivier     uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
532a66e657eSIgor Mammedov 
5337c0fa8dfSKnut Omang     if (pci_is_vf(pci_dev)) {
5347c0fa8dfSKnut Omang         /* Virtual function cannot be physically disconnected */
5357c0fa8dfSKnut Omang         return;
5367c0fa8dfSKnut Omang     }
5377c0fa8dfSKnut Omang 
538a66e657eSIgor Mammedov     /* Don't send event when device is enabled during qemu machine creation:
539a66e657eSIgor Mammedov      * it is present on boot, no hotplug event is necessary. We do send an
540a66e657eSIgor Mammedov      * event when the device is disabled later. */
541a66e657eSIgor Mammedov     if (!dev->hotplugged) {
542315a1350SMichael S. Tsirkin         pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
543315a1350SMichael S. Tsirkin                                    PCI_EXP_SLTSTA_PDS);
544df72184eSLaurent Vivier         if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA ||
545df72184eSLaurent Vivier             (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) {
5462f2b18f6SZheng Xiang             pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
5472f2b18f6SZheng Xiang                                        PCI_EXP_LNKSTA_DLLLA);
5482f2b18f6SZheng Xiang         }
549d5daff7dSGerd Hoffmann         pcie_cap_update_power(hotplug_pdev);
550a66e657eSIgor Mammedov         return;
551a66e657eSIgor Mammedov     }
552a66e657eSIgor Mammedov 
5533f1e1478SCao jin     /* To enable multifunction hot-plug, we just ensure the function
5543f1e1478SCao jin      * 0 added last. When function 0 is added, we set the sltsta and
5553f1e1478SCao jin      * inform OS via event notification.
5566e1f0a55SIgor Mammedov      */
5573f1e1478SCao jin     if (pci_get_function_0(pci_dev)) {
558a66e657eSIgor Mammedov         pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
559a66e657eSIgor Mammedov                                    PCI_EXP_SLTSTA_PDS);
560df72184eSLaurent Vivier         if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA ||
561df72184eSLaurent Vivier             (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) {
5622f2b18f6SZheng Xiang             pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
5632f2b18f6SZheng Xiang                                        PCI_EXP_LNKSTA_DLLLA);
5642f2b18f6SZheng Xiang         }
5656a1e0733SJulia Suvorova         pcie_cap_slot_event(hotplug_pdev,
566554f802dSMarcel Apfelbaum                             PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
567d5daff7dSGerd Hoffmann         pcie_cap_update_power(hotplug_pdev);
568a66e657eSIgor Mammedov     }
5693f1e1478SCao jin }
570a66e657eSIgor Mammedov 
pcie_cap_slot_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)571a1952d01SDavid Hildenbrand void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
572a1952d01SDavid Hildenbrand                              Error **errp)
5730d1c7d88SCao jin {
574981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
5750d1c7d88SCao jin }
5760d1c7d88SCao jin 
pcie_unplug_device(PCIBus * bus,PCIDevice * dev,void * opaque)577a1952d01SDavid Hildenbrand static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
578a1952d01SDavid Hildenbrand {
579a1952d01SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
580a1952d01SDavid Hildenbrand 
581a99c4da9SJens Freimann     if (dev->partially_hotplugged) {
582c000a9bdSJens Freimann         dev->qdev.pending_deleted_event = false;
583a99c4da9SJens Freimann         return;
584a99c4da9SJens Freimann     }
585a1952d01SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, DEVICE(dev), &error_abort);
58607578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
587a1952d01SDavid Hildenbrand }
588a1952d01SDavid Hildenbrand 
pcie_cap_slot_do_unplug(PCIDevice * dev)58944242d4dSGerd Hoffmann static void pcie_cap_slot_do_unplug(PCIDevice *dev)
59044242d4dSGerd Hoffmann {
59144242d4dSGerd Hoffmann     PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
59244242d4dSGerd Hoffmann     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
59344242d4dSGerd Hoffmann     uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
59444242d4dSGerd Hoffmann 
59544242d4dSGerd Hoffmann     pci_for_each_device_under_bus(sec_bus, pcie_unplug_device, NULL);
59644242d4dSGerd Hoffmann 
59744242d4dSGerd Hoffmann     pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
59844242d4dSGerd Hoffmann                                  PCI_EXP_SLTSTA_PDS);
59944242d4dSGerd Hoffmann     if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA ||
60044242d4dSGerd Hoffmann         (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) {
60144242d4dSGerd Hoffmann         pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
60244242d4dSGerd Hoffmann                                      PCI_EXP_LNKSTA_DLLLA);
60344242d4dSGerd Hoffmann     }
60444242d4dSGerd Hoffmann     pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
60544242d4dSGerd Hoffmann                                PCI_EXP_SLTSTA_PDC);
60644242d4dSGerd Hoffmann }
60744242d4dSGerd Hoffmann 
pcie_cap_slot_unplug_request_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)6085571727aSDavid Hildenbrand void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
60914d5a28fSIgor Mammedov                                      DeviceState *dev, Error **errp)
610a66e657eSIgor Mammedov {
611b9731850SDavid Hildenbrand     Error *local_err = NULL;
6120d1c7d88SCao jin     PCIDevice *pci_dev = PCI_DEVICE(dev);
613fd56e061SDavid Gibson     PCIBus *bus = pci_get_bus(pci_dev);
6140501e1aaSJulia Suvorova     PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
6150501e1aaSJulia Suvorova     uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
6160501e1aaSJulia Suvorova     uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
61781124b3cSGerd Hoffmann     uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
6180501e1aaSJulia Suvorova 
6190501e1aaSJulia Suvorova     /* Check if hot-unplug is disabled on the slot */
6200501e1aaSJulia Suvorova     if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
6210501e1aaSJulia Suvorova         error_setg(errp, "Hot-unplug failed: "
6220501e1aaSJulia Suvorova                          "unsupported by the port device '%s'",
6230501e1aaSJulia Suvorova                          DEVICE(hotplug_pdev)->id);
6240501e1aaSJulia Suvorova         return;
6250501e1aaSJulia Suvorova     }
626a66e657eSIgor Mammedov 
6276a1e0733SJulia Suvorova     pcie_cap_slot_plug_common(hotplug_pdev, dev, &local_err);
628b9731850SDavid Hildenbrand     if (local_err) {
629b9731850SDavid Hildenbrand         error_propagate(errp, local_err);
630b9731850SDavid Hildenbrand         return;
631b9731850SDavid Hildenbrand     }
632a66e657eSIgor Mammedov 
63381124b3cSGerd Hoffmann     if ((sltctl & PCI_EXP_SLTCTL_PIC) == PCI_EXP_SLTCTL_PWR_IND_BLINK) {
63481124b3cSGerd Hoffmann         error_setg(errp, "Hot-unplug failed: "
63581124b3cSGerd Hoffmann                    "guest is busy (power indicator blinking)");
63681124b3cSGerd Hoffmann         return;
63781124b3cSGerd Hoffmann     }
63881124b3cSGerd Hoffmann 
639c000a9bdSJens Freimann     dev->pending_deleted_event = true;
64018416c62SGerd Hoffmann     dev->pending_deleted_expires_ms =
64118416c62SGerd Hoffmann         qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 5000; /* 5 secs */
642c000a9bdSJens Freimann 
6430d1c7d88SCao jin     /* In case user cancel the operation of multi-function hot-add,
6440d1c7d88SCao jin      * remove the function that is unexposed to guest individually,
6450d1c7d88SCao jin      * without interaction with guest.
6460d1c7d88SCao jin      */
6470d1c7d88SCao jin     if (pci_dev->devfn &&
6480d1c7d88SCao jin         !bus->devices[0]) {
6490d1c7d88SCao jin         pcie_unplug_device(bus, pci_dev, NULL);
6500d1c7d88SCao jin 
6510d1c7d88SCao jin         return;
6520d1c7d88SCao jin     }
6530d1c7d88SCao jin 
6545aaed9caSVladimir Sementsov-Ogievskiy     if (pcie_sltctl_powered_off(sltctl)) {
6550d33415aSGerd Hoffmann         /* slot is powered off -> unplug without round-trip to the guest */
6560d33415aSGerd Hoffmann         pcie_cap_slot_do_unplug(hotplug_pdev);
6570d33415aSGerd Hoffmann         hotplug_event_notify(hotplug_pdev);
6580d33415aSGerd Hoffmann         pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
6590d33415aSGerd Hoffmann                                      PCI_EXP_SLTSTA_ABP);
6600d33415aSGerd Hoffmann         return;
6610d33415aSGerd Hoffmann     }
6620d33415aSGerd Hoffmann 
6636a1e0733SJulia Suvorova     pcie_cap_slot_push_attention_button(hotplug_pdev);
664315a1350SMichael S. Tsirkin }
665315a1350SMichael S. Tsirkin 
666315a1350SMichael S. Tsirkin /* pci express slot for pci express root/downstream port
667315a1350SMichael S. Tsirkin    PCI express capability slot registers */
pcie_cap_slot_init(PCIDevice * dev,PCIESlot * s)668530a0963SJulia Suvorova void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s)
669315a1350SMichael S. Tsirkin {
670315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
671315a1350SMichael S. Tsirkin 
672315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
673315a1350SMichael S. Tsirkin                                PCI_EXP_FLAGS_SLOT);
674315a1350SMichael S. Tsirkin 
675315a1350SMichael S. Tsirkin     pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
676315a1350SMichael S. Tsirkin                                  ~PCI_EXP_SLTCAP_PSN);
677315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
678530a0963SJulia Suvorova                                (s->slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
679315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCAP_EIP |
680315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCAP_PIP |
681315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCAP_AIP |
682315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCAP_ABP);
6833f3cbbb2SJulia Suvorova 
6843f3cbbb2SJulia Suvorova     /*
6851d77e157SIgor Mammedov      * Expose native hot-plug on all bridges if hot-plug is enabled on the slot.
6861d77e157SIgor Mammedov      * (unless broken 6.1 ABI is enforced for compat reasons)
6873f3cbbb2SJulia Suvorova      */
6883f3cbbb2SJulia Suvorova     if (s->hotplug &&
6891d77e157SIgor Mammedov         (!s->hide_native_hotplug_cap || DEVICE(dev)->hotplugged)) {
690530a0963SJulia Suvorova         pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
691530a0963SJulia Suvorova                                    PCI_EXP_SLTCAP_HPS |
692530a0963SJulia Suvorova                                    PCI_EXP_SLTCAP_HPC);
693530a0963SJulia Suvorova     }
694315a1350SMichael S. Tsirkin 
695f23b6bdcSMarcel Apfelbaum     if (dev->cap_present & QEMU_PCIE_SLTCAP_PCP) {
696f23b6bdcSMarcel Apfelbaum         pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
697f23b6bdcSMarcel Apfelbaum                                    PCI_EXP_SLTCAP_PCP);
698f23b6bdcSMarcel Apfelbaum         pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
699f23b6bdcSMarcel Apfelbaum                                      PCI_EXP_SLTCTL_PCC);
700f23b6bdcSMarcel Apfelbaum         pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
701f23b6bdcSMarcel Apfelbaum                                    PCI_EXP_SLTCTL_PCC);
702f23b6bdcSMarcel Apfelbaum     }
703f23b6bdcSMarcel Apfelbaum 
704315a1350SMichael S. Tsirkin     pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
705315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_PIC |
706315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_AIC);
707315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
7080a80f1cdSVladimir Sementsov-Ogievskiy                                PCI_EXP_SLTCTL_PWR_IND_OFF |
7090a80f1cdSVladimir Sementsov-Ogievskiy                                PCI_EXP_SLTCTL_ATTN_IND_OFF);
710315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
711315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_PIC |
712315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_AIC |
713315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_HPIE |
714315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_CCIE |
715315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_PDCE |
716315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_ABPE);
717315a1350SMichael S. Tsirkin     /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
718315a1350SMichael S. Tsirkin      * make the bit writable here in order to detect 1b is written.
719315a1350SMichael S. Tsirkin      * pcie_cap_slot_write_config() test-and-clear the bit, so
720315a1350SMichael S. Tsirkin      * this bit always returns 0 to the guest.
721315a1350SMichael S. Tsirkin      */
722315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
723315a1350SMichael S. Tsirkin                                PCI_EXP_SLTCTL_EIC);
724315a1350SMichael S. Tsirkin 
725315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
726315a1350SMichael S. Tsirkin                                PCI_EXP_HP_EV_SUPPORTED);
727315a1350SMichael S. Tsirkin 
728625b370cSLeonardo Bras     /* Avoid migration abortion when this device hot-removed by guest */
729625b370cSLeonardo Bras     pci_word_test_and_clear_mask(dev->cmask + pos + PCI_EXP_SLTSTA,
730625b370cSLeonardo Bras                                  PCI_EXP_SLTSTA_PDS);
731625b370cSLeonardo Bras 
732315a1350SMichael S. Tsirkin     dev->exp.hpev_notified = false;
733315a1350SMichael S. Tsirkin 
734a66e657eSIgor Mammedov     qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
7359bc6bfdfSMarkus Armbruster                              OBJECT(dev));
736315a1350SMichael S. Tsirkin }
737315a1350SMichael S. Tsirkin 
pcie_cap_slot_reset(PCIDevice * dev)738315a1350SMichael S. Tsirkin void pcie_cap_slot_reset(PCIDevice *dev)
739315a1350SMichael S. Tsirkin {
740315a1350SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
741f23b6bdcSMarcel Apfelbaum     uint8_t port_type = pcie_cap_get_type(dev);
742f23b6bdcSMarcel Apfelbaum 
743f23b6bdcSMarcel Apfelbaum     assert(port_type == PCI_EXP_TYPE_DOWNSTREAM ||
744f23b6bdcSMarcel Apfelbaum            port_type == PCI_EXP_TYPE_ROOT_PORT);
745315a1350SMichael S. Tsirkin 
746315a1350SMichael S. Tsirkin     PCIE_DEV_PRINTF(dev, "reset\n");
747315a1350SMichael S. Tsirkin 
748315a1350SMichael S. Tsirkin     pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
749315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_EIC |
750315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_PIC |
751315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_AIC |
752315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_HPIE |
753315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_CCIE |
754315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_PDCE |
755315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTCTL_ABPE);
756315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
7571768e97bSVladimir Sementsov-Ogievskiy                                PCI_EXP_SLTCTL_PWR_IND_OFF |
7580a80f1cdSVladimir Sementsov-Ogievskiy                                PCI_EXP_SLTCTL_ATTN_IND_OFF);
759315a1350SMichael S. Tsirkin 
760f23b6bdcSMarcel Apfelbaum     if (dev->cap_present & QEMU_PCIE_SLTCAP_PCP) {
761f23b6bdcSMarcel Apfelbaum         /* Downstream ports enforce device number 0. */
76220de98afSMichael S. Tsirkin         bool populated = pci_bridge_get_sec_bus(PCI_BRIDGE(dev))->devices[0];
76320de98afSMichael S. Tsirkin         uint16_t pic;
764f23b6bdcSMarcel Apfelbaum 
765f23b6bdcSMarcel Apfelbaum         if (populated) {
766f23b6bdcSMarcel Apfelbaum             pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
767f23b6bdcSMarcel Apfelbaum                                          PCI_EXP_SLTCTL_PCC);
768f23b6bdcSMarcel Apfelbaum         } else {
769f23b6bdcSMarcel Apfelbaum             pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
770f23b6bdcSMarcel Apfelbaum                                        PCI_EXP_SLTCTL_PCC);
771f23b6bdcSMarcel Apfelbaum         }
772f23b6bdcSMarcel Apfelbaum 
7730a80f1cdSVladimir Sementsov-Ogievskiy         pic = populated ?
7740a80f1cdSVladimir Sementsov-Ogievskiy                 PCI_EXP_SLTCTL_PWR_IND_ON : PCI_EXP_SLTCTL_PWR_IND_OFF;
775f23b6bdcSMarcel Apfelbaum         pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, pic);
776f23b6bdcSMarcel Apfelbaum     }
777f23b6bdcSMarcel Apfelbaum 
778315a1350SMichael S. Tsirkin     pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
779315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTSTA_EIS |/* on reset,
780315a1350SMichael S. Tsirkin                                                         the lock is released */
781315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTSTA_CC |
782315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTSTA_PDC |
783315a1350SMichael S. Tsirkin                                  PCI_EXP_SLTSTA_ABP);
784315a1350SMichael S. Tsirkin 
785d5daff7dSGerd Hoffmann     pcie_cap_update_power(dev);
786315a1350SMichael S. Tsirkin     hotplug_event_update_event_status(dev);
787315a1350SMichael S. Tsirkin }
788315a1350SMichael S. Tsirkin 
pcie_cap_slot_get(PCIDevice * dev,uint16_t * slt_ctl,uint16_t * slt_sta)7892841ab43SMichael S. Tsirkin void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slt_ctl, uint16_t *slt_sta)
7902841ab43SMichael S. Tsirkin {
7912841ab43SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
7922841ab43SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + pos;
7932841ab43SMichael S. Tsirkin     *slt_ctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
7942841ab43SMichael S. Tsirkin     *slt_sta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
7952841ab43SMichael S. Tsirkin }
7962841ab43SMichael S. Tsirkin 
find_child_fn(PCIBus * bus,PCIDevice * dev,void * opaque)79786f0aa1dSVladimir Sementsov-Ogievskiy static void find_child_fn(PCIBus *bus, PCIDevice *dev, void *opaque)
79886f0aa1dSVladimir Sementsov-Ogievskiy {
79986f0aa1dSVladimir Sementsov-Ogievskiy     PCIDevice **child = opaque;
80086f0aa1dSVladimir Sementsov-Ogievskiy 
80186f0aa1dSVladimir Sementsov-Ogievskiy     if (!*child) {
80286f0aa1dSVladimir Sementsov-Ogievskiy         *child = dev;
80386f0aa1dSVladimir Sementsov-Ogievskiy     }
80486f0aa1dSVladimir Sementsov-Ogievskiy }
80586f0aa1dSVladimir Sementsov-Ogievskiy 
80686f0aa1dSVladimir Sementsov-Ogievskiy /*
80786f0aa1dSVladimir Sementsov-Ogievskiy  * Returns the plugged device or first function of multifunction plugged device
80886f0aa1dSVladimir Sementsov-Ogievskiy  */
pcie_cap_slot_find_child(PCIDevice * dev)80986f0aa1dSVladimir Sementsov-Ogievskiy static PCIDevice *pcie_cap_slot_find_child(PCIDevice *dev)
81086f0aa1dSVladimir Sementsov-Ogievskiy {
81186f0aa1dSVladimir Sementsov-Ogievskiy     PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
81286f0aa1dSVladimir Sementsov-Ogievskiy     PCIDevice *child = NULL;
81386f0aa1dSVladimir Sementsov-Ogievskiy 
81486f0aa1dSVladimir Sementsov-Ogievskiy     pci_for_each_device(sec_bus, pci_bus_num(sec_bus), find_child_fn, &child);
81586f0aa1dSVladimir Sementsov-Ogievskiy 
81686f0aa1dSVladimir Sementsov-Ogievskiy     return child;
81786f0aa1dSVladimir Sementsov-Ogievskiy }
81886f0aa1dSVladimir Sementsov-Ogievskiy 
pcie_cap_slot_write_config(PCIDevice * dev,uint16_t old_slt_ctl,uint16_t old_slt_sta,uint32_t addr,uint32_t val,int len)819d85d65ccSMichael S. Tsirkin void pcie_cap_slot_write_config(PCIDevice *dev,
820d85d65ccSMichael S. Tsirkin                                 uint16_t old_slt_ctl, uint16_t old_slt_sta,
821315a1350SMichael S. Tsirkin                                 uint32_t addr, uint32_t val, int len)
822315a1350SMichael S. Tsirkin {
823315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
824315a1350SMichael S. Tsirkin     uint8_t *exp_cap = dev->config + pos;
825315a1350SMichael S. Tsirkin     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
826315a1350SMichael S. Tsirkin 
827315a1350SMichael S. Tsirkin     if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
828110c477cSMichael S. Tsirkin         /*
829110c477cSMichael S. Tsirkin          * Guests tend to clears all bits during init.
830110c477cSMichael S. Tsirkin          * If they clear bits that weren't set this is racy and will lose events:
831110c477cSMichael S. Tsirkin          * not a big problem for manual button presses, but a problem for us.
832110c477cSMichael S. Tsirkin          * As a work-around, detect this and revert status to what it was
833110c477cSMichael S. Tsirkin          * before the write.
834110c477cSMichael S. Tsirkin          *
835110c477cSMichael S. Tsirkin          * Note: in theory this can be detected as a duplicate button press
836110c477cSMichael S. Tsirkin          * which cancels the previous press. Does not seem to happen in
837110c477cSMichael S. Tsirkin          * practice as guests seem to only have this bug during init.
838110c477cSMichael S. Tsirkin          */
839110c477cSMichael S. Tsirkin #define PCIE_SLOT_EVENTS (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | \
840110c477cSMichael S. Tsirkin                           PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | \
841110c477cSMichael S. Tsirkin                           PCI_EXP_SLTSTA_CC)
842110c477cSMichael S. Tsirkin 
843d85d65ccSMichael S. Tsirkin         if (val & ~old_slt_sta & PCIE_SLOT_EVENTS) {
844d85d65ccSMichael S. Tsirkin             sltsta = (sltsta & ~PCIE_SLOT_EVENTS) | (old_slt_sta & PCIE_SLOT_EVENTS);
845110c477cSMichael S. Tsirkin             pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
846110c477cSMichael S. Tsirkin         }
847315a1350SMichael S. Tsirkin         hotplug_event_clear(dev);
848315a1350SMichael S. Tsirkin     }
849315a1350SMichael S. Tsirkin 
850315a1350SMichael S. Tsirkin     if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
851315a1350SMichael S. Tsirkin         return;
852315a1350SMichael S. Tsirkin     }
853315a1350SMichael S. Tsirkin 
854315a1350SMichael S. Tsirkin     if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
855315a1350SMichael S. Tsirkin                                      PCI_EXP_SLTCTL_EIC)) {
856315a1350SMichael S. Tsirkin         sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
857315a1350SMichael S. Tsirkin         pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
858315a1350SMichael S. Tsirkin         PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
859315a1350SMichael S. Tsirkin                         "sltsta -> 0x%02"PRIx16"\n",
860315a1350SMichael S. Tsirkin                         sltsta);
861315a1350SMichael S. Tsirkin     }
862315a1350SMichael S. Tsirkin 
86386f0aa1dSVladimir Sementsov-Ogievskiy     if (trace_event_get_state_backends(TRACE_PCIE_CAP_SLOT_WRITE_CONFIG)) {
86486f0aa1dSVladimir Sementsov-Ogievskiy         DeviceState *parent = DEVICE(dev);
86586f0aa1dSVladimir Sementsov-Ogievskiy         DeviceState *child = DEVICE(pcie_cap_slot_find_child(dev));
86686f0aa1dSVladimir Sementsov-Ogievskiy 
86786f0aa1dSVladimir Sementsov-Ogievskiy         trace_pcie_cap_slot_write_config(
86886f0aa1dSVladimir Sementsov-Ogievskiy             parent->canonical_path,
86986f0aa1dSVladimir Sementsov-Ogievskiy             child ? child->canonical_path : "no-child",
87086f0aa1dSVladimir Sementsov-Ogievskiy             (sltsta & PCI_EXP_SLTSTA_PDS) ? "present" : "not present",
87186f0aa1dSVladimir Sementsov-Ogievskiy             pcie_led_state_to_str(old_slt_ctl & PCI_EXP_SLTCTL_PIC),
87286f0aa1dSVladimir Sementsov-Ogievskiy             pcie_led_state_to_str(val & PCI_EXP_SLTCTL_PIC),
87386f0aa1dSVladimir Sementsov-Ogievskiy             pcie_led_state_to_str(old_slt_ctl & PCI_EXP_SLTCTL_AIC),
87486f0aa1dSVladimir Sementsov-Ogievskiy             pcie_led_state_to_str(val & PCI_EXP_SLTCTL_AIC),
87586f0aa1dSVladimir Sementsov-Ogievskiy             (old_slt_ctl & PCI_EXP_SLTCTL_PWR_OFF) ? "off" : "on",
87686f0aa1dSVladimir Sementsov-Ogievskiy             (val & PCI_EXP_SLTCTL_PWR_OFF) ? "off" : "on");
87786f0aa1dSVladimir Sementsov-Ogievskiy     }
87886f0aa1dSVladimir Sementsov-Ogievskiy 
879554f802dSMarcel Apfelbaum     /*
880d85d65ccSMichael S. Tsirkin      * If the slot is populated, power indicator is off and power
881554f802dSMarcel Apfelbaum      * controller is off, it is safe to detach the devices.
882d85d65ccSMichael S. Tsirkin      *
883d85d65ccSMichael S. Tsirkin      * Note: don't detach if condition was already true:
884d85d65ccSMichael S. Tsirkin      * this is a work around for guests that overwrite
885d85d65ccSMichael S. Tsirkin      * control of powered off slots before powering them on.
886554f802dSMarcel Apfelbaum      */
8875aaed9caSVladimir Sementsov-Ogievskiy     if ((sltsta & PCI_EXP_SLTSTA_PDS) && pcie_sltctl_powered_off(val) &&
8885aaed9caSVladimir Sementsov-Ogievskiy         !pcie_sltctl_powered_off(old_slt_ctl))
8895aaed9caSVladimir Sementsov-Ogievskiy     {
89044242d4dSGerd Hoffmann         pcie_cap_slot_do_unplug(dev);
891554f802dSMarcel Apfelbaum     }
892d5daff7dSGerd Hoffmann     pcie_cap_update_power(dev);
893554f802dSMarcel Apfelbaum 
894315a1350SMichael S. Tsirkin     hotplug_event_notify(dev);
895315a1350SMichael S. Tsirkin 
896315a1350SMichael S. Tsirkin     /*
897315a1350SMichael S. Tsirkin      * 6.7.3.2 Command Completed Events
898315a1350SMichael S. Tsirkin      *
899315a1350SMichael S. Tsirkin      * Software issues a command to a hot-plug capable Downstream Port by
900315a1350SMichael S. Tsirkin      * issuing a write transaction that targets any portion of the Port’s Slot
901315a1350SMichael S. Tsirkin      * Control register. A single write to the Slot Control register is
902315a1350SMichael S. Tsirkin      * considered to be a single command, even if the write affects more than
903315a1350SMichael S. Tsirkin      * one field in the Slot Control register. In response to this transaction,
904315a1350SMichael S. Tsirkin      * the Port must carry out the requested actions and then set the
905315a1350SMichael S. Tsirkin      * associated status field for the command completed event. */
906315a1350SMichael S. Tsirkin 
907315a1350SMichael S. Tsirkin     /* Real hardware might take a while to complete requested command because
908315a1350SMichael S. Tsirkin      * physical movement would be involved like locking the electromechanical
909315a1350SMichael S. Tsirkin      * lock.  However in our case, command is completed instantaneously above,
910315a1350SMichael S. Tsirkin      * so send a command completion event right now.
911315a1350SMichael S. Tsirkin      */
912315a1350SMichael S. Tsirkin     pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
913315a1350SMichael S. Tsirkin }
914315a1350SMichael S. Tsirkin 
pcie_cap_slot_post_load(void * opaque,int version_id)915315a1350SMichael S. Tsirkin int pcie_cap_slot_post_load(void *opaque, int version_id)
916315a1350SMichael S. Tsirkin {
917315a1350SMichael S. Tsirkin     PCIDevice *dev = opaque;
918315a1350SMichael S. Tsirkin     hotplug_event_update_event_status(dev);
919d5daff7dSGerd Hoffmann     pcie_cap_update_power(dev);
920315a1350SMichael S. Tsirkin     return 0;
921315a1350SMichael S. Tsirkin }
922315a1350SMichael S. Tsirkin 
pcie_cap_slot_push_attention_button(PCIDevice * dev)923315a1350SMichael S. Tsirkin void pcie_cap_slot_push_attention_button(PCIDevice *dev)
924315a1350SMichael S. Tsirkin {
925315a1350SMichael S. Tsirkin     pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
926315a1350SMichael S. Tsirkin }
927315a1350SMichael S. Tsirkin 
928315a1350SMichael S. Tsirkin /* root control/capabilities/status. PME isn't emulated for now */
pcie_cap_root_init(PCIDevice * dev)929315a1350SMichael S. Tsirkin void pcie_cap_root_init(PCIDevice *dev)
930315a1350SMichael S. Tsirkin {
931315a1350SMichael S. Tsirkin     pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
932315a1350SMichael S. Tsirkin                  PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
933315a1350SMichael S. Tsirkin                  PCI_EXP_RTCTL_SEFEE);
934315a1350SMichael S. Tsirkin }
935315a1350SMichael S. Tsirkin 
pcie_cap_root_reset(PCIDevice * dev)936315a1350SMichael S. Tsirkin void pcie_cap_root_reset(PCIDevice *dev)
937315a1350SMichael S. Tsirkin {
938315a1350SMichael S. Tsirkin     pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
939315a1350SMichael S. Tsirkin }
940315a1350SMichael S. Tsirkin 
941315a1350SMichael S. Tsirkin /* function level reset(FLR) */
pcie_cap_flr_init(PCIDevice * dev)942315a1350SMichael S. Tsirkin void pcie_cap_flr_init(PCIDevice *dev)
943315a1350SMichael S. Tsirkin {
944315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
945315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCAP_FLR);
946315a1350SMichael S. Tsirkin 
947315a1350SMichael S. Tsirkin     /* Although reading BCR_FLR returns always 0,
948315a1350SMichael S. Tsirkin      * the bit is made writable here in order to detect the 1b is written
949315a1350SMichael S. Tsirkin      * pcie_cap_flr_write_config() test-and-clear the bit, so
950315a1350SMichael S. Tsirkin      * this bit always returns 0 to the guest.
951315a1350SMichael S. Tsirkin      */
952315a1350SMichael S. Tsirkin     pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
953315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCTL_BCR_FLR);
954315a1350SMichael S. Tsirkin }
955315a1350SMichael S. Tsirkin 
pcie_cap_flr_write_config(PCIDevice * dev,uint32_t addr,uint32_t val,int len)956315a1350SMichael S. Tsirkin void pcie_cap_flr_write_config(PCIDevice *dev,
957315a1350SMichael S. Tsirkin                                uint32_t addr, uint32_t val, int len)
958315a1350SMichael S. Tsirkin {
959315a1350SMichael S. Tsirkin     uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
960315a1350SMichael S. Tsirkin     if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
961315a1350SMichael S. Tsirkin         /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
962315a1350SMichael S. Tsirkin            so the handler can detect FLR by looking at this bit. */
963315a1350SMichael S. Tsirkin         pci_device_reset(dev);
964315a1350SMichael S. Tsirkin         pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
965315a1350SMichael S. Tsirkin     }
966315a1350SMichael S. Tsirkin }
967315a1350SMichael S. Tsirkin 
968821be9dbSKnut Omang /* Alternative Routing-ID Interpretation (ARI)
969821be9dbSKnut Omang  * forwarding support for root and downstream ports
970821be9dbSKnut Omang  */
pcie_cap_arifwd_init(PCIDevice * dev)971821be9dbSKnut Omang void pcie_cap_arifwd_init(PCIDevice *dev)
972315a1350SMichael S. Tsirkin {
973315a1350SMichael S. Tsirkin     uint32_t pos = dev->exp.exp_cap;
974315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
975315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCAP2_ARI);
976315a1350SMichael S. Tsirkin     pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
977315a1350SMichael S. Tsirkin                                PCI_EXP_DEVCTL2_ARI);
978315a1350SMichael S. Tsirkin }
979315a1350SMichael S. Tsirkin 
pcie_cap_arifwd_reset(PCIDevice * dev)980821be9dbSKnut Omang void pcie_cap_arifwd_reset(PCIDevice *dev)
981315a1350SMichael S. Tsirkin {
982315a1350SMichael S. Tsirkin     uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
983315a1350SMichael S. Tsirkin     pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
984315a1350SMichael S. Tsirkin }
985315a1350SMichael S. Tsirkin 
pcie_cap_is_arifwd_enabled(const PCIDevice * dev)986821be9dbSKnut Omang bool pcie_cap_is_arifwd_enabled(const PCIDevice *dev)
987315a1350SMichael S. Tsirkin {
988315a1350SMichael S. Tsirkin     if (!pci_is_express(dev)) {
989315a1350SMichael S. Tsirkin         return false;
990315a1350SMichael S. Tsirkin     }
991315a1350SMichael S. Tsirkin     if (!dev->exp.exp_cap) {
992315a1350SMichael S. Tsirkin         return false;
993315a1350SMichael S. Tsirkin     }
994315a1350SMichael S. Tsirkin 
995315a1350SMichael S. Tsirkin     return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
996315a1350SMichael S. Tsirkin         PCI_EXP_DEVCTL2_ARI;
997315a1350SMichael S. Tsirkin }
998315a1350SMichael S. Tsirkin 
999315a1350SMichael S. Tsirkin /**************************************************************************
10004d5e17a5SGonglei  * pci express extended capability list management functions
1001315a1350SMichael S. Tsirkin  * uint16_t ext_cap_id (16 bit)
1002315a1350SMichael S. Tsirkin  * uint8_t cap_ver (4 bit)
1003315a1350SMichael S. Tsirkin  * uint16_t cap_offset (12 bit)
1004315a1350SMichael S. Tsirkin  * uint16_t ext_cap_size
1005315a1350SMichael S. Tsirkin  */
1006315a1350SMichael S. Tsirkin 
10074bb571d8SMichael S. Tsirkin /* Passing a cap_id value > 0xffff will return 0 and put end of list in prev */
pcie_find_capability_list(PCIDevice * dev,uint32_t cap_id,uint16_t * prev_p)10084bb571d8SMichael S. Tsirkin static uint16_t pcie_find_capability_list(PCIDevice *dev, uint32_t cap_id,
1009315a1350SMichael S. Tsirkin                                           uint16_t *prev_p)
1010315a1350SMichael S. Tsirkin {
1011315a1350SMichael S. Tsirkin     uint16_t prev = 0;
1012315a1350SMichael S. Tsirkin     uint16_t next;
1013315a1350SMichael S. Tsirkin     uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
1014315a1350SMichael S. Tsirkin 
1015315a1350SMichael S. Tsirkin     if (!header) {
1016315a1350SMichael S. Tsirkin         /* no extended capability */
1017315a1350SMichael S. Tsirkin         next = 0;
1018315a1350SMichael S. Tsirkin         goto out;
1019315a1350SMichael S. Tsirkin     }
1020315a1350SMichael S. Tsirkin     for (next = PCI_CONFIG_SPACE_SIZE; next;
1021315a1350SMichael S. Tsirkin          prev = next, next = PCI_EXT_CAP_NEXT(header)) {
1022315a1350SMichael S. Tsirkin 
1023315a1350SMichael S. Tsirkin         assert(next >= PCI_CONFIG_SPACE_SIZE);
1024315a1350SMichael S. Tsirkin         assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
1025315a1350SMichael S. Tsirkin 
1026315a1350SMichael S. Tsirkin         header = pci_get_long(dev->config + next);
1027315a1350SMichael S. Tsirkin         if (PCI_EXT_CAP_ID(header) == cap_id) {
1028315a1350SMichael S. Tsirkin             break;
1029315a1350SMichael S. Tsirkin         }
1030315a1350SMichael S. Tsirkin     }
1031315a1350SMichael S. Tsirkin 
1032315a1350SMichael S. Tsirkin out:
1033315a1350SMichael S. Tsirkin     if (prev_p) {
1034315a1350SMichael S. Tsirkin         *prev_p = prev;
1035315a1350SMichael S. Tsirkin     }
1036315a1350SMichael S. Tsirkin     return next;
1037315a1350SMichael S. Tsirkin }
1038315a1350SMichael S. Tsirkin 
pcie_find_capability(PCIDevice * dev,uint16_t cap_id)1039315a1350SMichael S. Tsirkin uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
1040315a1350SMichael S. Tsirkin {
1041315a1350SMichael S. Tsirkin     return pcie_find_capability_list(dev, cap_id, NULL);
1042315a1350SMichael S. Tsirkin }
1043315a1350SMichael S. Tsirkin 
pcie_ext_cap_set_next(PCIDevice * dev,uint16_t pos,uint16_t next)1044315a1350SMichael S. Tsirkin static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next)
1045315a1350SMichael S. Tsirkin {
1046812d2594SKnut Omang     uint32_t header = pci_get_long(dev->config + pos);
1047315a1350SMichael S. Tsirkin     assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
1048315a1350SMichael S. Tsirkin     header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
1049315a1350SMichael S. Tsirkin         ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
1050315a1350SMichael S. Tsirkin     pci_set_long(dev->config + pos, header);
1051315a1350SMichael S. Tsirkin }
1052315a1350SMichael S. Tsirkin 
1053315a1350SMichael S. Tsirkin /*
1054d62d1eb6SCao jin  * Caller must supply valid (offset, size) such that the range wouldn't
1055315a1350SMichael S. Tsirkin  * overlap with other capability or other registers.
1056315a1350SMichael S. Tsirkin  * This function doesn't check it.
1057315a1350SMichael S. Tsirkin  */
pcie_add_capability(PCIDevice * dev,uint16_t cap_id,uint8_t cap_ver,uint16_t offset,uint16_t size)1058315a1350SMichael S. Tsirkin void pcie_add_capability(PCIDevice *dev,
1059315a1350SMichael S. Tsirkin                          uint16_t cap_id, uint8_t cap_ver,
1060315a1350SMichael S. Tsirkin                          uint16_t offset, uint16_t size)
1061315a1350SMichael S. Tsirkin {
1062315a1350SMichael S. Tsirkin     assert(offset >= PCI_CONFIG_SPACE_SIZE);
1063bacf58caSDaniella Lee     assert(offset < (uint16_t)(offset + size));
1064bacf58caSDaniella Lee     assert((uint16_t)(offset + size) <= PCIE_CONFIG_SPACE_SIZE);
1065315a1350SMichael S. Tsirkin     assert(size >= 8);
1066315a1350SMichael S. Tsirkin     assert(pci_is_express(dev));
1067315a1350SMichael S. Tsirkin 
1068d4e9b75aSPeter Xu     if (offset != PCI_CONFIG_SPACE_SIZE) {
1069315a1350SMichael S. Tsirkin         uint16_t prev;
1070315a1350SMichael S. Tsirkin 
10714bb571d8SMichael S. Tsirkin         /*
10724bb571d8SMichael S. Tsirkin          * 0xffffffff is not a valid cap id (it's a 16 bit field). use
10734bb571d8SMichael S. Tsirkin          * internally to find the last capability in the linked list.
10744bb571d8SMichael S. Tsirkin          */
1075d4e9b75aSPeter Xu         pcie_find_capability_list(dev, 0xffffffff, &prev);
1076315a1350SMichael S. Tsirkin         assert(prev >= PCI_CONFIG_SPACE_SIZE);
1077315a1350SMichael S. Tsirkin         pcie_ext_cap_set_next(dev, prev, offset);
1078315a1350SMichael S. Tsirkin     }
1079d4e9b75aSPeter Xu     pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, 0));
1080315a1350SMichael S. Tsirkin 
1081315a1350SMichael S. Tsirkin     /* Make capability read-only by default */
1082315a1350SMichael S. Tsirkin     memset(dev->wmask + offset, 0, size);
1083315a1350SMichael S. Tsirkin     memset(dev->w1cmask + offset, 0, size);
1084315a1350SMichael S. Tsirkin     /* Check capability by default */
1085315a1350SMichael S. Tsirkin     memset(dev->cmask + offset, 0xFF, size);
1086315a1350SMichael S. Tsirkin }
1087315a1350SMichael S. Tsirkin 
1088727b4866SAlex Williamson /*
1089727b4866SAlex Williamson  * Sync the PCIe Link Status negotiated speed and width of a bridge with the
1090727b4866SAlex Williamson  * downstream device.  If downstream device is not present, re-write with the
109188c86919SAlex Williamson  * Link Capability fields.  If downstream device reports invalid width or
109288c86919SAlex Williamson  * speed, replace with minimum values (LnkSta fields are RsvdZ on VFs but such
109388c86919SAlex Williamson  * values interfere with PCIe native hotplug detecting new devices).  Limit
109488c86919SAlex Williamson  * width and speed to bridge capabilities for compatibility.  Use config_read
109588c86919SAlex Williamson  * to access the downstream device since it could be an assigned device with
109688c86919SAlex Williamson  * volatile link information.
1097727b4866SAlex Williamson  */
pcie_sync_bridge_lnk(PCIDevice * bridge_dev)1098727b4866SAlex Williamson void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
1099727b4866SAlex Williamson {
1100727b4866SAlex Williamson     PCIBridge *br = PCI_BRIDGE(bridge_dev);
1101727b4866SAlex Williamson     PCIBus *bus = pci_bridge_get_sec_bus(br);
1102727b4866SAlex Williamson     PCIDevice *target = bus->devices[0];
1103727b4866SAlex Williamson     uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
1104727b4866SAlex Williamson     uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);
1105727b4866SAlex Williamson 
1106727b4866SAlex Williamson     if (!target || !target->exp.exp_cap) {
1107727b4866SAlex Williamson         lnksta = lnkcap;
1108727b4866SAlex Williamson     } else {
1109727b4866SAlex Williamson         lnksta = target->config_read(target,
1110727b4866SAlex Williamson                                      target->exp.exp_cap + PCI_EXP_LNKSTA,
1111727b4866SAlex Williamson                                      sizeof(lnksta));
1112727b4866SAlex Williamson 
1113727b4866SAlex Williamson         if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
1114727b4866SAlex Williamson             lnksta &= ~PCI_EXP_LNKSTA_NLW;
1115727b4866SAlex Williamson             lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
1116727b4866SAlex Williamson         }
1117727b4866SAlex Williamson 
1118727b4866SAlex Williamson         if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
1119727b4866SAlex Williamson             lnksta &= ~PCI_EXP_LNKSTA_CLS;
1120727b4866SAlex Williamson             lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
1121727b4866SAlex Williamson         }
1122727b4866SAlex Williamson     }
1123727b4866SAlex Williamson 
1124*91b2cb9aSSebastian Ott     if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
1125*91b2cb9aSSebastian Ott         lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
1126*91b2cb9aSSebastian Ott     }
1127*91b2cb9aSSebastian Ott 
1128*91b2cb9aSSebastian Ott     if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
1129*91b2cb9aSSebastian Ott         lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
1130*91b2cb9aSSebastian Ott     }
1131*91b2cb9aSSebastian Ott 
1132727b4866SAlex Williamson     pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
1133727b4866SAlex Williamson                                  PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
1134727b4866SAlex Williamson     pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
1135727b4866SAlex Williamson                                (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
1136727b4866SAlex Williamson }
1137727b4866SAlex Williamson 
1138315a1350SMichael S. Tsirkin /**************************************************************************
1139315a1350SMichael S. Tsirkin  * pci express extended capability helper functions
1140315a1350SMichael S. Tsirkin  */
1141315a1350SMichael S. Tsirkin 
1142315a1350SMichael S. Tsirkin /* ARI */
pcie_ari_init(PCIDevice * dev,uint16_t offset)1143445416e3SAkihiko Odaki void pcie_ari_init(PCIDevice *dev, uint16_t offset)
1144315a1350SMichael S. Tsirkin {
11457c228c5fSAkihiko Odaki     uint16_t nextfn = dev->cap_present & QEMU_PCIE_ARI_NEXTFN_1 ? 1 : 0;
1146445416e3SAkihiko Odaki 
1147315a1350SMichael S. Tsirkin     pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
1148315a1350SMichael S. Tsirkin                         offset, PCI_ARI_SIZEOF);
1149ec70b46bSKnut Omang     pci_set_long(dev->config + offset + PCI_ARI_CAP, (nextfn & 0xff) << 8);
1150315a1350SMichael S. Tsirkin }
1151b56b9285SDmitry Fleytman 
pcie_dev_ser_num_init(PCIDevice * dev,uint16_t offset,uint64_t ser_num)1152b56b9285SDmitry Fleytman void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num)
1153b56b9285SDmitry Fleytman {
1154b56b9285SDmitry Fleytman     static const int pci_dsn_ver = 1;
1155b56b9285SDmitry Fleytman     static const int pci_dsn_cap = 4;
1156b56b9285SDmitry Fleytman 
1157b56b9285SDmitry Fleytman     pcie_add_capability(dev, PCI_EXT_CAP_ID_DSN, pci_dsn_ver, offset,
1158b56b9285SDmitry Fleytman                         PCI_EXT_CAP_DSN_SIZEOF);
1159b56b9285SDmitry Fleytman     pci_set_quad(dev->config + offset + pci_dsn_cap, ser_num);
1160b56b9285SDmitry Fleytman }
1161615c4ed2SJason Wang 
pcie_ats_init(PCIDevice * dev,uint16_t offset,bool aligned)1162d83f46d1SJason Wang void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned)
1163615c4ed2SJason Wang {
1164615c4ed2SJason Wang     pcie_add_capability(dev, PCI_EXT_CAP_ID_ATS, 0x1,
1165615c4ed2SJason Wang                         offset, PCI_EXT_CAP_ATS_SIZEOF);
1166615c4ed2SJason Wang 
1167615c4ed2SJason Wang     dev->exp.ats_cap = offset;
1168615c4ed2SJason Wang 
1169d83f46d1SJason Wang     /* Invalidate Queue Depth 0 */
1170d83f46d1SJason Wang     if (aligned) {
11714c708753SJason Wang         pci_set_word(dev->config + offset + PCI_ATS_CAP,
11724c708753SJason Wang                      PCI_ATS_CAP_PAGE_ALIGNED);
1173d83f46d1SJason Wang     }
1174615c4ed2SJason Wang     /* STU 0, Disabled by default */
1175615c4ed2SJason Wang     pci_set_word(dev->config + offset + PCI_ATS_CTRL, 0);
1176615c4ed2SJason Wang 
1177615c4ed2SJason Wang     pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f);
1178615c4ed2SJason Wang }
1179db891a9bSKnut Omang 
1180db891a9bSKnut Omang /* ACS (Access Control Services) */
pcie_acs_init(PCIDevice * dev,uint16_t offset)1181db891a9bSKnut Omang void pcie_acs_init(PCIDevice *dev, uint16_t offset)
1182db891a9bSKnut Omang {
1183db891a9bSKnut Omang     bool is_downstream = pci_is_express_downstream_port(dev);
1184db891a9bSKnut Omang     uint16_t cap_bits = 0;
1185db891a9bSKnut Omang 
1186db891a9bSKnut Omang     /* For endpoints, only multifunction devs may have an ACS capability: */
1187db891a9bSKnut Omang     assert(is_downstream ||
1188db891a9bSKnut Omang            (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) ||
1189db891a9bSKnut Omang            PCI_FUNC(dev->devfn));
1190db891a9bSKnut Omang 
1191db891a9bSKnut Omang     pcie_add_capability(dev, PCI_EXT_CAP_ID_ACS, PCI_ACS_VER, offset,
1192db891a9bSKnut Omang                         PCI_ACS_SIZEOF);
1193db891a9bSKnut Omang     dev->exp.acs_cap = offset;
1194db891a9bSKnut Omang 
1195db891a9bSKnut Omang     if (is_downstream) {
1196db891a9bSKnut Omang         /*
1197db891a9bSKnut Omang          * Downstream ports must implement SV, TB, RR, CR, UF, and DT (with
1198db891a9bSKnut Omang          * caveats on the latter four that we ignore for simplicity).
1199db891a9bSKnut Omang          * Endpoints may also implement a subset of ACS capabilities,
1200db891a9bSKnut Omang          * but these are optional if the endpoint does not support
1201db891a9bSKnut Omang          * peer-to-peer between functions and thus omitted here.
1202db891a9bSKnut Omang          */
1203db891a9bSKnut Omang         cap_bits = PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
1204db891a9bSKnut Omang             PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT;
1205db891a9bSKnut Omang     }
1206db891a9bSKnut Omang 
1207db891a9bSKnut Omang     pci_set_word(dev->config + offset + PCI_ACS_CAP, cap_bits);
1208db891a9bSKnut Omang     pci_set_word(dev->wmask + offset + PCI_ACS_CTRL, cap_bits);
1209db891a9bSKnut Omang }
1210db891a9bSKnut Omang 
pcie_acs_reset(PCIDevice * dev)1211db891a9bSKnut Omang void pcie_acs_reset(PCIDevice *dev)
1212db891a9bSKnut Omang {
1213db891a9bSKnut Omang     if (dev->exp.acs_cap) {
1214db891a9bSKnut Omang         pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0);
1215db891a9bSKnut Omang     }
1216db891a9bSKnut Omang }
1217