123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115 |
- /*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
- #include "qemu/osdep.h"
- #include "qapi/error.h"
- #include "qemu/timer.h"
- #include "xen_pt.h"
- #include "hw/xen/xen-legacy-backend.h"
- #define XEN_PT_MERGE_VALUE(value, data, val_mask) \
- (((value) & (val_mask)) | ((data) & ~(val_mask)))
- #define XEN_PT_INVALID_REG 0xFFFFFFFF /* invalid register value */
- /* prototype */
- static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data);
- /* helper */
- /* A return value of 1 means the capability should NOT be exposed to guest. */
- static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id)
- {
- switch (grp_id) {
- case PCI_CAP_ID_EXP:
- /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0. We should not try to expose it to guest.
- *
- * The datasheet is available at
- * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
- *
- * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
- * PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0, so the Capability Version is 0 and
- * xen_pt_pcie_size_init() would fail.
- */
- if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
- d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) {
- return 1;
- }
- break;
- }
- return 0;
- }
- /* find emulate register group entry */
- XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
- {
- XenPTRegGroup *entry = NULL;
- /* find register group entry */
- QLIST_FOREACH(entry, &s->reg_grps, entries) {
- /* check address */
- if ((entry->base_offset <= address)
- && ((entry->base_offset + entry->size) > address)) {
- return entry;
- }
- }
- /* group entry not found */
- return NULL;
- }
- /* find emulate register entry */
- XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
- {
- XenPTReg *reg_entry = NULL;
- XenPTRegInfo *reg = NULL;
- uint32_t real_offset = 0;
- /* find register entry */
- QLIST_FOREACH(reg_entry, ®_grp->reg_tbl_list, entries) {
- reg = reg_entry->reg;
- real_offset = reg_grp->base_offset + reg->offset;
- /* check address */
- if ((real_offset <= address)
- && ((real_offset + reg->size) > address)) {
- return reg_entry;
- }
- }
- return NULL;
- }
- static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t valid_mask)
- {
- uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
- if (!s->permissive) {
- throughable_mask &= ~reg->res_mask;
- }
- return throughable_mask & valid_mask;
- }
- /****************
- * general register functions
- */
- /* register initialization function */
- static int xen_pt_common_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- *data = reg->init_val;
- return 0;
- }
- /* Read register functions */
- static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *value, uint8_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t valid_emu_mask = 0;
- uint8_t *data = cfg_entry->ptr.byte;
- /* emulate byte register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
- return 0;
- }
- static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = 0;
- uint16_t *data = cfg_entry->ptr.half_word;
- /* emulate word register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
- return 0;
- }
- static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
- /* emulate long register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
- return 0;
- }
- /* Write register functions */
- static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t dev_value,
- uint8_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t writable_mask = 0;
- uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint8_t *data = cfg_entry->ptr.byte;
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
- return 0;
- }
- static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
- return 0;
- }
- static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint32_t *data = cfg_entry->ptr.word;
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
- return 0;
- }
- /* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- * other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
- /********************
- * Header Type0
- */
- static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- *data = s->real_device.vendor_id;
- return 0;
- }
- static int xen_pt_device_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- *data = s->real_device.device_id;
- return 0;
- }
- static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- XenPTRegGroup *reg_grp_entry = NULL;
- XenPTReg *reg_entry = NULL;
- uint32_t reg_field = 0;
- /* find Header register group */
- reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
- if (reg_grp_entry) {
- /* find Capabilities Pointer register */
- reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
- if (reg_entry) {
- /* check Capabilities Pointer register */
- if (*reg_entry->ptr.half_word) {
- reg_field |= PCI_STATUS_CAP_LIST;
- } else {
- reg_field &= ~PCI_STATUS_CAP_LIST;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
- " for Capabilities Pointer register."
- " (%s)\n", __func__);
- return -1;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
- " for Header. (%s)\n", __func__);
- return -1;
- }
- *data = reg_field;
- return 0;
- }
- static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- /* read PCI_HEADER_TYPE */
- *data = reg->init_val | 0x80;
- return 0;
- }
- /* initialize Interrupt Pin register */
- static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- if (s->real_device.irq) {
- *data = xen_pt_pci_read_intx(s);
- }
- return 0;
- }
- /* Command register */
- static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
- /* modify emulate register */
- writable_mask = ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- if (*val & PCI_COMMAND_INTX_DISABLE) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- } else {
- if (s->machine_irq) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- }
- }
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
- return 0;
- }
- /* BAR */
- #define XEN_PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */
- #define XEN_PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */
- #define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */
- #define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */
- static bool is_64bit_bar(PCIIORegion *r)
- {
- return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
- }
- static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
- {
- if (is_64bit_bar(r)) {
- uint64_t size64;
- size64 = (r + 1)->size;
- size64 <<= 32;
- size64 += r->size;
- return size64;
- }
- return r->size;
- }
- static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
- int index)
- {
- PCIDevice *d = PCI_DEVICE(s);
- XenPTRegion *region = NULL;
- PCIIORegion *r;
- /* check 64bit BAR */
- if ((0 < index) && (index < PCI_ROM_SLOT)) {
- int type = s->real_device.io_regions[index - 1].type;
- if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
- && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) {
- region = &s->bases[index - 1];
- if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
- return XEN_PT_BAR_FLAG_UPPER;
- }
- }
- }
- /* check unused BAR */
- r = &d->io_regions[index];
- if (!xen_pt_get_bar_size(r)) {
- return XEN_PT_BAR_FLAG_UNUSED;
- }
- /* for ExpROM BAR */
- if (index == PCI_ROM_SLOT) {
- return XEN_PT_BAR_FLAG_MEM;
- }
- /* check BAR I/O indicator */
- if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return XEN_PT_BAR_FLAG_IO;
- } else {
- return XEN_PT_BAR_FLAG_MEM;
- }
- }
- static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr)
- {
- if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
- } else {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
- }
- }
- static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data)
- {
- uint32_t reg_field = 0;
- int index;
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
- /* set BAR flag */
- s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, index);
- if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
- reg_field = XEN_PT_INVALID_REG;
- }
- *data = reg_field;
- return 0;
- }
- static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t bar_emu_mask = 0;
- int index;
- /* get BAR index */
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS - 1) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
- /* use fixed-up value from kernel sysfs */
- *value = base_address_with_flags(&s->real_device.io_regions[index]);
- /* set emulate mask depend on BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- bar_emu_mask = XEN_PT_BAR_ALLF;
- break;
- default:
- break;
- }
- /* emulate BAR */
- valid_emu_mask = bar_emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *cfg_entry->ptr.word, ~valid_emu_mask);
- return 0;
- }
- static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = PCI_DEVICE(s);
- const PCIIORegion *r;
- uint32_t writable_mask = 0;
- uint32_t bar_emu_mask = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t r_size = 0;
- int index = 0;
- uint32_t *data = cfg_entry->ptr.word;
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
- r = &d->io_regions[index];
- base = &s->bases[index];
- r_size = xen_pt_get_emul_size(base->bar_flag, r->size);
- /* set emulate mask and read-only mask values depend on the BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- if (!r_size) {
- /* low 32 bits mask for 64 bit bars */
- bar_ro_mask = XEN_PT_BAR_ALLF;
- } else {
- bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
- }
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- assert(index > 0);
- r_size = d->io_regions[index - 1].size >> 32;
- bar_emu_mask = XEN_PT_BAR_ALLF;
- bar_ro_mask = r_size ? r_size - 1 : 0;
- break;
- default:
- break;
- }
- /* modify emulate register */
- writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* check whether we need to update the virtual region address or not */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_UPPER:
- case XEN_PT_BAR_FLAG_MEM:
- /* nothing to do */
- break;
- case XEN_PT_BAR_FLAG_IO:
- /* nothing to do */
- break;
- default:
- break;
- }
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
- return 0;
- }
- /* write Exp ROM BAR */
- static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = PCI_DEVICE(s);
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- pcibus_t r_size = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
- r_size = d->io_regions[PCI_ROM_SLOT].size;
- base = &s->bases[PCI_ROM_SLOT];
- /* align memory type resource size */
- r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
- /* set emulate mask and read-only mask */
- bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
- /* modify emulate register */
- writable_mask = ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
- return 0;
- }
- static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
- {
- *value = igd_read_opregion(s);
- return 0;
- }
- static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *value,
- uint32_t dev_value, uint32_t valid_mask)
- {
- igd_write_opregion(s, *value);
- return 0;
- }
- /* Header Type0 reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_header0[] = {
- /* Vendor ID reg */
- {
- .offset = PCI_VENDOR_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_vendor_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device ID reg */
- {
- .offset = PCI_DEVICE_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_device_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Command reg */
- {
- .offset = PCI_COMMAND,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xF880,
- .emu_mask = 0x0743,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_cmd_reg_write,
- },
- /* Capabilities Pointer reg */
- {
- .offset = PCI_CAPABILITY_LIST,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Status reg */
- /* use emulated Cap Ptr value to initialize,
- * so need to be declared after Cap Ptr reg
- */
- {
- .offset = PCI_STATUS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x0007,
- .ro_mask = 0x06F8,
- .rw1c_mask = 0xF900,
- .emu_mask = 0x0010,
- .init = xen_pt_status_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Cache Line Size reg */
- {
- .offset = PCI_CACHE_LINE_SIZE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Latency Timer reg */
- {
- .offset = PCI_LATENCY_TIMER,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Header Type reg */
- {
- .offset = PCI_HEADER_TYPE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0x00,
- .init = xen_pt_header_type_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Line reg */
- {
- .offset = PCI_INTERRUPT_LINE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Pin reg */
- {
- .offset = PCI_INTERRUPT_PIN,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_irqpin_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* BAR 0 reg */
- /* mask of BAR need to be decided later, depends on IO/MEM type */
- {
- .offset = PCI_BASE_ADDRESS_0,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 1 reg */
- {
- .offset = PCI_BASE_ADDRESS_1,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 2 reg */
- {
- .offset = PCI_BASE_ADDRESS_2,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 3 reg */
- {
- .offset = PCI_BASE_ADDRESS_3,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 4 reg */
- {
- .offset = PCI_BASE_ADDRESS_4,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 5 reg */
- {
- .offset = PCI_BASE_ADDRESS_5,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* Expansion ROM BAR reg */
- {
- .offset = PCI_ROM_ADDRESS,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = ~PCI_ROM_ADDRESS_MASK & ~PCI_ROM_ADDRESS_ENABLE,
- .emu_mask = (uint32_t)PCI_ROM_ADDRESS_MASK,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_exp_rom_bar_reg_write,
- },
- {
- .size = 0,
- },
- };
- /*********************************
- * Vital Product Data Capability
- */
- /* Vital Product Data Capability Structure reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .offset = PCI_VPD_ADDR,
- .size = 2,
- .ro_mask = 0x0003,
- .emu_mask = 0x0003,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
- };
- /**************************************
- * Vendor Specific Capability
- */
- /* Vendor Specific Capability Structure reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .size = 0,
- },
- };
- /*****************************
- * PCI Express Capability
- */
- static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
- uint32_t offset)
- {
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return flag & PCI_EXP_FLAGS_VERS;
- }
- static inline uint8_t get_device_type(XenPCIPassthroughState *s,
- uint32_t offset)
- {
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return (flag & PCI_EXP_FLAGS_TYPE) >> 4;
- }
- /* initialize Link Control register */
- static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint8_t dev_type = get_device_type(s, real_offset - reg->offset);
- /* no need to initialize in case of Root Complex Integrated Endpoint
- * with cap_ver 1.x
- */
- if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
- *data = XEN_PT_INVALID_REG;
- }
- *data = reg->init_val;
- return 0;
- }
- /* initialize Device Control 2 register */
- static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- *data = XEN_PT_INVALID_REG;
- }
- *data = reg->init_val;
- return 0;
- }
- /* initialize Link Control 2 register */
- static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint32_t reg_field = 0;
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- reg_field = XEN_PT_INVALID_REG;
- } else {
- /* set Supported Link Speed */
- uint8_t lnkcap;
- int rc;
- rc = xen_host_pci_get_byte(&s->real_device,
- real_offset - reg->offset + PCI_EXP_LNKCAP,
- &lnkcap);
- if (rc) {
- return rc;
- }
- reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
- }
- *data = reg_field;
- return 0;
- }
- /* PCI Express Capability Structure reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Device Capabilities reg */
- {
- .offset = PCI_EXP_DEVCAP,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x10000000,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Device Control reg */
- {
- .offset = PCI_EXP_DEVCTL,
- .size = 2,
- .init_val = 0x2810,
- .ro_mask = 0x8400,
- .emu_mask = 0xFFFF,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Status reg */
- {
- .offset = PCI_EXP_DEVSTA,
- .size = 2,
- .res_mask = 0xFFC0,
- .ro_mask = 0x0030,
- .rw1c_mask = 0x000F,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control reg */
- {
- .offset = PCI_EXP_LNKCTL,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFC34,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Status reg */
- {
- .offset = PCI_EXP_LNKSTA,
- .size = 2,
- .ro_mask = 0x3FFF,
- .rw1c_mask = 0xC000,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Control 2 reg */
- {
- .offset = 0x28,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFA0,
- .emu_mask = 0xFFBF,
- .init = xen_pt_devctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control 2 reg */
- {
- .offset = 0x30,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xE040,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
- };
- /*********************************
- * Power Management Capability
- */
- /* Power Management Capability reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_pm[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Power Management Capabilities reg */
- {
- .offset = PCI_CAP_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xF9C8,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* PCI Power Management Control/Status reg */
- {
- .offset = PCI_PM_CTRL,
- .size = 2,
- .init_val = 0x0008,
- .res_mask = 0x00F0,
- .ro_mask = 0x610C,
- .rw1c_mask = 0x8000,
- .emu_mask = 0x810B,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
- };
- /********************************
- * MSI Capability
- */
- /* Helper */
- #define xen_pt_msi_check_type(offset, flags, what) \
- ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
- PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
- /* Message Control register */
- static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- XenPTMSI *msi = s->msi;
- uint16_t reg_field;
- int rc;
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, ®_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSI_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSI_FLAGS_ENABLE);
- }
- msi->flags |= reg_field;
- msi->ctrl_offset = real_offset;
- msi->initialized = false;
- msi->mapped = false;
- *data = reg->init_val;
- return 0;
- }
- static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
- /* Currently no support for multi-vector */
- if (*val & PCI_MSI_FLAGS_QSIZE) {
- XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
- }
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- msi->flags |= *data & ~PCI_MSI_FLAGS_ENABLE;
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
- /* update MSI */
- if (*val & PCI_MSI_FLAGS_ENABLE) {
- /* setup MSI pirq for the first time */
- if (!msi->initialized) {
- /* Init physical one */
- XEN_PT_LOG(&s->dev, "setup MSI (register: %x).\n", *val);
- if (xen_pt_msi_setup(s)) {
- /* We do not broadcast the error to the framework code, so
- * that MSI errors are contained in MSI emulation code and
- * QEMU can go on running.
- * Guest MSI would be actually not working.
- */
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not map MSI (register: %x)!\n", *val);
- return 0;
- }
- if (xen_pt_msi_update(s)) {
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not bind MSI (register: %x)!\n", *val);
- return 0;
- }
- msi->initialized = true;
- msi->mapped = true;
- }
- msi->flags |= PCI_MSI_FLAGS_ENABLE;
- } else if (msi->mapped) {
- xen_pt_msi_disable(s);
- }
- return 0;
- }
- /* initialize Message Upper Address register */
- static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- /* no need to initialize in case of 32 bit type */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- *data = XEN_PT_INVALID_REG;
- } else {
- *data = reg->init_val;
- }
- return 0;
- }
- /* this function will be called twice (for 32 bit and 64 bit type) */
- /* initialize Message Data register */
- static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint32_t flags = s->msi->flags;
- uint32_t offset = reg->offset;
- /* check the offset whether matches the type or not */
- if (xen_pt_msi_check_type(offset, flags, DATA)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
- }
- /* this function will be called twice (for 32 bit and 64 bit type) */
- /* initialize Mask register */
- static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint32_t flags = s->msi->flags;
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
- }
- /* this function will be called twice (for 32 bit and 64 bit type) */
- /* initialize Pending register */
- static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint32_t flags = s->msi->flags;
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
- }
- /* write Message Address register */
- static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- s->msi->addr_lo = *data;
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
- return 0;
- }
- /* write Message Upper Address register */
- static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
- /* check whether the type is 64 bit or not */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- XEN_PT_ERR(&s->dev,
- "Can't write to the upper address without 64 bit support\n");
- return -1;
- }
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- s->msi->addr_hi = *data;
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
- return 0;
- }
- /* this function will be called twice (for 32 bit and 64 bit type) */
- /* write Message Data register */
- static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t old_data = *cfg_entry->ptr.half_word;
- uint32_t offset = reg->offset;
- uint16_t *data = cfg_entry->ptr.half_word;
- /* check the offset whether matches the type or not */
- if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
- /* exit I/O emulator */
- XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
- return -1;
- }
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- msi->data = *data;
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
- /* update MSI */
- if (*data != old_data) {
- if (msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
- return 0;
- }
- static int xen_pt_mask_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
- {
- int rc;
- rc = xen_pt_long_reg_write(s, cfg_entry, val, dev_value, valid_mask);
- if (rc) {
- return rc;
- }
- s->msi->mask = *val;
- return 0;
- }
- /* MSI Capability Structure reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_msi[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xFE00,
- .ro_mask = 0x018E,
- .emu_mask = 0x017E,
- .init = xen_pt_msgctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgctrl_reg_write,
- },
- /* Message Address reg */
- {
- .offset = PCI_MSI_ADDRESS_LO,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000003,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr32_reg_write,
- },
- /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
- {
- .offset = PCI_MSI_ADDRESS_HI,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000000,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_msgaddr64_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr64_reg_write,
- },
- /* Message Data reg (16 bits of data for 32-bit devices) */
- {
- .offset = PCI_MSI_DATA_32,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Message Data reg (16 bits of data for 64-bit devices) */
- {
- .offset = PCI_MSI_DATA_64,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_mask_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_mask_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- {
- .size = 0,
- },
- };
- /**************************************
- * MSI-X Capability
- */
- /* Message Control register for MSI-X */
- static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- uint16_t reg_field;
- int rc;
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, ®_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSIX already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSIX_FLAGS_ENABLE);
- }
- s->msix->ctrl_offset = real_offset;
- *data = reg->init_val;
- return 0;
- }
- static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
- {
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- int debug_msix_enabled_old;
- uint16_t *data = cfg_entry->ptr.half_word;
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
- /* update MSI-X */
- if ((*val & PCI_MSIX_FLAGS_ENABLE)
- && !(*val & PCI_MSIX_FLAGS_MASKALL)) {
- xen_pt_msix_update(s);
- } else if (!(*val & PCI_MSIX_FLAGS_ENABLE) && s->msix->enabled) {
- xen_pt_msix_disable(s);
- }
- s->msix->maskall = *val & PCI_MSIX_FLAGS_MASKALL;
- debug_msix_enabled_old = s->msix->enabled;
- s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
- if (s->msix->enabled != debug_msix_enabled_old) {
- XEN_PT_LOG(&s->dev, "%s MSI-X\n",
- s->msix->enabled ? "enable" : "disable");
- }
- return 0;
- }
- /* MSI-X Capability Structure reg static information table */
- static XenPTRegInfo xen_pt_emu_reg_msix[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x3800,
- .ro_mask = 0x07FF,
- .emu_mask = 0x0000,
- .init = xen_pt_msixctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msixctrl_reg_write,
- },
- {
- .size = 0,
- },
- };
- static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
- /* Intel IGFX OpRegion reg */
- {
- .offset = 0x0,
- .size = 4,
- .init_val = 0,
- .emu_mask = 0xFFFFFFFF,
- .u.dw.read = xen_pt_intel_opregion_read,
- .u.dw.write = xen_pt_intel_opregion_write,
- },
- {
- .size = 0,
- },
- };
- /****************************
- * Capabilities
- */
- /* capability structure register group size functions */
- static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
- {
- *size = grp_reg->grp_size;
- return 0;
- }
- /* get Vendor Specific Capability Structure register group size */
- static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
- {
- return xen_host_pci_get_byte(&s->real_device, base_offset + 0x02, size);
- }
- /* get PCI Express Capability Structure register group size */
- static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
- {
- PCIDevice *d = PCI_DEVICE(s);
- uint8_t version = get_capability_version(s, base_offset);
- uint8_t type = get_device_type(s, base_offset);
- uint8_t pcie_size = 0;
- /* calculate size depend on capability version and device/port type */
- /* in case of PCI Express Base Specification Rev 1.x */
- if (version == 1) {
- /* The PCI Express Capabilities, Device Capabilities, and Device
- * Status/Control registers are required for all PCI Express devices.
- * The Link Capabilities and Link Status/Control are required for all
- * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
- * are not required to implement registers other than those listed
- * above and terminate the capability structure.
- */
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- pcie_size = 0x14;
- break;
- case PCI_EXP_TYPE_RC_END:
- /* has no link */
- pcie_size = 0x0C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type 0x%x.\n", type);
- return -1;
- }
- }
- /* in case of PCI Express Base Specification Rev 2.0 */
- else if (version == 2) {
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- case PCI_EXP_TYPE_RC_END:
- /* For Functions that do not implement the registers,
- * these spaces must be hardwired to 0b.
- */
- pcie_size = 0x3C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type 0x%x.\n", type);
- return -1;
- }
- } else {
- XEN_PT_ERR(d, "Unsupported capability version 0x%x.\n", version);
- return -1;
- }
- *size = pcie_size;
- return 0;
- }
- /* get MSI Capability Structure register group size */
- static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
- {
- uint16_t msg_ctrl = 0;
- uint8_t msi_size = 0xa;
- int rc;
- rc = xen_host_pci_get_word(&s->real_device, base_offset + PCI_MSI_FLAGS,
- &msg_ctrl);
- if (rc) {
- return rc;
- }
- /* check if 64-bit address is capable of per-vector masking */
- if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
- msi_size += 4;
- }
- if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
- msi_size += 10;
- }
- s->msi = g_new0(XenPTMSI, 1);
- s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
- *size = msi_size;
- return 0;
- }
- /* get MSI-X Capability Structure register group size */
- static int xen_pt_msix_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
- {
- int rc = 0;
- rc = xen_pt_msix_init(s, base_offset);
- if (rc < 0) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
- return rc;
- }
- *size = grp_reg->grp_size;
- return 0;
- }
- static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
- /* Header Type0 reg group */
- {
- .grp_id = 0xFF,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x40,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_header0,
- },
- /* PCI PowerManagement Capability reg group */
- {
- .grp_id = PCI_CAP_ID_PM,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = PCI_PM_SIZEOF,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_pm,
- },
- /* AGP Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vital Product Data Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VPD,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_vpd,
- },
- /* Slot Identification reg group */
- {
- .grp_id = PCI_CAP_ID_SLOTID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x04,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* MSI Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSI,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_msi_size_init,
- .emu_regs = xen_pt_emu_reg_msi,
- },
- /* PCI-X Capabilities List Item reg group */
- {
- .grp_id = PCI_CAP_ID_PCIX,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x18,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vendor Specific Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VNDR,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_vendor_size_init,
- .emu_regs = xen_pt_emu_reg_vendor,
- },
- /* SHPC Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SHPC,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SSVID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* AGP 8x Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP3,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* PCI Express Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_EXP,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_pcie_size_init,
- .emu_regs = xen_pt_emu_reg_pcie,
- },
- /* MSI-X Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSIX,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x0C,
- .size_init = xen_pt_msix_size_init,
- .emu_regs = xen_pt_emu_reg_msix,
- },
- /* Intel IGD Opregion group */
- {
- .grp_id = XEN_PCI_INTEL_OPREGION,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x4,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_igd_opregion,
- },
- {
- .grp_size = 0,
- },
- };
- /* initialize Capabilities Pointer or Next Pointer register */
- static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
- {
- int i, rc;
- uint8_t reg_field;
- uint8_t cap_id = 0;
- rc = xen_host_pci_get_byte(&s->real_device, real_offset, ®_field);
- if (rc) {
- return rc;
- }
- /* find capability offset */
- while (reg_field) {
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_ID, &cap_id);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to read capability @0x%x (rc:%d)\n",
- reg_field + PCI_CAP_LIST_ID, rc);
- return rc;
- }
- if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- goto out;
- }
- /* ignore the 0 hardwired capability, find next one */
- break;
- }
- }
- /* next capability */
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_NEXT, ®_field);
- if (rc) {
- return rc;
- }
- }
- out:
- *data = reg_field;
- return 0;
- }
- /*************
- * Main
- */
- static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
- {
- uint8_t id;
- unsigned max_cap = XEN_PCI_CAP_MAX;
- uint8_t pos = PCI_CAPABILITY_LIST;
- uint8_t status = 0;
- if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
- return 0;
- }
- if ((status & PCI_STATUS_CAP_LIST) == 0) {
- return 0;
- }
- while (max_cap--) {
- if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
- break;
- }
- if (pos < PCI_CONFIG_HEADER_SIZE) {
- break;
- }
- pos &= ~3;
- if (xen_host_pci_get_byte(&s->real_device,
- pos + PCI_CAP_LIST_ID, &id)) {
- break;
- }
- if (id == 0xff) {
- break;
- }
- if (id == cap) {
- return pos;
- }
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
- }
- static void xen_pt_config_reg_init(XenPCIPassthroughState *s,
- XenPTRegGroup *reg_grp, XenPTRegInfo *reg,
- Error **errp)
- {
- XenPTReg *reg_entry;
- uint32_t data = 0;
- int rc = 0;
- reg_entry = g_new0(XenPTReg, 1);
- reg_entry->reg = reg;
- if (reg->init) {
- uint32_t host_mask, size_mask;
- unsigned int offset;
- uint32_t val = 0;
- /* initialize emulate register */
- rc = reg->init(s, reg_entry->reg,
- reg_grp->base_offset + reg->offset, &data);
- if (rc < 0) {
- g_free(reg_entry);
- error_setg(errp, "Init emulate register fail");
- return;
- }
- if (data == XEN_PT_INVALID_REG) {
- /* free unused BAR register entry */
- g_free(reg_entry);
- return;
- }
- /* Sync up the data to dev.config */
- offset = reg_grp->base_offset + reg->offset;
- size_mask = 0xFFFFFFFF >> ((4 - reg->size) << 3);
- switch (reg->size) {
- case 1: rc = xen_host_pci_get_byte(&s->real_device, offset, (uint8_t *)&val);
- break;
- case 2: rc = xen_host_pci_get_word(&s->real_device, offset, (uint16_t *)&val);
- break;
- case 4: rc = xen_host_pci_get_long(&s->real_device, offset, &val);
- break;
- default: abort();
- }
- if (rc) {
- /* Serious issues when we cannot read the host values! */
- g_free(reg_entry);
- error_setg(errp, "Cannot read host values");
- return;
- }
- /* Set bits in emu_mask are the ones we emulate. The dev.config shall
- * contain the emulated view of the guest - therefore we flip the mask
- * to mask out the host values (which dev.config initially has) . */
- host_mask = size_mask & ~reg->emu_mask;
- if ((data & host_mask) != (val & host_mask)) {
- uint32_t new_val;
- /*
- * Merge the emulated bits (data) with the host bits (val)
- * and mask out the bits past size to enable restoration
- * of the proper value for logging below.
- */
- new_val = XEN_PT_MERGE_VALUE(val, data, host_mask) & size_mask;
- /* Leave intact host and emulated values past the size - even though
- * we do not care as we write per reg->size granularity, but for the
- * logging below lets have the proper value. */
- new_val |= ((val | data)) & ~size_mask;
- XEN_PT_LOG(&s->dev,"Offset 0x%04x mismatch! Emulated=0x%04x, host=0x%04x, syncing to 0x%04x.\n",
- offset, data, val, new_val);
- val = new_val;
- } else
- val = data;
- if (val & ~size_mask) {
- error_setg(errp, "Offset 0x%04x:0x%04x expands past"
- " register size (%d)", offset, val, reg->size);
- g_free(reg_entry);
- return;
- }
- /* This could be just pci_set_long as we don't modify the bits
- * past reg->size, but in case this routine is run in parallel or the
- * init value is larger, we do not want to over-write registers. */
- switch (reg->size) {
- case 1: pci_set_byte(s->dev.config + offset, (uint8_t)val);
- break;
- case 2: pci_set_word(s->dev.config + offset, (uint16_t)val);
- break;
- case 4: pci_set_long(s->dev.config + offset, val);
- break;
- default: abort();
- }
- /* set register value pointer to the data. */
- reg_entry->ptr.byte = s->dev.config + offset;
- }
- /* list add register entry */
- QLIST_INSERT_HEAD(®_grp->reg_tbl_list, reg_entry, entries);
- }
- void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
- {
- ERRP_GUARD();
- int i, rc;
- QLIST_INIT(&s->reg_grps);
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- uint32_t reg_grp_offset = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
- if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
- && xen_pt_emu_reg_grps[i].grp_id != XEN_PCI_INTEL_OPREGION) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
- reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id);
- if (!reg_grp_offset) {
- continue;
- }
- }
- if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) {
- if (!is_igd_vga_passthrough(&s->real_device) ||
- s->real_device.vendor_id != PCI_VENDOR_ID_INTEL) {
- continue;
- }
- /*
- * By default we will trap up to 0x40 in the cfg space.
- * If an intel device is pass through we need to trap 0xfc,
- * therefore the size should be 0xff.
- */
- reg_grp_offset = XEN_PCI_INTEL_OPREGION;
- }
- reg_grp_entry = g_new0(XenPTRegGroup, 1);
- QLIST_INIT(®_grp_entry->reg_tbl_list);
- QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
- reg_grp_entry->base_offset = reg_grp_offset;
- reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i;
- if (xen_pt_emu_reg_grps[i].size_init) {
- /* get register group size */
- rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp,
- reg_grp_offset,
- ®_grp_entry->size);
- if (rc < 0) {
- error_setg(errp, "Failed to initialize %d/%zu, type = 0x%x,"
- " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps),
- xen_pt_emu_reg_grps[i].grp_type, rc);
- xen_pt_config_delete(s);
- return;
- }
- }
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- if (xen_pt_emu_reg_grps[i].emu_regs) {
- int j = 0;
- XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs;
- /* initialize capability register */
- for (j = 0; regs->size != 0; j++, regs++) {
- xen_pt_config_reg_init(s, reg_grp_entry, regs, errp);
- if (*errp) {
- error_append_hint(errp, "Failed to init register %d"
- " offsets 0x%x in grp_type = 0x%x (%d/%zu)",
- j,
- regs->offset,
- xen_pt_emu_reg_grps[i].grp_type,
- i, ARRAY_SIZE(xen_pt_emu_reg_grps));
- xen_pt_config_delete(s);
- return;
- }
- }
- }
- }
- }
- }
- /* delete all emulate register */
- void xen_pt_config_delete(XenPCIPassthroughState *s)
- {
- struct XenPTRegGroup *reg_group, *next_grp;
- struct XenPTReg *reg, *next_reg;
- /* free MSI/MSI-X info table */
- if (s->msix) {
- xen_pt_msix_unmap(s);
- }
- g_free(s->msi);
- /* free all register group entry */
- QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
- /* free all register entry */
- QLIST_FOREACH_SAFE(reg, ®_group->reg_tbl_list, entries, next_reg) {
- QLIST_REMOVE(reg, entries);
- g_free(reg);
- }
- QLIST_REMOVE(reg_group, entries);
- g_free(reg_group);
- }
- }
|