xen_pt.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #ifndef XEN_PT_H
  2. #define XEN_PT_H
  3. #include "qemu-common.h"
  4. #include "xen_common.h"
  5. #include "pci.h"
  6. #include "xen-host-pci-device.h"
  7. void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
  8. #define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
  9. #ifdef XEN_PT_LOGGING_ENABLED
  10. # define XEN_PT_LOG(d, _f, _a...) xen_pt_log(d, "%s: " _f, __func__, ##_a)
  11. # define XEN_PT_WARN(d, _f, _a...) \
  12. xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
  13. #else
  14. # define XEN_PT_LOG(d, _f, _a...)
  15. # define XEN_PT_WARN(d, _f, _a...)
  16. #endif
  17. #ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
  18. # define XEN_PT_LOG_CONFIG(d, addr, val, len) \
  19. xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
  20. __func__, addr, val, len)
  21. #else
  22. # define XEN_PT_LOG_CONFIG(d, addr, val, len)
  23. #endif
  24. /* Helper */
  25. #define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
  26. typedef struct XenPTRegInfo XenPTRegInfo;
  27. typedef struct XenPTReg XenPTReg;
  28. typedef struct XenPCIPassthroughState XenPCIPassthroughState;
  29. /* function type for config reg */
  30. typedef int (*xen_pt_conf_reg_init)
  31. (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
  32. uint32_t *data);
  33. typedef int (*xen_pt_conf_dword_write)
  34. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  35. uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
  36. typedef int (*xen_pt_conf_word_write)
  37. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  38. uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
  39. typedef int (*xen_pt_conf_byte_write)
  40. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  41. uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
  42. typedef int (*xen_pt_conf_dword_read)
  43. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  44. uint32_t *val, uint32_t valid_mask);
  45. typedef int (*xen_pt_conf_word_read)
  46. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  47. uint16_t *val, uint16_t valid_mask);
  48. typedef int (*xen_pt_conf_byte_read)
  49. (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  50. uint8_t *val, uint8_t valid_mask);
  51. #define XEN_PT_BAR_ALLF 0xFFFFFFFF
  52. #define XEN_PT_BAR_UNMAPPED (-1)
  53. #define PCI_CAP_MAX 48
  54. typedef enum {
  55. XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
  56. XEN_PT_GRP_TYPE_EMU, /* emul reg group */
  57. } XenPTRegisterGroupType;
  58. typedef enum {
  59. XEN_PT_BAR_FLAG_MEM = 0, /* Memory type BAR */
  60. XEN_PT_BAR_FLAG_IO, /* I/O type BAR */
  61. XEN_PT_BAR_FLAG_UPPER, /* upper 64bit BAR */
  62. XEN_PT_BAR_FLAG_UNUSED, /* unused BAR */
  63. } XenPTBarFlag;
  64. typedef struct XenPTRegion {
  65. /* BAR flag */
  66. XenPTBarFlag bar_flag;
  67. /* Translation of the emulated address */
  68. union {
  69. uint64_t maddr;
  70. uint64_t pio_base;
  71. uint64_t u;
  72. } access;
  73. } XenPTRegion;
  74. /* XenPTRegInfo declaration
  75. * - only for emulated register (either a part or whole bit).
  76. * - for passthrough register that need special behavior (like interacting with
  77. * other component), set emu_mask to all 0 and specify r/w func properly.
  78. * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
  79. */
  80. /* emulated register information */
  81. struct XenPTRegInfo {
  82. uint32_t offset;
  83. uint32_t size;
  84. uint32_t init_val;
  85. /* reg read only field mask (ON:RO/ROS, OFF:other) */
  86. uint32_t ro_mask;
  87. /* reg emulate field mask (ON:emu, OFF:passthrough) */
  88. uint32_t emu_mask;
  89. /* no write back allowed */
  90. uint32_t no_wb;
  91. xen_pt_conf_reg_init init;
  92. /* read/write function pointer
  93. * for double_word/word/byte size */
  94. union {
  95. struct {
  96. xen_pt_conf_dword_write write;
  97. xen_pt_conf_dword_read read;
  98. } dw;
  99. struct {
  100. xen_pt_conf_word_write write;
  101. xen_pt_conf_word_read read;
  102. } w;
  103. struct {
  104. xen_pt_conf_byte_write write;
  105. xen_pt_conf_byte_read read;
  106. } b;
  107. } u;
  108. };
  109. /* emulated register management */
  110. struct XenPTReg {
  111. QLIST_ENTRY(XenPTReg) entries;
  112. XenPTRegInfo *reg;
  113. uint32_t data; /* emulated value */
  114. };
  115. typedef struct XenPTRegGroupInfo XenPTRegGroupInfo;
  116. /* emul reg group size initialize method */
  117. typedef int (*xen_pt_reg_size_init_fn)
  118. (XenPCIPassthroughState *, const XenPTRegGroupInfo *,
  119. uint32_t base_offset, uint8_t *size);
  120. /* emulated register group information */
  121. struct XenPTRegGroupInfo {
  122. uint8_t grp_id;
  123. XenPTRegisterGroupType grp_type;
  124. uint8_t grp_size;
  125. xen_pt_reg_size_init_fn size_init;
  126. XenPTRegInfo *emu_regs;
  127. };
  128. /* emul register group management table */
  129. typedef struct XenPTRegGroup {
  130. QLIST_ENTRY(XenPTRegGroup) entries;
  131. const XenPTRegGroupInfo *reg_grp;
  132. uint32_t base_offset;
  133. uint8_t size;
  134. QLIST_HEAD(, XenPTReg) reg_tbl_list;
  135. } XenPTRegGroup;
  136. #define XEN_PT_UNASSIGNED_PIRQ (-1)
  137. typedef struct XenPTMSI {
  138. uint16_t flags;
  139. uint32_t addr_lo; /* guest message address */
  140. uint32_t addr_hi; /* guest message upper address */
  141. uint16_t data; /* guest message data */
  142. uint32_t ctrl_offset; /* saved control offset */
  143. int pirq; /* guest pirq corresponding */
  144. bool initialized; /* when guest MSI is initialized */
  145. bool mapped; /* when pirq is mapped */
  146. } XenPTMSI;
  147. typedef struct XenPTMSIXEntry {
  148. int pirq;
  149. uint64_t addr;
  150. uint32_t data;
  151. uint32_t vector_ctrl;
  152. bool updated; /* indicate whether MSI ADDR or DATA is updated */
  153. } XenPTMSIXEntry;
  154. typedef struct XenPTMSIX {
  155. uint32_t ctrl_offset;
  156. bool enabled;
  157. int total_entries;
  158. int bar_index;
  159. uint64_t table_base;
  160. uint32_t table_offset_adjust; /* page align mmap */
  161. uint64_t mmio_base_addr;
  162. MemoryRegion mmio;
  163. void *phys_iomem_base;
  164. XenPTMSIXEntry msix_entry[0];
  165. } XenPTMSIX;
  166. struct XenPCIPassthroughState {
  167. PCIDevice dev;
  168. PCIHostDeviceAddress hostaddr;
  169. bool is_virtfn;
  170. XenHostPCIDevice real_device;
  171. XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
  172. QLIST_HEAD(, XenPTRegGroup) reg_grps;
  173. uint32_t machine_irq;
  174. XenPTMSI *msi;
  175. XenPTMSIX *msix;
  176. MemoryRegion bar[PCI_NUM_REGIONS - 1];
  177. MemoryRegion rom;
  178. MemoryListener memory_listener;
  179. };
  180. int xen_pt_config_init(XenPCIPassthroughState *s);
  181. void xen_pt_config_delete(XenPCIPassthroughState *s);
  182. XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
  183. XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
  184. int xen_pt_bar_offset_to_index(uint32_t offset);
  185. static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
  186. {
  187. /* align resource size (memory type only) */
  188. if (flag == XEN_PT_BAR_FLAG_MEM) {
  189. return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
  190. } else {
  191. return r_size;
  192. }
  193. }
  194. /* INTx */
  195. /* The PCI Local Bus Specification, Rev. 3.0,
  196. * Section 6.2.4 Miscellaneous Registers, pp 223
  197. * outlines 5 valid values for the interrupt pin (intx).
  198. * 0: For devices (or device functions) that don't use an interrupt in
  199. * 1: INTA#
  200. * 2: INTB#
  201. * 3: INTC#
  202. * 4: INTD#
  203. *
  204. * Xen uses the following 4 values for intx
  205. * 0: INTA#
  206. * 1: INTB#
  207. * 2: INTC#
  208. * 3: INTD#
  209. *
  210. * Observing that these list of values are not the same, xen_pt_pci_read_intx()
  211. * uses the following mapping from hw to xen values.
  212. * This seems to reflect the current usage within Xen.
  213. *
  214. * PCI hardware | Xen | Notes
  215. * ----------------+-----+----------------------------------------------------
  216. * 0 | 0 | No interrupt
  217. * 1 | 0 | INTA#
  218. * 2 | 1 | INTB#
  219. * 3 | 2 | INTC#
  220. * 4 | 3 | INTD#
  221. * any other value | 0 | This should never happen, log error message
  222. */
  223. static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
  224. {
  225. uint8_t v = 0;
  226. xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
  227. return v;
  228. }
  229. static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
  230. {
  231. uint8_t r_val = xen_pt_pci_read_intx(s);
  232. XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
  233. if (r_val < 1 || r_val > 4) {
  234. XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
  235. " value=%i, acceptable range is 1 - 4\n", r_val);
  236. r_val = 0;
  237. } else {
  238. r_val -= 1;
  239. }
  240. return r_val;
  241. }
  242. /* MSI/MSI-X */
  243. int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
  244. int xen_pt_msi_setup(XenPCIPassthroughState *s);
  245. int xen_pt_msi_update(XenPCIPassthroughState *d);
  246. void xen_pt_msi_disable(XenPCIPassthroughState *s);
  247. int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
  248. void xen_pt_msix_delete(XenPCIPassthroughState *s);
  249. int xen_pt_msix_update(XenPCIPassthroughState *s);
  250. int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
  251. void xen_pt_msix_disable(XenPCIPassthroughState *s);
  252. static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
  253. {
  254. return s->msix && s->msix->bar_index == bar;
  255. }
  256. #endif /* !XEN_PT_H */