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 --- |