linux/arch/i386/kernel/summit.c History
<<
>>
Prefs
   1/*
   2 * arch/i386/kernel/summit.c - IBM Summit-Specific Code
   3 *
   4 * Written By: Matthew Dobson, IBM Corporation
   5 *
   6 * Copyright (c) 2003 IBM Corp.
   7 *
   8 * All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or (at
  13 * your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful, but
  16 * WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  18 * NON INFRINGEMENT.  See the GNU General Public License for more
  19 * details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 *
  25 * Send feedback to <colpatch@us.ibm.com>
  26 *
  27 */
  28
  29#include <linux/mm.h>
  30#include <linux/init.h>
  31#include <asm/io.h>
  32#include <asm/mach-summit/mach_mpparse.h>
  33
  34static struct rio_table_hdr *rio_table_hdr __initdata;
  35static struct scal_detail   *scal_devs[MAX_NUMNODES] __initdata;
  36static struct rio_detail    *rio_devs[MAX_NUMNODES*4] __initdata;
  37
  38static int __init setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
  39{
  40        int twister = 0, node = 0;
  41        int i, bus, num_buses;
  42
  43        for(i = 0; i < rio_table_hdr->num_rio_dev; i++){
  44                if (rio_devs[i]->node_id == rio_devs[wpeg_num]->owner_id){
  45                        twister = rio_devs[i]->owner_id;
  46                        break;
  47                }
  48        }
  49        if (i == rio_table_hdr->num_rio_dev){
  50                printk(KERN_ERR "%s: Couldn't find owner Cyclone for Winnipeg!\n", __FUNCTION__);
  51                return last_bus;
  52        }
  53
  54        for(i = 0; i < rio_table_hdr->num_scal_dev; i++){
  55                if (scal_devs[i]->node_id == twister){
  56                        node = scal_devs[i]->node_id;
  57                        break;
  58                }
  59        }
  60        if (i == rio_table_hdr->num_scal_dev){
  61                printk(KERN_ERR "%s: Couldn't find owner Twister for Cyclone!\n", __FUNCTION__);
  62                return last_bus;
  63        }
  64
  65        switch (rio_devs[wpeg_num]->type){
  66        case CompatWPEG:
  67                /* The Compatability Winnipeg controls the 2 legacy buses,
  68                 * the 66MHz PCI bus [2 slots] and the 2 "extra" buses in case
  69                 * a PCI-PCI bridge card is used in either slot: total 5 buses.
  70                 */
  71                num_buses = 5;
  72                break;
  73        case AltWPEG:
  74                /* The Alternate Winnipeg controls the 2 133MHz buses [1 slot
  75                 * each], their 2 "extra" buses, the 100MHz bus [2 slots] and
  76                 * the "extra" buses for each of those slots: total 7 buses.
  77                 */
  78                num_buses = 7;
  79                break;
  80        case LookOutAWPEG:
  81        case LookOutBWPEG:
  82                /* A Lookout Winnipeg controls 3 100MHz buses [2 slots each]
  83                 * & the "extra" buses for each of those slots: total 9 buses.
  84                 */
  85                num_buses = 9;
  86                break;
  87        default:
  88                printk(KERN_INFO "%s: Unsupported Winnipeg type!\n", __FUNCTION__);
  89                return last_bus;
  90        }
  91
  92        for(bus = last_bus; bus < last_bus + num_buses; bus++)
  93                mp_bus_id_to_node[bus] = node;
  94        return bus;
  95}
  96
  97static int __init build_detail_arrays(void)
  98{
  99        unsigned long ptr;
 100        int i, scal_detail_size, rio_detail_size;
 101
 102        if (rio_table_hdr->num_scal_dev > MAX_NUMNODES){
 103                printk(KERN_WARNING "%s: MAX_NUMNODES too low!  Defined as %d, but system has %d nodes.\n", __FUNCTION__, MAX_NUMNODES, rio_table_hdr->num_scal_dev);
 104                return 0;
 105        }
 106
 107        switch (rio_table_hdr->version){
 108        default:
 109                printk(KERN_WARNING "%s: Invalid Rio Grande Table Version: %d\n", __FUNCTION__, rio_table_hdr->version);
 110                return 0;
 111        case 2:
 112                scal_detail_size = 11;
 113                rio_detail_size = 13;
 114                break;
 115        case 3:
 116                scal_detail_size = 12;
 117                rio_detail_size = 15;
 118                break;
 119        }
 120
 121        ptr = (unsigned long)rio_table_hdr + 3;
 122        for(i = 0; i < rio_table_hdr->num_scal_dev; i++, ptr += scal_detail_size)
 123                scal_devs[i] = (struct scal_detail *)ptr;
 124
 125        for(i = 0; i < rio_table_hdr->num_rio_dev; i++, ptr += rio_detail_size)
 126                rio_devs[i] = (struct rio_detail *)ptr;
 127
 128        return 1;
 129}
 130
 131void __init setup_summit(void)
 132{
 133        unsigned long           ptr;
 134        unsigned short          offset;
 135        int                     i, next_wpeg, next_bus = 0;
 136
 137        /* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
 138        ptr = *(unsigned short *)phys_to_virt(0x40Eul);
 139        ptr = (unsigned long)phys_to_virt(ptr << 4);
 140
 141        rio_table_hdr = NULL;
 142        offset = 0x180;
 143        while (offset){
 144                /* The block id is stored in the 2nd word */
 145                if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
 146                        /* set the pointer past the offset & block id */
 147                        rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
 148                        break;
 149                }
 150                /* The next offset is stored in the 1st word.  0 means no more */
 151                offset = *((unsigned short *)(ptr + offset));
 152        }
 153        if (!rio_table_hdr){
 154                printk(KERN_ERR "%s: Unable to locate Rio Grande Table in EBDA - bailing!\n", __FUNCTION__);
 155                return;
 156        }
 157
 158        if (!build_detail_arrays())
 159                return;
 160
 161        /* The first Winnipeg we're looking for has an index of 0 */
 162        next_wpeg = 0;
 163        do {
 164                for(i = 0; i < rio_table_hdr->num_rio_dev; i++){
 165                        if (is_WPEG(rio_devs[i]) && rio_devs[i]->WP_index == next_wpeg){
 166                                /* It's the Winnipeg we're looking for! */
 167                                next_bus = setup_pci_node_map_for_wpeg(i, next_bus);
 168                                next_wpeg++;
 169                                break;
 170                        }
 171                }
 172                /*
 173                 * If we go through all Rio devices and don't find one with
 174                 * the next index, it means we've found all the Winnipegs,
 175                 * and thus all the PCI buses.
 176                 */
 177                if (i == rio_table_hdr->num_rio_dev)
 178                        next_wpeg = 0;
 179        } while (next_wpeg != 0);
 180}
 181
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.