diff options
-rw-r--r-- | arch/arm/include/asm/pci.h | 7 | ||||
-rw-r--r-- | arch/mips/include/asm/pci.h | 7 | ||||
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/configs/efi_defconfig | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/dma.h | 36 | ||||
-rw-r--r-- | arch/x86/include/asm/pci.h | 7 | ||||
-rw-r--r-- | drivers/efi/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 5 | ||||
-rw-r--r-- | drivers/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/pci-efi.c | 342 | ||||
-rw-r--r-- | drivers/pci/pci-efi.h | 343 | ||||
-rw-r--r-- | drivers/pci/pci.c | 106 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 17 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/itco_wdt.c | 346 | ||||
-rw-r--r-- | include/linux/pci.h | 3 |
16 files changed, 1187 insertions, 38 deletions
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h new file mode 100644 index 0000000000..d7419cabe7 --- /dev/null +++ b/arch/arm/include/asm/pci.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_PCI_H +#define __ASM_PCI_H + +#define pcibios_assign_all_busses() 1 + +#endif diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h new file mode 100644 index 0000000000..d7419cabe7 --- /dev/null +++ b/arch/mips/include/asm/pci.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_PCI_H +#define __ASM_PCI_H + +#define pcibios_assign_all_busses() 1 + +#endif diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 311c3d1a8e..bcb44b23f0 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -4,6 +4,7 @@ config X86 bool select HAS_KALLSYMS + select HAS_DMA select GENERIC_FIND_NEXT_BIT default y diff --git a/arch/x86/configs/efi_defconfig b/arch/x86/configs/efi_defconfig index 761ffbe261..73614dd4b4 100644 --- a/arch/x86/configs/efi_defconfig +++ b/arch/x86/configs/efi_defconfig @@ -87,7 +87,9 @@ CONFIG_STATE_DRV=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_EFI=y CONFIG_F71808E_WDT=y +CONFIG_ITCO_WDT=y # CONFIG_PINCTRL is not set +CONFIG_PCI_EFI=y CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h index 3dab2b688d..8a3b044f3a 100644 --- a/arch/x86/include/asm/dma.h +++ b/arch/x86/include/asm/dma.h @@ -4,6 +4,40 @@ #ifndef __ASM_DMA_H #define __ASM_DMA_H -/* empty */ +#include <linux/string.h> +#include <linux/compiler.h> +#include <xfuncs.h> +#include <malloc.h> + +/* + * x86 is cache coherent, so we need not do anything special here + */ + +static inline void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle) +{ + void *ret = xmemalign(4096, size); + if (dma_handle) + *dma_handle = (dma_addr_t)ret; + + memset(ret, 0, size); + + return ret; +} + +static inline void dma_free_coherent(void *mem, dma_addr_t dma_handle, + size_t size) +{ + free(mem); +} + +static inline void dma_sync_single_for_cpu(dma_addr_t address, size_t size, + enum dma_data_direction dir) +{ +} + +static inline void dma_sync_single_for_device(dma_addr_t address, size_t size, + enum dma_data_direction dir) +{ +} #endif /* __ASM_DMA_H */ diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h new file mode 100644 index 0000000000..ca1c0f912d --- /dev/null +++ b/arch/x86/include/asm/pci.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_PCI_H +#define __ASM_PCI_H + +#define pcibios_assign_all_busses() 0 + +#endif diff --git a/drivers/efi/Kconfig b/drivers/efi/Kconfig index cca1a2e1d6..80d9e6f0c5 100644 --- a/drivers/efi/Kconfig +++ b/drivers/efi/Kconfig @@ -2,3 +2,4 @@ config EFI_BOOTUP bool select BLOCK select PARTITION_DISK + select HW_HAS_PCI diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0585460976..71d05055d4 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -54,6 +54,11 @@ config PCI_LAYERSCAPE select OF_PCI select PCI +config PCI_EFI + bool "EFI PCI protocol" + depends on EFI_BOOTUP + select PCI + endmenu endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index d227619ed4..6fc4eaf6b2 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCIE_DW) += pcie-designware.o pcie-designware-host.o obj-$(CONFIG_PCI_IMX6) += pci-imx6.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o +obj-$(CONFIG_PCI_EFI) += pci-efi.o diff --git a/drivers/pci/pci-efi.c b/drivers/pci/pci-efi.c new file mode 100644 index 0000000000..e1fe11d070 --- /dev/null +++ b/drivers/pci/pci-efi.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Ahmad Fatoum <a.fatoum@pengutronix.de> + */ +#define pr_fmt(fmt) "pci-efi: " fmt + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <xfuncs.h> +#include <efi.h> +#include <efi/efi.h> +#include <efi/efi-device.h> +#include <linux/pci.h> + +#include "pci-efi.h" + +struct efi_pci_priv { + struct efi_pci_root_bridge_io_protocol *protocol; + struct device_d *dev; + struct pci_controller pci; + struct resource mem; + struct resource mem_pref; + struct resource io; + struct list_head children; +}; + +struct pci_child_id { + size_t segmentno; + size_t busno; + size_t devno; + size_t funcno; +}; + +struct pci_child { + struct efi_pci_io_protocol *protocol; + struct device_d *dev; + struct list_head list; + struct pci_child_id id; +}; + +static inline bool pci_child_id_equal(struct pci_child_id *a, struct pci_child_id *b) +{ + return a->segmentno == b->segmentno + && a->busno == b->busno + && a->devno == b->devno + && a->funcno == b->funcno; +} + +#define host_to_efi_pci(host) container_of(host, struct efi_pci_priv, pci) + +static inline u64 efi_pci_addr(struct pci_bus *bus, u32 devfn, int where) +{ + return EFI_PCI_ADDRESS(bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), + where); +} + +static int efi_pci_rd_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 *val) +{ + struct efi_pci_priv *priv = host_to_efi_pci(bus->host); + efi_status_t efiret; + u32 value; + enum efi_pci_protocol_width width; + + switch (size) { + case 4: + width = EFI_PCI_WIDTH_U32; + break; + case 2: + width = EFI_PCI_WIDTH_U16; + break; + case 1: + width = EFI_PCI_WIDTH_U8; + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + efiret = priv->protocol->pci.read(priv->protocol, width, + efi_pci_addr(bus, devfn, where), + 1, &value); + + *val = 0xFFFFFFFF; + + if (EFI_ERROR(efiret)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + *val = value; + + return PCIBIOS_SUCCESSFUL; +} + +static int efi_pci_wr_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 val) +{ + struct efi_pci_priv *priv = host_to_efi_pci(bus->host); + efi_status_t efiret; + enum efi_pci_protocol_width width; + + switch (size) { + case 4: + width = EFI_PCI_WIDTH_U32; + break; + case 2: + width = EFI_PCI_WIDTH_U16; + break; + case 1: + width = EFI_PCI_WIDTH_U8; + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + efiret = priv->protocol->pci.write(priv->protocol, width, + efi_pci_addr(bus, devfn, where), + 1, &val); + if (EFI_ERROR(efiret)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +static inline struct resource build_resource(const char *name, + resource_size_t start, + resource_size_t len, + unsigned long flags) +{ + struct resource res; + + res.name = name; + res.start = start; + res.end = start + len - 1; + res.flags = flags; + res.parent = NULL; + INIT_LIST_HEAD(&res.children); + INIT_LIST_HEAD(&res.sibling); + + return res; +} + +static const struct pci_ops efi_pci_ops = { + .read = efi_pci_rd_conf, + .write = efi_pci_wr_conf, +}; + +static u8 *acpi_parse_resource(u8 *next, struct resource *out) +{ + struct efi_acpi_resource *res; + const char *name = NULL; + unsigned long flags = 0; + + do { + if (*next == ACPI_RESOURCE_END_TAG) + return NULL; + + if (*next != ACPI_RESOURCE_DESC_TAG) + return ERR_PTR(-EIO); + + res = container_of(next, struct efi_acpi_resource, asd); + + next = (u8 *)&res[1]; + } while (res->addr_len == 0); + + switch (res->restype) { + case ACPI_RESOURCE_TYPE_MEM: + if ((res->typflags & ACPI_RESOURCE_TYPFLAG_MTP_MASK) + != ACPI_RESOURCE_TYPFLAG_MTP_MEM) + break; + + name = "NP-MEM"; + flags = IORESOURCE_MEM; + + switch (res->typflags & ACPI_RESOURCE_TYPFLAG_MEM_MASK) { + case ACPI_RESOURCE_TYPFLAG_MEM_PREF: + name = "P-MEM"; + flags |= IORESOURCE_PREFETCH; + /* fallthrough */ + case ACPI_RESOURCE_TYPFLAG_MEM_WC: + case ACPI_RESOURCE_TYPFLAG_MEM_CACHEABLE: + flags |= IORESOURCE_CACHEABLE; + } + + if (res->typflags & ACPI_RESOURCE_TYPFLAG_RW_MASK) + flags |= IORESOURCE_MEM_WRITEABLE; + + break; + case ACPI_RESOURCE_TYPE_IO: + name = "IO"; + flags = IORESOURCE_IO; + break; + case ACPI_RESOURCE_TYPE_BUSNO: + name = "BUS"; + flags = IORESOURCE_BUS; + break; + default: + return ERR_PTR(-ENXIO); + } + + *out = build_resource(name, res->addr_min, res->addr_len, flags); + + pr_debug("%s: %llx-%llx (len=%llx, gr=%lld, xlate_off=%llx, resflags=%08lx)\n", + out->name, + res->addr_min, res->addr_max, res->addr_len, + res->addr_granularity, res->addr_xlate_off, + flags); + + return next; +} + +/* EFI already enumerated the bus for us, match our new pci devices with the efi + * handles + */ +static void efi_pci_fixup_dev_parent(struct pci_dev *dev) +{ + struct efi_pci_priv *priv = host_to_efi_pci(dev->bus->host); + struct pci_child *child; + struct pci_child_id id; + + id.segmentno = priv->protocol->segmentno; + id.busno = dev->bus->number; + id.devno = PCI_SLOT(dev->devfn); + id.funcno = PCI_FUNC(dev->devfn); + + list_for_each_entry(child, &priv->children, list) { + if (IS_ERR(child->protocol)) + continue; + + if (!child->protocol) { + struct efi_device *efichild = to_efi_device(child->dev); + efi_status_t efiret; + + BS->handle_protocol(efichild->handle, &EFI_PCI_IO_PROTOCOL_GUID, + (void **)&child->protocol); + if (!child->protocol) { + child->protocol = ERR_PTR(-ENODEV); + continue; + } + + efiret = child->protocol->get_location(child->protocol, + &child->id.segmentno, + &child->id.busno, + &child->id.devno, + &child->id.funcno); + + if (EFI_ERROR(efiret)) { + child->protocol = ERR_PTR(-efi_errno(efiret)); + continue; + } + } + + if (pci_child_id_equal(&child->id, &id)) { + dev->dev.priv = child->protocol; + dev->dev.parent = child->dev; + return; + } + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, efi_pci_fixup_dev_parent); + +static int efi_pci_probe(struct efi_device *efidev) +{ + struct device_d *child; + struct efi_pci_priv *priv; + efi_status_t efiret; + void *resources; + struct resource resource; + u8 *res; + + priv = xzalloc(sizeof(*priv)); + + BS->handle_protocol(efidev->handle, &EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID, + (void **)&priv->protocol); + if (!priv->protocol) + return -ENODEV; + + efiret = priv->protocol->configuration(priv->protocol, &resources); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + res = resources; + + while (1) { + res = acpi_parse_resource(res, &resource); + + if (IS_ERR(res)) + return PTR_ERR(res); + + if (!res) + break; + + if ((resource.flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) + == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) { + priv->pci.mem_pref_resource = &priv->mem_pref; + priv->mem_pref = resource; + } else if (resource.flags & IORESOURCE_MEM) { + priv->pci.mem_resource = &priv->mem; + priv->mem = resource; + } else if (resource.flags & IORESOURCE_IO) { + priv->pci.io_resource = &priv->io; + priv->io = resource; + } + } + + priv->pci.parent = &efidev->dev; + priv->pci.pci_ops = &efi_pci_ops; + + INIT_LIST_HEAD(&priv->children); + + device_for_each_child(&efidev->dev, child) { + struct pci_child *pci_child; + struct efi_device *efichild = to_efi_device(child); + + if (!efi_device_has_guid(efichild, EFI_PCI_IO_PROTOCOL_GUID)) + continue; + + pci_child = xzalloc(sizeof(*pci_child)); + + pci_child->dev = &efichild->dev; + + /* + * regiser_pci_controller can reconfigure bridge bus numbers, + * thus we only collect the child node handles here, but + * don't yet call GetLocation on them + */ + list_add_tail(&pci_child->list, &priv->children); + }; + + register_pci_controller(&priv->pci); + + return 0; +} + +static struct efi_driver efi_pci_driver = { + .driver = { + .name = "efi-pci", + }, + .probe = efi_pci_probe, + .guid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID, +}; +device_efi_driver(efi_pci_driver); diff --git a/drivers/pci/pci-efi.h b/drivers/pci/pci-efi.h new file mode 100644 index 0000000000..1943461cdf --- /dev/null +++ b/drivers/pci/pci-efi.h @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __PCI_EFI_H_ +#define __PCI_EFI_H_ + +#include <efi.h> + +struct efi_pci_root_bridge_io_protocol; +struct efi_pci_io_protocol; + +enum efi_pci_protocol_width { + EFI_PCI_WIDTH_U8, + EFI_PCI_WIDTH_U16, + EFI_PCI_WIDTH_U32, + EFI_PCI_WIDTH_U64, + EFI_PCI_WIDTH_FIFO_U8, + EFI_PCI_WIDTH_FIFO_U16, + EFI_PCI_WIDTH_FIFO_U32, + EFI_PCI_WIDTH_FIFO_U64, + EFI_PCI_WIDTH_FILL_U8, + EFI_PCI_WIDTH_FILL_U16, + EFI_PCI_WIDTH_FILL_U32, + EFI_PCI_WIDTH_FILL_U64, + EFI_PCI_WIDTH_MAX +}; + +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_io_mem) ( + struct efi_pci_root_bridge_io_protocol *this, + enum efi_pci_protocol_width width, + u64 addr, + size_t count, + void *buf +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_io_mem) ( + struct efi_pci_io_protocol *this, + enum efi_pci_protocol_width width, + u8 bar, + u64 offset, + size_t count, + void *buf +); + +struct efi_pci_root_bridge_io_protocol_access { + efi_pci_root_bridge_io_protocol_io_mem read; + efi_pci_root_bridge_io_protocol_io_mem write; +}; + +struct efi_pci_io_protocol_access { + efi_pci_io_protocol_io_mem read; + efi_pci_io_protocol_io_mem write; +}; + +#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 +#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004 +#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008 +#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010 +#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 +#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 +#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 +#define EFI_PCI_ATTRIBUTE_IO 0x0100 +#define EFI_PCI_ATTRIBUTE_MEMORY 0x0200 +#define EFI_PCI_ATTRIBUTE_BUS_MASTER 0x0400 +#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800 +#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000 +#define EFI_PCI_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 +#define EFI_PCI_ATTRIBUTE_EMBEDDED_ROM 0x4000 +#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 +#define EFI_PCI_ATTRIBUTE_ISA_IO_16 0x10000 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 +#define EFI_PCI_ATTRIBUTE_VGA_IO_16 0x40000 + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_poll_io_mem) ( + struct efi_pci_root_bridge_io_protocol *this, + enum efi_pci_protocol_width width, + u64 address, + u64 mask, + u64 value, + u64 delay, + u64 *result +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_poll_io_mem) ( + struct efi_pci_io_protocol *this, + enum efi_pci_protocol_width width, + u8 bar, + u64 offset, + u64 mask, + u64 value, + u64 delay, + u64 *result +); + +enum efi_pci_root_bridge_io_protocol_operation { + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_READ, + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_WRITE, + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_COMMON_BUFFER, + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_READ64, + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_WRITE64, + EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_COMMON_BUFFER64, + EFI_PCI_ROOT_BRIGE_IO_OP_MAX +}; + +enum efi_pci_io_protocol_operation { + EFI_PCI_IO_OP_BUS_MASTER_READ, + EFI_PCI_IO_OP_BUS_MASTER_WRITE, + EFI_PCI_IO_OP_BUS_MASTER_COMMON_BUFFER, + EFI_PCI_IO_OP_MAX +}; + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_copy_mem) ( + struct efi_pci_root_bridge_io_protocol *this, + enum efi_pci_protocol_width width, + u64 dst, + u64 src, + size_t count +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_copy_mem) ( + struct efi_pci_io_protocol *this, + enum efi_pci_protocol_width width, + u8 dst_bar, + u64 dst_offset, + u8 src_bar, + u64 src_offset, + size_t count +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_map) ( + struct efi_pci_root_bridge_io_protocol *this, + enum efi_pci_root_bridge_io_protocol_operation operation, + void *hostaddr, + size_t *nbytes, + efi_physical_addr_t *devaddr, + void **mapping +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_map) ( + struct efi_pci_io_protocol *this, + enum efi_pci_io_protocol_operation operation, + void *hostaddr, + size_t *nbytes, + efi_physical_addr_t *devaddr, + void **mapping +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_unmap) ( + struct efi_pci_root_bridge_io_protocol *this, + void *mapping +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_unmap) ( + struct efi_pci_io_protocol *this, + void *mapping +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_allocate_buffer) ( + struct efi_pci_root_bridge_io_protocol *this, + enum efi_allocate_type alloctype, + enum efi_memory_type memtype, + size_t npages, + void **hostaddr, + u64 attrs +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_allocate_buffer) ( + struct efi_pci_io_protocol *this, + enum efi_allocate_type alloctype, + enum efi_memory_type memtype, + size_t npages, + void **hostaddr, + u64 attrs +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_free_buffer) ( + struct efi_pci_root_bridge_io_protocol *this, + size_t npages, + void *hostaddr +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_free_buffer) ( + struct efi_pci_io_protocol *this, + size_t npages, + void *hostaddr +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_flush) ( + struct efi_pci_root_bridge_io_protocol *this +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_flush) ( + struct efi_pci_io_protocol *this +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_get_location) ( + struct efi_pci_io_protocol *this, + size_t *segmentno, + size_t *busno, + size_t *deveno, + size_t *funcno +); + +enum efi_io_protocol_attribute_operation { + PCI_IO_ATTR_OP_GET, + PCI_IO_ATTR_OP_SET, + PCI_IO_ATTR_OP_ENABLE, + PCI_IO_ATTR_OP_DISABLE, + PCI_IO_ATTR_OP_SUPPORTED, + PCI_IO_ATTR_OP_MAX, +}; + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_attributes) ( + struct efi_pci_io_protocol *this, + enum efi_io_protocol_attribute_operation operation, + u64 attrs, + u64 *result +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_get_attributes) ( + struct efi_pci_root_bridge_io_protocol *this, + u64 *supports, + u64 *attrs +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_get_bar_attributes) ( + struct efi_pci_io_protocol *this, + u8 bar, + u64 *supports, + void **resources +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_set_attributes) ( + struct efi_pci_root_bridge_io_protocol *this, + u64 attrs, + u64 *resource_base, + u64 *resource_len +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_set_bar_attributes) ( + struct efi_pci_io_protocol *this, + u64 attrs, + u8 bar, + u64 *offset, + u64 *len +); + +typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_configuration) ( + struct efi_pci_root_bridge_io_protocol *this, + void **resources +); + +typedef efi_status_t (EFIAPI *efi_pci_io_protocol_config) ( + struct efi_pci_io_protocol *this, + enum efi_pci_protocol_width width, + u32 offset, + size_t count, + void *buffer +); + +struct efi_pci_io_protocol_config_access { + efi_pci_io_protocol_config read; + efi_pci_io_protocol_config write; +}; + +struct __packed efi_acpi_resource { +#define ACPI_RESOURCE_DESC_TAG 0x8A +#define ACPI_RESOURCE_END_TAG 0x79 + u8 asd; /* 0x8A */ + u16 len; /* 0x2B */ +#define ACPI_RESOURCE_TYPE_MEM 0 +#define ACPI_RESOURCE_TYPE_IO 1 +#define ACPI_RESOURCE_TYPE_BUSNO 2 + u8 restype; + u8 genflags; +#define ACPI_RESOURCE_TYPFLAG_TTP_MASK 0b00100000 +#define ACPI_RESOURCE_TYPFLAG_MTP_MASK 0b00011000 +#define ACPI_RESOURCE_TYPFLAG_MTP_MEM 0 +#define ACPI_RESOURCE_TYPFLAG_MTP_RESERVED 1 +#define ACPI_RESOURCE_TYPFLAG_MTP_ACPI 2 +#define ACPI_RESOURCE_TYPFLAG_MTP_NVS 3 +#define ACPI_RESOURCE_TYPFLAG_MEM_MASK 0b00000110 +#define ACPI_RESOURCE_TYPFLAG_MEM_NONCACHEABLE 0 +#define ACPI_RESOURCE_TYPFLAG_MEM_CACHEABLE 1 +#define ACPI_RESOURCE_TYPFLAG_MEM_WC 2 +#define ACPI_RESOURCE_TYPFLAG_MEM_PREF 3 +#define ACPI_RESOURCE_TYPFLAG_RW_MASK 0b00000001 + u8 typflags; + u64 addr_granularity; + u64 addr_min; + u64 addr_max; + u64 addr_xlate_off; + u64 addr_len; +}; + +struct efi_pci_root_bridge_io_protocol { + efi_handle_t parent_handle; + efi_pci_root_bridge_io_protocol_poll_io_mem poll_mem; + efi_pci_root_bridge_io_protocol_poll_io_mem poll_io; + struct efi_pci_root_bridge_io_protocol_access mem; + struct efi_pci_root_bridge_io_protocol_access io; + struct efi_pci_root_bridge_io_protocol_access pci; + efi_pci_root_bridge_io_protocol_copy_mem copy_mem; + efi_pci_root_bridge_io_protocol_map map; + efi_pci_root_bridge_io_protocol_unmap unmap; + efi_pci_root_bridge_io_protocol_allocate_buffer allocate_buffer; + efi_pci_root_bridge_io_protocol_free_buffer free_buffer; + efi_pci_root_bridge_io_protocol_flush flush; + efi_pci_root_bridge_io_protocol_get_attributes get_attributes; + efi_pci_root_bridge_io_protocol_set_attributes set_attributes; + efi_pci_root_bridge_io_protocol_configuration configuration; + u32 segmentno; +}; + +struct efi_pci_io_protocol { + efi_pci_io_protocol_poll_io_mem poll_mem; + efi_pci_io_protocol_poll_io_mem poll_io; + struct efi_pci_io_protocol_access mem; + struct efi_pci_io_protocol_access io; + struct efi_pci_io_protocol_access pci; + efi_pci_io_protocol_copy_mem copy_mem; + efi_pci_io_protocol_map map; + efi_pci_io_protocol_unmap unmap; + efi_pci_io_protocol_allocate_buffer allocate_buffer; + efi_pci_io_protocol_free_buffer free_buffer; + efi_pci_io_protocol_flush flush; + efi_pci_io_protocol_get_location get_location; + efi_pci_io_protocol_attributes attributes; + efi_pci_io_protocol_get_bar_attributes get_bar_attributes; + efi_pci_io_protocol_set_bar_attributes set_bar_attributes; + u64 rom_size; + void *rom_image; +}; + +#define EFI_PCI_ADDRESS(bus, dev, func, reg) \ + (u64) ( \ + (((size_t) bus) << 24) | \ + (((size_t) dev) << 16) | \ + (((size_t) func) << 8) | \ + (((size_t) (reg)) < 256 ? ((size_t) (reg)) : ((u64)(reg)) << 32)) + +#endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 945a983387..950c509447 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -51,25 +51,27 @@ void register_pci_controller(struct pci_controller *hose) bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource; bus->resource[PCI_BUS_RESOURCE_MEM_PREF] = hose->mem_pref_resource; bus->resource[PCI_BUS_RESOURCE_IO] = hose->io_resource; - bus->number = bus_index++; - if (hose->set_busno) - hose->set_busno(hose, bus->number); - - if (bus->resource[PCI_BUS_RESOURCE_MEM]) - last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start; - else - last_mem = 0; - - if (bus->resource[PCI_BUS_RESOURCE_MEM_PREF]) - last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start; - else - last_mem_pref = 0; - - if (bus->resource[PCI_BUS_RESOURCE_IO]) - last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start; - else - last_io = 0; + if (pcibios_assign_all_busses()) { + bus->number = bus_index++; + if (hose->set_busno) + hose->set_busno(hose, bus->number); + + if (bus->resource[PCI_BUS_RESOURCE_MEM]) + last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start; + else + last_mem = 0; + + if (bus->resource[PCI_BUS_RESOURCE_MEM_PREF]) + last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start; + else + last_mem_pref = 0; + + if (bus->resource[PCI_BUS_RESOURCE_IO]) + last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start; + else + last_io = 0; + } pci_scan_bus(bus); pci_bus_register_devices(bus); @@ -156,13 +158,16 @@ static void setup_device(struct pci_dev *dev, int max_bar) u8 cmd; pci_read_config_byte(dev, PCI_COMMAND, &cmd); - pci_write_config_byte(dev, PCI_COMMAND, - cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + + if (pcibios_assign_all_busses()) + pci_write_config_byte(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for (bar = 0; bar < max_bar; bar++) { const int pci_base_address_0 = PCI_BASE_ADDRESS_0 + bar * 4; const int pci_base_address_1 = PCI_BASE_ADDRESS_1 + bar * 4; - resource_size_t *last_addr; + resource_size_t *last_addr, start; u32 orig, mask, size; unsigned long flags; const char *kind; @@ -207,32 +212,47 @@ static void setup_device(struct pci_dev *dev, int max_bar) pr_debug("pbar%d: mask=%08x %s %d bytes\n", bar, mask, kind, size); - if (ALIGN(*last_addr, size) + size > - dev->bus->resource[busres]->end) { - pr_debug("BAR does not fit within bus %s res\n", kind); - return; + if (pcibios_assign_all_busses()) { + if (ALIGN(*last_addr, size) + size > + dev->bus->resource[busres]->end) { + pr_debug("BAR does not fit within bus %s res\n", kind); + return; + } + + *last_addr = ALIGN(*last_addr, size); + pci_write_config_dword(dev, pci_base_address_0, *last_addr); + if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) + pci_write_config_dword(dev, pci_base_address_1, 0); + start = *last_addr; + *last_addr += size; + } else { + u32 tmp; + pci_read_config_dword(dev, pci_base_address_0, &tmp); + tmp &= mask & PCI_BASE_ADDRESS_SPACE_IO ? PCI_BASE_ADDRESS_IO_MASK + : PCI_BASE_ADDRESS_MEM_MASK; + start = tmp; + + if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(dev, pci_base_address_1, &tmp); + start |= (u64)tmp << 32; + } } - *last_addr = ALIGN(*last_addr, size); - pci_write_config_dword(dev, pci_base_address_0, *last_addr); dev->resource[bar].flags = flags; - dev->resource[bar].start = *last_addr; - dev->resource[bar].end = dev->resource[bar].start + size - 1; - - pr_debug("pbar%d: allocated at %pa\n", bar, last_addr); - - *last_addr += size; + dev->resource[bar].start = start; + dev->resource[bar].end = start + size - 1; if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) { dev->resource[bar].flags |= IORESOURCE_MEM_64; - pci_write_config_dword(dev, pci_base_address_1, 0); bar++; } } pci_fixup_device(pci_fixup_header, dev); - pci_write_config_byte(dev, PCI_COMMAND, cmd); + if (pcibios_assign_all_busses()) + pci_write_config_byte(dev, PCI_COMMAND, cmd); + list_add_tail(&dev->bus_list, &dev->bus->devices); } @@ -240,6 +260,12 @@ static void prescan_setup_bridge(struct pci_dev *dev) { u16 cmdstat; + if (!pcibios_assign_all_busses()) { + pci_read_config_byte(dev, PCI_PRIMARY_BUS, &dev->bus->number); + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &dev->subordinate->number); + return; + } + pci_read_config_word(dev, PCI_COMMAND, &cmdstat); /* Configure bus number registers */ @@ -283,6 +309,9 @@ static void prescan_setup_bridge(struct pci_dev *dev) static void postscan_setup_bridge(struct pci_dev *dev) { + if (!pcibios_assign_all_busses()) + return; + /* limit subordinate to last used bus number */ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, bus_index - 1); @@ -416,8 +445,11 @@ static unsigned int pci_scan_bus(struct pci_bus *bus) bus->resource[PCI_BUS_RESOURCE_IO]; child_bus->parent = &dev->dev; - child_bus->number = bus_index++; - child_bus->primary = bus->number; + + if (pcibios_assign_all_busses()) { + child_bus->number = bus_index++; + child_bus->primary = bus->number; + } list_add_tail(&child_bus->node, &bus->children); dev->subordinate = child_bus; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index df85a227ac..b785181c59 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -124,4 +124,21 @@ config GPIO_WATCHDOG If you say yes here you get support for watchdog device controlled through GPIO-line. +config ITCO_WDT + bool "Intel TCO Timer/Watchdog" + depends on X86 + depends on PCI + help + Hardware driver for the intel TCO timer based watchdog devices. + These drivers are included in the Intel 82801 I/O Controller + Hub family (from ICH0 up to ICH10) and in the Intel 63xxESB + controller hub. + + The TCO (Total Cost of Ownership) timer is a watchdog timer + that will reboot the machine after its second expiration. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. + endif diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e88da0adaf..0b598af402 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o +obj-$(CONFIG_ITCO_WDT) += itco_wdt.o diff --git a/drivers/watchdog/itco_wdt.c b/drivers/watchdog/itco_wdt.c new file mode 100644 index 0000000000..e7bd0fc99b --- /dev/null +++ b/drivers/watchdog/itco_wdt.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * EFI Boot Guard, iTCO support (Version 3 and later) + * + * Copyright (c) 2006-2011 Wim Van Sebroeck <wim@iguana.be>. + * Copyright (c) 2019 Siemens AG + * Copyright (c) 2019 Ahmad Fatoum, Pengutronix + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * Christian Storm <christian.storm@siemens.com> + */ + +#include <common.h> +#include <init.h> +#include <efi.h> +#include <linux/pci.h> +#include <watchdog.h> + +#define ACPIBASE 0x40 +#define ACPICTRL_PMCBASE 0x44 + +#define PMBASE_ADDRMASK 0x0000ff80 +#define PMCBASE_ADDRMASK 0xfffffe00 + +#define ACPIBASE_GCS_OFF 0x3410 + +#define ACPIBASE_SMI_OFF 0x30 +#define ACPIBASE_SMI_END 0x33 +#define ACPIBASE_PMC_OFF 0x08 +#define ACPIBASE_PMC_END 0x0c +#define ACPIBASE_TCO_OFF 0x60 +#define ACPIBASE_TCO_END 0x7f + +#define SMI_TCO_MASK (1 << 13) + +#define TCO_TMR_HLT_MASK (1 << 11) + +/* SMI Control and Enable Register */ +#define SMI_EN(itco) ((itco)->smibase) +/* TCO base address */ +#define TCOBASE(itco) ((itco)->tcobase) + +#define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */ +#define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/ +#define TCO_DAT_IN(p) (TCOBASE(p) + 0x02) /* TCO Data In Register */ +#define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register */ +#define TCO1_STS(p) (TCOBASE(p) + 0x04) /* TCO1 Status Register */ +#define TCO2_STS(p) (TCOBASE(p) + 0x06) /* TCO2 Status Register */ +#define TCO1_CNT(p) (TCOBASE(p) + 0x08) /* TCO1 Control Register */ +#define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */ +#define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/ + +#define PMC_NO_REBOOT_MASK (1 << 4) + +#define RCBABASE 0xf0 + +#define PCI_ID_ITCO_INTEL_ICH9 0x2918 + +struct itco_priv; + +struct itco_info { + u32 pci_id; + const char *name; + u32 pmbase; + u32 smireg; + int (*update_no_reboot_bit)(struct itco_priv *itco, bool set); + unsigned version; +}; + +struct itco_priv { + struct pci_dev *pdev; + struct watchdog wdd; + void __iomem *io; + u32 smibase; + u32 tcobase; + void __iomem *gcs_pmc; + struct itco_info *info; + unsigned timeout; +}; + +static u32 itco_get_pmbase(struct itco_priv *itco) +{ + u32 pmbase = itco->info->pmbase; + + if (!pmbase) + pci_read_config_dword(itco->pdev, ACPIBASE, &pmbase); + + return pmbase & PMBASE_ADDRMASK; +} + +static inline struct itco_priv *to_itco_priv(struct watchdog *wdd) +{ + return container_of(wdd, struct itco_priv, wdd); +} + +static void itco_wdt_ping(struct itco_priv *itco) +{ + /* Reload the timer by writing to the TCO Timer Counter register */ + outw(0x0001, TCO_RLD(itco)); +} + +static inline unsigned int seconds_to_ticks(struct itco_priv *itco, int secs) +{ + return itco->info->version == 3 ? secs : (secs * 10) / 6; +} + +static inline unsigned int ticks_to_seconds(struct itco_priv *itco, int ticks) +{ + return itco->info->version == 3 ? ticks : (ticks * 6) / 10; +} + + +static int itco_wdt_start(struct itco_priv *itco, unsigned int timeout) +{ + unsigned tmrval; + u32 value; + int ret; + + tmrval = seconds_to_ticks(itco, timeout); + + /* Enable TCO SMIs */ + value = inl(SMI_EN(itco)) | SMI_TCO_MASK; + outl(value, SMI_EN(itco)); + + /* Set timer value */ + value = inw(TCOv2_TMR(itco)); + + value &= 0xfc00; + value |= tmrval & 0x3ff; + + outw(value, TCOv2_TMR(itco)); + value = inw(TCOv2_TMR(itco)); + + if ((value & 0x3ff) != tmrval) + return -EINVAL; + + /* Force reloading of timer value */ + outw(1, TCO_RLD(itco)); + + /* Clear NO_REBOOT flag */ + ret = itco->info->update_no_reboot_bit(itco, false); + if (ret) + return ret; + + /* Clear HLT flag to start timer */ + value = inw(TCO1_CNT(itco)) & ~TCO_TMR_HLT_MASK; + outw(value, TCO1_CNT(itco)); + value = inw(TCO1_CNT(itco)); + + if (value & 0x0800) + return -EIO; + + return 0; +} + +static int itco_wdt_stop(struct itco_priv *itco) +{ + u32 val; + + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ + val = inw(TCO1_CNT(itco)) | 0x0800; + outw(val, TCO1_CNT(itco)); + val = inb(TCO1_CNT(itco)); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + itco->info->update_no_reboot_bit(itco, true); + + if ((val & 0x0800) == 0) + return -EIO; + return 0; +} + +static int itco_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) +{ + struct itco_priv *itco = to_itco_priv(wdd); + int ret; + + if (!timeout) + return itco_wdt_stop(itco); + + /* from the specs: */ + /* "Values of 0h-3h are ignored and should not be attempted" */ + if (timeout < 0x04) + return -EINVAL; + + if (itco->timeout != timeout) { + ret = itco_wdt_start(itco, timeout); + if (ret) { + dev_err(wdd->hwdev, "Fail to (re)start watchdog\n"); + return ret; + } + } + + itco_wdt_ping(itco); + return 0; +} + +static inline u32 no_reboot_bit(unsigned version) +{ + u32 enable_bit; + + switch (version) { + case 5: + case 3: + enable_bit = 0x00000010; + break; + case 2: + enable_bit = 0x00000020; + break; + case 4: + case 1: + default: + enable_bit = 0x00000002; + break; + } + + return enable_bit; +} + + +static int update_no_reboot_bit(struct itco_priv *itco, bool set) +{ + u32 val32 = 0, newval32 = 0; + + val32 = readl(itco->gcs_pmc); + if (set) + val32 |= no_reboot_bit(itco->info->version); + else + val32 &= ~no_reboot_bit(itco->info->version); + writel(val32, itco->gcs_pmc); + newval32 = readl(itco->gcs_pmc); + + /* make sure the update is successful */ + if (val32 != newval32) + return -EPERM; + + return 0; +} + +static void lpc_ich_enable_acpi_space(struct itco_priv *itco) +{ + u8 reg_save; + + pci_read_config_byte(itco->pdev, ACPICTRL_PMCBASE, ®_save); + pci_write_config_byte(itco->pdev, ACPICTRL_PMCBASE, reg_save | 0x80); +} + +enum itco_chipsets { + ITCO_INTEL_ICH9, +}; + +/* version 1 not supported! */ +static struct itco_info itco_chipset_info[] = { + [ITCO_INTEL_ICH9] = { + .pci_id = PCI_ID_ITCO_INTEL_ICH9, + .name = "ICH9", /* QEmu machine q35 */ + .smireg = 0x30, + .update_no_reboot_bit = update_no_reboot_bit, + .version = 2, + }, +}; + +static int itco_wdt_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct itco_priv *itco; + struct watchdog *wdd; + u32 rcba_base_cfg; + u32 pmbase; + int ret; + int i; + + pci_enable_device(pdev); + pci_set_master(pdev); + + itco = xzalloc(sizeof(*itco)); + + itco->pdev = pdev; + + for (i = 0; i < ARRAY_SIZE(itco_chipset_info); i++) { + if (id->device == itco_chipset_info[i].pci_id) { + itco->info = &itco_chipset_info[i]; + break; + } + } + + if (!itco->info) + return -ENODEV; + + + pci_read_config_dword(itco->pdev, RCBABASE, &rcba_base_cfg); + if (!(rcba_base_cfg & 1)) { + dev_notice(&pdev->dev, "RCBA is disabled by hardware/BIOS, device disabled\n"); + return -ENODEV; + } + + pmbase = itco_get_pmbase(itco); + if (!pmbase) { + dev_notice(&itco->pdev->dev, "I/O space for ACPI uninitialized\n"); + return -ENODEV; + } + + itco->smibase = pmbase + ACPIBASE_SMI_OFF; + itco->tcobase = pmbase + ACPIBASE_TCO_OFF; + + lpc_ich_enable_acpi_space(itco); + + itco->gcs_pmc = IOMEM(rcba_base_cfg & 0xffffc000UL) + ACPIBASE_GCS_OFF; + + + dev_notice(&pdev->dev, "gcs_pmc = 0x%p, smibase = 0x%x, tcobase = 0x%x\n", + itco->gcs_pmc, itco->smibase, itco->tcobase); + + wdd = &itco->wdd; + wdd->hwdev = &pdev->dev; + wdd->set_timeout = itco_wdt_set_timeout; + + wdd->timeout_max = ticks_to_seconds(itco, 0x3ff); + + outw(0x0008, TCO1_STS(itco)); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS(itco)); /* Clear SECOND_TO_STS bit */ + outw(0x0004, TCO2_STS(itco)); /* Clear BOOT_STS bit */ + + ret = watchdog_register(wdd); + if (ret) { + dev_err(&pdev->dev, "Failed to register watchdog device\n"); + return ret; + } + + dev_info(&pdev->dev, "probed Intel TCO %s watchdog\n", itco->info->name); + + return 0; +} + + +static DEFINE_PCI_DEVICE_TABLE(itco_wdt_pci_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ID_ITCO_INTEL_ICH9) }, + { /* sentinel */ }, +}; + +static struct pci_driver itco_wdt_driver = { + .name = "itco_wdt", + .id_table = itco_wdt_pci_tbl, + .probe = itco_wdt_probe, +}; +device_pci_driver(itco_wdt_driver); diff --git a/include/linux/pci.h b/include/linux/pci.h index 0c8fed7c8e..486d4251d4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -29,6 +29,9 @@ #include <linux/pci_ids.h> +/* Include architecture-dependent settings and functions */ + +#include <asm/pci.h> #define PCI_ANY_ID (~0) #define PCI_FIND_CAP_TTL 48 |