provide routines to access VPD data at the PCI layer...
remove sk's own implementation, and use the new calls to get the data... Reviewed by: -arch
This commit is contained in:
parent
e230c2c3ca
commit
667dc26e71
@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
@ -90,6 +90,13 @@ static int pci_modevent(module_t mod, int what, void *arg);
|
||||
static void pci_hdrtypedata(device_t pcib, int b, int s, int f,
|
||||
pcicfgregs *cfg);
|
||||
static void pci_read_extcap(device_t pcib, pcicfgregs *cfg);
|
||||
static uint32_t pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg,
|
||||
int reg);
|
||||
#if 0
|
||||
static void pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg,
|
||||
int reg, uint32_t data);
|
||||
#endif
|
||||
static void pci_read_vpd(device_t pcib, pcicfgregs *cfg);
|
||||
|
||||
static device_method_t pci_methods[] = {
|
||||
/* Device interface */
|
||||
@ -127,6 +134,8 @@ static device_method_t pci_methods[] = {
|
||||
DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
|
||||
DEVMETHOD(pci_enable_io, pci_enable_io_method),
|
||||
DEVMETHOD(pci_disable_io, pci_disable_io_method),
|
||||
DEVMETHOD(pci_get_vpd_ident, pci_get_vpd_ident_method),
|
||||
DEVMETHOD(pci_get_vpd_readonly, pci_get_vpd_readonly_method),
|
||||
DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method),
|
||||
DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method),
|
||||
DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
|
||||
@ -344,7 +353,6 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
|
||||
}
|
||||
|
||||
/* read configuration header into pcicfgregs structure */
|
||||
|
||||
struct pci_devinfo *
|
||||
pci_read_device(device_t pcib, int b, int s, int f, size_t size)
|
||||
{
|
||||
@ -428,7 +436,7 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
|
||||
ptrptr = PCIR_CAP_PTR;
|
||||
break;
|
||||
case 2:
|
||||
ptrptr = PCIR_CAP_PTR_2;
|
||||
ptrptr = PCIR_CAP_PTR_2; /* cardbus capabilities ptr */
|
||||
break;
|
||||
default:
|
||||
return; /* no extended capabilities support */
|
||||
@ -468,13 +476,304 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
|
||||
cfg->msi.msi_data = PCIR_MSI_DATA;
|
||||
cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl &
|
||||
PCIM_MSICTRL_MMC_MASK)>>1);
|
||||
break;
|
||||
case PCIY_VPD: /* PCI Vital Product Data */
|
||||
cfg->vpd.vpd_reg = ptr;
|
||||
pci_read_vpd(pcib, cfg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* REG use carry through to next functions */
|
||||
}
|
||||
|
||||
/*
|
||||
* PCI Vital Product Data
|
||||
*/
|
||||
static uint32_t
|
||||
pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg)
|
||||
{
|
||||
#define WREG(n, v, w) PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w)
|
||||
|
||||
KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned"));
|
||||
|
||||
WREG(cfg->vpd.vpd_reg + 2, reg, 2);
|
||||
while ((REG(cfg->vpd.vpd_reg + 2, 2) & 0x8000) != 0x8000)
|
||||
DELAY(1); /* limit looping */
|
||||
|
||||
return REG(cfg->vpd.vpd_reg + 4, 4);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data)
|
||||
{
|
||||
KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned"));
|
||||
|
||||
WREG(cfg->vpd.vpd_reg + 4, data, 4);
|
||||
WREG(cfg->vpd.vpd_reg + 2, reg | 0x8000, 2);
|
||||
while ((REG(cfg->vpd.vpd_reg + 2, 2) & 0x8000) == 0x8000)
|
||||
DELAY(1); /* limit looping */
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#undef WREG
|
||||
|
||||
struct vpd_readstate {
|
||||
device_t pcib;
|
||||
pcicfgregs *cfg;
|
||||
uint32_t val;
|
||||
int bytesinval;
|
||||
int off;
|
||||
uint8_t cksum;
|
||||
};
|
||||
|
||||
static uint8_t
|
||||
vpd_nextbyte(struct vpd_readstate *vrs)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (vrs->bytesinval == 0) {
|
||||
vrs->val = le32toh(pci_read_vpd_reg(vrs->pcib, vrs->cfg,
|
||||
vrs->off));
|
||||
vrs->off += 4;
|
||||
byte = vrs->val & 0xff;
|
||||
vrs->bytesinval = 3;
|
||||
} else {
|
||||
vrs->val = vrs->val >> 8;
|
||||
byte = vrs->val & 0xff;
|
||||
vrs->bytesinval--;
|
||||
}
|
||||
|
||||
vrs->cksum += byte;
|
||||
return byte;
|
||||
}
|
||||
|
||||
static void
|
||||
pci_read_vpd(device_t pcib, pcicfgregs *cfg)
|
||||
{
|
||||
struct vpd_readstate vrs;
|
||||
int state;
|
||||
int name;
|
||||
int remain;
|
||||
int end;
|
||||
int i;
|
||||
uint8_t byte;
|
||||
int alloc, off; /* alloc/off for RO/W arrays */
|
||||
int cksumvalid;
|
||||
int dflen;
|
||||
|
||||
/* init vpd reader */
|
||||
vrs.bytesinval = 0;
|
||||
vrs.off = 0;
|
||||
vrs.pcib = pcib;
|
||||
vrs.cfg = cfg;
|
||||
vrs.cksum = 0;
|
||||
|
||||
state = 0;
|
||||
name = remain = i = 0; /* shut up stupid gcc */
|
||||
alloc = off = 0; /* shut up stupid gcc */
|
||||
dflen = 0; /* shut up stupid gcc */
|
||||
end = 0;
|
||||
cksumvalid = -1;
|
||||
for (; !end;) {
|
||||
byte = vpd_nextbyte(&vrs);
|
||||
#if 0
|
||||
printf("vpd: val: %#x, off: %d, bytesinval: %d, byte: %#hhx, " \
|
||||
"state: %d, remain: %d, name: %#x, i: %d\n", vrs.val,
|
||||
vrs.off, vrs.bytesinval, byte, state, remain, name, i);
|
||||
#endif
|
||||
switch (state) {
|
||||
case 0: /* item name */
|
||||
if (byte & 0x80) {
|
||||
remain = vpd_nextbyte(&vrs);
|
||||
remain |= vpd_nextbyte(&vrs) << 8;
|
||||
if (remain > (0x7f*4 - vrs.off)) {
|
||||
end = 1;
|
||||
printf(
|
||||
"pci%d:%d:%d: invalid vpd data, remain %#x\n",
|
||||
cfg->bus, cfg->slot, cfg->func,
|
||||
remain);
|
||||
}
|
||||
name = byte & 0x7f;
|
||||
} else {
|
||||
remain = byte & 0x7;
|
||||
name = (byte >> 3) & 0xf;
|
||||
}
|
||||
switch (name) {
|
||||
case 0x2: /* String */
|
||||
cfg->vpd.vpd_ident = malloc(remain + 1,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
i = 0;
|
||||
state = 1;
|
||||
break;
|
||||
case 0xf: /* End */
|
||||
end = 1;
|
||||
state = -1;
|
||||
break;
|
||||
case 0x10: /* VPD-R */
|
||||
alloc = 8;
|
||||
off = 0;
|
||||
cfg->vpd.vpd_ros = malloc(alloc *
|
||||
sizeof *cfg->vpd.vpd_ros, M_DEVBUF,
|
||||
M_WAITOK);
|
||||
state = 2;
|
||||
break;
|
||||
case 0x11: /* VPD-W */
|
||||
alloc = 8;
|
||||
off = 0;
|
||||
cfg->vpd.vpd_w = malloc(alloc *
|
||||
sizeof *cfg->vpd.vpd_w, M_DEVBUF,
|
||||
M_WAITOK);
|
||||
state = 5;
|
||||
break;
|
||||
default: /* XXX - unimplemented */
|
||||
state = 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: /* Identifier String */
|
||||
cfg->vpd.vpd_ident[i++] = byte;
|
||||
remain--;
|
||||
if (remain == 0) {
|
||||
cfg->vpd.vpd_ident[i] = '\0';
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* VPD-R Keyword Header */
|
||||
if (off == alloc) {
|
||||
cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros,
|
||||
(alloc *= 2) * sizeof *cfg->vpd.vpd_ros,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
}
|
||||
cfg->vpd.vpd_ros[off].keyword[0] = byte;
|
||||
cfg->vpd.vpd_ros[off].keyword[1] = vpd_nextbyte(&vrs);
|
||||
dflen = vpd_nextbyte(&vrs);
|
||||
cfg->vpd.vpd_ros[off].value = malloc((dflen + 1) *
|
||||
sizeof *cfg->vpd.vpd_ros[off].value,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
remain -= 3;
|
||||
i = 0;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: /* VPD-R Keyword Value */
|
||||
cfg->vpd.vpd_ros[off].value[i++] = byte;
|
||||
if (strncmp(cfg->vpd.vpd_ros[off].keyword,
|
||||
"RV", 2) == 0 && cksumvalid == -1) {
|
||||
if (vrs.cksum == 0)
|
||||
cksumvalid = 1;
|
||||
else {
|
||||
printf(
|
||||
"pci%d:%d:%d: bad VPD cksum, remain %hhu\n",
|
||||
cfg->bus, cfg->slot, cfg->func,
|
||||
vrs.cksum);
|
||||
cksumvalid = 0;
|
||||
}
|
||||
}
|
||||
dflen--;
|
||||
remain--;
|
||||
if (dflen == 0)
|
||||
cfg->vpd.vpd_ros[off++].value[i++] = '\0';
|
||||
if (dflen == 0 && remain == 0) {
|
||||
cfg->vpd.vpd_rocnt = off;
|
||||
cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros,
|
||||
off * sizeof *cfg->vpd.vpd_ros,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
state = 0;
|
||||
} else if (dflen == 0)
|
||||
state = 2;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
remain--;
|
||||
if (remain == 0)
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
case 5: /* VPD-W Keyword Header */
|
||||
if (off == alloc) {
|
||||
cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w,
|
||||
(alloc *= 2) * sizeof *cfg->vpd.vpd_w,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
}
|
||||
cfg->vpd.vpd_w[off].keyword[0] = byte;
|
||||
cfg->vpd.vpd_w[off].keyword[1] = vpd_nextbyte(&vrs);
|
||||
cfg->vpd.vpd_w[off].len = dflen = vpd_nextbyte(&vrs);
|
||||
cfg->vpd.vpd_w[off].start = vrs.off - vrs.bytesinval;
|
||||
cfg->vpd.vpd_w[off].value = malloc((dflen + 1) *
|
||||
sizeof *cfg->vpd.vpd_w[off].value,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
remain -= 3;
|
||||
i = 0;
|
||||
state = 6;
|
||||
break;
|
||||
|
||||
case 6: /* VPD-W Keyword Value */
|
||||
cfg->vpd.vpd_w[off].value[i++] = byte;
|
||||
dflen--;
|
||||
remain--;
|
||||
if (dflen == 0)
|
||||
cfg->vpd.vpd_w[off++].value[i++] = '\0';
|
||||
if (dflen == 0 && remain == 0) {
|
||||
cfg->vpd.vpd_wcnt = off;
|
||||
cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w,
|
||||
off * sizeof *cfg->vpd.vpd_w,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
state = 0;
|
||||
} else if (dflen == 0)
|
||||
state = 5;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("pci%d:%d:%d: invalid state: %d\n",
|
||||
cfg->bus, cfg->slot, cfg->func, state);
|
||||
end = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef REG
|
||||
}
|
||||
|
||||
int
|
||||
pci_get_vpd_ident_method(device_t dev, device_t child, const char **identptr)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
|
||||
*identptr = cfg->vpd.vpd_ident;
|
||||
|
||||
if (*identptr == NULL)
|
||||
return ENXIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw,
|
||||
const char **vptr)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfg->vpd.vpd_rocnt; i++)
|
||||
if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword,
|
||||
sizeof cfg->vpd.vpd_ros[i].keyword) == 0) {
|
||||
*vptr = cfg->vpd.vpd_ros[i].value;
|
||||
}
|
||||
|
||||
if (i != cfg->vpd.vpd_rocnt)
|
||||
return 0;
|
||||
|
||||
*vptr = NULL;
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the offset in configuration space of the requested extended
|
||||
* capability entry or 0 if the specified capability was not found.
|
||||
@ -532,9 +831,19 @@ int
|
||||
pci_freecfg(struct pci_devinfo *dinfo)
|
||||
{
|
||||
struct devlist *devlist_head;
|
||||
int i;
|
||||
|
||||
devlist_head = &pci_devq;
|
||||
|
||||
if (dinfo->cfg.vpd.vpd_reg) {
|
||||
free(dinfo->cfg.vpd.vpd_ident, M_DEVBUF);
|
||||
for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++)
|
||||
free(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF);
|
||||
free(dinfo->cfg.vpd.vpd_ros, M_DEVBUF);
|
||||
for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++)
|
||||
free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
|
||||
free(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
|
||||
}
|
||||
STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
|
||||
free(dinfo, M_DEVBUF);
|
||||
|
||||
@ -766,6 +1075,8 @@ pci_disable_io_method(device_t dev, device_t child, int space)
|
||||
void
|
||||
pci_print_verbose(struct pci_devinfo *dinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bootverbose) {
|
||||
pcicfgregs *cfg = &dinfo->cfg;
|
||||
|
||||
@ -794,6 +1105,31 @@ pci_print_verbose(struct pci_devinfo *dinfo)
|
||||
cfg->pp.pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "",
|
||||
status & PCIM_PSTAT_DMASK);
|
||||
}
|
||||
if (cfg->vpd.vpd_reg) {
|
||||
printf("\tVPD Ident: %s\n", cfg->vpd.vpd_ident);
|
||||
for (i = 0; i < cfg->vpd.vpd_rocnt; i++) {
|
||||
struct vpd_readonly *vrop;
|
||||
vrop = &cfg->vpd.vpd_ros[i];
|
||||
if (strncmp("CP", vrop->keyword, 2) == 0)
|
||||
printf("CP: id %d, BAR%d, off %#x\n",
|
||||
vrop->value[0], vrop->value[1],
|
||||
le16toh(
|
||||
*(uint16_t *)&vrop->value[2]));
|
||||
else if (strncmp("RV", vrop->keyword, 2) == 0)
|
||||
printf("RV: %#hhx\n", vrop->value[0]);
|
||||
else
|
||||
printf("\t%.2s: %s\n", vrop->keyword,
|
||||
vrop->value);
|
||||
}
|
||||
for (i = 0; i < cfg->vpd.vpd_wcnt; i++) {
|
||||
struct vpd_write *vwp;
|
||||
vwp = &cfg->vpd.vpd_w[i];
|
||||
if (strncmp("RW", vwp->keyword, 2) != 0)
|
||||
printf("\t%.2s(%#x-%#x): %s\n",
|
||||
vwp->keyword, vwp->start,
|
||||
vwp->start + vwp->len, vwp->value);
|
||||
}
|
||||
}
|
||||
if (cfg->msi.msi_data) {
|
||||
int ctrl;
|
||||
|
||||
|
@ -56,6 +56,19 @@ METHOD int set_powerstate {
|
||||
int state;
|
||||
};
|
||||
|
||||
METHOD int get_vpd_ident {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
const char **identptr;
|
||||
};
|
||||
|
||||
METHOD int get_vpd_readonly {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
const char *kw;
|
||||
const char **vptr;
|
||||
};
|
||||
|
||||
METHOD int enable_busmaster {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
|
@ -49,6 +49,10 @@ int pci_read_ivar(device_t dev, device_t child, int which,
|
||||
uintptr_t *result);
|
||||
int pci_write_ivar(device_t dev, device_t child, int which,
|
||||
uintptr_t value);
|
||||
int pci_get_vpd_ident_method(device_t dev, device_t child,
|
||||
const char **identptr);
|
||||
int pci_get_vpd_readonly_method(device_t dev, device_t child,
|
||||
const char *kw, const char **vptr);
|
||||
int pci_set_powerstate_method(device_t dev, device_t child,
|
||||
int state);
|
||||
int pci_get_powerstate_method(device_t dev, device_t child);
|
||||
|
@ -59,6 +59,27 @@ struct pcicfg_pp {
|
||||
uint8_t pp_data; /* config space address of PCI power data reg */
|
||||
};
|
||||
|
||||
struct vpd_readonly {
|
||||
char keyword[2];
|
||||
char *value;
|
||||
};
|
||||
|
||||
struct vpd_write {
|
||||
char keyword[2];
|
||||
char *value;
|
||||
int start;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct pcicfg_vpd {
|
||||
uint8_t vpd_reg; /* base register, + 2 for addr, + 4 data */
|
||||
char *vpd_ident; /* string identifier */
|
||||
int vpd_rocnt;
|
||||
struct vpd_readonly *vpd_ros;
|
||||
int vpd_wcnt;
|
||||
struct vpd_write *vpd_w;
|
||||
};
|
||||
|
||||
/* Interesting values for PCI MSI */
|
||||
struct pcicfg_msi {
|
||||
uint16_t msi_ctrl; /* Message Control */
|
||||
@ -103,6 +124,7 @@ typedef struct pcicfg {
|
||||
uint8_t func; /* config space function number */
|
||||
|
||||
struct pcicfg_pp pp; /* pci power management */
|
||||
struct pcicfg_vpd vpd; /* pci vital product data */
|
||||
struct pcicfg_msi msi; /* pci msi */
|
||||
} pcicfgregs;
|
||||
|
||||
@ -292,6 +314,18 @@ pci_disable_io(device_t dev, int space)
|
||||
return(PCI_DISABLE_IO(device_get_parent(dev), dev, space));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_get_vpd_ident(device_t dev, const char **identptr)
|
||||
{
|
||||
return(PCI_GET_VPD_IDENT(device_get_parent(dev), dev, identptr));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
pci_get_vpd_readonly(device_t dev, const char *kw, const char **identptr)
|
||||
{
|
||||
return(PCI_GET_VPD_READONLY(device_get_parent(dev), dev, kw, identptr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the address range falls within the VGA defined address range(s)
|
||||
*/
|
||||
|
@ -256,9 +256,6 @@ static u_int8_t sk_win_read_1(struct sk_softc *, int);
|
||||
static void sk_win_write_4(struct sk_softc *, int, u_int32_t);
|
||||
static void sk_win_write_2(struct sk_softc *, int, u_int32_t);
|
||||
static void sk_win_write_1(struct sk_softc *, int, u_int32_t);
|
||||
static u_int8_t sk_vpd_readbyte(struct sk_softc *, int);
|
||||
static void sk_vpd_read_res(struct sk_softc *, struct vpd_res *, int);
|
||||
static void sk_vpd_read(struct sk_softc *);
|
||||
|
||||
static int sk_miibus_readreg(device_t, int, int);
|
||||
static int sk_miibus_writereg(device_t, int, int, int);
|
||||
@ -472,113 +469,6 @@ sk_win_write_1(sc, reg, val)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VPD EEPROM contains Vital Product Data, as suggested in
|
||||
* the PCI 2.1 specification. The VPD data is separared into areas
|
||||
* denoted by resource IDs. The SysKonnect VPD contains an ID string
|
||||
* resource (the name of the adapter), a read-only area resource
|
||||
* containing various key/data fields and a read/write area which
|
||||
* can be used to store asset management information or log messages.
|
||||
* We read the ID string and read-only into buffers attached to
|
||||
* the controller softc structure for later use. At the moment,
|
||||
* we only use the ID string during skc_attach().
|
||||
*/
|
||||
static u_int8_t
|
||||
sk_vpd_readbyte(sc, addr)
|
||||
struct sk_softc *sc;
|
||||
int addr;
|
||||
{
|
||||
int i;
|
||||
|
||||
sk_win_write_2(sc, SK_PCI_REG(SK_PCI_VPD_ADDR), addr);
|
||||
for (i = 0; i < SK_TIMEOUT; i++) {
|
||||
/* ASUS LOM takes a very long time to read VPD. */
|
||||
DELAY(100);
|
||||
if (sk_win_read_2(sc,
|
||||
SK_PCI_REG(SK_PCI_VPD_ADDR)) & SK_VPD_FLAG)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == SK_TIMEOUT)
|
||||
return(0);
|
||||
|
||||
return(sk_win_read_1(sc, SK_PCI_REG(SK_PCI_VPD_DATA)));
|
||||
}
|
||||
|
||||
static void
|
||||
sk_vpd_read_res(sc, res, addr)
|
||||
struct sk_softc *sc;
|
||||
struct vpd_res *res;
|
||||
int addr;
|
||||
{
|
||||
int i;
|
||||
u_int8_t *ptr;
|
||||
|
||||
ptr = (u_int8_t *)res;
|
||||
for (i = 0; i < sizeof(struct vpd_res); i++)
|
||||
ptr[i] = sk_vpd_readbyte(sc, i + addr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
sk_vpd_read(sc)
|
||||
struct sk_softc *sc;
|
||||
{
|
||||
int pos = 0, i;
|
||||
struct vpd_res res;
|
||||
|
||||
/* Check VPD capability */
|
||||
if (sk_win_read_1(sc, SK_PCI_REG(SK_PCI_VPD_CAPID)) != PCIY_VPD)
|
||||
return;
|
||||
if (sc->sk_vpd_prodname != NULL)
|
||||
free(sc->sk_vpd_prodname, M_DEVBUF);
|
||||
if (sc->sk_vpd_readonly != NULL)
|
||||
free(sc->sk_vpd_readonly, M_DEVBUF);
|
||||
sc->sk_vpd_prodname = NULL;
|
||||
sc->sk_vpd_readonly = NULL;
|
||||
sc->sk_vpd_readonly_len = 0;
|
||||
|
||||
sk_vpd_read_res(sc, &res, pos);
|
||||
|
||||
/*
|
||||
* Bail out quietly if the eeprom appears to be missing or empty.
|
||||
*/
|
||||
if (res.vr_id == 0xff && res.vr_len == 0xff && res.vr_pad == 0xff)
|
||||
return;
|
||||
|
||||
if (res.vr_id != VPD_RES_ID) {
|
||||
device_printf(sc->sk_dev, "bad VPD resource id: expected %x "
|
||||
"got %x\n", VPD_RES_ID, res.vr_id);
|
||||
return;
|
||||
}
|
||||
|
||||
pos += sizeof(res);
|
||||
sc->sk_vpd_prodname = malloc(res.vr_len + 1, M_DEVBUF, M_NOWAIT);
|
||||
if (sc->sk_vpd_prodname != NULL) {
|
||||
for (i = 0; i < res.vr_len; i++)
|
||||
sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos);
|
||||
sc->sk_vpd_prodname[i] = '\0';
|
||||
}
|
||||
pos += res.vr_len;
|
||||
|
||||
sk_vpd_read_res(sc, &res, pos);
|
||||
|
||||
if (res.vr_id != VPD_RES_READ) {
|
||||
device_printf(sc->sk_dev, "bad VPD resource id: expected %x "
|
||||
"got %x\n", VPD_RES_READ, res.vr_id);
|
||||
return;
|
||||
}
|
||||
|
||||
pos += sizeof(res);
|
||||
sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
|
||||
for (i = 0; i < res.vr_len; i++)
|
||||
sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos);
|
||||
sc->sk_vpd_readonly_len = res.vr_len;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
sk_miibus_readreg(dev, phy, reg)
|
||||
device_t dev;
|
||||
@ -1690,7 +1580,8 @@ skc_attach(dev)
|
||||
struct sk_softc *sc;
|
||||
int error = 0, *port, sk_macs;
|
||||
uint8_t skrs;
|
||||
char *pname, *revstr;
|
||||
const char *pname;
|
||||
char *revstr;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sk_dev = dev;
|
||||
@ -1757,9 +1648,6 @@ skc_attach(dev)
|
||||
/* Reset the adapter. */
|
||||
sk_reset(sc);
|
||||
|
||||
/* Read and save vital product data from EEPROM. */
|
||||
sk_vpd_read(sc);
|
||||
|
||||
skrs = sk_win_read_1(sc, SK_EPROM0);
|
||||
if (sc->sk_type == SK_GENESIS) {
|
||||
/* Read and save RAM size and RAMbuffer offset */
|
||||
@ -1811,7 +1699,8 @@ skc_attach(dev)
|
||||
case DEVICEID_DLINK_DGE530T_A1:
|
||||
case DEVICEID_DLINK_DGE530T_B1:
|
||||
/* Stay with VPD PN. */
|
||||
pname = sc->sk_vpd_prodname;
|
||||
if (pci_get_vpd_ident(dev, &pname))
|
||||
goto vpdfailed;
|
||||
break;
|
||||
case DEVICEID_SK_V2:
|
||||
case DEVICEID_MRVL_4360:
|
||||
@ -1821,7 +1710,8 @@ skc_attach(dev)
|
||||
switch (sc->sk_type) {
|
||||
case SK_GENESIS:
|
||||
/* Stay with VPD PN. */
|
||||
pname = sc->sk_vpd_prodname;
|
||||
if (pci_get_vpd_ident(dev, &pname))
|
||||
goto vpdfailed;
|
||||
break;
|
||||
case SK_YUKON:
|
||||
pname = "Marvell Yukon Gigabit Ethernet";
|
||||
@ -1861,6 +1751,7 @@ skc_attach(dev)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpdfailed:
|
||||
device_printf(dev, "unknown device: vendor=%04x, device=%04x, "
|
||||
"chipver=%02x, rev=%x\n",
|
||||
pci_get_vendor(dev), pci_get_device(dev),
|
||||
@ -1908,33 +1799,6 @@ skc_attach(dev)
|
||||
pname != NULL ? pname : "<unknown>", revstr, sc->sk_rev);
|
||||
|
||||
if (bootverbose) {
|
||||
if (sc->sk_vpd_readonly != NULL &&
|
||||
sc->sk_vpd_readonly_len != 0) {
|
||||
char buf[256];
|
||||
char *dp = sc->sk_vpd_readonly;
|
||||
uint16_t l, len = sc->sk_vpd_readonly_len;
|
||||
|
||||
while (len >= 3) {
|
||||
if ((*dp == 'P' && *(dp+1) == 'N') ||
|
||||
(*dp == 'E' && *(dp+1) == 'C') ||
|
||||
(*dp == 'M' && *(dp+1) == 'N') ||
|
||||
(*dp == 'S' && *(dp+1) == 'N')) {
|
||||
l = 0;
|
||||
while (l < *(dp+2)) {
|
||||
buf[l] = *(dp+3+l);
|
||||
++l;
|
||||
}
|
||||
buf[l] = '\0';
|
||||
device_printf(dev, "%c%c: %s\n",
|
||||
*dp, *(dp+1), buf);
|
||||
len -= (3 + l);
|
||||
dp += (3 + l);
|
||||
} else {
|
||||
len -= (3 + *(dp+2));
|
||||
dp += (3 + *(dp+2));
|
||||
}
|
||||
}
|
||||
}
|
||||
device_printf(dev, "chip ver = 0x%02x\n", sc->sk_type);
|
||||
device_printf(dev, "chip rev = 0x%02x\n", sc->sk_rev);
|
||||
device_printf(dev, "SK_EPROM0 = 0x%02x\n", skrs);
|
||||
@ -2084,11 +1948,6 @@ skc_detach(dev)
|
||||
bus_generic_detach(dev);
|
||||
}
|
||||
|
||||
if (sc->sk_vpd_prodname != NULL)
|
||||
free(sc->sk_vpd_prodname, M_DEVBUF);
|
||||
if (sc->sk_vpd_readonly != NULL)
|
||||
free(sc->sk_vpd_readonly, M_DEVBUF);
|
||||
|
||||
if (sc->sk_intrhand)
|
||||
bus_teardown_intr(dev, sc->sk_res[1], sc->sk_intrhand);
|
||||
bus_release_resources(dev, sc->sk_res_spec, sc->sk_res);
|
||||
|
@ -1290,10 +1290,6 @@
|
||||
#define SK_PCI_PWRMGMTCAP 0x004A /* 16 bits */
|
||||
#define SK_PCI_PWRMGMTCTRL 0x004C /* 16 bits */
|
||||
#define SK_PCI_PME_EVENT 0x004F
|
||||
#define SK_PCI_VPD_CAPID 0x0050
|
||||
#define SK_PCI_VPD_NEXTPTR 0x0051
|
||||
#define SK_PCI_VPD_ADDR 0x0052
|
||||
#define SK_PCI_VPD_DATA 0x0054
|
||||
|
||||
#define SK_PSTATE_MASK 0x0003
|
||||
#define SK_PSTATE_D0 0x0000
|
||||
@ -1303,30 +1299,6 @@
|
||||
#define SK_PME_EN 0x0010
|
||||
#define SK_PME_STATUS 0x8000
|
||||
|
||||
/*
|
||||
* VPD flag bit. Set to 0 to initiate a read, will become 1 when
|
||||
* read is complete. Set to 1 to initiate a write, will become 0
|
||||
* when write is finished.
|
||||
*/
|
||||
#define SK_VPD_FLAG 0x8000
|
||||
|
||||
/* VPD structures */
|
||||
struct vpd_res {
|
||||
u_int8_t vr_id;
|
||||
u_int8_t vr_len;
|
||||
u_int8_t vr_pad;
|
||||
};
|
||||
|
||||
struct vpd_key {
|
||||
char vk_key[2];
|
||||
u_int8_t vk_len;
|
||||
};
|
||||
|
||||
#define VPD_RES_ID 0x82 /* ID string */
|
||||
#define VPD_RES_READ 0x90 /* start of read only area */
|
||||
#define VPD_RES_WRITE 0x81 /* start of read/write area */
|
||||
#define VPD_RES_END 0x78 /* end tag */
|
||||
|
||||
#define CSR_WRITE_4(sc, reg, val) \
|
||||
bus_write_4((sc)->sk_res[0], (reg), (val))
|
||||
#define CSR_WRITE_2(sc, reg, val) \
|
||||
@ -1528,9 +1500,6 @@ struct sk_softc {
|
||||
u_int8_t sk_type;
|
||||
u_int8_t sk_rev;
|
||||
u_int8_t spare;
|
||||
char *sk_vpd_prodname;
|
||||
char *sk_vpd_readonly;
|
||||
uint16_t sk_vpd_readonly_len;
|
||||
u_int32_t sk_rboff; /* RAMbuffer offset */
|
||||
u_int32_t sk_ramsize; /* amount of RAM on NIC */
|
||||
u_int32_t sk_pmd; /* physical media type */
|
||||
|
Loading…
Reference in New Issue
Block a user