diff options
author | Linus Torvalds | 2011-07-29 23:35:05 -0700 |
---|---|---|
committer | Linus Torvalds | 2011-07-29 23:35:05 -0700 |
commit | f85f19de90a9997583bb26e6f1f9297a4e152c18 (patch) | |
tree | 2dfe61dab6c39ca202f114cb68c68978da1624e3 /drivers/pci | |
parent | b993fdbc7fe26f96b59003a3552c418a71aa0a9f (diff) | |
parent | 7b87c9df5602efd6c7edeb291bbd104d49a6babf (diff) |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
PCI: remove printks about disabled bridge windows
PCI: fold pci_calc_resource_flags() into decode_bar()
PCI: treat mem BAR type "11" (reserved) as 32-bit, not 64-bit, BAR
PCI: correct pcie_set_readrq write size
PCI: pciehp: change wait time for valid configuration access
x86/PCI: Preserve existing pci=bfsort whitelist for Dell systems
PCI: ARI is a PCIe v2 feature
x86/PCI: quirks: Use pci_dev->revision
PCI: Make the struct pci_dev * argument of pci_fixup_irqs const.
PCI hotplug: cpqphp: use pci_dev->vendor
PCI hotplug: cpqphp: use pci_dev->subsystem_{vendor|device}
x86/PCI: config space accessor functions should not ignore the segment argument
PCI: Assign values to 'pci_obff_signal_type' enumeration constants
x86/PCI: reduce severity of host bridge window conflict warnings
PCI: enumerate the PCI device only removed out PCI hieratchy of OS when re-scanning PCI
PCI: PCIe AER: add aer_recover_queue
x86/PCI: select direct access mode for mmconfig option
PCI hotplug: Rename is_ejectable which also exists in dock.c
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpqphp_core.c | 17 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 11 | ||||
-rw-r--r-- | drivers/pci/pci.c | 11 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 76 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 3 | ||||
-rw-r--r-- | drivers/pci/probe.c | 87 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 3 | ||||
-rw-r--r-- | drivers/pci/setup-irq.c | 4 | ||||
-rw-r--r-- | drivers/pci/setup-res.c | 3 |
11 files changed, 136 insertions, 88 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 8f3faf343f75..095f29e13734 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -408,7 +408,7 @@ got_one: } EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); -static int is_ejectable(acpi_handle handle) +static int pcihp_is_ejectable(acpi_handle handle) { acpi_status status; acpi_handle tmp; @@ -442,7 +442,7 @@ int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle) return 0; if (bridge_handle != parent_handle) return 0; - return is_ejectable(handle); + return pcihp_is_ejectable(handle); } EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); @@ -450,7 +450,7 @@ static acpi_status check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) { int *found = (int *)context; - if (is_ejectable(handle)) { + if (pcihp_is_ejectable(handle)) { *found = 1; return AE_CTRL_TERMINATE; } diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 4952c3b9379d..f1ce99cceac6 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -840,8 +840,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Need to read VID early b/c it's used to differentiate CPQ and INTC * discovery */ - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + vendor_id = pdev->vendor; + if ((vendor_id != PCI_VENDOR_ID_COMPAQ) && + (vendor_id != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_non_compaq_or_intel); rc = -ENODEV; goto err_disable_device; @@ -868,11 +869,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* TODO: This code can be made to support non-Compaq or Intel * subsystem IDs */ - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_disable_device; - } + subsystem_vid = pdev->subsystem_vendor; dbg("Subsystem Vendor ID: %x\n", subsystem_vid); if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_non_compaq_or_intel); @@ -887,11 +884,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_disable_device; } - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_free_ctrl; - } + subsystem_deviceid = pdev->subsystem_device; info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 085dbb5fc168..1e9c9aacc3a6 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -213,6 +213,9 @@ static int board_added(struct slot *p_slot) goto err_exit; } + /* Wait for 1 second after checking link training status */ + msleep(1000); + /* Check for a power fault */ if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 50a23da5d24d..96dc4734e4af 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -275,16 +275,9 @@ int pciehp_check_link_status(struct controller *ctrl) * hot-plug capable downstream port. But old controller might * not implement it. In this case, we wait for 1000 ms. */ - if (ctrl->link_active_reporting){ - /* Wait for Data Link Layer Link Active bit to be set */ + if (ctrl->link_active_reporting) pcie_wait_link_active(ctrl); - /* - * We must wait for 100 ms after the Data Link Layer - * Link Active bit reads 1b before initiating a - * configuration access to the hot added device. - */ - msleep(100); - } else + else msleep(1000); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 692671b11667..08a95b369d85 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1905,7 +1905,7 @@ void pci_enable_ari(struct pci_dev *dev) { int pos; u32 cap; - u16 ctrl; + u16 flags, ctrl; struct pci_dev *bridge; if (!pci_is_pcie(dev) || dev->devfn) @@ -1923,6 +1923,11 @@ void pci_enable_ari(struct pci_dev *dev) if (!pos) return; + /* ARI is a PCIe v2 feature */ + pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags); + if ((flags & PCI_EXP_FLAGS_VERS) < 2) + return; + pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap); if (!(cap & PCI_EXP_DEVCAP2_ARI)) return; @@ -3186,7 +3191,7 @@ EXPORT_SYMBOL(pcie_get_readrq); * @rq: maximum memory read count in bytes * valid values are 128, 256, 512, 1024, 2048, 4096 * - * If possible sets maximum read byte count + * If possible sets maximum memory read request in bytes */ int pcie_set_readrq(struct pci_dev *dev, int rq) { @@ -3209,7 +3214,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) { ctl &= ~PCI_EXP_DEVCTL_READRQ; ctl |= v; - err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl); + err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl); } out: diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 43421fbe080a..9674e9f30d49 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -24,6 +24,7 @@ #include <linux/suspend.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/kfifo.h> #include "aerdrv.h" static int forceload; @@ -445,8 +446,7 @@ static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev) return drv; } -static pci_ers_result_t reset_link(struct pcie_device *aerdev, - struct pci_dev *dev) +static pci_ers_result_t reset_link(struct pci_dev *dev) { struct pci_dev *udev; pci_ers_result_t status; @@ -486,7 +486,6 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev, /** * do_recovery - handle nonfatal/fatal error recovery process - * @aerdev: pointer to a pcie_device data structure of root port * @dev: pointer to a pci_dev data structure of agent detecting an error * @severity: error severity type * @@ -494,8 +493,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev, * error detected message to all downstream drivers within a hierarchy in * question and return the returned code. */ -static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev, - int severity) +static void do_recovery(struct pci_dev *dev, int severity) { pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED; enum pci_channel_state state; @@ -511,7 +509,7 @@ static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev, report_error_detected); if (severity == AER_FATAL) { - result = reset_link(aerdev, dev); + result = reset_link(dev); if (result != PCI_ERS_RESULT_RECOVERED) goto failed; } @@ -576,9 +574,73 @@ static void handle_error_source(struct pcie_device *aerdev, pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, info->status); } else - do_recovery(aerdev, dev, info->severity); + do_recovery(dev, info->severity); } +#ifdef CONFIG_ACPI_APEI_PCIEAER +static void aer_recover_work_func(struct work_struct *work); + +#define AER_RECOVER_RING_ORDER 4 +#define AER_RECOVER_RING_SIZE (1 << AER_RECOVER_RING_ORDER) + +struct aer_recover_entry +{ + u8 bus; + u8 devfn; + u16 domain; + int severity; +}; + +static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry, + AER_RECOVER_RING_SIZE); +/* + * Mutual exclusion for writers of aer_recover_ring, reader side don't + * need lock, because there is only one reader and lock is not needed + * between reader and writer. + */ +static DEFINE_SPINLOCK(aer_recover_ring_lock); +static DECLARE_WORK(aer_recover_work, aer_recover_work_func); + +void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, + int severity) +{ + unsigned long flags; + struct aer_recover_entry entry = { + .bus = bus, + .devfn = devfn, + .domain = domain, + .severity = severity, + }; + + spin_lock_irqsave(&aer_recover_ring_lock, flags); + if (kfifo_put(&aer_recover_ring, &entry)) + schedule_work(&aer_recover_work); + else + pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", + domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + spin_unlock_irqrestore(&aer_recover_ring_lock, flags); +} +EXPORT_SYMBOL_GPL(aer_recover_queue); + +static void aer_recover_work_func(struct work_struct *work) +{ + struct aer_recover_entry entry; + struct pci_dev *pdev; + + while (kfifo_get(&aer_recover_ring, &entry)) { + pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, + entry.devfn); + if (!pdev) { + pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n", + entry.domain, entry.bus, + PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); + continue; + } + do_recovery(pdev, entry.severity); + } +} +#endif + /** * get_device_error_info - read error status from dev and store it to info * @dev: pointer to the device expected to have a error record diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index b07a42e0b350..3ea51736f18d 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -204,7 +204,7 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) } #ifdef CONFIG_ACPI_APEI_PCIEAER -static int cper_severity_to_aer(int cper_severity) +int cper_severity_to_aer(int cper_severity) { switch (cper_severity) { case CPER_SEV_RECOVERABLE: @@ -215,6 +215,7 @@ static int cper_severity_to_aer(int cper_severity) return AER_CORRECTABLE; } } +EXPORT_SYMBOL_GPL(cper_severity_to_aer); void cper_print_aer(const char *prefix, int cper_severity, struct aer_capability_regs *aer) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9ab492f21f86..795c9026d55f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -68,21 +68,6 @@ static int __init pcibus_class_init(void) } postcore_initcall(pcibus_class_init); -/* - * Translate the low bits of the PCI base - * to the resource type - */ -static inline unsigned int pci_calc_resource_flags(unsigned int flags) -{ - if (flags & PCI_BASE_ADDRESS_SPACE_IO) - return IORESOURCE_IO; - - if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) - return IORESOURCE_MEM | IORESOURCE_PREFETCH; - - return IORESOURCE_MEM; -} - static u64 pci_size(u64 base, u64 maxbase, u64 mask) { u64 size = mask & maxbase; /* Find the significant bits */ @@ -101,18 +86,39 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask) return size; } -static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) +static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar) { + u32 mem_type; + unsigned long flags; + if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { - res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; - return pci_bar_io; + flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; + flags |= IORESOURCE_IO; + return flags; } - res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; + flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; + flags |= IORESOURCE_MEM; + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) + flags |= IORESOURCE_PREFETCH; - if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) - return pci_bar_mem64; - return pci_bar_mem32; + mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + switch (mem_type) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + flags |= IORESOURCE_MEM_64; + break; + default: + dev_warn(&dev->dev, + "mem unknown type %x treated as 32-bit BAR\n", + mem_type); + break; + } + return flags; } /** @@ -165,9 +171,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, l = 0; if (type == pci_bar_unknown) { - type = decode_bar(res, l); - res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; - if (type == pci_bar_io) { + res->flags = decode_bar(dev, l); + res->flags |= IORESOURCE_SIZEALIGN; + if (res->flags & IORESOURCE_IO) { l &= PCI_BASE_ADDRESS_IO_MASK; mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; } else { @@ -180,7 +186,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, mask = (u32)PCI_ROM_ADDRESS_MASK; } - if (type == pci_bar_mem64) { + if (res->flags & IORESOURCE_MEM_64) { u64 l64 = l; u64 sz64 = sz; u64 mask64 = mask | (u64)~0 << 32; @@ -204,7 +210,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto fail; } - res->flags |= IORESOURCE_MEM_64; if ((sizeof(resource_size_t) < 8) && l) { /* Address above 32-bit boundary; disable the BAR */ pci_write_config_dword(dev, pos, 0); @@ -230,7 +235,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } out: - return (type == pci_bar_mem64) ? 1 : 0; + return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; fail: res->flags = 0; goto out; @@ -284,10 +289,6 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) if (!res->end) res->end = limit + 0xfff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [io %#06lx-%#06lx] (disabled)\n", - base, limit); } } @@ -308,10 +309,6 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem %#010lx-%#010lx] (disabled)\n", - base, limit + 0xfffff); } } @@ -359,10 +356,6 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem %#010lx-%#010lx pref] (disabled)\n", - base, limit + 0xfffff); } } @@ -725,12 +718,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, pci_write_config_word(dev, PCI_STATUS, 0xffff); /* Prevent assigning a bus number that already exists. - * This can happen when a bridge is hot-plugged */ - if (pci_find_bus(pci_domain_nr(bus), max+1)) - goto out; - child = pci_add_new_bus(bus, dev, ++max); - if (!child) - goto out; + * This can happen when a bridge is hot-plugged, so in + * this case we only re-scan this bus. */ + child = pci_find_bus(pci_domain_nr(bus), max+1); + if (!child) { + child = pci_add_new_bus(bus, dev, ++max); + if (!child) + goto out; + } buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 9995842e45b5..8a1d3c7863a8 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -336,7 +336,6 @@ static void pci_setup_bridge_io(struct pci_bus *bus) /* Clear upper 16 bits of I/O base/limit. */ io_upper16 = 0; l = 0x00f0; - dev_info(&bridge->dev, " bridge window [io disabled]\n"); } /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); @@ -362,7 +361,6 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus) dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " bridge window [mem disabled]\n"); } pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); } @@ -393,7 +391,6 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " bridge window [mem pref disabled]\n"); } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index eec9738f3492..eb219a1d16f7 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -21,7 +21,7 @@ static void __init pdev_fixup_irq(struct pci_dev *dev, u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(struct pci_dev *, u8, u8)) + int (*map_irq)(const struct pci_dev *, u8, u8)) { u8 pin, slot; int irq = 0; @@ -56,7 +56,7 @@ pdev_fixup_irq(struct pci_dev *dev, void __init pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(struct pci_dev *, u8, u8)) + int (*map_irq)(const struct pci_dev *, u8, u8)) { struct pci_dev *dev = NULL; for_each_pci_dev(dev) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index bc0e6eea0fff..319f359906e8 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -74,8 +74,7 @@ void pci_update_resource(struct pci_dev *dev, int resno) resno, new, check); } - if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == - (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) { + if (res->flags & IORESOURCE_MEM_64) { new = region.start >> 16 >> 16; pci_write_config_dword(dev, reg + 4, new); pci_read_config_dword(dev, reg + 4, &check); |