Commit 6f4cbd3950b10ceec95fcda3946839be2e009027

Authored by Michael S. Tsirkin
Committed by Anthony Liguori
1 parent 14e12559

qemu/pci: add routines to manage PCI capabilities

Add routines to manage PCI capability list. First user will be MSI-X.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 2 changed files with 90 additions and 2 deletions
hw/pci.c
@@ -164,7 +164,6 @@ int pci_device_load(PCIDevice *s, QEMUFile *f) @@ -164,7 +164,6 @@ int pci_device_load(PCIDevice *s, QEMUFile *f)
164 if (version_id >= 2) 164 if (version_id >= 2)
165 for (i = 0; i < 4; i ++) 165 for (i = 0; i < 4; i ++)
166 s->irq_state[i] = qemu_get_be32(f); 166 s->irq_state[i] = qemu_get_be32(f);
167 -  
168 return 0; 167 return 0;
169 } 168 }
170 169
@@ -895,3 +894,76 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) @@ -895,3 +894,76 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
895 894
896 return (PCIDevice *)dev; 895 return (PCIDevice *)dev;
897 } 896 }
  897 +
  898 +static int pci_find_space(PCIDevice *pdev, uint8_t size)
  899 +{
  900 + int offset = PCI_CONFIG_HEADER_SIZE;
  901 + int i;
  902 + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
  903 + if (pdev->used[i])
  904 + offset = i + 1;
  905 + else if (i - offset + 1 == size)
  906 + return offset;
  907 + return 0;
  908 +}
  909 +
  910 +static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
  911 + uint8_t *prev_p)
  912 +{
  913 + uint8_t next, prev;
  914 +
  915 + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
  916 + return 0;
  917 +
  918 + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
  919 + prev = next + PCI_CAP_LIST_NEXT)
  920 + if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
  921 + break;
  922 +
  923 + if (prev_p)
  924 + *prev_p = prev;
  925 + return next;
  926 +}
  927 +
  928 +/* Reserve space and add capability to the linked list in pci config space */
  929 +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
  930 +{
  931 + uint8_t offset = pci_find_space(pdev, size);
  932 + uint8_t *config = pdev->config + offset;
  933 + if (!offset)
  934 + return -ENOSPC;
  935 + config[PCI_CAP_LIST_ID] = cap_id;
  936 + config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
  937 + pdev->config[PCI_CAPABILITY_LIST] = offset;
  938 + pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
  939 + memset(pdev->used + offset, 0xFF, size);
  940 + /* Make capability read-only by default */
  941 + memset(pdev->wmask + offset, 0, size);
  942 + return offset;
  943 +}
  944 +
  945 +/* Unlink capability from the pci config space. */
  946 +void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
  947 +{
  948 + uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
  949 + if (!offset)
  950 + return;
  951 + pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
  952 + /* Make capability writeable again */
  953 + memset(pdev->wmask + offset, 0xff, size);
  954 + memset(pdev->used + offset, 0, size);
  955 +
  956 + if (!pdev->config[PCI_CAPABILITY_LIST])
  957 + pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
  958 +}
  959 +
  960 +/* Reserve space for capability at a known offset (to call after load). */
  961 +void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
  962 +{
  963 + memset(pdev->used + offset, 0xff, size);
  964 +}
  965 +
  966 +uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
  967 +{
  968 + return pci_find_capability_list(pdev, cap_id, NULL);
  969 +}
hw/pci.h
@@ -121,6 +121,10 @@ typedef struct PCIIORegion { @@ -121,6 +121,10 @@ typedef struct PCIIORegion {
121 #define PCI_MIN_GNT 0x3e /* 8 bits */ 121 #define PCI_MIN_GNT 0x3e /* 8 bits */
122 #define PCI_MAX_LAT 0x3f /* 8 bits */ 122 #define PCI_MAX_LAT 0x3f /* 8 bits */
123 123
  124 +/* Capability lists */
  125 +#define PCI_CAP_LIST_ID 0 /* Capability ID */
  126 +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
  127 +
124 #define PCI_REVISION 0x08 /* obsolete, use PCI_REVISION_ID */ 128 #define PCI_REVISION 0x08 /* obsolete, use PCI_REVISION_ID */
125 #define PCI_SUBVENDOR_ID 0x2c /* obsolete, use PCI_SUBSYSTEM_VENDOR_ID */ 129 #define PCI_SUBVENDOR_ID 0x2c /* obsolete, use PCI_SUBSYSTEM_VENDOR_ID */
126 #define PCI_SUBDEVICE_ID 0x2e /* obsolete, use PCI_SUBSYSTEM_ID */ 130 #define PCI_SUBDEVICE_ID 0x2e /* obsolete, use PCI_SUBSYSTEM_ID */
@@ -128,7 +132,7 @@ typedef struct PCIIORegion { @@ -128,7 +132,7 @@ typedef struct PCIIORegion {
128 /* Bits in the PCI Status Register (PCI 2.3 spec) */ 132 /* Bits in the PCI Status Register (PCI 2.3 spec) */
129 #define PCI_STATUS_RESERVED1 0x007 133 #define PCI_STATUS_RESERVED1 0x007
130 #define PCI_STATUS_INT_STATUS 0x008 134 #define PCI_STATUS_INT_STATUS 0x008
131 -#define PCI_STATUS_CAPABILITIES 0x010 135 +#define PCI_STATUS_CAP_LIST 0x010
132 #define PCI_STATUS_66MHZ 0x020 136 #define PCI_STATUS_66MHZ 0x020
133 #define PCI_STATUS_RESERVED2 0x040 137 #define PCI_STATUS_RESERVED2 0x040
134 #define PCI_STATUS_FAST_BACK 0x080 138 #define PCI_STATUS_FAST_BACK 0x080
@@ -158,6 +162,9 @@ struct PCIDevice { @@ -158,6 +162,9 @@ struct PCIDevice {
158 /* Used to implement R/W bytes */ 162 /* Used to implement R/W bytes */
159 uint8_t wmask[PCI_CONFIG_SPACE_SIZE]; 163 uint8_t wmask[PCI_CONFIG_SPACE_SIZE];
160 164
  165 + /* Used to allocate config space for capabilities. */
  166 + uint8_t used[PCI_CONFIG_SPACE_SIZE];
  167 +
161 /* the following fields are read only */ 168 /* the following fields are read only */
162 PCIBus *bus; 169 PCIBus *bus;
163 int devfn; 170 int devfn;
@@ -186,6 +193,15 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, @@ -186,6 +193,15 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
186 uint32_t size, int type, 193 uint32_t size, int type,
187 PCIMapIORegionFunc *map_func); 194 PCIMapIORegionFunc *map_func);
188 195
  196 +int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
  197 +
  198 +void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
  199 +
  200 +void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
  201 +
  202 +uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
  203 +
  204 +
189 uint32_t pci_default_read_config(PCIDevice *d, 205 uint32_t pci_default_read_config(PCIDevice *d,
190 uint32_t address, int len); 206 uint32_t address, int len);
191 void pci_default_write_config(PCIDevice *d, 207 void pci_default_write_config(PCIDevice *d,