[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).
Signed-off-by: Hidetoshi Seto <[email protected]>
---
arch/ia64/lib/iomap_check.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+)
Index: linux-2.6.11.11/arch/ia64/lib/iomap_check.c
===================================================================
--- linux-2.6.11.11.orig/arch/ia64/lib/iomap_check.c
+++ linux-2.6.11.11/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);
@@ -93,5 +101,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/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]