From 789448b7674b8b4437ad744299ead524a73848cc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 Aug 2003 11:02:02 -0700 Subject: [PATCH] [ALPHA] Forward port SRM restore code from 2.4. From Jay Estabrook . --- arch/alpha/kernel/core_cia.c | 118 ++++++++++++++++++++++------------ arch/alpha/kernel/core_lca.c | 31 ++++++--- arch/alpha/kernel/pci.c | 77 +++++++++++++++++----- arch/alpha/kernel/pci_impl.h | 27 ++++++++ arch/alpha/kernel/process.c | 2 +- arch/alpha/kernel/sys_alcor.c | 28 +++++++- arch/alpha/kernel/sys_miata.c | 2 + arch/alpha/kernel/sys_sio.c | 38 ++++++++++- 8 files changed, 253 insertions(+), 70 deletions(-) diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 8e7688e899a27..54d7a6c31e76c 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -47,15 +47,6 @@ #define vip volatile int * -/* Save CIA configuration data as the console had it set up. */ - -struct -{ - unsigned int w_base; - unsigned int w_mask; - unsigned int t_base; -} saved_config[4] __attribute((common)); - /* * Given a bus, device, and function number, compute resulting * configuration space address. It is therefore not safe to have @@ -566,6 +557,77 @@ failed: alpha_mv.mv_pci_tbi = NULL; goto exit; } + +#if defined(ALPHA_RESTORE_SRM_SETUP) +/* Save CIA configuration data as the console had it set up. */ +struct +{ + unsigned int hae_mem; + unsigned int hae_io; + unsigned int pci_dac_offset; + unsigned int err_mask; + unsigned int cia_ctrl; + unsigned int cia_cnfg; + struct { + unsigned int w_base; + unsigned int w_mask; + unsigned int t_base; + } window[4]; +} saved_config __attribute((common)); + +void +cia_save_srm_settings(int is_pyxis) +{ + int i; + + /* Save some important registers. */ + saved_config.err_mask = *(vip)CIA_IOC_ERR_MASK; + saved_config.cia_ctrl = *(vip)CIA_IOC_CIA_CTRL; + saved_config.hae_mem = *(vip)CIA_IOC_HAE_MEM; + saved_config.hae_io = *(vip)CIA_IOC_HAE_IO; + saved_config.pci_dac_offset = *(vip)CIA_IOC_PCI_W_DAC; + + if (is_pyxis) + saved_config.cia_cnfg = *(vip)CIA_IOC_CIA_CNFG; + else + saved_config.cia_cnfg = 0; + + /* Save DMA windows configuration. */ + for (i = 0; i < 4; i++) { + saved_config.window[i].w_base = *(vip)CIA_IOC_PCI_Wn_BASE(i); + saved_config.window[i].w_mask = *(vip)CIA_IOC_PCI_Wn_MASK(i); + saved_config.window[i].t_base = *(vip)CIA_IOC_PCI_Tn_BASE(i); + } + mb(); +} + +void +cia_restore_srm_settings(void) +{ + int i; + + for (i = 0; i < 4; i++) { + *(vip)CIA_IOC_PCI_Wn_BASE(i) = saved_config.window[i].w_base; + *(vip)CIA_IOC_PCI_Wn_MASK(i) = saved_config.window[i].w_mask; + *(vip)CIA_IOC_PCI_Tn_BASE(i) = saved_config.window[i].t_base; + } + + *(vip)CIA_IOC_HAE_MEM = saved_config.hae_mem; + *(vip)CIA_IOC_HAE_IO = saved_config.hae_io; + *(vip)CIA_IOC_PCI_W_DAC = saved_config.pci_dac_offset; + *(vip)CIA_IOC_ERR_MASK = saved_config.err_mask; + *(vip)CIA_IOC_CIA_CTRL = saved_config.cia_ctrl; + + if (saved_config.cia_cnfg) /* Must be pyxis. */ + *(vip)CIA_IOC_CIA_CNFG = saved_config.cia_cnfg; + + mb(); +} +#else /* ALPHA_RESTORE_SRM_SETUP */ +#define cia_save_srm_settings(p) do {} while (0) +#define cia_restore_srm_settings() do {} while (0) +#endif /* ALPHA_RESTORE_SRM_SETUP */ + static void __init do_init_arch(int is_pyxis) @@ -577,6 +639,9 @@ do_init_arch(int is_pyxis) printk("pci: cia revision %d%s\n", cia_rev, is_pyxis ? " (pyxis)" : ""); + if (alpha_using_srm) + cia_save_srm_settings(is_pyxis); + /* Set up error reporting. */ temp = *(vip)CIA_IOC_ERR_MASK; temp &= ~(CIA_ERR_CPU_PE | CIA_ERR_MEM_NEM | CIA_ERR_PA_PTE_INV @@ -646,24 +711,6 @@ do_init_arch(int is_pyxis) hose->dense_io_base = CIA_BW_IO - IDENT_ADDR; } - /* Save CIA configuration data as the console had it set up. */ - - saved_config[0].w_base = *(vip)CIA_IOC_PCI_W0_BASE; - saved_config[0].w_mask = *(vip)CIA_IOC_PCI_W0_MASK; - saved_config[0].t_base = *(vip)CIA_IOC_PCI_T0_BASE; - - saved_config[1].w_base = *(vip)CIA_IOC_PCI_W1_BASE; - saved_config[1].w_mask = *(vip)CIA_IOC_PCI_W1_MASK; - saved_config[1].t_base = *(vip)CIA_IOC_PCI_T1_BASE; - - saved_config[2].w_base = *(vip)CIA_IOC_PCI_W2_BASE; - saved_config[2].w_mask = *(vip)CIA_IOC_PCI_W2_MASK; - saved_config[2].t_base = *(vip)CIA_IOC_PCI_T2_BASE; - - saved_config[3].w_base = *(vip)CIA_IOC_PCI_W3_BASE; - saved_config[3].w_mask = *(vip)CIA_IOC_PCI_W3_MASK; - saved_config[3].t_base = *(vip)CIA_IOC_PCI_T3_BASE; - /* * Set up the PCI to main memory translation windows. * @@ -761,21 +808,8 @@ pyxis_init_arch(void) void cia_kill_arch(int mode) { - *(vip)CIA_IOC_PCI_W0_BASE = saved_config[0].w_base; - *(vip)CIA_IOC_PCI_W0_MASK = saved_config[0].w_mask; - *(vip)CIA_IOC_PCI_T0_BASE = saved_config[0].t_base; - - *(vip)CIA_IOC_PCI_W1_BASE = saved_config[1].w_base; - *(vip)CIA_IOC_PCI_W1_MASK = saved_config[1].w_mask; - *(vip)CIA_IOC_PCI_T1_BASE = saved_config[1].t_base; - - *(vip)CIA_IOC_PCI_W2_BASE = saved_config[2].w_base; - *(vip)CIA_IOC_PCI_W2_MASK = saved_config[2].w_mask; - *(vip)CIA_IOC_PCI_T2_BASE = saved_config[2].t_base; - - *(vip)CIA_IOC_PCI_W3_BASE = saved_config[3].w_base; - *(vip)CIA_IOC_PCI_W3_MASK = saved_config[3].w_mask; - *(vip)CIA_IOC_PCI_T3_BASE = saved_config[3].t_base; + if (alpha_using_srm) + cia_restore_srm_settings(); } void __init diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c index 197f03c10ea00..7f8768ff9d00d 100644 --- a/arch/alpha/kernel/core_lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -242,7 +242,7 @@ void lca_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); - *(vip)LCA_IOC_TBIA = 0; + *(vulp)LCA_IOC_TBIA = 0; mb(); } @@ -268,21 +268,25 @@ lca_init_arch(void) /* * Set up the PCI to main memory translation windows. * - * Window 0 is direct access 1GB at 1GB - * Window 1 is scatter-gather 8MB at 8MB (for isa) + * Mimic the SRM settings for the direct-map window. + * Window 0 is scatter-gather 8MB at 8MB (for isa). + * Window 1 is direct access 1GB at 1GB. + * + * Note that we do not try to save any of the DMA window CSRs + * before setting them, since we cannot read those CSRs on LCA. */ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); hose->sg_pci = NULL; __direct_map_base = 0x40000000; __direct_map_size = 0x40000000; - *(vulp)LCA_IOC_W_BASE0 = __direct_map_base | (2UL << 32); - *(vulp)LCA_IOC_W_MASK0 = (__direct_map_size - 1) & 0xfff00000; - *(vulp)LCA_IOC_T_BASE0 = 0; + *(vulp)LCA_IOC_W_BASE0 = hose->sg_isa->dma_base | (3UL << 32); + *(vulp)LCA_IOC_W_MASK0 = (hose->sg_isa->size - 1) & 0xfff00000; + *(vulp)LCA_IOC_T_BASE0 = virt_to_phys(hose->sg_isa->ptes); - *(vulp)LCA_IOC_W_BASE1 = hose->sg_isa->dma_base | (3UL << 32); - *(vulp)LCA_IOC_W_MASK1 = (hose->sg_isa->size - 1) & 0xfff00000; - *(vulp)LCA_IOC_T_BASE1 = virt_to_phys(hose->sg_isa->ptes); + *(vulp)LCA_IOC_W_BASE1 = __direct_map_base | (2UL << 32); + *(vulp)LCA_IOC_W_MASK1 = (__direct_map_size - 1) & 0xfff00000; + *(vulp)LCA_IOC_T_BASE1 = 0; *(vulp)LCA_IOC_TB_ENA = 0x80; @@ -294,6 +298,15 @@ lca_init_arch(void) * data parity errors. */ *(vulp)LCA_IOC_PAR_DIS = 1UL<<5; + + /* + * Finally, set up for restoring the correct HAE if using SRM. + * Again, since we cannot read many of the CSRs on the LCA, + * one of which happens to be the HAE, we save the value that + * the SRM will expect... + */ + if (alpha_using_srm) + srm_hae = 0x80000000UL; } /* diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index aa6abb1d7a0a5..1e3abbb5ca5d0 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "proto.h" @@ -44,7 +45,11 @@ const char *const pci_mem_names[] = { const char pci_hae0_name[] = "HAE0"; /* Indicate whether we respect the PCI setup left by console. */ -int __initdata pci_probe_only; +/* + * Make this long-lived so that we know when shutting down + * whether we probed only or not. + */ +int pci_probe_only; /* * The PCI controller list. @@ -202,6 +207,52 @@ pcibios_setup(char *str) return str; } +#ifdef ALPHA_RESTORE_SRM_SETUP +static struct pdev_srm_saved_conf *srm_saved_configs; + +void __init +pdev_save_srm_config(struct pci_dev *dev) +{ + struct pdev_srm_saved_conf *tmp; + static int printed = 0; + + if (!alpha_using_srm || pci_probe_only) + return; + + if (!printed) { + printk(KERN_INFO "pci: enabling save/restore of SRM state\n"); + printed = 1; + } + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + printk(KERN_ERR "%s: kmalloc() failed!\n", __FUNCTION__); + return; + } + tmp->next = srm_saved_configs; + tmp->dev = dev; + + pci_save_state(dev, tmp->regs); + + srm_saved_configs = tmp; +} + +void +pci_restore_srm_config(void) +{ + struct pdev_srm_saved_conf *tmp; + + /* No need to restore if probed only. */ + if (pci_probe_only) + return; + + /* Restore SRM config. */ + for (tmp = srm_saved_configs; tmp; tmp = tmp->next) { + pci_restore_state(tmp->dev, tmp->regs); + } +} +#endif + void __init pcibios_fixup_resource(struct resource *res, struct resource *root) { @@ -260,6 +311,8 @@ pcibios_fixup_bus(struct pci_bus *bus) for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { struct pci_dev *dev = pci_dev_b(ln); + + pdev_save_srm_config(dev); if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) pcibios_fixup_device_resources(dev, bus); } @@ -269,8 +322,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); - - /* ??? FIXME -- record old value for shutdown. */ } /* Most Alphas have straight-forward swizzling needs. */ @@ -278,20 +329,16 @@ pcibios_update_irq(struct pci_dev *dev, int irq) u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) { - struct pci_controller *hose = dev->sysdata; - - if (dev->bus != hose->bus) { - u8 pin = *pinp; - do { - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - /* Move up the chain of bridges. */ - dev = dev->bus->self; - } while (dev->bus->parent); - *pinp = pin; + u8 pin = *pinp; - /* The slot is the slot of the last bridge. */ - } + while (dev->bus->parent) { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } + *pinp = pin; + /* The slot is the slot of the last bridge. */ return PCI_SLOT(dev->devfn); } diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index 68448627b226b..54fb8f178494d 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -147,6 +147,33 @@ struct pci_iommu_arena unsigned int align_entry; }; +#if defined(CONFIG_ALPHA_SRM) && \ + (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA)) +# define NEED_SRM_SAVE_RESTORE +#else +# undef NEED_SRM_SAVE_RESTORE +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(NEED_SRM_SAVE_RESTORE) +# define ALPHA_RESTORE_SRM_SETUP +#else +# undef ALPHA_RESTORE_SRM_SETUP +#endif + +#ifdef ALPHA_RESTORE_SRM_SETUP +/* Store PCI device configuration left by SRM here. */ +struct pdev_srm_saved_conf +{ + struct pdev_srm_saved_conf *next; + struct pci_dev *dev; + u32 regs[16]; +}; + +extern void pci_restore_srm_config(void); +#else +#define pdev_save_srm_config(dev) do {} while (0) +#define pci_restore_srm_config() do {} while (0) +#endif /* The hose list. */ extern struct pci_controller *hose_head, **hose_tail; diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 497d9057be510..975e9312f8b95 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -129,7 +129,7 @@ common_shutdown_1(void *generic_ptr) /* This has the effect of resetting the VGA video origin. */ take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif - /* reset_for_srm(); */ + pci_restore_srm_config(); set_hae(srm_hae); } diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index a90b51837c7f9..bf2cfa1b015dc 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -223,6 +223,7 @@ alcor_kill_arch(int mode) { cia_kill_arch(mode); +#ifndef ALPHA_RESTORE_SRM_SETUP switch(mode) { case LINUX_REBOOT_CMD_RESTART: /* Who said DEC engineer's have no sense of humor? ;-) */ @@ -238,6 +239,29 @@ alcor_kill_arch(int mode) } halt(); +#endif +} + +static void __init +alcor_init_pci(void) +{ + struct pci_dev *dev; + + cia_init_pci(); + + /* + * Now we can look to see if we are really running on an XLT-type + * motherboard, by looking for a 21040 TULIP in slot 6, which is + * built into XLT and BRET/MAVERICK, but not available on ALCOR. + */ + dev = pci_find_device(PCI_VENDOR_ID_DEC, + PCI_DEVICE_ID_DEC_TULIP, + NULL); + if (dev && dev->devfn == PCI_DEVFN(6,0)) { + alpha_mv.sys.cia.gru_int_req_bits = XLT_GRU_INT_REQ_BITS; + printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n", + __FUNCTION__); + } } @@ -262,7 +286,7 @@ struct alpha_machine_vector alcor_mv __initmv = { .init_arch = cia_init_arch, .init_irq = alcor_init_irq, .init_rtc = common_init_rtc, - .init_pci = cia_init_pci, + .init_pci = alcor_init_pci, .kill_arch = alcor_kill_arch, .pci_map_irq = alcor_map_irq, .pci_swizzle = common_swizzle, @@ -290,7 +314,7 @@ struct alpha_machine_vector xlt_mv __initmv = { .init_arch = cia_init_arch, .init_irq = alcor_init_irq, .init_rtc = common_init_rtc, - .init_pci = cia_init_pci, + .init_pci = alcor_init_pci, .kill_arch = alcor_kill_arch, .pci_map_irq = alcor_map_irq, .pci_swizzle = common_swizzle, diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index e3cb7b77989fc..a8cd711e81c57 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -240,6 +240,7 @@ miata_kill_arch(int mode) { cia_kill_arch(mode); +#ifndef ALPHA_RESTORE_SRM_SETUP switch(mode) { case LINUX_REBOOT_CMD_RESTART: /* Who said DEC engineers have no sense of humor? ;-) */ @@ -255,6 +256,7 @@ miata_kill_arch(int mode) } halt(); +#endif } diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index 279f9e7134963..177e1275d41dc 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -36,6 +36,14 @@ #include "pci_impl.h" #include "machvec_impl.h" +#if defined(ALPHA_RESTORE_SRM_SETUP) +/* Save LCA configuration data as the console had it set up. */ +struct +{ + unsigned int orig_route_tab; /* for SAVE/RESTORE */ +} saved_config __attribute((common)); +#endif + static void __init sio_init_irq(void) @@ -77,6 +85,15 @@ alphabook1_init_arch(void) static void __init sio_pci_route(void) { +#if defined(ALPHA_RESTORE_SRM_SETUP) + /* First, read and save the original setting. */ + pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, + &saved_config.orig_route_tab); + printk("%s: PIRQ original 0x%x new 0x%x\n", __FUNCTION__, + saved_config.orig_route_tab, alpha_mv.sys.sio.route_tab); +#endif + + /* Now override with desired setting. */ pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, alpha_mv.sys.sio.route_tab); } @@ -245,6 +262,21 @@ alphabook1_init_pci(void) outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */ } +void +sio_kill_arch(int mode) +{ +#if defined(ALPHA_RESTORE_SRM_SETUP) + /* Since we cannot read the PCI DMA Window CSRs, we + * cannot restore them here. + * + * However, we CAN read the PIRQ route register, so restore it + * now... + */ + pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, + saved_config.orig_route_tab); +#endif +} + /* * The System Vectors @@ -269,7 +301,7 @@ struct alpha_machine_vector alphabook1_mv __initmv = { .init_irq = sio_init_irq, .init_rtc = common_init_rtc, .init_pci = alphabook1_init_pci, - .kill_arch = NULL, + .kill_arch = sio_kill_arch, .pci_map_irq = noname_map_irq, .pci_swizzle = common_swizzle, @@ -300,6 +332,7 @@ struct alpha_machine_vector avanti_mv __initmv = { .init_irq = sio_init_irq, .init_rtc = common_init_rtc, .init_pci = noname_init_pci, + .kill_arch = sio_kill_arch, .pci_map_irq = noname_map_irq, .pci_swizzle = common_swizzle, @@ -329,6 +362,7 @@ struct alpha_machine_vector noname_mv __initmv = { .init_irq = sio_init_irq, .init_rtc = common_init_rtc, .init_pci = noname_init_pci, + .kill_arch = sio_kill_arch, .pci_map_irq = noname_map_irq, .pci_swizzle = common_swizzle, @@ -367,6 +401,7 @@ struct alpha_machine_vector p2k_mv __initmv = { .init_irq = sio_init_irq, .init_rtc = common_init_rtc, .init_pci = noname_init_pci, + .kill_arch = sio_kill_arch, .pci_map_irq = p2k_map_irq, .pci_swizzle = common_swizzle, @@ -396,6 +431,7 @@ struct alpha_machine_vector xl_mv __initmv = { .init_irq = sio_init_irq, .init_rtc = common_init_rtc, .init_pci = noname_init_pci, + .kill_arch = sio_kill_arch, .pci_map_irq = noname_map_irq, .pci_swizzle = common_swizzle, -- 2.53.0