/*
* This file is provided under a CDDLv1 license. When using or
* redistributing this file, you may do so under this license.
* In redistributing this file this license must be included
* and no other modification of this header file is permitted.
*
* CDDL LICENSE SUMMARY
*
* Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
*
* The contents of this file are subject to the terms of Version
* 1.0 of the Common Development and Distribution License (the "License").
*
* You should have received a copy of the License with this software.
* You can obtain a copy of the License at
* http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
/*
* **********************************************************************
* *
* Module Name: *
* e1000g_debug.c *
* *
* Abstract: *
* This module includes the debug routines *
* *
* **********************************************************************
*/
#ifdef GCC
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#define _SYS_VARARGS_H
#endif
#include "e1000g_debug.h"
#include "e1000g_sw.h"
#ifdef E1000G_DEBUG
#include <sys/pcie.h>
#endif
#ifdef E1000G_DEBUG
#define WPL 8 /* 8 16-bit words per line */
#define NUM_REGS 155 /* must match the array initializer */
typedef struct {
char name[10];
uint32_t offset;
} Regi_t;
int e1000g_debug = E1000G_WARN_LEVEL;
#endif /* E1000G_DEBUG */
int e1000g_log_mode = E1000G_LOG_PRINT;
void
e1000g_log(void *instance, int level, char *fmt, ...)
{
struct e1000g *Adapter = (struct e1000g *)instance;
auto char name[NAMELEN];
auto char buf[BUFSZ];
va_list ap;
switch (level) {
#ifdef E1000G_DEBUG
case E1000G_VERBOSE_LEVEL: /* 16 or 0x010 */
if (e1000g_debug < E1000G_VERBOSE_LEVEL)
return;
level = CE_CONT;
break;
case E1000G_TRACE_LEVEL: /* 8 or 0x008 */
if (e1000g_debug < E1000G_TRACE_LEVEL)
return;
level = CE_CONT;
break;
case E1000G_INFO_LEVEL: /* 4 or 0x004 */
if (e1000g_debug < E1000G_INFO_LEVEL)
return;
level = CE_CONT;
break;
case E1000G_WARN_LEVEL: /* 2 or 0x002 */
if (e1000g_debug < E1000G_WARN_LEVEL)
return;
level = CE_CONT;
break;
case E1000G_ERRS_LEVEL: /* 1 or 0x001 */
level = CE_CONT;
break;
#else
case CE_CONT:
case CE_NOTE:
case CE_WARN:
case CE_PANIC:
break;
#endif
default:
level = CE_CONT;
break;
}
if (Adapter != NULL) {
(void) sprintf(name, "%s - e1000g[%d] ",
ddi_get_name(Adapter->dip), ddi_get_instance(Adapter->dip));
} else {
(void) sprintf(name, "e1000g");
}
/*
* va_start uses built in macro __builtin_va_alist from the
* compiler libs which requires compiler system to have
* __BUILTIN_VA_ARG_INCR defined.
*/
/*
* Many compilation systems depend upon the use of special functions
* built into the the compilation system to handle variable argument
* lists and stack allocations. The method to obtain this in SunOS
* is to define the feature test macro "__BUILTIN_VA_ARG_INCR" which
* enables the following special built-in functions:
* __builtin_alloca
* __builtin_va_alist
* __builtin_va_arg_incr
* It is intended that the compilation system define this feature test
* macro, not the user of the system.
*
* The tests on the processor type are to provide a transitional period
* for existing compilation systems, and may be removed in a future
* release.
*/
/*
* Using GNU gcc compiler it doesn't expand to va_start....
*/
va_start(ap, fmt);
(void) vsprintf(buf, fmt, ap);
va_end(ap);
if ((e1000g_log_mode & E1000G_LOG_ALL) == E1000G_LOG_ALL)
cmn_err(level, "%s: %s", name, buf);
else if (e1000g_log_mode & E1000G_LOG_DISPLAY)
cmn_err(level, "^%s: %s", name, buf);
else if (e1000g_log_mode & E1000G_LOG_PRINT)
cmn_err(level, "!%s: %s", name, buf);
else /* if they are not set properly then do both */
cmn_err(level, "%s: %s", name, buf);
}
#ifdef E1000G_DEBUG
extern kmutex_t e1000g_nvm_lock;
void
eeprom_dump(void *instance)
{
struct e1000g *Adapter = (struct e1000g *)instance;
struct e1000_hw *hw = &Adapter->shared;
uint16_t eeprom[WPL], size_field;
int i, ret, sign, size, lines, offset = 0;
int ee_size[] =
{128, 256, 512, 1024, 2048, 4096, 16 * 1024, 32 * 1024, 64 * 1024};
mutex_enter(&e1000g_nvm_lock);
if (ret = e1000_read_nvm(hw, 0x12, 1, &size_field)) {
e1000g_log(Adapter, CE_WARN,
"e1000_read_nvm failed to read size: %d", ret);
goto eeprom_dump_end;
}
sign = (size_field & 0xc000) >> 14;
if (sign != 1) {
e1000g_log(Adapter, CE_WARN,
"eeprom_dump invalid signature: %d", sign);
}
size = (size_field & 0x3c00) >> 10;
if (size < 0 || size > 11) {
e1000g_log(Adapter, CE_WARN,
"eeprom_dump invalid size: %d", size);
}
e1000g_log(Adapter, CE_CONT,
"eeprom_dump size field: %d eeprom bytes: %d\n",
size, ee_size[size]);
e1000g_log(Adapter, CE_CONT,
"e1000_read_nvm hebs: %d\n", ((size_field & 0x000f) >> 10));
lines = ee_size[size] / WPL / 2;
e1000g_log(Adapter, CE_CONT,
"dump eeprom %d lines of %d words per line\n", lines, WPL);
for (i = 0; i < lines; i++) {
if (ret = e1000_read_nvm(hw, offset, WPL, eeprom)) {
e1000g_log(Adapter, CE_WARN,
"e1000_read_nvm failed: %d", ret);
goto eeprom_dump_end;
}
e1000g_log(Adapter, CE_CONT,
"0x%04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
offset,
eeprom[0], eeprom[1], eeprom[2], eeprom[3],
eeprom[4], eeprom[5], eeprom[6], eeprom[7]);
offset += WPL;
}
eeprom_dump_end:
mutex_exit(&e1000g_nvm_lock);
}
/*
* phy_dump - dump important phy registers
*/
void
phy_dump(void *instance)
{
struct e1000g *Adapter = (struct e1000g *)instance;
struct e1000_hw *hw = &Adapter->shared;
/* offset to each phy register */
int32_t offset[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 0x1796, 0x187A, 0x1895, 0x1F30, 0x1F35, 0x1F3E, 0x1F54,
0x1F55, 0x1F56, 0x1F72, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F98,
0x2010, 0x2011, 0x20DC, 0x20DD, 0x20DE, 0x28B4, 0x2F52, 0x2F5B,
0x2F70, 0x2F90, 0x2FB1, 0x2FB2 };
uint16_t value; /* register value */
uint32_t stat; /* status from e1000_read_phy_reg */
int i;
e1000g_log(Adapter, CE_CONT, "Begin PHY dump\n");
for (i = 0; i < ((sizeof (offset)) / sizeof (offset[0])); i++) {
stat = e1000_read_phy_reg(hw, offset[i], &value);
if (stat == 0) {
e1000g_log(Adapter, CE_CONT,
"phyreg offset: %d value: 0x%x\n",
offset[i], value);
} else {
e1000g_log(Adapter, CE_WARN,
"phyreg offset: %d ERROR: 0x%x\n",
offset[i], stat);
}
}
}
uint32_t
e1000_read_reg(struct e1000_hw *hw, uint32_t offset)
{
return (ddi_get32(((struct e1000g_osdep *)(hw)->back)->reg_handle,
(uint32_t *)((uintptr_t)(hw)->hw_addr + offset)));
}
/*
* mac_dump - dump important mac registers
*/
void
mac_dump(void *instance)
{
struct e1000g *Adapter = (struct e1000g *)instance;
struct e1000_hw *hw = &Adapter->shared;
int i;
/* {name, offset} for each mac register */
Regi_t macreg[NUM_REGS] = {
{"CTRL", E1000_CTRL}, {"STATUS", E1000_STATUS},
{"EECD", E1000_EECD}, {"EERD", E1000_EERD},
{"CTRL_EXT", E1000_CTRL_EXT}, {"FLA", E1000_FLA},
{"MDIC", E1000_MDIC}, {"SCTL", E1000_SCTL},
{"FCAL", E1000_FCAL}, {"FCAH", E1000_FCAH},
{"FCT", E1000_FCT}, {"VET", E1000_VET},
{"ICR", E1000_ICR}, {"ITR", E1000_ITR},
{"ICS", E1000_ICS}, {"IMS", E1000_IMS},
{"IMC", E1000_IMC}, {"IAM", E1000_IAM},
{"RCTL", E1000_RCTL}, {"FCTTV", E1000_FCTTV},
{"TXCW", E1000_TXCW}, {"RXCW", E1000_RXCW},
{"TCTL", E1000_TCTL}, {"TIPG", E1000_TIPG},
{"AIT", E1000_AIT}, {"LEDCTL", E1000_LEDCTL},
{"PBA", E1000_PBA}, {"PBS", E1000_PBS},
{"EEMNGCTL", E1000_EEMNGCTL}, {"ERT", E1000_ERT},
{"FCRTL", E1000_FCRTL}, {"FCRTH", E1000_FCRTH},
{"PSRCTL", E1000_PSRCTL}, {"RDBAL(0)", E1000_RDBAL(0)},
{"RDBAH(0)", E1000_RDBAH(0)}, {"RDLEN(0)", E1000_RDLEN(0)},
{"RDH(0)", E1000_RDH(0)}, {"RDT(0)", E1000_RDT(0)},
{"RDTR", E1000_RDTR}, {"RXDCTL(0)", E1000_RXDCTL(0)},
{"RADV", E1000_RADV}, {"RDBAL(1)", E1000_RDBAL(1)},
{"RDBAH(1)", E1000_RDBAH(1)}, {"RDLEN(1)", E1000_RDLEN(1)},
{"RDH(1)", E1000_RDH(1)}, {"RDT(1)", E1000_RDT(1)},
{"RXDCTL(1)", E1000_RXDCTL(1)}, {"RSRPD", E1000_RSRPD},
{"RAID", E1000_RAID}, {"CPUVEC", E1000_CPUVEC},
{"TDFH", E1000_TDFH}, {"TDFT", E1000_TDFT},
{"TDFHS", E1000_TDFHS}, {"TDFTS", E1000_TDFTS},
{"TDFPC", E1000_TDFPC}, {"TDBAL(0)", E1000_TDBAL(0)},
{"TDBAH(0)", E1000_TDBAH(0)}, {"TDLEN(0)", E1000_TDLEN(0)},
{"TDH(0)", E1000_TDH(0)}, {"TDT(0)", E1000_TDT(0)},
{"TIDV", E1000_TIDV}, {"TXDCTL(0)", E1000_TXDCTL(0)},
{"TADV", E1000_TADV}, {"TARC(0)", E1000_TARC(0)},
{"TDBAL(1)", E1000_TDBAL(1)}, {"TDBAH(1)", E1000_TDBAH(1)},
{"TDLEN(1)", E1000_TDLEN(1)}, {"TDH(1)", E1000_TDH(1)},
{"TDT(1)", E1000_TDT(1)}, {"TXDCTL(1)", E1000_TXDCTL(1)},
{"TARC(1)", E1000_TARC(1)}, {"ALGNERRC", E1000_ALGNERRC},
{"RXERRC", E1000_RXERRC}, {"MPC", E1000_MPC},
{"SCC", E1000_SCC}, {"ECOL", E1000_ECOL},
{"MCC", E1000_MCC}, {"LATECOL", E1000_LATECOL},
{"COLC", E1000_COLC}, {"DC", E1000_DC},
{"TNCRS", E1000_TNCRS}, {"SEC", E1000_SEC},
{"CEXTERR", E1000_CEXTERR}, {"RLEC", E1000_RLEC},
{"XONRXC", E1000_XONRXC}, {"XONTXC", E1000_XONTXC},
{"XOFFRXC", E1000_XOFFRXC}, {"XOFFTXC", E1000_XOFFTXC},
{"FCRUC", E1000_FCRUC}, {"PRC64", E1000_PRC64},
{"PRC127", E1000_PRC127}, {"PRC255", E1000_PRC255},
{"PRC511", E1000_PRC511}, {"PRC1023", E1000_PRC1023},
{"PRC1522", E1000_PRC1522}, {"GPRC", E1000_GPRC},
{"BPRC", E1000_BPRC}, {"MPRC", E1000_MPRC},
{"GPTC", E1000_GPTC}, {"GORCL", E1000_GORCL},
{"GORCH", E1000_GORCH}, {"GOTCL", E1000_GOTCL},
{"GOTCH", E1000_GOTCH}, {"RNBC", E1000_RNBC},
{"RUC", E1000_RUC}, {"RFC", E1000_RFC},
{"ROC", E1000_ROC}, {"RJC", E1000_RJC},
{"MGTPRC", E1000_MGTPRC}, {"MGTPDC", E1000_MGTPDC},
{"MGTPTC", E1000_MGTPTC}, {"TORL", E1000_TORL},
{"TORH", E1000_TORH}, {"TOTL", E1000_TOTL},
{"TOTH", E1000_TOTH}, {"TPR", E1000_TPR},
{"TPT", E1000_TPT}, {"PTC64", E1000_PTC64},
{"PTC127", E1000_PTC127}, {"PTC255", E1000_PTC255},
{"PTC511", E1000_PTC511}, {"PTC1023", E1000_PTC1023},
{"PTC1522", E1000_PTC1522}, {"MPTC", E1000_MPTC},
{"BPTC", E1000_BPTC}, {"TSCTC", E1000_TSCTC},
{"TSCTFC", E1000_TSCTFC}, {"IAC", E1000_IAC},
{"ICRXPTC", E1000_ICRXPTC}, {"ICRXATC", E1000_ICRXATC},
{"ICTXPTC", E1000_ICTXPTC}, {"ICTXATC", E1000_ICTXATC},
{"ICTXQEC", E1000_ICTXQEC}, {"ICTXQMTC", E1000_ICTXQMTC},
{"ICRXDMTC", E1000_ICRXDMTC}, {"ICRXOC", E1000_ICRXOC},
{"RXCSUM", E1000_RXCSUM}, {"RFCTL", E1000_RFCTL},
{"WUC", E1000_WUC}, {"WUFC", E1000_WUFC},
{"WUS", E1000_WUS}, {"MRQC", E1000_MRQC},
{"MANC", E1000_MANC}, {"IPAV", E1000_IPAV},
{"MANC2H", E1000_MANC2H}, {"RSSIM", E1000_RSSIM},
{"RSSIR", E1000_RSSIR}, {"WUPL", E1000_WUPL},
{"GCR", E1000_GCR}, {"GSCL_1", E1000_GSCL_1},
{"GSCL_2", E1000_GSCL_2}, {"GSCL_3", E1000_GSCL_3},
{"GSCL_4", E1000_GSCL_4}, {"FACTPS", E1000_FACTPS},
{"FWSM", E1000_FWSM},
};
e1000g_log(Adapter, CE_CONT, "Begin MAC dump\n");
for (i = 0; i < NUM_REGS; i++) {
e1000g_log(Adapter, CE_CONT,
"macreg %10s offset: 0x%x value: 0x%x\n",
macreg[i].name, macreg[i].offset,
e1000_read_reg(hw, macreg[i].offset));
}
}
void
pciconfig_dump(void *instance)
{
struct e1000g *Adapter = (struct e1000g *)instance;
ddi_acc_handle_t handle;
uint8_t cap_ptr;
uint8_t next_ptr;
off_t offset;
handle = Adapter->osdep.cfg_handle;
e1000g_log(Adapter, CE_CONT, "Begin dump PCI config space\n");
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_VENID:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_VENID));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_DEVID:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_DEVID));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_COMMAND:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_COMM));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_STATUS:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_STAT));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_REVID:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_REVID));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_PROG_CLASS:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_PROGCLASS));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_SUB_CLASS:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_SUBCLASS));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_BAS_CLASS:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_BASCLASS));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_CACHE_LINESZ:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_CACHE_LINESZ));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_LATENCY_TIMER:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_LATENCY_TIMER));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_HEADER_TYPE:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_HEADER));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_BIST:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_BIST));
pciconfig_bar(Adapter, PCI_CONF_BASE0, "PCI_CONF_BASE0");
pciconfig_bar(Adapter, PCI_CONF_BASE1, "PCI_CONF_BASE1");
pciconfig_bar(Adapter, PCI_CONF_BASE2, "PCI_CONF_BASE2");
pciconfig_bar(Adapter, PCI_CONF_BASE3, "PCI_CONF_BASE3");
pciconfig_bar(Adapter, PCI_CONF_BASE4, "PCI_CONF_BASE4");
pciconfig_bar(Adapter, PCI_CONF_BASE5, "PCI_CONF_BASE5");
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_CIS:\t0x%x\n",
pci_config_get32(handle, PCI_CONF_CIS));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_SUBVENID:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_SUBVENID));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_SUBSYSID:\t0x%x\n",
pci_config_get16(handle, PCI_CONF_SUBSYSID));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_ROM:\t0x%x\n",
pci_config_get32(handle, PCI_CONF_ROM));
cap_ptr = pci_config_get8(handle, PCI_CONF_CAP_PTR);
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_CAP_PTR:\t0x%x\n", cap_ptr);
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_ILINE:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_ILINE));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_IPIN:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_IPIN));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_MIN_G:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_MIN_G));
e1000g_log(Adapter, CE_CONT,
"PCI_CONF_MAX_L:\t0x%x\n",
pci_config_get8(handle, PCI_CONF_MAX_L));
/* Power Management */
offset = cap_ptr;
e1000g_log(Adapter, CE_CONT,
"PCI_PM_CAP_ID:\t0x%x\n",
pci_config_get8(handle, offset));
next_ptr = pci_config_get8(handle, offset + 1);
e1000g_log(Adapter, CE_CONT,
"PCI_PM_NEXT_PTR:\t0x%x\n", next_ptr);
e1000g_log(Adapter, CE_CONT,
"PCI_PM_CAP:\t0x%x\n",
pci_config_get16(handle, offset + PCI_PMCAP));
e1000g_log(Adapter, CE_CONT,
"PCI_PM_CSR:\t0x%x\n",
pci_config_get16(handle, offset + PCI_PMCSR));
e1000g_log(Adapter, CE_CONT,
"PCI_PM_CSR_BSE:\t0x%x\n",
pci_config_get8(handle, offset + PCI_PMCSR_BSE));
e1000g_log(Adapter, CE_CONT,
"PCI_PM_DATA:\t0x%x\n",
pci_config_get8(handle, offset + PCI_PMDATA));
/* MSI Configuration */
offset = next_ptr;
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_CAP_ID:\t0x%x\n",
pci_config_get8(handle, offset));
next_ptr = pci_config_get8(handle, offset + 1);
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_NEXT_PTR:\t0x%x\n", next_ptr);
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_CTRL:\t0x%x\n",
pci_config_get16(handle, offset + PCI_MSI_CTRL));
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_ADDR:\t0x%x\n",
pci_config_get32(handle, offset + PCI_MSI_ADDR_OFFSET));
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_ADDR_HI:\t0x%x\n",
pci_config_get32(handle, offset + 0x8));
e1000g_log(Adapter, CE_CONT,
"PCI_MSI_DATA:\t0x%x\n",
pci_config_get16(handle, offset + 0xC));
/* PCI Express Configuration */
offset = next_ptr;
e1000g_log(Adapter, CE_CONT,
"PCIE_CAP_ID:\t0x%x\n",
pci_config_get8(handle, offset + PCIE_CAP_ID));
next_ptr = pci_config_get8(handle, offset + PCIE_CAP_NEXT_PTR);
e1000g_log(Adapter, CE_CONT,
"PCIE_CAP_NEXT_PTR:\t0x%x\n", next_ptr);
e1000g_log(Adapter, CE_CONT,
"PCIE_PCIECAP:\t0x%x\n",
pci_config_get16(handle, offset + PCIE_PCIECAP));
e1000g_log(Adapter, CE_CONT,
"PCIE_DEVCAP:\t0x%x\n",
pci_config_get32(handle, offset + PCIE_DEVCAP));
e1000g_log(Adapter, CE_CONT,
"PCIE_DEVCTL:\t0x%x\n",
pci_config_get16(handle, offset + PCIE_DEVCTL));
e1000g_log(Adapter, CE_CONT,
"PCIE_DEVSTS:\t0x%x\n",
pci_config_get16(handle, offset + PCIE_DEVSTS));
e1000g_log(Adapter, CE_CONT,
"PCIE_LINKCAP:\t0x%x\n",
pci_config_get32(handle, offset + PCIE_LINKCAP));
e1000g_log(Adapter, CE_CONT,
"PCIE_LINKCTL:\t0x%x\n",
pci_config_get16(handle, offset + PCIE_LINKCTL));
e1000g_log(Adapter, CE_CONT,
"PCIE_LINKSTS:\t0x%x\n",
pci_config_get16(handle, offset + PCIE_LINKSTS));
}
void
pciconfig_bar(void *instance, uint32_t offset, char *name)
{
struct e1000g *Adapter = (struct e1000g *)instance;
ddi_acc_handle_t handle = Adapter->osdep.cfg_handle;
uint32_t base = pci_config_get32(handle, offset);
uint16_t comm = pci_config_get16(handle, PCI_CONF_COMM);
uint32_t size; /* derived size of the region */
uint32_t bits_comm; /* command word bits to disable */
uint32_t size_mask; /* mask for size extraction */
char tag_type[32]; /* tag to show memory vs. i/o */
char tag_mem[32]; /* tag to show memory characteristiccs */
/* base address zero, simple print */
if (base == 0) {
e1000g_log(Adapter, CE_CONT, "%s:\t0x%x\n", name, base);
/* base address non-zero, get size */
} else {
/* i/o factors that decode from the base address */
if (base & PCI_BASE_SPACE_IO) {
bits_comm = PCI_COMM_IO;
size_mask = PCI_BASE_IO_ADDR_M;
(void) strcpy(tag_type, "i/o port size:");
(void) strcpy(tag_mem, "");
/* memory factors that decode from the base address */
} else {
bits_comm = PCI_COMM_MAE;
size_mask = PCI_BASE_M_ADDR_M;
(void) strcpy(tag_type, "memory size:");
if (base & PCI_BASE_TYPE_ALL)
(void) strcpy(tag_mem, "64bit ");
else
(void) strcpy(tag_mem, "32bit ");
if (base & PCI_BASE_PREF_M)
(void) strcat(tag_mem, "prefetchable");
else
(void) strcat(tag_mem, "non-prefetchable");
}
/* disable memory decode */
pci_config_put16(handle, PCI_CONF_COMM, (comm & ~bits_comm));
/* write to base register */
pci_config_put32(handle, offset, 0xffffffff);
/* read back & compute size */
size = pci_config_get32(handle, offset);
size &= size_mask;
size = (~size) + 1;
/* restore base register */
pci_config_put32(handle, offset, base);
/* re-enable memory decode */
pci_config_put16(handle, PCI_CONF_COMM, comm);
/* print results */
e1000g_log(Adapter, CE_CONT, "%s:\t0x%x %s 0x%x %s\n",
name, base, tag_type, size, tag_mem);
}
}
#endif /* E1000G_DEBUG */