Improve mac+phy configuration so that hints can be used to describe

layouts different than the defaults:
o hint.npe.0.mac="A", "B", etc. specifies the window for MAC register accesses
o hint.npe.0.mii="A", "B", etc. specifies PHY registers
o hint.npe.1.phy=%d specifies the PHY to map to a port

This allows devices like NSLU to be setup w/o code changes and will
also be used for forthcoming support for more Avila boards.

Reviewed by:	imp
MFC after	1 week
This commit is contained in:
Sam Leffler 2008-03-22 16:53:28 +00:00
parent 0e3ec582c6
commit c7ad0d8736

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2006 Sam Leffler. All rights reserved.
* Copyright (c) 2006-2008 Sam Leffler. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -134,6 +134,7 @@ struct npe_softc {
int rx_freeqid; /* rx free buffers qid */
int tx_qid; /* tx qid */
int tx_doneqid; /* tx completed qid */
int sc_phy; /* PHY id */
struct ifmib_iso_8802_3 mibdata;
bus_dma_tag_t sc_stats_tag; /* bus dma tag for stats block */
struct npestats *sc_stats;
@ -160,6 +161,7 @@ static const struct {
int regsize;
uint32_t miibase;
int miisize;
int phy; /* phy id */
uint8_t rx_qid;
uint8_t rx_freeqid;
uint8_t tx_qid;
@ -172,6 +174,7 @@ static const struct {
.regsize = IXP425_MAC_A_SIZE,
.miibase = IXP425_MAC_A_HWBASE,
.miisize = IXP425_MAC_A_SIZE,
.phy = 0,
.rx_qid = 4,
.rx_freeqid = 27,
.tx_qid = 24,
@ -184,6 +187,7 @@ static const struct {
.regsize = IXP425_MAC_B_SIZE,
.miibase = IXP425_MAC_A_HWBASE,
.miisize = IXP425_MAC_A_SIZE,
.phy = 1,
.rx_qid = 12,
.rx_freeqid = 28,
.tx_qid = 25,
@ -543,12 +547,62 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
memset(dma, 0, sizeof(*dma));
}
static int
override_addr(device_t dev, const char *resname, int *base, int *size)
{
int unit = device_get_unit(dev);
const char *resval;
/* XXX warn for wrong hint type */
if (resource_string_value("npe", unit, resname, &resval) != 0)
return 0;
switch (resval[0]) {
case 'A':
*base = IXP425_MAC_A_HWBASE;
*size = IXP425_MAC_A_SIZE;
break;
case 'B':
*base = IXP425_MAC_B_HWBASE;
*size = IXP425_MAC_B_SIZE;
break;
default:
device_printf(dev, "Warning, bad value %s for "
"npe.%d.%s ignored\n", resval, unit, resname);
return 0;
}
if (bootverbose)
device_printf(dev, "using npe.%d.%s=%s override\n",
unit, resname, resval);
return 1;
}
static int
override_unit(device_t dev, const char *resname, int *val, int min, int max)
{
int unit = device_get_unit(dev);
int resval;
if (resource_int_value("npe", unit, resname, &resval) != 0)
return 0;
if (!(min <= resval && resval <= max)) {
device_printf(dev, "Warning, bad value %d for npe.%d.%s "
"ignored (value must be [%d-%d])\n", resval, unit,
resname, min, max);
return 0;
}
if (bootverbose)
device_printf(dev, "using npe.%d.%s=%d override\n",
unit, resname, resval);
*val = resval;
return 1;
}
static int
npe_activate(device_t dev)
{
struct npe_softc * sc = device_get_softc(dev);
int unit = device_get_unit(dev);
int error, i;
int error, i, regbase, regsize, miibase, miisize;
uint32_t imageid;
/*
@ -571,24 +625,29 @@ npe_activate(device_t dev)
imageid++;
}
if (bus_space_map(sc->sc_iot, npeconfig[unit].regbase,
npeconfig[unit].regsize, 0, &sc->sc_ioh)) {
if (!override_addr(dev, "mac", &regbase, &regsize)) {
regbase = npeconfig[unit].regbase;
regbase = npeconfig[unit].regsize;
}
if (bus_space_map(sc->sc_iot, regbase, regsize, 0, &sc->sc_ioh)) {
device_printf(dev, "Cannot map registers 0x%x:0x%x\n",
npeconfig[unit].regbase, npeconfig[unit].regsize);
regbase, regsize);
return ENOMEM;
}
if (npeconfig[unit].miibase != npeconfig[unit].regbase) {
if (!override_addr(dev, "mii", &miibase, &miisize)) {
miibase = npeconfig[unit].miibase;
miisize = npeconfig[unit].miisize;
}
if (miibase != regbase) {
/*
* The PHY's are only accessible from one MAC (it appears)
* so for other MAC's setup an additional mapping for
* frobbing the PHY registers.
* PHY is mapped through a different MAC, setup an
* additional mapping for frobbing the PHY registers.
*/
if (bus_space_map(sc->sc_iot, npeconfig[unit].miibase,
npeconfig[unit].miisize, 0, &sc->sc_miih)) {
if (bus_space_map(sc->sc_iot, miibase, miisize, 0, &sc->sc_miih)) {
device_printf(dev,
"Cannot map MII registers 0x%x:0x%x\n",
npeconfig[unit].miibase, npeconfig[unit].miisize);
miibase, miisize);
return ENOMEM;
}
} else
@ -667,6 +726,13 @@ device_printf(sc->sc_dev, "remember to fix rx q setup\n");
tx_doneqid = sc->tx_doneqid;
}
/*
* Setup phy port number. We allow override via hints
* to handle different board configs.
*/
if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1))
sc->sc_phy = npeconfig[unit].phy;
KASSERT(npes[npeconfig[unit].npeid] == NULL,
("npe %u already setup", npeconfig[unit].npeid));
npes[npeconfig[unit].npeid] = sc;
@ -1478,8 +1544,6 @@ npe_child_detached(device_t dev, device_t child)
/*
* MII bus support routines.
*
* NB: ixp425 has one PHY per NPE
*/
static uint32_t
npe_mii_mdio_read(struct npe_softc *sc, int reg)
@ -1532,7 +1596,7 @@ npe_miibus_readreg(device_t dev, int phy, int reg)
struct npe_softc *sc = device_get_softc(dev);
uint32_t v;
if (phy != device_get_unit(dev)) /* XXX */
if (phy != sc->sc_phy) /* XXX no auto-detect */
return 0xffff;
v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
| NPE_MII_GO;
@ -1551,7 +1615,7 @@ npe_miibus_writereg(device_t dev, int phy, int reg, int data)
struct npe_softc *sc = device_get_softc(dev);
uint32_t v;
if (phy != device_get_unit(dev)) /* XXX */
if (phy != sc->sc_phy) /* XXX */
return;
v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
| data | NPE_MII_WRITE