The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ipmi/ipmi_smbios.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/condvar.h>
   36 #include <sys/eventhandler.h>
   37 #include <sys/kernel.h>
   38 #include <sys/selinfo.h>
   39 #include <sys/efi.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 #if defined(__amd64__) || defined(__i386__)
   44 #include <machine/pc/bios.h>
   45 #endif
   46 #include <dev/smbios/smbios.h>
   47 
   48 #ifdef LOCAL_MODULE
   49 #include <ipmi.h>
   50 #include <ipmivars.h>
   51 #else
   52 #include <sys/ipmi.h>
   53 #include <dev/ipmi/ipmivars.h>
   54 #endif
   55 
   56 struct ipmi_entry {
   57         uint8_t         type;
   58         uint8_t         length;
   59         uint16_t        handle;
   60         uint8_t         interface_type;
   61         uint8_t         spec_revision;
   62         uint8_t         i2c_slave_address;
   63         uint8_t         NV_storage_device_address;
   64         uint64_t        base_address;
   65         uint8_t         base_address_modifier;
   66         uint8_t         interrupt_number;
   67 };
   68 
   69 /* Fields in the base_address field of an IPMI entry. */
   70 #define IPMI_BAR_MODE(ba)       ((ba) & 0x0000000000000001)
   71 #define IPMI_BAR_ADDR(ba)       ((ba) & 0xfffffffffffffffe)
   72 
   73 /* Fields in the base_address_modifier field of an IPMI entry. */
   74 #define IPMI_BAM_IRQ_TRIGGER    0x01
   75 #define IPMI_BAM_IRQ_POLARITY   0x02
   76 #define IPMI_BAM_IRQ_VALID      0x08
   77 #define IPMI_BAM_ADDR_LSB(bam)  (((bam) & 0x10) >> 4)
   78 #define IPMI_BAM_REG_SPACING(bam) (((bam) & 0xc0) >> 6)
   79 #define SPACING_8               0x0
   80 #define SPACING_32              0x1
   81 #define SPACING_16              0x2
   82 
   83 static struct ipmi_get_info ipmi_info;
   84 static int ipmi_probed;
   85 static struct mtx ipmi_info_mtx;
   86 MTX_SYSINIT(ipmi_info, &ipmi_info_mtx, "ipmi info", MTX_DEF);
   87 
   88 static void     ipmi_smbios_probe(struct ipmi_get_info *);
   89 static int      smbios_cksum(struct smbios_eps *);
   90 static void     smbios_ipmi_info(struct smbios_structure_header *, void *);
   91 
   92 static void
   93 smbios_ipmi_info(struct smbios_structure_header *h, void *arg)
   94 {
   95         struct ipmi_get_info *info;
   96         struct ipmi_entry *s;
   97 
   98         if (h->type != 38 || h->length <
   99             offsetof(struct ipmi_entry, interrupt_number))
  100                 return;
  101         s = (struct ipmi_entry *)h;
  102         info = arg;
  103         bzero(info, sizeof(struct ipmi_get_info));
  104         switch (s->interface_type) {
  105         case KCS_MODE:
  106         case SMIC_MODE:
  107                 info->address = IPMI_BAR_ADDR(s->base_address) |
  108                     IPMI_BAM_ADDR_LSB(s->base_address_modifier);
  109                 info->io_mode = IPMI_BAR_MODE(s->base_address);
  110                 switch (IPMI_BAM_REG_SPACING(s->base_address_modifier)) {
  111                 case SPACING_8:
  112                         info->offset = 1;
  113                         break;
  114                 case SPACING_32:
  115                         info->offset = 4;
  116                         break;
  117                 case SPACING_16:
  118                         info->offset = 2;
  119                         break;
  120                 default:
  121                         printf("SMBIOS: Invalid register spacing\n");
  122                         return;
  123                 }
  124                 break;
  125         case SSIF_MODE:
  126                 if ((s->base_address & 0xffffffffffffff00) != 0) {
  127                         printf("SMBIOS: Invalid SSIF SMBus address, using BMC I2C slave address instead\n");
  128                         info->address = s->i2c_slave_address;
  129                         break;
  130                 }
  131                 info->address = IPMI_BAR_ADDR(s->base_address);
  132                 break;
  133         default:
  134                 return;
  135         }
  136         if (s->length > offsetof(struct ipmi_entry, interrupt_number)) {
  137                 if (s->interrupt_number > 15)
  138                         printf("SMBIOS: Non-ISA IRQ %d for IPMI\n",
  139                             s->interrupt_number);
  140                 else
  141                         info->irq = s->interrupt_number;
  142         }
  143         info->iface_type = s->interface_type;
  144 }
  145 
  146 /*
  147  * Walk the SMBIOS table looking for an IPMI (type 38) entry.  If we find
  148  * one, return the parsed data in the passed in ipmi_get_info structure and
  149  * return true.  If we don't find one, return false.
  150  */
  151 static void
  152 ipmi_smbios_probe(struct ipmi_get_info *info)
  153 {
  154 #ifdef ARCH_MAY_USE_EFI
  155         struct uuid efi_smbios;
  156         void *addr_efi;
  157 #endif
  158         struct smbios_eps *header;
  159         void *table;
  160         u_int32_t addr;
  161 
  162         addr = 0;
  163         bzero(info, sizeof(struct ipmi_get_info));
  164 
  165 #ifdef ARCH_MAY_USE_EFI
  166         efi_smbios = (struct uuid)EFI_TABLE_SMBIOS;
  167         if (!efi_get_table(&efi_smbios, &addr_efi))
  168                 addr = (vm_paddr_t)addr_efi;
  169 #endif
  170 
  171         if (addr == 0)
  172                 /* Find the SMBIOS table header. */
  173                 addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN,
  174                         SMBIOS_STEP, SMBIOS_OFF);
  175         if (addr == 0)
  176                 return;
  177 
  178         /*
  179          * Map the header.  We first map a fixed size to get the actual
  180          * length and then map it a second time with the actual length so
  181          * we can verify the checksum.
  182          */
  183         header = pmap_mapbios(addr, sizeof(struct smbios_eps));
  184         table = pmap_mapbios(addr, header->length);
  185         pmap_unmapbios(header, sizeof(struct smbios_eps));
  186         header = table;
  187         if (smbios_cksum(header) != 0) {
  188                 pmap_unmapbios(header, header->length);
  189                 return;
  190         }
  191 
  192         /* Now map the actual table and walk it looking for an IPMI entry. */
  193         table = pmap_mapbios(header->structure_table_address,
  194             header->structure_table_length);
  195         smbios_walk_table(table, header->number_structures, smbios_ipmi_info,
  196             info);
  197 
  198         /* Unmap everything. */
  199         pmap_unmapbios(table, header->structure_table_length);
  200         pmap_unmapbios(header, header->length);
  201 }
  202 
  203 /*
  204  * Return the SMBIOS IPMI table entry info to the caller.  If we haven't
  205  * searched the IPMI table yet, search it.  Otherwise, return a cached
  206  * copy of the data.
  207  */
  208 int
  209 ipmi_smbios_identify(struct ipmi_get_info *info)
  210 {
  211 
  212         mtx_lock(&ipmi_info_mtx);
  213         switch (ipmi_probed) {
  214         case 0:
  215                 /* Need to probe the SMBIOS table. */
  216                 ipmi_probed++;
  217                 mtx_unlock(&ipmi_info_mtx);
  218                 ipmi_smbios_probe(&ipmi_info);
  219                 mtx_lock(&ipmi_info_mtx);
  220                 ipmi_probed++;
  221                 wakeup(&ipmi_info);
  222                 break;
  223         case 1:
  224                 /* Another thread is currently probing the table, so wait. */
  225                 while (ipmi_probed == 1)
  226                         msleep(&ipmi_info, &ipmi_info_mtx, 0, "ipmi info", 0);
  227                 break;
  228         default:
  229                 /* The cached data is available. */
  230                 break;
  231         }
  232 
  233         bcopy(&ipmi_info, info, sizeof(ipmi_info));
  234         mtx_unlock(&ipmi_info_mtx);
  235 
  236         return (info->iface_type != 0);
  237 }
  238 
  239 static int
  240 smbios_cksum(struct smbios_eps *e)
  241 {
  242         u_int8_t *ptr;
  243         u_int8_t cksum;
  244         int i;
  245 
  246         ptr = (u_int8_t *)e;
  247         cksum = 0;
  248         for (i = 0; i < e->length; i++) {
  249                 cksum += ptr[i];
  250         }
  251 
  252         return (cksum);
  253 }

Cache object: 7c0a239465083903f4f6365aee021aba


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.