[This is 5 of 10 patches, "iochk-05-check_bridge.patch"]
- Consider three devices, A, B, and C are placed under a same host bridge H. After A and B checked-in (=passed iochk_clear, doing some I/Os, not come to call iochk_read yet), now C is going to check-in, just entered iochk_clear, but C finds out that H indicates error. It means that A or B hits a bus error, but there is no data which one actually hits the error. So, C should notify the error to both of A and B, and clear the H's status to start its own I/Os. If there are only two devices, it become more simple. It is clear if one find a bridge error while another is check-in, the error is nothing except for another's. Well, works concerning registers (devices and bridges) are almost shaped up. So, from next, I'll move to deep phase to implement more arch-specific codes... see next (6 of 10). Changes from previous one for 2.6.11.11: - (non) Signed-off-by: Hidetoshi Seto <[EMAIL PROTECTED]> --- arch/ia64/lib/iomap_check.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 45 insertions(+) Index: linux-2.6.13-rc1/arch/ia64/lib/iomap_check.c =================================================================== --- linux-2.6.13-rc1.orig/arch/ia64/lib/iomap_check.c +++ linux-2.6.13-rc1/arch/ia64/lib/iomap_check.c @@ -17,6 +17,9 @@ DEFINE_SPINLOCK(iochk_lock); /* all work static struct pci_dev *search_host_bridge(struct pci_dev *dev); static int have_error(struct pci_dev *dev); +void notify_bridge_error(struct pci_dev *bridge); +void clear_bridge_error(struct pci_dev *bridge); + void iochk_init(void) { /* setup */ @@ -33,6 +36,11 @@ void iochk_clear(iocookie *cookie, struc cookie->host = search_host_bridge(dev); spin_lock_irqsave(&iochk_lock, flag); + if (cookie->host && have_error(cookie->host)) { + /* someone under my bridge causes error... */ + notify_bridge_error(cookie->host); + clear_bridge_error(cookie->host); + } list_add(&cookie->list, &iochk_devices); spin_unlock_irqrestore(&iochk_lock, flag); @@ -95,5 +103,42 @@ static int have_error(struct pci_dev *de return 0; } +void notify_bridge_error(struct pci_dev *bridge) +{ + iocookie *cookie; + + if (list_empty(&iochk_devices)) + return; + + /* notify error to all transactions using this host bridge */ + if (bridge) { + /* local notify, ex. Parity, Abort etc. */ + list_for_each_entry(cookie, &iochk_devices, list) { + if (cookie->host == bridge) + cookie->error = 1; + } + } +} + +void clear_bridge_error(struct pci_dev *bridge) +{ + u16 status = ( PCI_STATUS_REC_TARGET_ABORT + | PCI_STATUS_REC_MASTER_ABORT + | PCI_STATUS_DETECTED_PARITY ); + + /* clear bridge status */ + switch (bridge->hdr_type) { + case PCI_HEADER_TYPE_NORMAL: /* 0 */ + pci_write_config_word(bridge, PCI_STATUS, status); + break; + case PCI_HEADER_TYPE_BRIDGE: /* 1 */ + pci_write_config_word(bridge, PCI_SEC_STATUS, status); + break; + case PCI_HEADER_TYPE_CARDBUS: /* 2 */ + default: + BUG(); + } +} + EXPORT_SYMBOL(iochk_read); EXPORT_SYMBOL(iochk_clear); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/