linux/arch/x86/pci/broadcom_bus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Read address ranges from a Broadcom CNB20LE Host Bridge
   4 *
   5 * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
   6 */
   7
   8#include <linux/acpi.h>
   9#include <linux/delay.h>
  10#include <linux/dmi.h>
  11#include <linux/pci.h>
  12#include <linux/init.h>
  13#include <asm/pci_x86.h>
  14#include <asm/pci-direct.h>
  15
  16#include "bus_numa.h"
  17
  18static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
  19{
  20        struct pci_root_info *info;
  21        struct pci_root_res *root_res;
  22        struct resource res;
  23        u16 word1, word2;
  24        u8 fbus, lbus;
  25
  26        /* read the PCI bus numbers */
  27        fbus = read_pci_config_byte(bus, slot, func, 0x44);
  28        lbus = read_pci_config_byte(bus, slot, func, 0x45);
  29        info = alloc_pci_root_info(fbus, lbus, 0, 0);
  30
  31        /*
  32         * Add the legacy IDE ports on bus 0
  33         *
  34         * These do not exist anywhere in the bridge registers, AFAICT. I do
  35         * not have the datasheet, so this is the best I can do.
  36         */
  37        if (fbus == 0) {
  38                update_res(info, 0x01f0, 0x01f7, IORESOURCE_IO, 0);
  39                update_res(info, 0x03f6, 0x03f6, IORESOURCE_IO, 0);
  40                update_res(info, 0x0170, 0x0177, IORESOURCE_IO, 0);
  41                update_res(info, 0x0376, 0x0376, IORESOURCE_IO, 0);
  42                update_res(info, 0xffa0, 0xffaf, IORESOURCE_IO, 0);
  43        }
  44
  45        /* read the non-prefetchable memory window */
  46        word1 = read_pci_config_16(bus, slot, func, 0xc0);
  47        word2 = read_pci_config_16(bus, slot, func, 0xc2);
  48        if (word1 != word2) {
  49                res.start = ((resource_size_t) word1 << 16) | 0x0000;
  50                res.end   = ((resource_size_t) word2 << 16) | 0xffff;
  51                res.flags = IORESOURCE_MEM;
  52                update_res(info, res.start, res.end, res.flags, 0);
  53        }
  54
  55        /* read the prefetchable memory window */
  56        word1 = read_pci_config_16(bus, slot, func, 0xc4);
  57        word2 = read_pci_config_16(bus, slot, func, 0xc6);
  58        if (word1 != word2) {
  59                res.start = ((resource_size_t) word1 << 16) | 0x0000;
  60                res.end   = ((resource_size_t) word2 << 16) | 0xffff;
  61                res.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
  62                update_res(info, res.start, res.end, res.flags, 0);
  63        }
  64
  65        /* read the IO port window */
  66        word1 = read_pci_config_16(bus, slot, func, 0xd0);
  67        word2 = read_pci_config_16(bus, slot, func, 0xd2);
  68        if (word1 != word2) {
  69                res.start = word1;
  70                res.end   = word2;
  71                res.flags = IORESOURCE_IO;
  72                update_res(info, res.start, res.end, res.flags, 0);
  73        }
  74
  75        /* print information about this host bridge */
  76        res.start = fbus;
  77        res.end   = lbus;
  78        res.flags = IORESOURCE_BUS;
  79        printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res);
  80
  81        list_for_each_entry(root_res, &info->resources, list)
  82                printk(KERN_INFO "host bridge window %pR\n", &root_res->res);
  83}
  84
  85static int __init broadcom_postcore_init(void)
  86{
  87        u8 bus = 0, slot = 0;
  88        u32 id;
  89        u16 vendor, device;
  90
  91#ifdef CONFIG_ACPI
  92        /*
  93         * We should get host bridge information from ACPI unless the BIOS
  94         * doesn't support it.
  95         */
  96        if (!acpi_disabled && acpi_os_get_root_pointer())
  97                return 0;
  98#endif
  99
 100        id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
 101        vendor = id & 0xffff;
 102        device = (id >> 16) & 0xffff;
 103
 104        if (vendor == PCI_VENDOR_ID_SERVERWORKS &&
 105            device == PCI_DEVICE_ID_SERVERWORKS_LE) {
 106                cnb20le_res(bus, slot, 0);
 107                cnb20le_res(bus, slot, 1);
 108        }
 109        return 0;
 110}
 111
 112postcore_initcall(broadcom_postcore_init);
 113