pcie.c (110c477c2ede4d06d3a95a2bfda5c4c58d2af516) pcie.c (d85d65cc297fa85b7b2db3b9025c6341d6986d7e)
1/*
2 * pcie.c
3 *
4 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
5 * VA Linux Systems Japan K.K.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by

--- 588 unchanged lines hidden (view full) ---

597void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slt_ctl, uint16_t *slt_sta)
598{
599 uint32_t pos = dev->exp.exp_cap;
600 uint8_t *exp_cap = dev->config + pos;
601 *slt_ctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
602 *slt_sta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
603}
604
1/*
2 * pcie.c
3 *
4 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
5 * VA Linux Systems Japan K.K.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by

--- 588 unchanged lines hidden (view full) ---

597void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slt_ctl, uint16_t *slt_sta)
598{
599 uint32_t pos = dev->exp.exp_cap;
600 uint8_t *exp_cap = dev->config + pos;
601 *slt_ctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
602 *slt_sta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
603}
604
605void pcie_cap_slot_write_config(PCIDevice *dev, uint16_t slt_ctl, uint16_t slt_sta,
605void pcie_cap_slot_write_config(PCIDevice *dev,
606 uint16_t old_slt_ctl, uint16_t old_slt_sta,
606 uint32_t addr, uint32_t val, int len)
607{
608 uint32_t pos = dev->exp.exp_cap;
609 uint8_t *exp_cap = dev->config + pos;
610 uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
611
612 if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
613 /*

--- 6 unchanged lines hidden (view full) ---

620 * Note: in theory this can be detected as a duplicate button press
621 * which cancels the previous press. Does not seem to happen in
622 * practice as guests seem to only have this bug during init.
623 */
624#define PCIE_SLOT_EVENTS (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | \
625 PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | \
626 PCI_EXP_SLTSTA_CC)
627
607 uint32_t addr, uint32_t val, int len)
608{
609 uint32_t pos = dev->exp.exp_cap;
610 uint8_t *exp_cap = dev->config + pos;
611 uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
612
613 if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
614 /*

--- 6 unchanged lines hidden (view full) ---

621 * Note: in theory this can be detected as a duplicate button press
622 * which cancels the previous press. Does not seem to happen in
623 * practice as guests seem to only have this bug during init.
624 */
625#define PCIE_SLOT_EVENTS (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | \
626 PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | \
627 PCI_EXP_SLTSTA_CC)
628
628 if (val & ~slt_sta & PCIE_SLOT_EVENTS) {
629 sltsta = (sltsta & ~PCIE_SLOT_EVENTS) | (slt_sta & PCIE_SLOT_EVENTS);
629 if (val & ~old_slt_sta & PCIE_SLOT_EVENTS) {
630 sltsta = (sltsta & ~PCIE_SLOT_EVENTS) | (old_slt_sta & PCIE_SLOT_EVENTS);
630 pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
631 }
632 hotplug_event_clear(dev);
633 }
634
635 if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
636 return;
637 }
638
639 if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
640 PCI_EXP_SLTCTL_EIC)) {
641 sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
642 pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
643 PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
644 "sltsta -> 0x%02"PRIx16"\n",
645 sltsta);
646 }
647
648 /*
631 pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
632 }
633 hotplug_event_clear(dev);
634 }
635
636 if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
637 return;
638 }
639
640 if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
641 PCI_EXP_SLTCTL_EIC)) {
642 sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
643 pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
644 PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
645 "sltsta -> 0x%02"PRIx16"\n",
646 sltsta);
647 }
648
649 /*
649 * If the slot is polulated, power indicator is off and power
650 * If the slot is populated, power indicator is off and power
650 * controller is off, it is safe to detach the devices.
651 * controller is off, it is safe to detach the devices.
652 *
653 * Note: don't detach if condition was already true:
654 * this is a work around for guests that overwrite
655 * control of powered off slots before powering them on.
651 */
652 if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
653 (val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
656 */
657 if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
658 (val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
654 (!(slt_ctl & PCI_EXP_SLTCTL_PCC) ||
655 (slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
659 (!(old_slt_ctl & PCI_EXP_SLTCTL_PCC) ||
660 (old_slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
656 PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
657 pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
658 pcie_unplug_device, NULL);
659
660 pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
661 PCI_EXP_SLTSTA_PDS);
662 if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
663 pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,

--- 319 unchanged lines hidden ---
661 PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
662 pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
663 pcie_unplug_device, NULL);
664
665 pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
666 PCI_EXP_SLTSTA_PDS);
667 if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
668 pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,

--- 319 unchanged lines hidden ---