From: Jun Sun <jsun@mvista.com>
To: "Bradley D. LaRonde" <brad@ltc.com>
Cc: linux-mips@oss.sgi.com, linux-mips-kernel@lists.sourceforge.net
Subject: Re: PATCH: pci_auto bridge support
Date: Mon, 29 Oct 2001 11:24:02 -0800 [thread overview]
Message-ID: <3BDDACD2.7121F905@mvista.com> (raw)
In-Reply-To: 20011026210746.A20395@dev1.ltc.com
Brad,
Have you considered embedding "topbus" argument into hose structure? That
sounds like potentially better solution.
"Bradley D. LaRonde" wrote:
>
> 2001-10-26 Bradley D. LaRonde <brad@ltc.com>
>
> * PCI bridge support. See change log entry below.
>
> --- arch/mips/kernel/pci_auto.c 2001/08/18 06:21:53 1.1
> +++ arch/mips/kernel/pci_auto.c 2001/10/27 01:01:21
> @@ -4,6 +4,7 @@
> * Author: Matt Porter <mporter@mvista.com>
> *
> * Copyright 2000, 2001 MontaVista Software Inc.
> + * Copyright 2001 Bradley D. LaRonde <brad@ltc.com>
> *
> * This program is free software; you can redistribute it and/or modify it
> * under the terms of the GNU General Public License as published by the
> @@ -19,6 +20,15 @@
> * . change most int to u32.
> *
> * Further modified to include it as mips generic code, ppopov@mvista.com.
> + *
> + * 2001-10-26 Bradley D. LaRonde <brad@ltc.com>
> + * - Add a top_bus argument to the "early config" functions so that
> + * they can set a fake parent bus pointer to convince the underlying
> + * pci ops to use type 1 configuration for sub busses.
> + * - Set bridge base and limit registers correctly.
> + * - Align io and memory base properly before and after bridge setup.
> + * - Don't fall through to pci_setup_bars for bridge.
> + * - Reformat the debug output to look more like lspci's output.
> */
>
> #include <linux/kernel.h>
> @@ -34,14 +44,47 @@
> #else
> #define DBG(x...)
> #endif
> +
> +/*
> + * These functions are used early on before PCI scanning is done
> + * and all of the pci_dev and pci_bus structures have been created.
> + */
> +static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
> + int top_bus, int busnr, int devfn)
> +{
> + static struct pci_dev dev;
> + static struct pci_bus bus;
> +
> + dev.bus = &bus;
> + dev.sysdata = hose;
> + dev.devfn = devfn;
> + bus.number = busnr;
> + bus.ops = hose->pci_ops;
> +
> + if(busnr != top_bus)
> + /* Fake a parent bus structure. */
> + bus.parent = &bus;
> + else
> + bus.parent = NULL;
> +
> + return &dev;
> +}
> +
> +#define EARLY_PCI_OP(rw, size, type) \
> +int early_##rw##_config_##size(struct pci_channel *hose, \
> + int top_bus, int bus, int devfn, int offset, type value) \
> +{ \
> + return pci_##rw##_config_##size( \
> + fake_pci_dev(hose, top_bus, bus, devfn), \
> + offset, value); \
> +}
>
> -/* These are used for config access before all the PCI probing has been done. */
> -int early_read_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 *val);
> -int early_read_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 *val);
> -int early_read_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 *val);
> -int early_write_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 val);
> -int early_write_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 val);
> -int early_write_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 val);
> +EARLY_PCI_OP(read, byte, u8 *)
> +EARLY_PCI_OP(read, word, u16 *)
> +EARLY_PCI_OP(read, dword, u32 *)
> +EARLY_PCI_OP(write, byte, u8)
> +EARLY_PCI_OP(write, word, u16)
> +EARLY_PCI_OP(write, dword, u32)
>
> static u32 pciauto_lower_iospc;
> static u32 pciauto_upper_iospc;
> @@ -51,6 +94,7 @@
>
> void __init
> pciauto_setup_bars(struct pci_channel *hose,
> + int top_bus,
> int current_bus,
> int pci_devfn)
> {
> @@ -60,17 +104,14 @@
> u32 * lower_limit;
> int found_mem64 = 0;
>
> - DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
> - current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
> -
> for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) {
> /* Tickle the BAR and get the response */
> - early_write_config_dword(hose,
> + early_write_config_dword(hose, top_bus,
> current_bus,
> pci_devfn,
> bar,
> 0xffffffff);
> - early_read_config_dword(hose,
> + early_read_config_dword(hose, top_bus,
> current_bus,
> pci_devfn,
> bar,
> @@ -80,12 +121,20 @@
> if (!bar_response)
> continue;
>
> + /*
> + * Workaround for a BAR that doesn't use its upper word,
> + * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457).
> + * bdl <brad@ltc.com>
> + */
> + if (!(bar_response & 0xffff0000))
> + bar_response |= 0xffff0000;
> +
> /* Check the BAR type and set our address mask */
> if (bar_response & PCI_BASE_ADDRESS_SPACE) {
> addr_mask = PCI_BASE_ADDRESS_IO_MASK;
> upper_limit = &pciauto_upper_iospc;
> lower_limit = &pciauto_lower_iospc;
> - DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr);
> + DBG(" I/O");
> } else {
> if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
> PCI_BASE_ADDRESS_MEM_TYPE_64)
> @@ -94,7 +143,7 @@
> addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
> upper_limit = &pciauto_upper_memspc;
> lower_limit = &pciauto_lower_memspc;
> - DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr);
> + DBG(" Mem");
> }
>
> /* Calculate requested size */
> @@ -104,7 +153,7 @@
> bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size;
>
> /* Write it out and update our limit */
> - early_write_config_dword(hose, current_bus, pci_devfn,
> + early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
> bar, bar_value);
>
> *lower_limit = bar_value + bar_size;
> @@ -116,97 +165,99 @@
> */
> if (found_mem64) {
> bar += 4;
> - early_write_config_dword(hose,
> + early_write_config_dword(hose, top_bus,
> current_bus,
> pci_devfn,
> bar,
> 0x00000000);
> }
>
> - bar_nr++;
> + DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size);
>
> - DBG("size=0x%x, address=0x%x\n",
> - bar_size, bar_value);
> + bar_nr++;
> }
>
> }
>
> void __init
> pciauto_prescan_setup_bridge(struct pci_channel *hose,
> + int top_bus,
> int current_bus,
> int pci_devfn,
> int sub_bus)
> {
> - int cmdstat;
> -
> /* Configure bus number registers */
> - early_write_config_byte(hose, current_bus, pci_devfn,
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_PRIMARY_BUS, current_bus);
> - early_write_config_byte(hose, current_bus, pci_devfn,
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_SECONDARY_BUS, sub_bus + 1);
> - early_write_config_byte(hose, current_bus, pci_devfn,
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_SUBORDINATE_BUS, 0xff);
> -
> - /* Round memory allocator to 1MB boundary */
> - pciauto_upper_memspc &= ~(0x100000 - 1);
>
> - /* Round I/O allocator to 4KB boundary */
> - pciauto_upper_iospc &= ~(0x1000 - 1);
> + /* Align memory and I/O to 1MB and 4KB boundaries. */
> + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
> + & ~(0x100000 - 1);
> + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
> + & ~(0x1000 - 1);
> +
> + /* Set base (lower limit) of address range behind bridge. */
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_MEMORY_BASE, pciauto_lower_memspc >> 16);
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> + PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8);
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16);
>
> - /* Set up memory and I/O filter limits, assume 32-bit I/O space */
> - early_write_config_word(hose, current_bus, pci_devfn, PCI_MEMORY_LIMIT,
> - ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
> - early_write_config_byte(hose, current_bus, pci_devfn, PCI_IO_LIMIT,
> - ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
> - early_write_config_word(hose, current_bus, pci_devfn,
> - PCI_IO_LIMIT_UPPER16,
> - ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
> -
> /* We don't support prefetchable memory for now, so disable */
> - early_write_config_word(hose, current_bus, pci_devfn,
> - PCI_PREF_MEMORY_BASE, 0x1000);
> - early_write_config_word(hose, current_bus, pci_devfn,
> - PCI_PREF_MEMORY_LIMIT, 0x1000);
> -
> - /* Enable memory and I/O accesses, enable bus master */
> - early_read_config_dword(hose, current_bus, pci_devfn, PCI_COMMAND,
> - &cmdstat);
> - early_write_config_dword(hose, current_bus, pci_devfn, PCI_COMMAND,
> - cmdstat | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> - PCI_COMMAND_MASTER);
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_PREF_MEMORY_BASE, 0);
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_PREF_MEMORY_LIMIT, 0);
> }
>
> void __init
> pciauto_postscan_setup_bridge(struct pci_channel *hose,
> + int top_bus,
> int current_bus,
> int pci_devfn,
> int sub_bus)
> {
> + u32 temp;
> +
> /* Configure bus number registers */
> - early_write_config_byte(hose, current_bus, pci_devfn,
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_SUBORDINATE_BUS, sub_bus);
>
> - /* Round memory allocator to 1MB boundary */
> - pciauto_upper_memspc &= ~(0x100000 - 1);
> - early_write_config_word(hose, current_bus, pci_devfn, PCI_MEMORY_BASE,
> - pciauto_upper_memspc >> 16);
> -
> - /* Round I/O allocator to 4KB boundary */
> - pciauto_upper_iospc &= ~(0x1000 - 1);
> - early_write_config_byte(hose, current_bus, pci_devfn, PCI_IO_BASE,
> - (pciauto_upper_iospc & 0x0000f000) >> 8);
> - early_write_config_word(hose, current_bus, pci_devfn,
> - PCI_IO_BASE_UPPER16, pciauto_upper_iospc >> 16);
> + /* Set upper limit of address range behind bridge. */
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16);
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> + PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8);
> + early_write_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16);
> +
> + /* Align memory and I/O to 1MB and 4KB boundaries. */
> + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
> + & ~(0x100000 - 1);
> + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
> + & ~(0x1000 - 1);
> +
> + /* Enable memory and I/O accesses, enable bus master */
> + early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
> + PCI_COMMAND, &temp);
> + early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
> + PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
> + | PCI_COMMAND_MASTER);
> }
>
> #define PCIAUTO_IDE_MODE_MASK 0x05
>
> int __init
> -pciauto_bus_scan(struct pci_channel *hose, int current_bus)
> +pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
> {
> int sub_bus;
> u32 pci_devfn, pci_class, cmdstat, found_multi=0;
> - unsigned short vid;
> + unsigned short vid, did;
> unsigned char header_type;
> int devfn_start = 0;
> int devfn_stop = 0xff;
> @@ -223,54 +274,70 @@
> if (PCI_FUNC(pci_devfn) && !found_multi)
> continue;
>
> - early_read_config_byte(hose, current_bus, pci_devfn,
> + early_read_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_VENDOR_ID, &vid);
> +
> + if (vid == 0xffff) continue;
> +
> + early_read_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_HEADER_TYPE, &header_type);
>
> if (!PCI_FUNC(pci_devfn))
> found_multi = header_type & 0x80;
>
> - early_read_config_word(hose, current_bus, pci_devfn,
> - PCI_VENDOR_ID, &vid);
> + early_read_config_word(hose, top_bus, current_bus, pci_devfn,
> + PCI_DEVICE_ID, &did);
>
> - if (vid == 0xffff) continue;
> -
> - early_read_config_dword(hose, current_bus, pci_devfn,
> + early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
> PCI_CLASS_REVISION, &pci_class);
> +
> + DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x",
> + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn),
> + pci_class >> 16, vid, did);
> + if (pci_class & 0xff)
> + DBG(" (rev %.2x)", pci_class & 0xff);
> + DBG("\n");
> +
> if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
> - DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
> - pciauto_prescan_setup_bridge(hose, current_bus,
> + DBG(" Bridge: primary=%.2x, secondary=%.2x\n",
> + current_bus, sub_bus + 1);
> + pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
> pci_devfn, sub_bus);
> - sub_bus = pciauto_bus_scan(hose, sub_bus+1);
> - pciauto_postscan_setup_bridge(hose, current_bus,
> + DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
> + sub_bus + 1,
> + pciauto_lower_iospc, pciauto_lower_memspc);
> + sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
> + DBG("Back to bus %.2x\n", current_bus);
> + pciauto_postscan_setup_bridge(hose, top_bus, current_bus,
> pci_devfn, sub_bus);
> -
> + continue;
> } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
>
> unsigned char prg_iface;
>
> - early_read_config_byte(hose, current_bus, pci_devfn,
> - PCI_CLASS_PROG, &prg_iface);
> + early_read_config_byte(hose, top_bus, current_bus,
> + pci_devfn, PCI_CLASS_PROG, &prg_iface);
> if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
> - DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
> + DBG("Skipping legacy mode IDE controller\n");
> continue;
> }
> }
>
> - /*
> + /*
> * Found a peripheral, enable some standard
> * settings
> */
> - early_read_config_dword(hose, current_bus, pci_devfn,
> + early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
> PCI_COMMAND, &cmdstat);
> - early_write_config_dword(hose, current_bus, pci_devfn,
> + early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
> PCI_COMMAND, cmdstat | PCI_COMMAND_IO |
> PCI_COMMAND_MEMORY |
> PCI_COMMAND_MASTER);
> - early_write_config_byte(hose, current_bus, pci_devfn,
> + early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
> PCI_LATENCY_TIMER, 0x80);
>
> /* Allocate PCI I/O and/or memory space */
> - pciauto_setup_bars(hose, current_bus, pci_devfn);
> + pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn);
> }
> return sub_bus;
> }
> @@ -283,41 +350,9 @@
> pciauto_upper_iospc = hose->io_resource->end + 1;
> pciauto_lower_memspc = hose->mem_resource->start;
> pciauto_upper_memspc = hose->mem_resource->end + 1;
> + DBG("Autoconfig PCI channel 0x%p\n", hose);
> + DBG("Scanning bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
> + busno, pciauto_lower_iospc, pciauto_lower_memspc);
>
> - return pciauto_bus_scan(hose, busno);
> + return pciauto_bus_scan(hose, busno, busno);
> }
> -
> -
> -/*
> - * These functions are used early on before PCI scanning is done
> - * and all of the pci_dev and pci_bus structures have been created.
> - */
> -static struct pci_dev *fake_pci_dev(struct pci_channel *hose, int busnr,
> - int devfn)
> -{
> - static struct pci_dev dev;
> - static struct pci_bus bus;
> -
> - dev.bus = &bus;
> - dev.sysdata = hose;
> - dev.devfn = devfn;
> - bus.number = busnr;
> - bus.ops = hose->pci_ops;
> -
> - return &dev;
> -}
> -
> -#define EARLY_PCI_OP(rw, size, type) \
> -int early_##rw##_config_##size(struct pci_channel *hose, int bus, \
> - int devfn, int offset, type value) \
> -{ \
> - return pci_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \
> - offset, value); \
> -}
> -
> -EARLY_PCI_OP(read, byte, u8 *)
> -EARLY_PCI_OP(read, word, u16 *)
> -EARLY_PCI_OP(read, dword, u32 *)
> -EARLY_PCI_OP(write, byte, u8)
> -EARLY_PCI_OP(write, word, u16)
> -EARLY_PCI_OP(write, dword, u32)
next prev parent reply other threads:[~2001-10-29 19:40 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-10-27 1:07 PATCH: pci_auto bridge support Bradley D. LaRonde
2001-10-29 19:24 ` Jun Sun [this message]
2001-10-29 19:30 ` Bradley D. LaRonde
2001-10-29 19:30 ` Bradley D. LaRonde
2001-10-29 22:38 ` Jun Sun
2001-10-30 0:00 ` [Linux-mips-kernel]Re: " Bradley D. LaRonde
2001-10-30 0:00 ` Bradley D. LaRonde
2001-10-30 0:19 ` Jun Sun
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3BDDACD2.7121F905@mvista.com \
--to=jsun@mvista.com \
--cc=brad@ltc.com \
--cc=linux-mips-kernel@lists.sourceforge.net \
--cc=linux-mips@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox