linux/arch/powerpc/platforms/iseries/vpdinfo.c
<<
>>
Prefs
   1/*
   2 * This code gets the card location of the hardware
   3 * Copyright (C) 2001  <Allan H Trautman> <IBM Corp>
   4 * Copyright (C) 2005  Stephen Rothwel, IBM Corp
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the:
  18 * Free Software Foundation, Inc.,
  19 * 59 Temple Place, Suite 330,
  20 * Boston, MA  02111-1307  USA
  21 *
  22 * Change Activity:
  23 *   Created, Feb 2, 2001
  24 *   Ported to ppc64, August 20, 2001
  25 * End Change Activity
  26 */
  27#include <linux/init.h>
  28#include <linux/module.h>
  29#include <linux/pci.h>
  30
  31#include <asm/types.h>
  32#include <asm/resource.h>
  33#include <asm/abs_addr.h>
  34#include <asm/pci-bridge.h>
  35#include <asm/iseries/hv_types.h>
  36
  37#include "pci.h"
  38#include "call_pci.h"
  39
  40/*
  41 * Size of Bus VPD data
  42 */
  43#define BUS_VPDSIZE      1024
  44
  45/*
  46 * Bus Vpd Tags
  47 */
  48#define  VpdEndOfAreaTag   0x79
  49#define  VpdIdStringTag    0x82
  50#define  VpdVendorAreaTag  0x84
  51
  52/*
  53 * Mfg Area Tags
  54 */
  55#define  VpdFruFrameId    0x4649     // "FI"
  56#define  VpdSlotMapFormat 0x4D46     // "MF"
  57#define  VpdSlotMap       0x534D     // "SM"
  58
  59/*
  60 * Structures of the areas
  61 */
  62struct MfgVpdAreaStruct {
  63        u16 Tag;
  64        u8  TagLength;
  65        u8  AreaData1;
  66        u8  AreaData2;
  67};
  68typedef struct MfgVpdAreaStruct MfgArea;
  69#define MFG_ENTRY_SIZE   3
  70
  71struct SlotMapStruct {
  72        u8   AgentId;
  73        u8   SecondaryAgentId;
  74        u8   PhbId;
  75        char CardLocation[3];
  76        char Parms[8];
  77        char Reserved[2];
  78};
  79typedef struct SlotMapStruct SlotMap;
  80#define SLOT_ENTRY_SIZE   16
  81
  82/*
  83 * Parse the Slot Area
  84 */
  85static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
  86                HvAgentId agent, u8 *PhbId, char card[4])
  87{
  88        int SlotMapLen = MapLen;
  89        SlotMap *SlotMapPtr = MapPtr;
  90
  91        /*
  92         * Parse Slot label until we find the one requested
  93         */
  94        while (SlotMapLen > 0) {
  95                if (SlotMapPtr->AgentId == agent) {
  96                        /*
  97                         * If Phb wasn't found, grab the entry first one found.
  98                         */
  99                        if (*PhbId == 0xff)
 100                                *PhbId = SlotMapPtr->PhbId;
 101                        /* Found it, extract the data. */
 102                        if (SlotMapPtr->PhbId == *PhbId) {
 103                                memcpy(card, &SlotMapPtr->CardLocation, 3);
 104                                card[3]  = 0;
 105                                break;
 106                        }
 107                }
 108                /* Point to the next Slot */
 109                SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE);
 110                SlotMapLen -= SLOT_ENTRY_SIZE;
 111        }
 112}
 113
 114/*
 115 * Parse the Mfg Area
 116 */
 117static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
 118                HvAgentId agent, u8 *PhbId,
 119                u8 *frame, char card[4])
 120{
 121        MfgArea *MfgAreaPtr = (MfgArea *)AreaData;
 122        int MfgAreaLen = AreaLen;
 123        u16 SlotMapFmt = 0;
 124
 125        /* Parse Mfg Data */
 126        while (MfgAreaLen > 0) {
 127                int MfgTagLen = MfgAreaPtr->TagLength;
 128                /* Frame ID         (FI 4649020310 ) */
 129                if (MfgAreaPtr->Tag == VpdFruFrameId)           /* FI  */
 130                        *frame = MfgAreaPtr->AreaData1;
 131                /* Slot Map Format  (MF 4D46020004 ) */
 132                else if (MfgAreaPtr->Tag == VpdSlotMapFormat)   /* MF  */
 133                        SlotMapFmt = (MfgAreaPtr->AreaData1 * 256)
 134                                + MfgAreaPtr->AreaData2;
 135                /* Slot Map         (SM 534D90 */
 136                else if (MfgAreaPtr->Tag == VpdSlotMap) {       /* SM  */
 137                        SlotMap *SlotMapPtr;
 138
 139                        if (SlotMapFmt == 0x1004)
 140                                SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
 141                                                + MFG_ENTRY_SIZE + 1);
 142                        else
 143                                SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
 144                                                + MFG_ENTRY_SIZE);
 145                        iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen,
 146                                        agent, PhbId, card);
 147                }
 148                /*
 149                 * Point to the next Mfg Area
 150                 * Use defined size, sizeof give wrong answer
 151                 */
 152                MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen
 153                                + MFG_ENTRY_SIZE);
 154                MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
 155        }
 156}
 157
 158/*
 159 * Look for "BUS".. Data is not Null terminated.
 160 * PHBID of 0xFF indicates PHB was not found in VPD Data.
 161 */
 162static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
 163{
 164        u8 *PhbPtr = AreaPtr;
 165        int DataLen = AreaLength;
 166        char PhbId = 0xFF;
 167
 168        while (DataLen > 0) {
 169                if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U')
 170                                && (*(PhbPtr + 2) == 'S')) {
 171                        PhbPtr += 3;
 172                        while (*PhbPtr == ' ')
 173                                ++PhbPtr;
 174                        PhbId = (*PhbPtr & 0x0F);
 175                        break;
 176                }
 177                ++PhbPtr;
 178                --DataLen;
 179        }
 180        return PhbId;
 181}
 182
 183/*
 184 * Parse out the VPD Areas
 185 */
 186static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
 187                HvAgentId agent, u8 *frame, char card[4])
 188{
 189        u8 *TagPtr = VpdData;
 190        int DataLen = VpdDataLen - 3;
 191        u8 PhbId = 0xff;
 192
 193        while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
 194                int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
 195                u8 *AreaData  = TagPtr + 3;
 196
 197                if (*TagPtr == VpdIdStringTag)
 198                        PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
 199                else if (*TagPtr == VpdVendorAreaTag)
 200                        iSeries_Parse_MfgArea(AreaData, AreaLen,
 201                                        agent, &PhbId, frame, card);
 202                /* Point to next Area. */
 203                TagPtr  = AreaData + AreaLen;
 204                DataLen -= AreaLen;
 205        }
 206}
 207
 208static int __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
 209                u8 *frame, char card[4])
 210{
 211        int status = 0;
 212        int BusVpdLen = 0;
 213        u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
 214
 215        if (BusVpdPtr == NULL) {
 216                printk("PCI: Bus VPD Buffer allocation failure.\n");
 217                return 0;
 218        }
 219        BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr),
 220                                        BUS_VPDSIZE);
 221        if (BusVpdLen == 0) {
 222                printk("PCI: Bus VPD Buffer zero length.\n");
 223                goto out_free;
 224        }
 225        /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */
 226        /* Make sure this is what I think it is */
 227        if (*BusVpdPtr != VpdIdStringTag) {     /* 0x82 */
 228                printk("PCI: Bus VPD Buffer missing starting tag.\n");
 229                goto out_free;
 230        }
 231        iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
 232        status = 1;
 233out_free:
 234        kfree(BusVpdPtr);
 235        return status;
 236}
 237
 238/*
 239 * Prints the device information.
 240 * - Pass in pci_dev* pointer to the device.
 241 * - Pass in the device count
 242 *
 243 * Format:
 244 * PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet
 245 * controller
 246 */
 247void __init iSeries_Device_Information(struct pci_dev *PciDev, int count)
 248{
 249        struct device_node *DevNode = PciDev->sysdata;
 250        struct pci_dn *pdn;
 251        u16 bus;
 252        u8 frame = 0;
 253        char card[4];
 254        HvSubBusNumber subbus;
 255        HvAgentId agent;
 256
 257        if (DevNode == NULL) {
 258                printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n",
 259                                count);
 260                return;
 261        }
 262
 263        pdn = PCI_DN(DevNode);
 264        bus = pdn->busno;
 265        subbus = pdn->bussubno;
 266        agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
 267                        ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
 268
 269        if (iSeries_Get_Location_Code(bus, agent, &frame, card)) {
 270                printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
 271                        "Card %4s  0x%04X\n", count, bus,
 272                        PCI_SLOT(PciDev->devfn), PciDev->vendor, frame,
 273                        card, (int)(PciDev->class >> 8));
 274        }
 275}
 276