Annotation of qemu/hw/shpc.c, revision 1.1.1.1

1.1       root        1: #include <strings.h>
                      2: #include <stdint.h>
                      3: #include "range.h"
                      4: #include "range.h"
                      5: #include "shpc.h"
                      6: #include "pci.h"
                      7: #include "pci_internals.h"
                      8: #include "msi.h"
                      9: 
                     10: /* TODO: model power only and disabled slot states. */
                     11: /* TODO: handle SERR and wakeups */
                     12: /* TODO: consider enabling 66MHz support */
                     13: 
                     14: /* TODO: remove fully only on state DISABLED and LED off.
                     15:  * track state to properly record this. */
                     16: 
                     17: /* SHPC Working Register Set */
                     18: #define SHPC_BASE_OFFSET  0x00 /* 4 bytes */
                     19: #define SHPC_SLOTS_33     0x04 /* 4 bytes. Also encodes PCI-X slots. */
                     20: #define SHPC_SLOTS_66     0x08 /* 4 bytes. */
                     21: #define SHPC_NSLOTS       0x0C /* 1 byte */
                     22: #define SHPC_FIRST_DEV    0x0D /* 1 byte */
                     23: #define SHPC_PHYS_SLOT    0x0E /* 2 byte */
                     24: #define SHPC_PHYS_NUM_MAX 0x7ff
                     25: #define SHPC_PHYS_NUM_UP  0x2000
                     26: #define SHPC_PHYS_MRL     0x4000
                     27: #define SHPC_PHYS_BUTTON  0x8000
                     28: #define SHPC_SEC_BUS      0x10 /* 2 bytes */
                     29: #define SHPC_SEC_BUS_33   0x0
                     30: #define SHPC_SEC_BUS_66   0x1 /* Unused */
                     31: #define SHPC_SEC_BUS_MASK 0x7
                     32: #define SHPC_MSI_CTL      0x12 /* 1 byte */
                     33: #define SHPC_PROG_IFC     0x13 /* 1 byte */
                     34: #define SHPC_PROG_IFC_1_0 0x1
                     35: #define SHPC_CMD_CODE     0x14 /* 1 byte */
                     36: #define SHPC_CMD_TRGT     0x15 /* 1 byte */
                     37: #define SHPC_CMD_TRGT_MIN 0x1
                     38: #define SHPC_CMD_TRGT_MAX 0x1f
                     39: #define SHPC_CMD_STATUS   0x16 /* 2 bytes */
                     40: #define SHPC_CMD_STATUS_BUSY          0x1
                     41: #define SHPC_CMD_STATUS_MRL_OPEN      0x2
                     42: #define SHPC_CMD_STATUS_INVALID_CMD   0x4
                     43: #define SHPC_CMD_STATUS_INVALID_MODE  0x8
                     44: #define SHPC_INT_LOCATOR  0x18 /* 4 bytes */
                     45: #define SHPC_INT_COMMAND  0x1
                     46: #define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */
                     47: #define SHPC_SERR_INT     0x20 /* 4 bytes */
                     48: #define SHPC_INT_DIS      0x1
                     49: #define SHPC_SERR_DIS     0x2
                     50: #define SHPC_CMD_INT_DIS  0x4
                     51: #define SHPC_ARB_SERR_DIS 0x8
                     52: #define SHPC_CMD_DETECTED 0x10000
                     53: #define SHPC_ARB_DETECTED 0x20000
                     54:  /* 4 bytes * slot # (start from 0) */
                     55: #define SHPC_SLOT_REG(s)         (0x24 + (s) * 4)
                     56:  /* 2 bytes */
                     57: #define SHPC_SLOT_STATUS(s)       (0x0 + SHPC_SLOT_REG(s))
                     58: 
                     59: /* Same slot state masks are used for command and status registers */
                     60: #define SHPC_SLOT_STATE_MASK     0x03
                     61: #define SHPC_SLOT_STATE_SHIFT \
                     62:     (ffs(SHPC_SLOT_STATE_MASK) - 1)
                     63: 
                     64: #define SHPC_STATE_NO       0x0
                     65: #define SHPC_STATE_PWRONLY  0x1
                     66: #define SHPC_STATE_ENABLED  0x2
                     67: #define SHPC_STATE_DISABLED 0x3
                     68: 
                     69: #define SHPC_SLOT_PWR_LED_MASK   0xC
                     70: #define SHPC_SLOT_PWR_LED_SHIFT \
                     71:     (ffs(SHPC_SLOT_PWR_LED_MASK) - 1)
                     72: #define SHPC_SLOT_ATTN_LED_MASK  0x30
                     73: #define SHPC_SLOT_ATTN_LED_SHIFT \
                     74:     (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1)
                     75: 
                     76: #define SHPC_LED_NO     0x0
                     77: #define SHPC_LED_ON     0x1
                     78: #define SHPC_LED_BLINK  0x2
                     79: #define SHPC_LED_OFF    0x3
                     80: 
                     81: #define SHPC_SLOT_STATUS_PWR_FAULT      0x40
                     82: #define SHPC_SLOT_STATUS_BUTTON         0x80
                     83: #define SHPC_SLOT_STATUS_MRL_OPEN       0x100
                     84: #define SHPC_SLOT_STATUS_66             0x200
                     85: #define SHPC_SLOT_STATUS_PRSNT_MASK     0xC00
                     86: #define SHPC_SLOT_STATUS_PRSNT_EMPTY    0x3
                     87: #define SHPC_SLOT_STATUS_PRSNT_25W      0x1
                     88: #define SHPC_SLOT_STATUS_PRSNT_15W      0x2
                     89: #define SHPC_SLOT_STATUS_PRSNT_7_5W     0x0
                     90: 
                     91: #define SHPC_SLOT_STATUS_PRSNT_PCIX     0x3000
                     92: 
                     93: 
                     94:  /* 1 byte */
                     95: #define SHPC_SLOT_EVENT_LATCH(s)        (0x2 + SHPC_SLOT_REG(s))
                     96:  /* 1 byte */
                     97: #define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s))
                     98: #define SHPC_SLOT_EVENT_PRESENCE        0x01
                     99: #define SHPC_SLOT_EVENT_ISOLATED_FAULT  0x02
                    100: #define SHPC_SLOT_EVENT_BUTTON          0x04
                    101: #define SHPC_SLOT_EVENT_MRL             0x08
                    102: #define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10
                    103: /* Bits below are used for Serr/Int disable only */
                    104: #define SHPC_SLOT_EVENT_MRL_SERR_DIS    0x20
                    105: #define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40
                    106: 
                    107: #define SHPC_MIN_SLOTS        1
                    108: #define SHPC_MAX_SLOTS        31
                    109: #define SHPC_SIZEOF(d)    SHPC_SLOT_REG((d)->shpc->nslots)
                    110: 
                    111: /* SHPC Slot identifiers */
                    112: 
                    113: /* Hotplug supported at 31 slots out of the total 32.  We reserve slot 0,
                    114:    and give the rest of them physical *and* pci numbers starting from 1, so
                    115:    they match logical numbers.  Note: this means that multiple slots must have
                    116:    different chassis number values, to make chassis+physical slot unique.
                    117:    TODO: make this configurable? */
                    118: #define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1)
                    119: #define SHPC_LOGICAL_TO_IDX(target) ((target) - 1)
                    120: #define SHPC_IDX_TO_PCI(slot) ((slot) + 1)
                    121: #define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
                    122: #define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
                    123: 
                    124: static int roundup_pow_of_two(int x)
                    125: {
                    126:     x |= (x >> 1);
                    127:     x |= (x >> 2);
                    128:     x |= (x >> 4);
                    129:     x |= (x >> 8);
                    130:     x |= (x >> 16);
                    131:     return x + 1;
                    132: }
                    133: 
                    134: static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
                    135: {
                    136:     uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
                    137:     return (pci_get_word(status) & msk) >> (ffs(msk) - 1);
                    138: }
                    139: 
                    140: static void shpc_set_status(SHPCDevice *shpc,
                    141:                             int slot, uint8_t value, uint16_t msk)
                    142: {
                    143:     uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
                    144:     pci_word_test_and_clear_mask(status, msk);
                    145:     pci_word_test_and_set_mask(status, value << (ffs(msk) - 1));
                    146: }
                    147: 
                    148: static void shpc_interrupt_update(PCIDevice *d)
                    149: {
                    150:     SHPCDevice *shpc = d->shpc;
                    151:     int slot;
                    152:     int level = 0;
                    153:     uint32_t serr_int;
                    154:     uint32_t int_locator = 0;
                    155: 
                    156:     /* Update interrupt locator register */
                    157:     for (slot = 0; slot < shpc->nslots; ++slot) {
                    158:         uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)];
                    159:         uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)];
                    160:         uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot);
                    161:         if (event & ~disable) {
                    162:             int_locator |= mask;
                    163:         }
                    164:     }
                    165:     serr_int = pci_get_long(shpc->config + SHPC_SERR_INT);
                    166:     if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) {
                    167:         int_locator |= SHPC_INT_COMMAND;
                    168:     }
                    169:     pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator);
                    170:     level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0;
                    171:     if (msi_enabled(d) && shpc->msi_requested != level)
                    172:         msi_notify(d, 0);
                    173:     else
                    174:         qemu_set_irq(d->irq[0], level);
                    175:     shpc->msi_requested = level;
                    176: }
                    177: 
                    178: static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
                    179: {
                    180:     switch (speed) {
                    181:     case SHPC_SEC_BUS_33:
                    182:         shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
                    183:         shpc->config[SHPC_SEC_BUS] |= speed;
                    184:         break;
                    185:     default:
                    186:         pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
                    187:                                    SHPC_CMD_STATUS_INVALID_MODE);
                    188:     }
                    189: }
                    190: 
                    191: void shpc_reset(PCIDevice *d)
                    192: {
                    193:     SHPCDevice *shpc = d->shpc;
                    194:     int nslots = shpc->nslots;
                    195:     int i;
                    196:     memset(shpc->config, 0, SHPC_SIZEOF(d));
                    197:     pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
                    198:     pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
                    199:     pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
                    200:     pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
                    201:     pci_set_word(shpc->config + SHPC_PHYS_SLOT,
                    202:                  SHPC_IDX_TO_PHYSICAL(0) |
                    203:                  SHPC_PHYS_NUM_UP |
                    204:                  SHPC_PHYS_MRL |
                    205:                  SHPC_PHYS_BUTTON);
                    206:     pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS |
                    207:                  SHPC_SERR_DIS |
                    208:                  SHPC_CMD_INT_DIS |
                    209:                  SHPC_ARB_SERR_DIS);
                    210:     pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0);
                    211:     pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33);
                    212:     for (i = 0; i < shpc->nslots; ++i) {
                    213:         pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
                    214:                      SHPC_SLOT_EVENT_PRESENCE |
                    215:                      SHPC_SLOT_EVENT_ISOLATED_FAULT |
                    216:                      SHPC_SLOT_EVENT_BUTTON |
                    217:                      SHPC_SLOT_EVENT_MRL |
                    218:                      SHPC_SLOT_EVENT_CONNECTED_FAULT |
                    219:                      SHPC_SLOT_EVENT_MRL_SERR_DIS |
                    220:                      SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
                    221:         if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) {
                    222:             shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK);
                    223:             shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN);
                    224:             shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W,
                    225:                             SHPC_SLOT_STATUS_PRSNT_MASK);
                    226:             shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK);
                    227:         } else {
                    228:             shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK);
                    229:             shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN);
                    230:             shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY,
                    231:                             SHPC_SLOT_STATUS_PRSNT_MASK);
                    232:             shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
                    233:         }
                    234:         shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
                    235:     }
                    236:     shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
                    237:     shpc->msi_requested = 0;
                    238:     shpc_interrupt_update(d);
                    239: }
                    240: 
                    241: static void shpc_invalid_command(SHPCDevice *shpc)
                    242: {
                    243:     pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
                    244:                                SHPC_CMD_STATUS_INVALID_CMD);
                    245: }
                    246: 
                    247: static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
                    248: {
                    249:     int devfn;
                    250:     int pci_slot = SHPC_IDX_TO_PCI(slot);
                    251:     for (devfn = PCI_DEVFN(pci_slot, 0);
                    252:          devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1);
                    253:          ++devfn) {
                    254:         PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
                    255:         if (affected_dev) {
                    256:             qdev_free(&affected_dev->qdev);
                    257:         }
                    258:     }
                    259: }
                    260: 
                    261: static void shpc_slot_command(SHPCDevice *shpc, uint8_t target,
                    262:                               uint8_t state, uint8_t power, uint8_t attn)
                    263: {
                    264:     uint8_t current_state;
                    265:     int slot = SHPC_LOGICAL_TO_IDX(target);
                    266:     if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
                    267:         shpc_invalid_command(shpc);
                    268:         return;
                    269:     }
                    270:     current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
                    271:     if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) {
                    272:         shpc_invalid_command(shpc);
                    273:         return;
                    274:     }
                    275: 
                    276:     switch (power) {
                    277:     case SHPC_LED_NO:
                    278:         break;
                    279:     default:
                    280:         /* TODO: send event to monitor */
                    281:         shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK);
                    282:     }
                    283:     switch (attn) {
                    284:     case SHPC_LED_NO:
                    285:         break;
                    286:     default:
                    287:         /* TODO: send event to monitor */
                    288:         shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK);
                    289:     }
                    290: 
                    291:     if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) ||
                    292:         (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) {
                    293:         shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
                    294:     } else if ((current_state == SHPC_STATE_ENABLED ||
                    295:                 current_state == SHPC_STATE_PWRONLY) &&
                    296:                state == SHPC_STATE_DISABLED) {
                    297:         shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
                    298:         power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
                    299:         /* TODO: track what monitor requested. */
                    300:         /* Look at LED to figure out whether it's ok to remove the device. */
                    301:         if (power == SHPC_LED_OFF) {
                    302:             shpc_free_devices_in_slot(shpc, slot);
                    303:             shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
                    304:             shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
                    305:                             SHPC_SLOT_STATUS_PRSNT_MASK);
                    306:             shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
                    307:                 SHPC_SLOT_EVENT_BUTTON |
                    308:                 SHPC_SLOT_EVENT_MRL |
                    309:                 SHPC_SLOT_EVENT_PRESENCE;
                    310:         }
                    311:     }
                    312: }
                    313: 
                    314: static void shpc_command(SHPCDevice *shpc)
                    315: {
                    316:     uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE);
                    317:     uint8_t speed;
                    318:     uint8_t target;
                    319:     uint8_t attn;
                    320:     uint8_t power;
                    321:     uint8_t state;
                    322:     int i;
                    323: 
                    324:     /* Clear status from the previous command. */
                    325:     pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS,
                    326:                                  SHPC_CMD_STATUS_BUSY |
                    327:                                  SHPC_CMD_STATUS_MRL_OPEN |
                    328:                                  SHPC_CMD_STATUS_INVALID_CMD |
                    329:                                  SHPC_CMD_STATUS_INVALID_MODE);
                    330:     switch (code) {
                    331:     case 0x00 ... 0x3f:
                    332:         target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX;
                    333:         state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT;
                    334:         power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT;
                    335:         attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT;
                    336:         shpc_slot_command(shpc, target, state, power, attn);
                    337:         break;
                    338:     case 0x40 ... 0x47:
                    339:         speed = code & SHPC_SEC_BUS_MASK;
                    340:         shpc_set_sec_bus_speed(shpc, speed);
                    341:         break;
                    342:     case 0x48:
                    343:         /* Power only all slots */
                    344:         /* first verify no slots are enabled */
                    345:         for (i = 0; i < shpc->nslots; ++i) {
                    346:             state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
                    347:             if (state == SHPC_STATE_ENABLED) {
                    348:                 shpc_invalid_command(shpc);
                    349:                 goto done;
                    350:             }
                    351:         }
                    352:         for (i = 0; i < shpc->nslots; ++i) {
                    353:             if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
                    354:                 shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
                    355:                                   SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO);
                    356:             } else {
                    357:                 shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
                    358:                                   SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
                    359:             }
                    360:         }
                    361:         break;
                    362:     case 0x49:
                    363:         /* Enable all slots */
                    364:         /* TODO: Spec says this shall fail if some are already enabled.
                    365:          * This doesn't make sense - why not? a spec bug? */
                    366:         for (i = 0; i < shpc->nslots; ++i) {
                    367:             state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
                    368:             if (state == SHPC_STATE_ENABLED) {
                    369:                 shpc_invalid_command(shpc);
                    370:                 goto done;
                    371:             }
                    372:         }
                    373:         for (i = 0; i < shpc->nslots; ++i) {
                    374:             if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
                    375:                 shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
                    376:                                   SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO);
                    377:             } else {
                    378:                 shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
                    379:                                   SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
                    380:             }
                    381:         }
                    382:         break;
                    383:     default:
                    384:         shpc_invalid_command(shpc);
                    385:         break;
                    386:     }
                    387: done:
                    388:     pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED);
                    389: }
                    390: 
                    391: static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l)
                    392: {
                    393:     SHPCDevice *shpc = d->shpc;
                    394:     int i;
                    395:     if (addr >= SHPC_SIZEOF(d)) {
                    396:         return;
                    397:     }
                    398:     l = MIN(l, SHPC_SIZEOF(d) - addr);
                    399: 
                    400:     /* TODO: code duplicated from pci.c */
                    401:     for (i = 0; i < l; val >>= 8, ++i) {
                    402:         unsigned a = addr + i;
                    403:         uint8_t wmask = shpc->wmask[a];
                    404:         uint8_t w1cmask = shpc->w1cmask[a];
                    405:         assert(!(wmask & w1cmask));
                    406:         shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask);
                    407:         shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
                    408:     }
                    409:     if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) {
                    410:         shpc_command(shpc);
                    411:     }
                    412:     shpc_interrupt_update(d);
                    413: }
                    414: 
                    415: static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l)
                    416: {
                    417:     uint64_t val = 0x0;
                    418:     if (addr >= SHPC_SIZEOF(d)) {
                    419:         return val;
                    420:     }
                    421:     l = MIN(l, SHPC_SIZEOF(d) - addr);
                    422:     memcpy(&val, d->shpc->config + addr, l);
                    423:     return val;
                    424: }
                    425: 
                    426: /* SHPC Bridge Capability */
                    427: #define SHPC_CAP_LENGTH 0x08
                    428: #define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */
                    429: #define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */
                    430: #define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */
                    431: #define SHPC_CAP_CSP_MASK 0x4
                    432: #define SHPC_CAP_CIP_MASK 0x8
                    433: 
                    434: static uint8_t shpc_cap_dword(PCIDevice *d)
                    435: {
                    436:     return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT);
                    437: }
                    438: 
                    439: /* Update dword data capability register */
                    440: static void shpc_cap_update_dword(PCIDevice *d)
                    441: {
                    442:     unsigned data;
                    443:     data = shpc_read(d, shpc_cap_dword(d) * 4, 4);
                    444:     pci_set_long(d->config  + d->shpc->cap + SHPC_CAP_DWORD_DATA, data);
                    445: }
                    446: 
                    447: /* Add SHPC capability to the config space for the device. */
                    448: static int shpc_cap_add_config(PCIDevice *d)
                    449: {
                    450:     uint8_t *config;
                    451:     int config_offset;
                    452:     config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
                    453:                                        0, SHPC_CAP_LENGTH);
                    454:     if (config_offset < 0) {
                    455:         return config_offset;
                    456:     }
                    457:     config = d->config + config_offset;
                    458: 
                    459:     pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
                    460:     pci_set_byte(config + SHPC_CAP_CxP, 0);
                    461:     pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
                    462:     d->shpc->cap = config_offset;
                    463:     /* Make dword select and data writeable. */
                    464:     pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
                    465:     pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
                    466:     return 0;
                    467: }
                    468: 
                    469: static uint64_t shpc_mmio_read(void *opaque, target_phys_addr_t addr,
                    470:                                unsigned size)
                    471: {
                    472:     return shpc_read(opaque, addr, size);
                    473: }
                    474: 
                    475: static void shpc_mmio_write(void *opaque, target_phys_addr_t addr,
                    476:                             uint64_t val, unsigned size)
                    477: {
                    478:     shpc_write(opaque, addr, val, size);
                    479: }
                    480: 
                    481: static const MemoryRegionOps shpc_mmio_ops = {
                    482:     .read = shpc_mmio_read,
                    483:     .write = shpc_mmio_write,
                    484:     .endianness = DEVICE_LITTLE_ENDIAN,
                    485:     .valid = {
                    486:         /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't.
                    487:          * It's easier to suppport all sizes than worry about it. */
                    488:         .min_access_size = 1,
                    489:         .max_access_size = 4,
                    490:     },
                    491: };
                    492: 
                    493: static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
                    494:                                PCIHotplugState hotplug_state)
                    495: {
                    496:     int pci_slot = PCI_SLOT(affected_dev->devfn);
                    497:     uint8_t state;
                    498:     uint8_t led;
                    499:     PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
                    500:     SHPCDevice *shpc = d->shpc;
                    501:     int slot = SHPC_PCI_TO_IDX(pci_slot);
                    502:     if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
                    503:         error_report("Unsupported PCI slot %d for standard hotplug "
                    504:                      "controller. Valid slots are between %d and %d.",
                    505:                      pci_slot, SHPC_IDX_TO_PCI(0),
                    506:                      SHPC_IDX_TO_PCI(shpc->nslots) - 1);
                    507:         return -1;
                    508:     }
                    509:     /* Don't send event when device is enabled during qemu machine creation:
                    510:      * it is present on boot, no hotplug event is necessary. We do send an
                    511:      * event when the device is disabled later. */
                    512:     if (hotplug_state == PCI_COLDPLUG_ENABLED) {
                    513:         shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
                    514:         shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
                    515:                         SHPC_SLOT_STATUS_PRSNT_MASK);
                    516:         return 0;
                    517:     }
                    518:     if (hotplug_state == PCI_HOTPLUG_DISABLED) {
                    519:         shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
                    520:         state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
                    521:         led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
                    522:         if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
                    523:             shpc_free_devices_in_slot(shpc, slot);
                    524:             shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
                    525:             shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
                    526:                             SHPC_SLOT_STATUS_PRSNT_MASK);
                    527:             shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
                    528:                 SHPC_SLOT_EVENT_MRL |
                    529:                 SHPC_SLOT_EVENT_PRESENCE;
                    530:         }
                    531:     } else {
                    532:         /* This could be a cancellation of the previous removal.
                    533:          * We check MRL state to figure out. */
                    534:         if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
                    535:             shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
                    536:             shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
                    537:                             SHPC_SLOT_STATUS_PRSNT_MASK);
                    538:             shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
                    539:                 SHPC_SLOT_EVENT_BUTTON |
                    540:                 SHPC_SLOT_EVENT_MRL |
                    541:                 SHPC_SLOT_EVENT_PRESENCE;
                    542:         } else {
                    543:             /* Press attention button to cancel removal */
                    544:             shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
                    545:                 SHPC_SLOT_EVENT_BUTTON;
                    546:         }
                    547:     }
                    548:     shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
                    549:     shpc_interrupt_update(d);
                    550:     return 0;
                    551: }
                    552: 
                    553: /* Initialize the SHPC structure in bridge's BAR. */
                    554: int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
                    555: {
                    556:     int i, ret;
                    557:     int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
                    558:     SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
                    559:     shpc->sec_bus = sec_bus;
                    560:     ret = shpc_cap_add_config(d);
                    561:     if (ret) {
                    562:         g_free(d->shpc);
                    563:         return ret;
                    564:     }
                    565:     if (nslots < SHPC_MIN_SLOTS) {
                    566:         return 0;
                    567:     }
                    568:     if (nslots > SHPC_MAX_SLOTS ||
                    569:         SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) {
                    570:         /* TODO: report an error mesage that makes sense. */
                    571:         return -EINVAL;
                    572:     }
                    573:     shpc->nslots = nslots;
                    574:     shpc->config = g_malloc0(SHPC_SIZEOF(d));
                    575:     shpc->cmask = g_malloc0(SHPC_SIZEOF(d));
                    576:     shpc->wmask = g_malloc0(SHPC_SIZEOF(d));
                    577:     shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d));
                    578: 
                    579:     shpc_reset(d);
                    580: 
                    581:     pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset);
                    582: 
                    583:     pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff);
                    584:     pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
                    585:     pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
                    586:     pci_set_long(shpc->wmask + SHPC_SERR_INT,
                    587:                  SHPC_INT_DIS |
                    588:                  SHPC_SERR_DIS |
                    589:                  SHPC_CMD_INT_DIS |
                    590:                  SHPC_ARB_SERR_DIS);
                    591:     pci_set_long(shpc->w1cmask + SHPC_SERR_INT,
                    592:                  SHPC_CMD_DETECTED |
                    593:                  SHPC_ARB_DETECTED);
                    594:     for (i = 0; i < nslots; ++i) {
                    595:         pci_set_byte(shpc->wmask +
                    596:                      SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
                    597:                      SHPC_SLOT_EVENT_PRESENCE |
                    598:                      SHPC_SLOT_EVENT_ISOLATED_FAULT |
                    599:                      SHPC_SLOT_EVENT_BUTTON |
                    600:                      SHPC_SLOT_EVENT_MRL |
                    601:                      SHPC_SLOT_EVENT_CONNECTED_FAULT |
                    602:                      SHPC_SLOT_EVENT_MRL_SERR_DIS |
                    603:                      SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
                    604:         pci_set_byte(shpc->w1cmask +
                    605:                      SHPC_SLOT_EVENT_LATCH(i),
                    606:                      SHPC_SLOT_EVENT_PRESENCE |
                    607:                      SHPC_SLOT_EVENT_ISOLATED_FAULT |
                    608:                      SHPC_SLOT_EVENT_BUTTON |
                    609:                      SHPC_SLOT_EVENT_MRL |
                    610:                      SHPC_SLOT_EVENT_CONNECTED_FAULT);
                    611:     }
                    612: 
                    613:     /* TODO: init cmask */
                    614:     memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio",
                    615:                           SHPC_SIZEOF(d));
                    616:     shpc_cap_update_dword(d);
                    617:     memory_region_add_subregion(bar, offset, &shpc->mmio);
                    618:     pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
                    619: 
                    620:     d->cap_present |= QEMU_PCI_CAP_SHPC;
                    621:     return 0;
                    622: }
                    623: 
                    624: int shpc_bar_size(PCIDevice *d)
                    625: {
                    626:     return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS));
                    627: }
                    628: 
                    629: void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
                    630: {
                    631:     SHPCDevice *shpc = d->shpc;
                    632:     d->cap_present &= ~QEMU_PCI_CAP_SHPC;
                    633:     memory_region_del_subregion(bar, &shpc->mmio);
                    634:     /* TODO: cleanup config space changes? */
                    635:     g_free(shpc->config);
                    636:     g_free(shpc->cmask);
                    637:     g_free(shpc->wmask);
                    638:     g_free(shpc->w1cmask);
                    639:     memory_region_destroy(&shpc->mmio);
                    640:     g_free(shpc);
                    641: }
                    642: 
                    643: void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
                    644: {
                    645:     if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) {
                    646:         return;
                    647:     }
                    648:     if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) {
                    649:         unsigned dword_data;
                    650:         dword_data = pci_get_long(d->shpc->config + d->shpc->cap
                    651:                                   + SHPC_CAP_DWORD_DATA);
                    652:         shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4);
                    653:     }
                    654:     /* Update cap dword data in case guest is going to read it. */
                    655:     shpc_cap_update_dword(d);
                    656: }
                    657: 
                    658: static void shpc_save(QEMUFile *f, void *pv, size_t size)
                    659: {
                    660:     PCIDevice *d = container_of(pv, PCIDevice, shpc);
                    661:     qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
                    662: }
                    663: 
                    664: static int shpc_load(QEMUFile *f, void *pv, size_t size)
                    665: {
                    666:     PCIDevice *d = container_of(pv, PCIDevice, shpc);
                    667:     int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
                    668:     if (ret != SHPC_SIZEOF(d)) {
                    669:         return -EINVAL;
                    670:     }
                    671:     /* Make sure we don't lose notifications. An extra interrupt is harmless. */
                    672:     d->shpc->msi_requested = 0;
                    673:     shpc_interrupt_update(d);
                    674:     return 0;
                    675: }
                    676: 
                    677: VMStateInfo shpc_vmstate_info = {
                    678:     .name = "shpc",
                    679:     .get  = shpc_load,
                    680:     .put  = shpc_save,
                    681: };

unix.superglobalmegacorp.com