LCOV - code coverage report
Current view: top level - hdata - iohub.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 100 390 25.6 %
Date: 2024-01-02 21:04:04 Functions: 8 20 40.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :            : /* Copyright 2013-2019 IBM Corp. */
       3                 :            : 
       4                 :            : #include <skiboot.h>
       5                 :            : #include "spira.h"
       6                 :            : #include <cpu.h>
       7                 :            : #include <fsp.h>
       8                 :            : #include <opal.h>
       9                 :            : #include <ccan/str/str.h>
      10                 :            : #include <ccan/array_size/array_size.h>
      11                 :            : #include <device.h>
      12                 :            : #include <vpd.h>
      13                 :            : #include <inttypes.h>
      14                 :            : #include <string.h>
      15                 :            : 
      16                 :            : #include "hdata.h"
      17                 :            : 
      18                 :          1 : static bool io_get_lx_info(const void *kwvpd, unsigned int kwvpd_sz,
      19                 :            :                            int lx_idx, struct dt_node *hn)
      20                 :            : {
      21                 :            :         const void *lxr;
      22                 :            :         char recname[5];
      23                 :          1 :         beint32_t lxrbuf[2] = { 0, 0 };
      24                 :            : 
      25                 :            :         /* Find LXRn, where n is the index passed in*/
      26                 :          1 :         strcpy(recname, "LXR0");
      27                 :          1 :         recname[3] += lx_idx;
      28                 :          1 :         lxr = vpd_find(kwvpd, kwvpd_sz, recname, "LX", NULL);
      29                 :          1 :         if (!lxr) {
      30                 :            :                 /* Not found, try VINI */
      31                 :          0 :                 lxr = vpd_find(kwvpd, kwvpd_sz, "VINI",
      32                 :            :                                "LX",  NULL);
      33                 :          0 :                 if (lxr)
      34                 :          0 :                         lx_idx = VPD_LOAD_LXRN_VINI;
      35                 :            :         }
      36                 :          1 :         if (!lxr) {
      37                 :          0 :                 prlog(PR_DEBUG, "CEC:     LXR%x not found !\n", lx_idx);
      38                 :          0 :                 return false;
      39                 :            :         }
      40                 :            : 
      41                 :          1 :         memcpy(lxrbuf, lxr, sizeof(beint32_t)*2);
      42                 :            : 
      43                 :          1 :         prlog(PR_DEBUG, "CEC:     LXRn=%d LXR=%08x%08x\n", lx_idx, be32_to_cpu(lxrbuf[0]), be32_to_cpu(lxrbuf[1]));
      44                 :          1 :         prlog(PR_DEBUG, "CEC:     LX Info added to %llx\n", (long long)hn);
      45                 :            : 
      46                 :            :         /* Add the LX info */
      47                 :          1 :         if (!dt_has_node_property(hn, "ibm,vpd-lx-info", NULL)) {
      48                 :          1 :                 dt_add_property_cells(hn, "ibm,vpd-lx-info",
      49                 :            :                                       lx_idx,
      50                 :            :                                       be32_to_cpu(lxrbuf[0]),
      51                 :            :                                       be32_to_cpu(lxrbuf[1]));
      52                 :            :         }
      53                 :            : 
      54                 :          1 :         return true;
      55                 :            : }
      56                 :            : 
      57                 :            : 
      58                 :          5 : static void io_get_loc_code(const void *sp_iohubs, struct dt_node *hn, const char *prop_name)
      59                 :            : {
      60                 :            :         const struct spira_fru_id *fru_id;
      61                 :            :         unsigned int fru_id_sz;
      62                 :            :         char loc_code[LOC_CODE_SIZE + 1];
      63                 :            :         const char *slca_loc_code;
      64                 :            : 
      65                 :            :         /* Find SLCA Index */
      66                 :          5 :         fru_id = HDIF_get_idata(sp_iohubs, CECHUB_FRU_ID_DATA, &fru_id_sz);
      67                 :          5 :         if (fru_id) {
      68                 :          5 :                 memset(loc_code, 0, sizeof(loc_code));
      69                 :            : 
      70                 :            :                 /* Find LOC Code from SLCA Index */
      71                 :          5 :                 slca_loc_code = slca_get_loc_code_index(be16_to_cpu(fru_id->slca_index));
      72                 :          5 :                 if (slca_loc_code) {
      73                 :          5 :                         strncpy(loc_code, slca_loc_code, LOC_CODE_SIZE);
      74                 :          5 :                         if (!dt_has_node_property(hn, prop_name, NULL)) {
      75                 :          5 :                                 dt_add_property(hn, prop_name, loc_code,
      76                 :          5 :                                                 strlen(loc_code) + 1);
      77                 :            :                         }
      78                 :          5 :                         prlog(PR_DEBUG, "CEC:     %s: %s (SLCA rsrc 0x%x)\n",
      79                 :            :                               prop_name, loc_code,
      80                 :            :                               be16_to_cpu(fru_id->rsrc_id));
      81                 :            :                 } else {
      82                 :          0 :                         prlog(PR_DEBUG, "CEC:     SLCA Loc not found: "
      83                 :            :                               "index %d\n", fru_id->slca_index);
      84                 :            :                 }
      85                 :            :         } else {
      86                 :          0 :                 prlog(PR_DEBUG, "CEC:     Hub FRU ID not found...\n");
      87                 :            :         }
      88                 :          5 : }
      89                 :            : 
      90                 :          4 : static struct dt_node *io_add_phb3(const struct cechub_io_hub *hub,
      91                 :            :                                    const struct HDIF_common_hdr *sp_iohubs,
      92                 :            :                                    unsigned int index, struct dt_node *xcom,
      93                 :            :                                    unsigned int pe_xscom,
      94                 :            :                                    unsigned int pci_xscom,
      95                 :            :                                    unsigned int spci_xscom)
      96                 :            : {
      97                 :            :         struct dt_node *pbcq;
      98                 :            :         unsigned int hdif_vers;
      99                 :            : 
     100                 :            :         /* Get HDIF version */
     101                 :          4 :         hdif_vers = be16_to_cpu(sp_iohubs->version);
     102                 :            : 
     103                 :            :         /* Create PBCQ node under xscom */
     104                 :          4 :         pbcq = dt_new_addr(xcom, "pbcq", pe_xscom);
     105                 :          4 :         if (!pbcq)
     106                 :          0 :                 return NULL;
     107                 :            : 
     108                 :            :         /* "reg" property contains in order the PE, PCI and SPCI XSCOM
     109                 :            :          * addresses
     110                 :            :          */
     111                 :          4 :         dt_add_property_cells(pbcq, "reg",
     112                 :            :                                 pe_xscom, 0x20,
     113                 :            :                                 pci_xscom, 0x05,
     114                 :            :                                 spci_xscom, 0x15);
     115                 :            : 
     116                 :            :         /* A couple more things ... */
     117                 :          4 :         dt_add_property_strings(pbcq, "compatible", "ibm,power8-pbcq");
     118                 :          4 :         dt_add_property_cells(pbcq, "ibm,phb-index", index);
     119                 :          4 :         dt_add_property_cells(pbcq, "ibm,hub-id", be16_to_cpu(hub->hub_num));
     120                 :            : 
     121                 :            :         /* The loc code of the PHB itself is different from the base
     122                 :            :          * loc code of the slots (It's actually the DCM's loc code).
     123                 :            :          */
     124                 :          4 :         io_get_loc_code(sp_iohubs, pbcq, "ibm,loc-code");
     125                 :            : 
     126                 :            :         /* We indicate that this is an IBM setup, which means that
     127                 :            :          * the presence detect A/B bits are meaningful. So far we
     128                 :            :          * don't know whether they make any sense on customer setups
     129                 :            :          * so we only set that when booting with HDAT
     130                 :            :          */
     131                 :          4 :         dt_add_property(pbcq, "ibm,use-ab-detect", NULL, 0);
     132                 :            : 
     133                 :            :         /* HDAT spec has these in version 0x6A and later */
     134                 :          4 :         if (hdif_vers >= 0x6a) {
     135                 :          4 :                 u64 eq0 = be64_to_cpu(hub->phb_lane_eq[index][0]);
     136                 :          4 :                 u64 eq1 = be64_to_cpu(hub->phb_lane_eq[index][1]);
     137                 :          4 :                 u64 eq2 = be64_to_cpu(hub->phb_lane_eq[index][2]);
     138                 :          4 :                 u64 eq3 = be64_to_cpu(hub->phb_lane_eq[index][3]);
     139                 :            : 
     140                 :          4 :                 dt_add_property_u64s(pbcq, "ibm,lane-eq", eq0, eq1, eq2, eq3);
     141                 :            :         }
     142                 :            : 
     143                 :            :         /* Currently we only create a PBCQ node, the actual PHB nodes
     144                 :            :          * will be added by sapphire later on.
     145                 :            :          */
     146                 :          4 :         return pbcq;
     147                 :            : }
     148                 :            : 
     149                 :          0 : static struct dt_node *add_pec_stack(const struct cechub_io_hub *hub,
     150                 :            :                                      struct dt_node *pbcq, int stack_index,
     151                 :            :                                      int phb_index, u8 active_phbs)
     152                 :            : {
     153                 :            :         struct dt_node *stack;
     154                 :            :         const char *compat;
     155                 :            :         u64 eq[12];
     156                 :            :         u8 *ptr;
     157                 :            :         int i;
     158                 :            : 
     159                 :          0 :         stack = dt_new_addr(pbcq, "stack", stack_index);
     160                 :          0 :         assert(stack);
     161                 :            : 
     162                 :          0 :         if (proc_gen == proc_gen_p9)
     163                 :          0 :                 compat = "ibm,power9-phb-stack";
     164                 :            :         else
     165                 :          0 :                 compat = "ibm,power10-phb-stack";
     166                 :            : 
     167                 :          0 :         dt_add_property_cells(stack, "reg", stack_index);
     168                 :          0 :         dt_add_property_cells(stack, "ibm,phb-index", phb_index);
     169                 :          0 :         dt_add_property_string(stack, "compatible", compat);
     170                 :            : 
     171                 :            :         /* XXX: This should probably just return if the PHB is disabled
     172                 :            :          *      rather than adding the extra properties.
     173                 :            :          */
     174                 :            : 
     175                 :          0 :         if (active_phbs & (0x80 >> phb_index))
     176                 :          0 :                 dt_add_property_string(stack, "status", "okay");
     177                 :            :         else
     178                 :          0 :                 dt_add_property_string(stack, "status", "disabled");
     179                 :            : 
     180                 :          0 :         for (i = 0; i < 4; i++) /* gen 3 eq settings */
     181                 :          0 :                 eq[i] = be64_to_cpu(hub->phb_lane_eq[phb_index][i]);
     182                 :          0 :         for (i = 0; i < 4; i++) /* gen 4 eq settings */
     183                 :          0 :                 eq[i+4] = be64_to_cpu(hub->phb4_lane_eq[phb_index][i]);
     184                 :          0 :         for (i = 0; i < 4; i++) /* gen 5 eq settings */
     185                 :          0 :                 eq[i+8] = be64_to_cpu(hub->phb5_lane_eq[phb_index][i]);
     186                 :            : 
     187                 :            :         /* Lane-eq settings are packed 2 bytes per lane for 16 lanes
     188                 :            :          * On P9 DD2 and P10, 1 byte per lane is used in the hardware
     189                 :            :          */
     190                 :            : 
     191                 :            :         /* Repack 2 byte lane settings into 1 byte for gen 4 & 5 */
     192                 :          0 :         ptr = (u8 *)&eq[4];
     193                 :          0 :         for (i = 0; i < 32; i++)
     194                 :          0 :                 ptr[i] = ptr[2*i];
     195                 :            : 
     196                 :          0 :         if (proc_gen == proc_gen_p9)
     197                 :          0 :                 dt_add_property_u64s(stack, "ibm,lane-eq",
     198                 :            :                                      eq[0], eq[1], eq[2], eq[3],
     199                 :            :                                      eq[4], eq[5]);
     200                 :            :         else
     201                 :          0 :                 dt_add_property_u64s(stack, "ibm,lane-eq",
     202                 :            :                                      eq[0], eq[1], eq[2], eq[3],
     203                 :            :                                      eq[4], eq[5],
     204                 :            :                                      eq[6], eq[7]);
     205                 :          0 :         return stack;
     206                 :            : }
     207                 :            : 
     208                 :            : /* Add PHB4 on p9, PHB5 on p10 */
     209                 :          0 : static struct dt_node *io_add_phb4(const struct cechub_io_hub *hub,
     210                 :            :                                    const struct HDIF_common_hdr *sp_iohubs,
     211                 :            :                                    struct dt_node *xcom,
     212                 :            :                                    unsigned int pec_index,
     213                 :            :                                    int stacks,
     214                 :            :                                    int phb_base)
     215                 :            : {
     216                 :            :         struct dt_node *pbcq;
     217                 :          0 :         uint8_t active_phb_mask = hub->fab_br0_pdt;
     218                 :            :         uint32_t pe_xscom;
     219                 :            :         uint32_t pci_xscom;
     220                 :            :         const char *compat;
     221                 :            :         int i;
     222                 :            : 
     223                 :          0 :         if (proc_gen == proc_gen_p9) {
     224                 :          0 :                 pe_xscom  = 0x4010c00 + (pec_index * 0x0000400);
     225                 :          0 :                 pci_xscom = 0xd010800 + (pec_index * 0x1000000);
     226                 :          0 :                 compat = "ibm,power9-pbcq";
     227                 :            :         } else {
     228                 :          0 :                 pe_xscom  = 0x3011800 - (pec_index * 0x1000000);
     229                 :          0 :                 pci_xscom = 0x8010800 + (pec_index * 0x1000000);
     230                 :          0 :                 compat = "ibm,power10-pbcq";
     231                 :            :         }
     232                 :            : 
     233                 :            :         /* Create PBCQ node under xscom */
     234                 :          0 :         pbcq = dt_new_addr(xcom, "pbcq", pe_xscom);
     235                 :          0 :         if (!pbcq)
     236                 :          0 :                 return NULL;
     237                 :            : 
     238                 :            :         /* "reg" property contains (in order) the PE and PCI XSCOM addresses */
     239                 :          0 :         dt_add_property_cells(pbcq, "reg",
     240                 :            :                                 pe_xscom, 0x100,
     241                 :            :                                 pci_xscom, 0x200);
     242                 :            : 
     243                 :            :         /* The hubs themselves go under the stacks */
     244                 :          0 :         dt_add_property_strings(pbcq, "compatible", compat);
     245                 :          0 :         dt_add_property_cells(pbcq, "ibm,pec-index", pec_index);
     246                 :          0 :         dt_add_property_cells(pbcq, "#address-cells", 1);
     247                 :          0 :         dt_add_property_cells(pbcq, "#size-cells", 0);
     248                 :            : 
     249                 :          0 :         for (i = 0; i < stacks; i++)
     250                 :          0 :                 add_pec_stack(hub, pbcq, i, phb_base + i, active_phb_mask);
     251                 :            : 
     252                 :          0 :         dt_add_property_cells(pbcq, "ibm,hub-id", be16_to_cpu(hub->hub_num));
     253                 :            : 
     254                 :            :         /* The loc code of the PHB itself is different from the base
     255                 :            :          * loc code of the slots (It's actually the DCM's loc code).
     256                 :            :          */
     257                 :          0 :         io_get_loc_code(sp_iohubs, pbcq, "ibm,loc-code");
     258                 :            : 
     259                 :          0 :         prlog(PR_INFO, "CEC: Added PBCQ %d with %d stacks\n",
     260                 :            :                 pec_index, stacks);
     261                 :            : 
     262                 :            :         /* the actual PHB nodes created later on by skiboot */
     263                 :          0 :         return pbcq;
     264                 :            : }
     265                 :            : 
     266                 :          2 : static struct dt_node *io_add_p8(const struct cechub_io_hub *hub,
     267                 :            :                                  const struct HDIF_common_hdr *sp_iohubs)
     268                 :            : {
     269                 :            :         struct dt_node *xscom;
     270                 :            :         unsigned int i, chip_id;
     271                 :            : 
     272                 :          2 :         chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
     273                 :            : 
     274                 :          2 :         prlog(PR_INFO, "CEC:     HW CHIP=0x%x, HW TOPO=0x%04x\n", chip_id,
     275                 :            :               be16_to_cpu(hub->hw_topology));
     276                 :            : 
     277                 :          2 :         xscom = find_xscom_for_chip(chip_id);
     278                 :          2 :         if (!xscom) {
     279                 :          0 :                 prerror("P8: Can't find XSCOM for chip %d\n", chip_id);
     280                 :          0 :                 return NULL;
     281                 :            :         }
     282                 :            : 
     283                 :            :         /* Create PHBs, max 3 */
     284                 :          8 :         for (i = 0; i < 3; i++) {
     285                 :          6 :                 if (hub->fab_br0_pdt & (0x80 >> i))
     286                 :            :                         /* XSCOM addresses are the same on Murano and Venice */
     287                 :          4 :                         io_add_phb3(hub, sp_iohubs, i, xscom,
     288                 :          4 :                                     0x02012000 + (i * 0x400),
     289                 :          4 :                                     0x09012000 + (i * 0x400),
     290                 :          4 :                                     0x09013c00 + (i * 0x40));
     291                 :            :         }
     292                 :            : 
     293                 :            :         /* HACK: We return the XSCOM device for the VPD info */
     294                 :          2 :         return xscom;
     295                 :            : }
     296                 :            : 
     297                 :            : /* Add PBCQs for p9/p10 */
     298                 :          0 : static struct dt_node *io_add_p9(const struct cechub_io_hub *hub,
     299                 :            :                                  const struct HDIF_common_hdr *sp_iohubs)
     300                 :            : {
     301                 :            :         struct dt_node *xscom;
     302                 :            :         unsigned int chip_id;
     303                 :            : 
     304                 :          0 :         chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
     305                 :            : 
     306                 :          0 :         prlog(PR_INFO, "CEC:     HW CHIP=0x%x, HW TOPO=0x%04x\n", chip_id,
     307                 :            :               be16_to_cpu(hub->hw_topology));
     308                 :            : 
     309                 :          0 :         xscom = find_xscom_for_chip(chip_id);
     310                 :          0 :         if (!xscom) {
     311                 :          0 :                 prerror("IOHUB: Can't find XSCOM for chip %d\n", chip_id);
     312                 :          0 :                 return NULL;
     313                 :            :         }
     314                 :            : 
     315                 :          0 :         prlog(PR_DEBUG, "IOHUB: PHB active bridge mask %x\n",
     316                 :            :                 (u32) hub->fab_br0_pdt);
     317                 :            : 
     318                 :            :         /* Create PBCQs */
     319                 :          0 :         if (proc_gen == proc_gen_p9) {
     320                 :          0 :                 io_add_phb4(hub, sp_iohubs, xscom, 0, 1, 0);
     321                 :          0 :                 io_add_phb4(hub, sp_iohubs, xscom, 1, 2, 1);
     322                 :          0 :                 io_add_phb4(hub, sp_iohubs, xscom, 2, 3, 3);
     323                 :            :         } else { /* p10 */
     324                 :          0 :                 io_add_phb4(hub, sp_iohubs, xscom, 0, 3, 0);
     325                 :          0 :                 io_add_phb4(hub, sp_iohubs, xscom, 1, 3, 3);
     326                 :            :         }
     327                 :            : 
     328                 :          0 :         return xscom;
     329                 :            : }
     330                 :            : 
     331                 :            : 
     332                 :          1 : static void io_add_p8_cec_vpd(const struct HDIF_common_hdr *sp_iohubs)
     333                 :            : {
     334                 :            :         const struct HDIF_child_ptr *iokids;
     335                 :            :         const void *iokid;      
     336                 :            :         const void *kwvpd;
     337                 :            :         unsigned int kwvpd_sz;
     338                 :            : 
     339                 :            :         /* P8 LXR0 kept in IO KID Keyword VPD */
     340                 :          1 :         iokids = HDIF_child_arr(sp_iohubs, CECHUB_CHILD_IO_KIDS);
     341                 :          1 :         if (!CHECK_SPPTR(iokids)) {
     342                 :          0 :                 prlog(PR_WARNING, "CEC:     No IOKID child array !\n");
     343                 :          0 :                 return;
     344                 :            :         }
     345                 :          1 :         if (!iokids->count) {
     346                 :          0 :                 prlog(PR_WARNING, "CEC:     IOKID count is 0 !\n");
     347                 :          0 :                 return;
     348                 :            :         }
     349                 :          1 :         if (be32_to_cpu(iokids->count) > 1) {
     350                 :          0 :                 prlog(PR_WARNING, "CEC:     WARNING ! More than 1 IO KID !!! (%d)\n",
     351                 :            :                       be32_to_cpu(iokids->count));
     352                 :            :                 /* Ignoring the additional ones */
     353                 :            :         }
     354                 :            : 
     355                 :          1 :         iokid = HDIF_child(sp_iohubs, iokids, 0, "IO KID");
     356                 :          1 :         if (!iokid) {
     357                 :          0 :                 prlog(PR_WARNING, "CEC:     No IO KID structure in child array !\n");
     358                 :          0 :                 return;
     359                 :            :         }
     360                 :            : 
     361                 :            :         /* Grab base location code for slots */
     362                 :          1 :         io_get_loc_code(iokid, dt_root, "ibm,io-base-loc-code");
     363                 :            : 
     364                 :          1 :         kwvpd = HDIF_get_idata(iokid, CECHUB_ASCII_KEYWORD_VPD, &kwvpd_sz);
     365                 :          1 :         if (!kwvpd) {
     366                 :          0 :                 prlog(PR_WARNING, "CEC:     No VPD entry in IO KID !\n");
     367                 :          0 :                 return;
     368                 :            :         }
     369                 :            : 
     370                 :            :         /* Grab LX load info */
     371                 :          1 :         io_get_lx_info(kwvpd, kwvpd_sz, 0, dt_root);
     372                 :            : }
     373                 :            : 
     374                 :            : /*
     375                 :            :  * Assumptions:
     376                 :            :  *
     377                 :            :  * a) the IOSLOT index is the hub ID -CHECK
     378                 :            :  *
     379                 :            :  */
     380                 :            : 
     381                 :            : static struct dt_node *dt_slots;
     382                 :            : 
     383                 :          0 : static void add_i2c_link(struct dt_node *node, const char *link_name,
     384                 :            :                         u32 i2c_link)
     385                 :            : {
     386                 :            :         /* FIXME: Do something not shit */
     387                 :          0 :         dt_add_property_cells(node, link_name, i2c_link);
     388                 :          0 : }
     389                 :            : 
     390                 :            : /*
     391                 :            :  * the root of the slots node has #address-cells = 2, <hub-index, phb-index>
     392                 :            :  * can we ditch hub-index?
     393                 :            :  */
     394                 :            : 
     395                 :            : 
     396                 :          0 : static const struct slot_map_details *find_slot_details(
     397                 :            :                 const struct HDIF_common_hdr *ioslot, int entry)
     398                 :            : {
     399                 :          0 :         const struct slot_map_details *details = NULL;
     400                 :            :         const struct HDIF_array_hdr *arr;
     401                 :            :         unsigned int i;
     402                 :            : 
     403                 :          0 :         arr = HDIF_get_iarray(ioslot, IOSLOT_IDATA_DETAILS, NULL);
     404                 :          0 :         HDIF_iarray_for_each(arr, i, details)
     405                 :          0 :                 if (be16_to_cpu(details->entry) == entry)
     406                 :          0 :                         break;
     407                 :            : 
     408                 :          0 :         return details;
     409                 :            : }
     410                 :            : 
     411                 :          0 : static void parse_slot_details(struct dt_node *slot,
     412                 :            :                 const struct slot_map_details *details)
     413                 :            : {
     414                 :            :         u32 slot_caps;
     415                 :            : 
     416                 :            :         /*
     417                 :            :          * generic slot options
     418                 :            :          */
     419                 :            : 
     420                 :          0 :         dt_add_property_cells(slot, "max-power",
     421                 :            :                 be16_to_cpu(details->max_power));
     422                 :            : 
     423                 :          0 :         if (details->perst_ctl_type == SLOT_PERST_PHB_OR_SW)
     424                 :          0 :                 dt_add_property(slot, "pci-perst", NULL, 0);
     425                 :          0 :         else if (details->perst_ctl_type == SLOT_PERST_SW_GPIO)
     426                 :          0 :                 dt_add_property_cells(slot, "gpio-perst", details->perst_gpio);
     427                 :            : 
     428                 :          0 :         if (details->presence_det_type == SLOT_PRESENCE_PCI)
     429                 :          0 :                 dt_add_property(slot, "pci-presence-detect", NULL, 0);
     430                 :            : 
     431                 :            :         /*
     432                 :            :          * specific slot capabilities
     433                 :            :          */
     434                 :          0 :         slot_caps = be32_to_cpu(details->slot_caps);
     435                 :            : 
     436                 :          0 :         if (slot_caps & SLOT_CAP_LSI)
     437                 :          0 :                 dt_add_property(slot, "lsi", NULL, 0);
     438                 :            : 
     439                 :          0 :         if (slot_caps & SLOT_CAP_CAPI) {
     440                 :            :                 /* XXX: should we be more specific here?
     441                 :            :                  *
     442                 :            :                  * Also we should double check that this slot
     443                 :            :                  * is a root connected slot.
     444                 :            :                  */
     445                 :          0 :                 dt_add_property(slot, "capi", NULL, 0);
     446                 :            :         }
     447                 :            : 
     448                 :          0 :         if (slot_caps & SLOT_CAP_CCARD) {
     449                 :          0 :                 dt_add_property(slot, "cable-card", NULL, 0);
     450                 :            : 
     451                 :          0 :                 if (details->presence_det_type == SLOT_PRESENCE_I2C)
     452                 :          0 :                         add_i2c_link(slot, "i2c-presence-detect",
     453                 :          0 :                                 be32_to_cpu(details->i2c_cable_card));
     454                 :            :         }
     455                 :            : 
     456                 :          0 :         if (slot_caps & SLOT_CAP_HOTPLUG) {
     457                 :          0 :                 dt_add_property(slot, "hotplug", NULL, 0);
     458                 :            : 
     459                 :            :                 /*
     460                 :            :                  * Power control should only exist when the slot is hotplug
     461                 :            :                  * capable
     462                 :            :                  */
     463                 :          0 :                 if (details->power_ctrl_type == SLOT_PWR_I2C)
     464                 :          0 :                         add_i2c_link(slot, "i2c-power-ctrl",
     465                 :          0 :                                 be32_to_cpu(details->i2c_power_ctl));
     466                 :            :         }
     467                 :            : 
     468                 :            :         /*
     469                 :            :          * NB: Additional NVLink specific info is added to this node
     470                 :            :          *     when the SMP Link structures are parsed later on.
     471                 :            :          */
     472                 :          0 :         if (slot_caps & SLOT_CAP_NVLINK)
     473                 :          0 :                 dt_add_property(slot, "nvlink", NULL, 0);
     474                 :          0 : }
     475                 :            : 
     476                 :          0 : struct dt_node *find_slot_entry_node(struct dt_node *root, u32 entry_id)
     477                 :            : {
     478                 :            :         struct dt_node *node;
     479                 :            : 
     480                 :          0 :         for (node = dt_first(root); node; node = dt_next(root, node)) {
     481                 :          0 :                 if (!dt_has_node_property(node, DT_PRIVATE "entry_id", NULL))
     482                 :          0 :                         continue;
     483                 :            : 
     484                 :          0 :                 if (dt_prop_get_u32(node, DT_PRIVATE "entry_id") == entry_id)
     485                 :          0 :                         return node;
     486                 :            :         }
     487                 :            : 
     488                 :          0 :         return NULL;
     489                 :            : }
     490                 :            : 
     491                 :            : /*
     492                 :            :  * The internal HDAT representation of the various types of slot is kinda
     493                 :            :  * dumb, translate it into something more sensible
     494                 :            :  */
     495                 :            : enum slot_types {
     496                 :            :         st_root,
     497                 :            :         st_slot,
     498                 :            :         st_rc_slot,
     499                 :            :         st_sw_upstream,
     500                 :            :         st_sw_downstream,
     501                 :            :         st_builtin
     502                 :            : };
     503                 :            : 
     504                 :          0 : static const char *st_name(enum slot_types type)
     505                 :            : {
     506                 :          0 :         switch(type) {
     507                 :          0 :         case st_root:           return "root-complex";
     508                 :          0 :         case st_slot:           return "pluggable";
     509                 :          0 :         case st_rc_slot:        return "pluggable"; /* differentiate? */
     510                 :          0 :         case st_sw_upstream:    return "switch-up";
     511                 :          0 :         case st_sw_downstream:  return "switch-down";
     512                 :          0 :         case st_builtin:        return "builtin";
     513                 :            :         }
     514                 :            : 
     515                 :          0 :         return "(none)";
     516                 :            : }
     517                 :            : 
     518                 :          0 : static enum slot_types xlate_type(uint8_t type, u32 features)
     519                 :            : {
     520                 :          0 :         bool is_slot = features & SLOT_FEAT_SLOT;
     521                 :            : 
     522                 :          0 :         switch (type) {
     523                 :          0 :         case SLOT_TYPE_ROOT_COMPLEX:
     524                 :          0 :                 return is_slot ? st_rc_slot : st_root;
     525                 :          0 :         case SLOT_TYPE_BUILTIN:
     526                 :          0 :                 return st_builtin;
     527                 :          0 :         case SLOT_TYPE_SWITCH_UP:
     528                 :          0 :                 return st_sw_upstream;
     529                 :          0 :         case SLOT_TYPE_SWITCH_DOWN:
     530                 :          0 :                 return is_slot ? st_slot : st_sw_downstream;
     531                 :            :         }
     532                 :            : 
     533                 :          0 :         return -1; /* shouldn't happen */
     534                 :            : }
     535                 :            : 
     536                 :          0 : static bool is_port(struct dt_node *n)
     537                 :            : {
     538                 :            :         //return dt_node_is_compatible(n, "compatible", "ibm,pcie-port");
     539                 :          0 :         return dt_node_is_compatible(n, "ibm,pcie-port");
     540                 :            : }
     541                 :            : 
     542                 :            : /* this only works inside parse_one_ioslot() */
     543                 :            : #define SM_LOG(level, fmt, ...) \
     544                 :            :         prlog(level, "SLOTMAP: %x:%d:%d " \
     545                 :            :                 fmt, /* user input */ \
     546                 :            :                 chip_id, entry->phb_index, eid, \
     547                 :            :                 ##__VA_ARGS__ /* user args */)
     548                 :            : 
     549                 :            : #define SM_ERR(fmt, ...) SM_LOG(PR_ERR, fmt, ##__VA_ARGS__)
     550                 :            : #define SM_DBG(fmt, ...) SM_LOG(PR_DEBUG, fmt, ##__VA_ARGS__)
     551                 :            : 
     552                 :          0 : static void parse_one_slot(const struct slot_map_entry *entry,
     553                 :            :                 const struct slot_map_details *details, int chip_id)
     554                 :            : {
     555                 :          0 :         struct dt_node *node, *parent = NULL;
     556                 :            :         u16 eid, pid, vid, did;
     557                 :            :         u32 flags;
     558                 :            :         int type;
     559                 :            : 
     560                 :          0 :         flags = be32_to_cpu(entry->features);
     561                 :          0 :         type = xlate_type(entry->type, flags);
     562                 :            : 
     563                 :          0 :         eid = be16_to_cpu(entry->entry_id);
     564                 :          0 :         pid = be16_to_cpu(entry->parent_id);
     565                 :            : 
     566                 :          0 :         SM_DBG("%s - eid = %d, pid = %d, name = %8s\n",
     567                 :            :                 st_name(type), eid, pid,
     568                 :            :                 strnlen(entry->name, 8) ? entry->name : "");
     569                 :            : 
     570                 :            :         /* empty slot, ignore it */
     571                 :          0 :         if (eid == 0x0 && pid == 0x0)
     572                 :          0 :                 return;
     573                 :            : 
     574                 :          0 :         if (type != st_root && type != st_rc_slot) {
     575                 :          0 :                 parent = find_slot_entry_node(dt_slots, pid);
     576                 :          0 :                 if (!parent) {
     577                 :          0 :                         SM_ERR("Unable to find node for parent slot (id = %d)\n",
     578                 :            :                                 pid);
     579                 :          0 :                         return;
     580                 :            :                 }
     581                 :            :         }
     582                 :            : 
     583                 :          0 :         switch (type) {
     584                 :          0 :         case st_root:
     585                 :            :         case st_rc_slot:
     586                 :          0 :                 node = dt_new_2addr(dt_slots, "root-complex",
     587                 :          0 :                                                 chip_id, entry->phb_index);
     588                 :          0 :                 if (!node) {
     589                 :          0 :                         SM_ERR("Couldn't add DT node\n");
     590                 :          0 :                         return;
     591                 :            :                 }
     592                 :          0 :                 dt_add_property_cells(node, "reg", chip_id, entry->phb_index);
     593                 :          0 :                 dt_add_property_cells(node, "#address-cells", 2);
     594                 :          0 :                 dt_add_property_cells(node, "#size-cells", 0);
     595                 :          0 :                 dt_add_property_strings(node, "compatible",
     596                 :            :                                 "ibm,pcie-port", "ibm,pcie-root-port");
     597                 :          0 :                 dt_add_property_cells(node, "ibm,chip-id", chip_id);
     598                 :          0 :                 parent = node;
     599                 :            : 
     600                 :            :                 /*
     601                 :            :                  * The representation of slots attached directly to the
     602                 :            :                  * root complex is a bit wierd. If this is just a root
     603                 :            :                  * complex then stop here, otherwise fall through to create
     604                 :            :                  * the slot node.
     605                 :            :                  */
     606                 :          0 :                 if (type == st_root)
     607                 :          0 :                         break;
     608                 :            : 
     609                 :            :                 /* fallthrough*/
     610                 :            :         case st_sw_upstream:
     611                 :            :         case st_builtin:
     612                 :            :         case st_slot:
     613                 :          0 :                 if (!is_port(parent)) {
     614                 :          0 :                         SM_ERR("%s connected to %s (%d), should be %s or %s!\n",
     615                 :            :                                 st_name(type), parent->name, pid,
     616                 :            :                                 st_name(st_root), st_name(st_sw_downstream));
     617                 :          0 :                         return;
     618                 :            :                 }
     619                 :            : 
     620                 :          0 :                 vid = (be32_to_cpu(entry->vendor_id) & 0xffff);
     621                 :          0 :                 did = (be32_to_cpu(entry->device_id) & 0xffff);
     622                 :            : 
     623                 :          0 :                 prlog(PR_DEBUG, "Found %s slot with %x:%x\n",
     624                 :            :                         st_name(type), vid, did);
     625                 :            : 
     626                 :            :                 /* The VID:DID is only meaningful for builtins and switches */
     627                 :          0 :                 if (type == st_sw_upstream && vid && did) {
     628                 :          0 :                         node = dt_new_2addr(parent, st_name(type), vid, did);
     629                 :          0 :                         dt_add_property_cells(node, "reg", vid, did);
     630                 :            :                 } else {
     631                 :            :                         /*
     632                 :            :                          * If we get no vdid then create a "wildcard" slot
     633                 :            :                          * that matches any device
     634                 :            :                          */
     635                 :          0 :                         node = dt_new(parent, st_name(type));
     636                 :            :                 }
     637                 :            : 
     638                 :          0 :                 if (type == st_sw_upstream) {
     639                 :          0 :                         dt_add_property_cells(node, "#address-cells", 1);
     640                 :          0 :                         dt_add_property_cells(node, "#size-cells", 0);
     641                 :          0 :                         dt_add_property_cells(node, "upstream-port",
     642                 :            :                                         entry->up_port);
     643                 :            :                 }
     644                 :          0 :                 break;
     645                 :            : 
     646                 :          0 :         case st_sw_downstream: /* slot connected to switch output */
     647                 :          0 :                 node = dt_new_addr(parent, "down-port", entry->down_port);
     648                 :          0 :                 dt_add_property_strings(node, "compatible",
     649                 :            :                                 "ibm,pcie-port");
     650                 :          0 :                 dt_add_property_cells(node, "reg", entry->down_port);
     651                 :            : 
     652                 :          0 :                 break;
     653                 :            : 
     654                 :          0 :         default:
     655                 :          0 :                 SM_ERR("Unknown slot map type %x\n", entry->type);
     656                 :          0 :                 return;
     657                 :            :         }
     658                 :            : 
     659                 :            :         /*
     660                 :            :          * Now add any generic slot map properties.
     661                 :            :          */
     662                 :            : 
     663                 :            :         /* private since we don't want hdat stuff leaking */
     664                 :          0 :         dt_add_property_cells(node, DT_PRIVATE "entry_id", eid);
     665                 :            : 
     666                 :          0 :         if (entry->mrw_slot_id)
     667                 :          0 :                 dt_add_property_cells(node, "mrw-slot-id",
     668                 :            :                                 be16_to_cpu(entry->mrw_slot_id));
     669                 :            : 
     670                 :          0 :         if (entry->lane_mask)
     671                 :          0 :                 dt_add_property_cells(node, "lane-mask",
     672                 :            :                                 be16_to_cpu(entry->lane_mask));
     673                 :            : 
     674                 :            :         /* what is the difference between this and the lane reverse? */
     675                 :          0 :         if (entry->lane_reverse)
     676                 :          0 :                 dt_add_property_cells(node, "lanes-reversed",
     677                 :            :                                 be16_to_cpu(entry->lane_reverse));
     678                 :            : 
     679                 :          0 :         if (strnlen(entry->name, sizeof(entry->name))) {
     680                 :            :                 /*
     681                 :            :                  * HACK: On some platforms (witherspoon) the slot label is
     682                 :            :                  * applied to the device rather than the pcie downstream port
     683                 :            :                  * that has the slot under it. Hack around this by moving the
     684                 :            :                  * slot label up if the parent port doesn't have one.
     685                 :            :                  */
     686                 :          0 :                 if (dt_node_is_compatible(node->parent, "ibm,pcie-port") &&
     687                 :          0 :                     !dt_find_property(node->parent, "ibm,slot-label")) {
     688                 :          0 :                         dt_add_property_nstr(node->parent, "ibm,slot-label",
     689                 :          0 :                                         entry->name, sizeof(entry->name));
     690                 :            :                 }
     691                 :            : 
     692                 :          0 :                 dt_add_property_nstr(node, "ibm,slot-label",
     693                 :          0 :                                 entry->name, sizeof(entry->name));
     694                 :            :         }
     695                 :            : 
     696                 :          0 :         if (entry->type == st_slot || entry->type == st_rc_slot)
     697                 :          0 :                 dt_add_property(node, "ibm,pluggable", NULL, 0);
     698                 :            : 
     699                 :          0 :         if (details)
     700                 :          0 :                 parse_slot_details(node, details);
     701                 :            : }
     702                 :            : 
     703                 :            : /*
     704                 :            :  * Under the IOHUB structure we have and idata array describing
     705                 :            :  * the PHBs under each chip. The IOHUB structure also has a child
     706                 :            :  * array called IOSLOT which describes slot map. The i`th element
     707                 :            :  * of the IOSLOT array corresponds to the slot map of the i`th
     708                 :            :  * element of the iohubs idata array.
     709                 :            :  *
     710                 :            :  * Probably.
     711                 :            :  *
     712                 :            :  * Furthermore, arrayarrayarrayarrayarray.
     713                 :            :  */
     714                 :            : 
     715                 :          0 : static struct dt_node *get_slot_node(void)
     716                 :            : {
     717                 :          0 :         struct dt_node *slots = dt_find_by_name(dt_root, "ibm,pcie-slots");
     718                 :            : 
     719                 :          0 :         if (!slots) {
     720                 :          0 :                 slots = dt_new(dt_root, "ibm,pcie-slots");
     721                 :          0 :                 dt_add_property_cells(slots, "#address-cells", 2);
     722                 :          0 :                 dt_add_property_cells(slots, "#size-cells", 0);
     723                 :            :         }
     724                 :            : 
     725                 :          0 :         return slots;
     726                 :            : }
     727                 :            : 
     728                 :          2 : static void io_parse_slots(const struct HDIF_common_hdr *sp_iohubs, int hub_id)
     729                 :            : {
     730                 :            :         const struct HDIF_child_ptr *ioslot_arr;
     731                 :            :         const struct HDIF_array_hdr *entry_arr;
     732                 :            :         const struct HDIF_common_hdr *ioslot;
     733                 :            :         const struct slot_map_entry *entry;
     734                 :            :         unsigned int i, count;
     735                 :            : 
     736                 :          2 :         if (be16_to_cpu(sp_iohubs->child_count) <= CECHUB_CHILD_IOSLOTS)
     737                 :          2 :                 return;
     738                 :            : 
     739                 :          0 :         ioslot_arr = HDIF_child_arr(sp_iohubs, CECHUB_CHILD_IOSLOTS);
     740                 :          0 :         if (!ioslot_arr)
     741                 :          0 :                 return;
     742                 :            : 
     743                 :          0 :         count = be32_to_cpu(ioslot_arr->count); /* should only be 1 */
     744                 :          0 :         if (!count)
     745                 :          0 :                 return;
     746                 :            : 
     747                 :          0 :         dt_slots = get_slot_node();
     748                 :            : 
     749                 :          0 :         prlog(PR_DEBUG, "CEC: Found slot map for IOHUB %d\n", hub_id);
     750                 :          0 :         if (count > 1)
     751                 :          0 :                 prerror("CEC: Multiple IOSLOTs found for IO HUB %d\n", hub_id);
     752                 :            : 
     753                 :          0 :         ioslot = HDIF_child(sp_iohubs, ioslot_arr, 0, "IOSLOT");
     754                 :          0 :         if (!ioslot)
     755                 :          0 :                 return;
     756                 :            : 
     757                 :          0 :         entry_arr = HDIF_get_iarray(ioslot, IOSLOT_IDATA_SLOTMAP, NULL);
     758                 :          0 :         HDIF_iarray_for_each(entry_arr, i, entry) {
     759                 :            :                 const struct slot_map_details *details;
     760                 :            : 
     761                 :          0 :                 details = find_slot_details(ioslot,
     762                 :          0 :                                 be16_to_cpu(entry->entry_id));
     763                 :          0 :                 parse_one_slot(entry, details, hub_id);
     764                 :            :         }
     765                 :            : }
     766                 :            : 
     767                 :          1 : static void io_parse_fru(const void *sp_iohubs)
     768                 :            : {
     769                 :            :         unsigned int i;
     770                 :            :         int count;
     771                 :            : 
     772                 :          1 :         count = HDIF_get_iarray_size(sp_iohubs, CECHUB_FRU_IO_HUBS);
     773                 :          1 :         if (count < 1) {
     774                 :          0 :                 prerror("CEC: IO FRU with no chips !\n");
     775                 :          0 :                 return;
     776                 :            :         }
     777                 :            : 
     778                 :          1 :         prlog(PR_INFO, "CEC:   %d chips in FRU\n", count);
     779                 :            : 
     780                 :            :         /* Iterate IO hub array */
     781                 :          3 :         for (i = 0; i < count; i++) {
     782                 :            :                 const struct cechub_io_hub *hub;
     783                 :            :                 unsigned int size, hub_id;
     784                 :            :                 uint32_t chip_id;
     785                 :            : 
     786                 :          2 :                 hub = HDIF_get_iarray_item(sp_iohubs, CECHUB_FRU_IO_HUBS,
     787                 :            :                                            i, &size);
     788                 :          2 :                 if (!hub || size < CECHUB_IOHUB_MIN_SIZE) {
     789                 :          0 :                         prerror("CEC:     IO-HUB Chip %d bad idata\n", i);
     790                 :          0 :                         continue;
     791                 :            :                 }
     792                 :            : 
     793                 :          2 :                 switch (hub->flags & CECHUB_HUB_FLAG_STATE_MASK) {
     794                 :          2 :                 case CECHUB_HUB_FLAG_STATE_OK:
     795                 :          2 :                         prlog(PR_DEBUG, "CEC:   IO Hub Chip #%d OK\n", i);
     796                 :          2 :                         break;
     797                 :          0 :                 case CECHUB_HUB_FLAG_STATE_FAILURES:
     798                 :          0 :                         prlog(PR_WARNING, "CEC:   IO Hub Chip #%d OK"
     799                 :            :                               " with failures\n", i);
     800                 :          0 :                         break;
     801                 :          0 :                 case CECHUB_HUB_FLAG_STATE_NOT_INST:
     802                 :          0 :                         prlog(PR_DEBUG, "CEC:   IO Hub Chip #%d"
     803                 :            :                               " Not installed\n", i);
     804                 :          0 :                         continue;
     805                 :          0 :                 case CECHUB_HUB_FLAG_STATE_UNUSABLE:
     806                 :          0 :                         prlog(PR_DEBUG, "CEC:   IO Hub Chip #%d Unusable\n", i);
     807                 :          0 :                         continue;
     808                 :            :                 }
     809                 :            : 
     810                 :          2 :                 hub_id = be16_to_cpu(hub->iohub_id);
     811                 :            : 
     812                 :            :                 /* GX BAR assignment */
     813                 :          2 :                 prlog(PR_DEBUG, "CEC:   PChip: %d HUB ID: %04x [EC=0x%x]"
     814                 :            :                       " Hub#=%d)\n",
     815                 :            :                       be32_to_cpu(hub->proc_chip_id), hub_id,
     816                 :            :                       be32_to_cpu(hub->ec_level), be16_to_cpu(hub->hub_num));
     817                 :            : 
     818                 :          2 :                 switch(hub_id) {
     819                 :          2 :                 case CECHUB_HUB_MURANO:
     820                 :            :                 case CECHUB_HUB_MURANO_SEGU:
     821                 :          2 :                         prlog(PR_INFO, "CEC:     Murano !\n");
     822                 :          2 :                         io_add_p8(hub, sp_iohubs);
     823                 :          2 :                         break;
     824                 :          0 :                 case CECHUB_HUB_VENICE_WYATT:
     825                 :          0 :                         prlog(PR_INFO, "CEC:     Venice !\n");
     826                 :          0 :                         io_add_p8(hub, sp_iohubs);
     827                 :          0 :                         break;
     828                 :          0 :                 case CECHUB_HUB_NIMBUS_SFORAZ:
     829                 :            :                 case CECHUB_HUB_NIMBUS_MONZA:
     830                 :            :                 case CECHUB_HUB_NIMBUS_LAGRANGE:
     831                 :          0 :                         prlog(PR_INFO, "CEC:     Nimbus !\n");
     832                 :          0 :                         io_add_p9(hub, sp_iohubs);
     833                 :          0 :                         break;
     834                 :          0 :                 case CECHUB_HUB_CUMULUS_DUOMO:
     835                 :          0 :                         prlog(PR_INFO, "CEC:     Cumulus !\n");
     836                 :          0 :                         io_add_p9(hub, sp_iohubs);
     837                 :          0 :                         break;
     838                 :          0 :                 case CECHUB_HUB_AXONE_HOPPER:
     839                 :          0 :                         prlog(PR_INFO, "CEC:     Axone !\n");
     840                 :          0 :                         io_add_p9(hub, sp_iohubs);
     841                 :          0 :                         break;
     842                 :          0 :                 case CECHUB_HUB_RAINIER:
     843                 :          0 :                         prlog(PR_INFO, "CEC:     Rainier !\n");
     844                 :          0 :                         io_add_p9(hub, sp_iohubs);
     845                 :          0 :                         break;
     846                 :          0 :                 case CECHUB_HUB_DENALI:
     847                 :          0 :                         prlog(PR_INFO, "CEC:     Denali !\n");
     848                 :          0 :                         io_add_p9(hub, sp_iohubs);
     849                 :          0 :                         break;
     850                 :          0 :                 default:
     851                 :          0 :                         prlog(PR_ERR, "CEC:     Hub ID 0x%04x unsupported !\n",
     852                 :            :                               hub_id);
     853                 :            :                 }
     854                 :            : 
     855                 :          2 :                 chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
     856                 :            : 
     857                 :            :                 /* parse the slot map if we have one */
     858                 :          2 :                 io_parse_slots(sp_iohubs, chip_id);
     859                 :            :         }
     860                 :            : 
     861                 :          1 :         if (proc_gen == proc_gen_p8 || proc_gen == proc_gen_p9 || proc_gen == proc_gen_p10)
     862                 :          1 :                 io_add_p8_cec_vpd(sp_iohubs);
     863                 :            : }
     864                 :            : 
     865                 :          1 : void io_parse(void)
     866                 :            : {
     867                 :            :         const struct HDIF_common_hdr *sp_iohubs;
     868                 :            :         unsigned int i, size;
     869                 :            : 
     870                 :            :         /* Look for IO Hubs */
     871                 :          1 :         if (!get_hdif(&spiras->ntuples.cec_iohub_fru, "IO HUB")) {
     872                 :          0 :                 prerror("CEC: Cannot locate IO Hub FRU data !\n");
     873                 :          0 :                 return;
     874                 :            :         }
     875                 :            : 
     876                 :            :         /*
     877                 :            :          * Note about LXRn numbering ...
     878                 :            :          *
     879                 :            :          * I can't completely make sense of what that is supposed to be, so
     880                 :            :          * for now, what we do is look for the first one we can find and
     881                 :            :          * increment it for each chip. Works for the machines I have here
     882                 :            :          */
     883                 :            : 
     884                 :          2 :         for_each_ntuple_idx(&spiras->ntuples.cec_iohub_fru, sp_iohubs, i,
     885                 :            :                             CECHUB_FRU_HDIF_SIG) {
     886                 :            :                 const struct cechub_hub_fru_id *fru_id_data;
     887                 :            :                 unsigned int type;
     888                 :            :                 static const char *typestr[] = {
     889                 :            :                         "Reservation",
     890                 :            :                         "Card",
     891                 :            :                         "CPU Card",
     892                 :            :                         "Backplane",
     893                 :            :                         "Backplane Extension"
     894                 :            :                 };
     895                 :          1 :                 fru_id_data = HDIF_get_idata(sp_iohubs, CECHUB_FRU_ID_DATA_AREA,
     896                 :            :                                              &size);
     897                 :          1 :                 if (!fru_id_data || size < sizeof(struct cechub_hub_fru_id)) {
     898                 :          0 :                         prerror("CEC: IO-HUB FRU %d, bad ID data\n", i);
     899                 :          0 :                         continue;
     900                 :            :                 }
     901                 :          1 :                 type = be32_to_cpu(fru_id_data->card_type);
     902                 :            : 
     903                 :          1 :                 prlog(PR_INFO, "CEC: HUB FRU %d is %s\n",
     904                 :            :                       i, type > 4 ? "Unknown" : typestr[type]);
     905                 :            : 
     906                 :            :                 /*
     907                 :            :                  * We currently only handle the backplane (Juno) and
     908                 :            :                  * processor FRU (P8 machines)
     909                 :            :                  */
     910                 :          1 :                 if (type != CECHUB_FRU_TYPE_CEC_BKPLANE &&
     911                 :            :                     type != CECHUB_FRU_TYPE_CPU_CARD) {
     912                 :          0 :                         prerror("CEC:   Unsupported type\n");
     913                 :          0 :                         continue;
     914                 :            :                 }
     915                 :            : 
     916                 :            :                 /* We don't support Hubs connected to pass-through ports */
     917                 :          1 :                 if (fru_id_data->flags & (CECHUB_FRU_FLAG_HEADLESS |
     918                 :            :                                           CECHUB_FRU_FLAG_PASSTHROUGH)) {
     919                 :          0 :                         prerror("CEC:   Headless or Passthrough unsupported\n");
     920                 :          0 :                         continue;
     921                 :            :                 }
     922                 :            : 
     923                 :            :                 /* Ok, we have a reasonable candidate */
     924                 :          1 :                 io_parse_fru(sp_iohubs);
     925                 :            :         }
     926                 :            : }
     927                 :            : 

Generated by: LCOV version 1.14