mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-21 17:25:09 +00:00
Fixed autonegotiation. Card registers are now accessed via memory
not i/o space.
This commit is contained in:
parent
4af3a821f1
commit
72a43c1b0a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=35170
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* version: stable-167
|
||||
* $Id: $
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -31,8 +31,6 @@
|
|||
* EtherPower II 10/100 Fast Ethernet (tx0)
|
||||
* (aka SMC9432TX based on SMC83c170 EPIC chip)
|
||||
*
|
||||
* Written by Semen Ustimenko.
|
||||
*
|
||||
* TODO:
|
||||
* Deal with TX threshold (probably we should calculate it depending
|
||||
* on processor speed, as did the MS-DOS driver).
|
||||
|
@ -46,6 +44,7 @@
|
|||
|
||||
/* We should define compile time options before smc83c170.h included */
|
||||
/*#define EPIC_NOIFMEDIA 1*/
|
||||
/*#define EPIC_USEIOSPACE 1*/
|
||||
/*#define EPIC_DEBUG 1*/
|
||||
#define RX_TO_MBUF 1 /* Receive directly to mbuf enstead of */
|
||||
/* static allocated buffer */
|
||||
|
@ -105,7 +104,10 @@ DATA_SET ( pcidevice_set, txdevice );
|
|||
* splimp() invoked here
|
||||
*/
|
||||
static int
|
||||
epic_ifioctl(register struct ifnet * ifp, int command, caddr_t data){
|
||||
epic_ifioctl __P((
|
||||
register struct ifnet * ifp,
|
||||
int command, caddr_t data))
|
||||
{
|
||||
epic_softc_t *sc = ifp->if_softc;
|
||||
struct ifreq *ifr = (struct ifreq *) data;
|
||||
int x, error = 0;
|
||||
|
@ -218,6 +220,7 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
|
||||
/* If no more mbuf's to send, return */
|
||||
if( NULL == m ) return;
|
||||
|
||||
/* Save mbuf header */
|
||||
m0 = m;
|
||||
|
||||
|
@ -234,6 +237,36 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
flist->numfrags++;
|
||||
}
|
||||
|
||||
if( NULL != m0 ){
|
||||
/* Copy packet to new allocated mbuf */
|
||||
MGETHDR(m0,M_DONTWAIT,MT_DATA);
|
||||
if( NULL == m0 ) {
|
||||
printf("tx%d: cannot allocate mbuf header\n",sc->unit);
|
||||
sc->epic_if.if_oerrors++;
|
||||
m_freem(m);
|
||||
continue;
|
||||
}
|
||||
MCLGET(m0,M_DONTWAIT);
|
||||
if( NULL == (m0->m_flags & M_EXT) ){
|
||||
printf("tx%d: cannot allocate mbuf cluster\n",sc->unit);
|
||||
m_freem(m0);
|
||||
m_freem(m);
|
||||
sc->epic_if.if_oerrors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (len = 0; m != 0; m = m->m_next) {
|
||||
bcopy( mtod(m, caddr_t), mtod(m0, caddr_t) + len, m->m_len);
|
||||
len += m->m_len;
|
||||
}
|
||||
|
||||
m_freem(buf->mbuf);
|
||||
buf->mbuf = m0;
|
||||
flist->numfrags = 1;
|
||||
flist->frag[0].fraglen = len;
|
||||
flist->frag[0].fragaddr = vtophys( mtod(m0, caddr_t) );
|
||||
}
|
||||
|
||||
/* Does not generate TXC unless ring is full more then a half */
|
||||
desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x05:0x01;
|
||||
#else
|
||||
|
@ -264,7 +297,7 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
m_freem( m );
|
||||
#endif
|
||||
/* Trigger an immediate transmit demand. */
|
||||
outl( sc->iobase + COMMAND, COMMAND_TXQUEUED );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED );
|
||||
|
||||
/* Packet queued successful */
|
||||
sc->pending_txs++;
|
||||
|
@ -531,11 +564,10 @@ epic_intr_normal(
|
|||
void *arg)
|
||||
{
|
||||
epic_softc_t * sc = (epic_softc_t *) arg;
|
||||
int iobase = sc->iobase;
|
||||
int status;
|
||||
|
||||
status = inl(iobase + INTSTAT);
|
||||
outl( iobase + INTSTAT, status & (
|
||||
status = CSR_READ_4( sc, INTSTAT);
|
||||
CSR_WRITE_4( sc, INTSTAT, status & (
|
||||
INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC|
|
||||
INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE|
|
||||
INTSTAT_FATAL|INTSTAT_GP2|
|
||||
|
@ -544,7 +576,7 @@ epic_intr_normal(
|
|||
if( status & (INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC) ) {
|
||||
epic_rx_done( sc );
|
||||
if( status & INTSTAT_RQE )
|
||||
outl( iobase + COMMAND, COMMAND_RXQUEUED );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED );
|
||||
}
|
||||
|
||||
if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) )
|
||||
|
@ -556,23 +588,25 @@ epic_intr_normal(
|
|||
if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) {
|
||||
u_int32_t status;
|
||||
|
||||
status = epic_read_phy_register(sc->iobase,29);
|
||||
status = epic_read_phy_register( sc, QS6612_INTSTAT );
|
||||
|
||||
if( (status & INTSTAT_AN_COMPLETE) &&
|
||||
(epic_autoneg(sc) == EPIC_FULL_DUPLEX) ) {
|
||||
status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
outl( sc->iobase + TXCON,
|
||||
status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc, DP83840_BMCR );
|
||||
CSR_WRITE_4( sc, TXCON,
|
||||
TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT );
|
||||
} else
|
||||
status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
} else {
|
||||
status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc, DP83840_BMCR );
|
||||
CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
|
||||
}
|
||||
|
||||
/* There is apparently QS6612 chip bug: */
|
||||
/* BMCR_FULL_DUPLEX flag is not updated by */
|
||||
/* autonegotiation process, so update manual */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, status);
|
||||
/* autonegotiation process, so update it by hands */
|
||||
epic_write_phy_register( sc, DP83840_BMCR, status);
|
||||
|
||||
/* We should clear GP2 int source after we clear it on PHY */
|
||||
outl( iobase + INTSTAT, INTSTAT_GP2 );
|
||||
/* We should clear GP2 int again after we clear it on PHY */
|
||||
CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 );
|
||||
}
|
||||
|
||||
if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE) ){
|
||||
|
@ -609,9 +643,9 @@ epic_intr_normal(
|
|||
if (status & (INTSTAT_CNT | INTSTAT_TXU | INTSTAT_OVW | INTSTAT_RXE)) {
|
||||
|
||||
/* update dot3 Rx statistics */
|
||||
sc->dot3stats.dot3StatsMissedFrames += inb(iobase + MPCNT);
|
||||
sc->dot3stats.dot3StatsFrameTooLongs += inb(iobase + ALICNT);
|
||||
sc->dot3stats.dot3StatsFCSErrors += inb(iobase + CRCCNT);
|
||||
sc->dot3stats.dot3StatsMissedFrames += CSR_READ_1( sc, MPCNT);
|
||||
sc->dot3stats.dot3StatsFrameTooLongs += CSR_READ_1( sc, ALICNT);
|
||||
sc->dot3stats.dot3StatsFCSErrors += CSR_READ_1( sc, CRCCNT);
|
||||
|
||||
/* Update if Rx statistics */
|
||||
if (status & (INTSTAT_OVW | INTSTAT_RXE))
|
||||
|
@ -624,7 +658,7 @@ epic_intr_normal(
|
|||
sc->epic_if.if_oerrors++;
|
||||
|
||||
/* Restart the transmit process. */
|
||||
outl(iobase + COMMAND, COMMAND_TXUGO);
|
||||
CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,18 +698,14 @@ epic_pci_attach(
|
|||
{
|
||||
struct ifnet * ifp;
|
||||
epic_softc_t *sc;
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
u_int32_t iobase;
|
||||
u_int32_t irq;
|
||||
#else
|
||||
caddr_t pmembase;
|
||||
#endif
|
||||
int i,s,media;
|
||||
u_int32_t pool;
|
||||
|
||||
/*
|
||||
* Get iobase and irq level
|
||||
*/
|
||||
irq = PCI_CONF_READ(PCI_CFIT) & (0xFF);
|
||||
if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &iobase))
|
||||
return;
|
||||
|
||||
/* Allocate memory for softc and hardware descriptors */
|
||||
sc = (epic_softc_t *) malloc(
|
||||
sizeof(epic_softc_t) +
|
||||
|
@ -696,8 +726,20 @@ epic_pci_attach(
|
|||
bzero(sc, sizeof(epic_softc_t));
|
||||
epics[ unit ] = sc;
|
||||
sc->unit = unit;
|
||||
sc->iobase = iobase;
|
||||
sc->irq = irq;
|
||||
|
||||
/* Get iobase or membase */
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) {
|
||||
printf("tx%d: cannot map port\n",unit);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) {
|
||||
printf("tx%d: cannot map memory\n",unit);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(TX_FRAG_LIST)
|
||||
sc->tx_flist = (void *)pool;
|
||||
|
@ -708,14 +750,14 @@ epic_pci_attach(
|
|||
sc->tx_desc = (void *)pool;
|
||||
|
||||
/* Bring the chip out of low-power mode. */
|
||||
outl( iobase + GENCTL, 0x0000 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0x0000 );
|
||||
|
||||
/* Magic?! If we don't set this bit the MII interface won't work. */
|
||||
outl( iobase + TEST1, 0x0008 );
|
||||
CSR_WRITE_4( sc, TEST1, 0x0008 );
|
||||
|
||||
/* Read mac address (may be better is read from EEPROM?) */
|
||||
for (i = 0; i < ETHER_ADDR_LEN / sizeof( u_int16_t); i++)
|
||||
((u_int16_t *)sc->epic_macaddr)[i] = inw(iobase + LAN0 + i*4);
|
||||
((u_int16_t *)sc->epic_macaddr)[i] = CSR_READ_2( sc, LAN0 + i*4 );
|
||||
|
||||
/* Display some info */
|
||||
printf("tx%d: address %02x:%02x:%02x:%02x:%02x:%02x,",sc->unit,
|
||||
|
@ -758,27 +800,27 @@ epic_pci_attach(
|
|||
printf(" type SMC9432TX, ");
|
||||
|
||||
/* Identify PHY */
|
||||
sc->phyid = epic_read_phy_register(iobase,DP83840_PHYIDR1)<<6;
|
||||
sc->phyid|= ((epic_read_phy_register(iobase,DP83840_PHYIDR2)>>10)&0x3F);
|
||||
sc->phyid = epic_read_phy_register( sc, DP83840_PHYIDR1 )<<6;
|
||||
sc->phyid|= (epic_read_phy_register( sc, DP83840_PHYIDR2 )>>10)&0x3F;
|
||||
|
||||
if( QS6612_OUI == sc->phyid ){
|
||||
printf("phy QS6612, ");
|
||||
} else if( DP83840_OUI == sc->phyid ){
|
||||
printf("phy DP83840, ");
|
||||
} else {
|
||||
printf("phy: unknown (%x), ",sc->phyid);
|
||||
printf("phy unknown (%x), ",sc->phyid);
|
||||
sc->phyid = DP83840_OUI;
|
||||
}
|
||||
|
||||
/* Read current config */
|
||||
i = epic_read_phy_register(iobase, DP83840_BMCR);
|
||||
i = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
|
||||
#if defined(_NET_IF_MEDIA_H_)
|
||||
media = IFM_ETHER;
|
||||
#endif
|
||||
|
||||
if( i & BMCR_AUTONEGOTIATION ){
|
||||
i = epic_read_phy_register( iobase, DP83840_LPAR );
|
||||
i = epic_read_phy_register( sc, DP83840_LPAR );
|
||||
|
||||
printf("Auto-Neg ");
|
||||
|
||||
|
@ -833,8 +875,8 @@ epic_pci_attach(
|
|||
#endif
|
||||
|
||||
/* Read MBSR twice to update latched bits */
|
||||
epic_read_phy_register(iobase,DP83840_BMSR);
|
||||
i=epic_read_phy_register(iobase,DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if( !(i & BMSR_LINK_STATUS) )
|
||||
printf("tx%d: WARNING! no link estabilished\n",sc->unit);
|
||||
|
@ -879,20 +921,22 @@ epic_ifmedia_status __P((
|
|||
u_int32_t bmcr;
|
||||
u_int32_t bmsr;
|
||||
|
||||
bmcr = epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
bmcr = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
|
||||
epic_read_phy_register(sc->iobase,DP83840_BMSR);
|
||||
bmsr = epic_read_phy_register(sc->iobase,DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
bmsr = epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
ifmr->ifm_active = IFM_ETHER;
|
||||
ifmr->ifm_status = IFM_AVALID;
|
||||
|
||||
if( !(bmsr & BMSR_LINK_STATUS) ) {
|
||||
ifmr->ifm_active |= bmcr&BMCR_AUTONEGOTIATION?IFM_AUTO:IFM_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
ifmr->ifm_active |= bmcr&BMCR_100MBPS?IFM_100_TX:IFM_10_T;
|
||||
ifmr->ifm_active |= bmcr&BMCR_FULL_DUPLEX?IFM_FDX:0;
|
||||
ifmr->ifm_status |= IFM_ACTIVE;
|
||||
ifmr->ifm_active |= (bmcr&BMCR_100MBPS)?IFM_100_TX:IFM_10_T;
|
||||
ifmr->ifm_active |= (bmcr&BMCR_FULL_DUPLEX)?IFM_FDX:0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -906,22 +950,21 @@ epic_init __P((
|
|||
epic_softc_t * sc))
|
||||
{
|
||||
struct ifnet *ifp = &sc->epic_if;
|
||||
int iobase = sc->iobase;
|
||||
int i,s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
/* Soft reset the chip */
|
||||
outl(iobase + GENCTL, GENCTL_SOFT_RESET );
|
||||
CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
|
||||
|
||||
/* Reset takes 15 pci ticks which depends on processor speed*/
|
||||
DELAY(1);
|
||||
|
||||
/* Wake up */
|
||||
outl( iobase + GENCTL, 0 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0 );
|
||||
|
||||
/* ?????? */
|
||||
outl( iobase + TEST1, 0x0008);
|
||||
CSR_WRITE_4( sc, TEST1, 0x0008);
|
||||
|
||||
/* Initialize rings */
|
||||
if( -1 == epic_init_rings( sc ) ) {
|
||||
|
@ -932,17 +975,18 @@ epic_init __P((
|
|||
}
|
||||
|
||||
/* Put node address to EPIC */
|
||||
outl( iobase + LAN0 + 0x0, ((u_int16_t *)sc->epic_macaddr)[0] );
|
||||
outl( iobase + LAN0 + 0x4, ((u_int16_t *)sc->epic_macaddr)[1] );
|
||||
outl( iobase + LAN0 + 0x8, ((u_int16_t *)sc->epic_macaddr)[2] );
|
||||
CSR_WRITE_4( sc, LAN0, ((u_int16_t *)sc->epic_macaddr)[0] );
|
||||
CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->epic_macaddr)[1] );
|
||||
CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->epic_macaddr)[2] );
|
||||
|
||||
/* Set transmit threshold */
|
||||
outl( iobase + ETXTHR, 0x40 );
|
||||
CSR_WRITE_4( sc, ETXTHR, 0x40 );
|
||||
|
||||
/* Compute and set RXCON. */
|
||||
epic_set_rx_mode( sc );
|
||||
|
||||
/* Set media speed mode */
|
||||
epic_init_phy( sc );
|
||||
epic_set_media_speed( sc );
|
||||
|
||||
/* Set multicast table */
|
||||
|
@ -950,13 +994,13 @@ epic_init __P((
|
|||
|
||||
/* Enable interrupts by setting the interrupt mask. */
|
||||
if( QS6612_OUI == sc->phyid ) {
|
||||
outl( iobase + INTMASK,
|
||||
CSR_WRITE_4( sc, INTMASK,
|
||||
INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
|
||||
INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
|
||||
INTSTAT_CNT | INTSTAT_GP2 | INTSTAT_FATAL |
|
||||
INTSTAT_PTA | INTSTAT_PMA | INTSTAT_APE | INTSTAT_DPE );
|
||||
} else {
|
||||
outl( iobase + INTMASK,
|
||||
CSR_WRITE_4( sc, INTMASK,
|
||||
INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
|
||||
INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
|
||||
INTSTAT_CNT | INTSTAT_FATAL |
|
||||
|
@ -964,12 +1008,12 @@ epic_init __P((
|
|||
}
|
||||
|
||||
/* Enable interrupts, set for PCI read multiple and etc */
|
||||
outl( iobase + GENCTL,
|
||||
CSR_WRITE_4( sc, GENCTL,
|
||||
GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE |
|
||||
GENCTL_ONECOPY | GENCTL_RECEIVE_FIFO_THRESHOLD64 );
|
||||
|
||||
/* Start rx process */
|
||||
outl( iobase + COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX );
|
||||
|
||||
/* Mark interface running ... */
|
||||
if( ifp->if_flags & IFF_UP ) ifp->if_flags |= IFF_RUNNING;
|
||||
|
@ -1003,11 +1047,39 @@ epic_set_rx_mode(
|
|||
if( sc->epic_if.if_flags & IFF_MULTICAST )
|
||||
rxcon |= RXCON_RECEIVE_MULTICAST_FRAMES;
|
||||
|
||||
outl( sc->iobase + RXCON, rxcon );
|
||||
CSR_WRITE_4( sc, RXCON, rxcon );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
epic_init_phy __P((
|
||||
epic_softc_t * sc))
|
||||
{
|
||||
u_int32_t i;
|
||||
|
||||
/* Reset PHY */
|
||||
epic_write_phy_register( sc, DP83840_BMCR, BMCR_RESET );
|
||||
for(i=0;i<0x100000;i++)
|
||||
if( !(epic_read_phy_register( sc, DP83840_BMCR ) & BMCR_RESET) )
|
||||
break;
|
||||
|
||||
if( epic_read_phy_register( sc, DP83840_BMCR ) & BMCR_RESET )
|
||||
printf("tx%d: WARNING! cannot reset PHY\n",sc->unit);
|
||||
|
||||
switch( sc->phyid ){
|
||||
case QS6612_OUI:
|
||||
/* Init QS6612 to generate interrupt when AutoNeg complete */
|
||||
CSR_WRITE_4( sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
|
||||
epic_read_phy_register( sc, QS6612_INTSTAT );
|
||||
epic_write_phy_register( sc, QS6612_INTMASK,
|
||||
INTMASK_THUNDERLAN|INTSTAT_AN_COMPLETE );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function should set MII to mode specified by IFF_LINK* flags or
|
||||
* ifmedia structure.
|
||||
|
@ -1022,16 +1094,6 @@ epic_set_media_speed __P((
|
|||
struct ifnet *ifp = &sc->epic_if;
|
||||
#endif
|
||||
u_int16_t media;
|
||||
u_int32_t i;
|
||||
|
||||
/* Reset PHY */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, BMCR_RESET );
|
||||
for(i=0;i<0x100000;i++)
|
||||
if( !(epic_read_phy_register(sc->iobase,DP83840_BMCR) & BMCR_RESET) )
|
||||
break;
|
||||
|
||||
if( epic_read_phy_register(sc->iobase, DP83840_BMCR) & BMCR_RESET )
|
||||
printf("tx%d: WARNING! cannot reset PHY\n",sc->unit);
|
||||
|
||||
/* Set media speed */
|
||||
|
||||
|
@ -1039,14 +1101,14 @@ epic_set_media_speed __P((
|
|||
if( IFM_SUBTYPE(tgtmedia) != IFM_AUTO ){
|
||||
/* Set mode */
|
||||
media = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX) ? BMCR_100MBPS : 0;
|
||||
media|= ((tgtmedia&IFM_GMASK)==IFM_FDX) ? BMCR_FULL_DUPLEX : 0;
|
||||
media|= (tgtmedia&IFM_FDX) ? BMCR_FULL_DUPLEX : 0;
|
||||
|
||||
sc->epic_if.if_baudrate =
|
||||
(IFM_SUBTYPE(tgtmedia)==IFM_100_TX)?100000000:10000000;
|
||||
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, media );
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
outl( sc->iobase + TXCON,((tgtmedia&IFM_GMASK)==IFM_FDX)?TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT:TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON,(tgtmedia&IFM_FDX)?TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT:TXCON_DEFAULT );
|
||||
}
|
||||
#else
|
||||
if( ifp->if_flags & IFF_LINK0 ) {
|
||||
|
@ -1057,26 +1119,18 @@ epic_set_media_speed __P((
|
|||
sc->epic_if.if_baudrate =
|
||||
(ifp->if_flags & IFF_LINK2)?100000000:10000000;
|
||||
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, media );
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
outl( sc->iobase + TXCON, (ifp->if_flags & IFF_LINK2) ? TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT : TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON, (ifp->if_flags & IFF_LINK2) ? TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT : TXCON_DEFAULT );
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Init QS6612 to generate interrupt when AutoNeg complete */
|
||||
if( QS6612_OUI == sc->phyid ) {
|
||||
outl( sc->iobase + NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
|
||||
epic_read_phy_register( sc->iobase, QS6612_INTSTAT );
|
||||
epic_write_phy_register( sc->iobase, QS6612_INTMASK,
|
||||
INTMASK_THUNDERLAN|INTSTAT_AN_COMPLETE );
|
||||
}
|
||||
|
||||
sc->epic_if.if_baudrate = 100000000;
|
||||
|
||||
outl( sc->iobase + TXCON, TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
|
||||
|
||||
/* Set and restart autoneg */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR,
|
||||
epic_write_phy_register( sc, DP83840_BMCR,
|
||||
BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG );
|
||||
|
||||
/* If it is not QS6612 PHY, try to get result of autoneg. */
|
||||
|
@ -1088,7 +1142,7 @@ epic_set_media_speed __P((
|
|||
DELAY(3000000);
|
||||
|
||||
if( epic_autoneg(sc) == EPIC_FULL_DUPLEX )
|
||||
outl( sc->iobase + TXCON,
|
||||
CSR_WRITE_4( sc, TXCON,
|
||||
TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT);
|
||||
}
|
||||
/* Else it will be done when GP2 int occured */
|
||||
|
@ -1114,11 +1168,11 @@ epic_autoneg(
|
|||
/* BMSR must be read twice to update the link status bit
|
||||
* since that bit is a latch bit
|
||||
*/
|
||||
epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
i = epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR);
|
||||
i = epic_read_phy_register( sc, DP83840_BMSR);
|
||||
|
||||
if ((i & BMSR_LINK_STATUS) && (i & BMSR_AUTONEG_COMPLETE)){
|
||||
i = epic_read_phy_register( sc->iobase, DP83840_LPAR );
|
||||
i = epic_read_phy_register( sc, DP83840_LPAR );
|
||||
|
||||
if ( i & (ANAR_100_TX_FD|ANAR_10_FD) )
|
||||
return EPIC_FULL_DUPLEX;
|
||||
|
@ -1133,19 +1187,19 @@ epic_autoneg(
|
|||
/* ANER must be read twice to get the correct reading for the
|
||||
* Multiple link fault bit -- it is a latched bit
|
||||
*/
|
||||
epic_read_phy_register (sc->iobase, DP83840_ANER);
|
||||
i = epic_read_phy_register (sc->iobase, DP83840_ANER);
|
||||
epic_read_phy_register( sc, DP83840_ANER );
|
||||
i = epic_read_phy_register( sc, DP83840_ANER );
|
||||
|
||||
if ( i & ANER_MULTIPLE_LINK_FAULT ) {
|
||||
/* it can be forced to 100Mb/s Half-Duplex */
|
||||
media = epic_read_phy_register(sc->iobase,DP83840_BMCR);
|
||||
media = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX);
|
||||
media |= BMCR_100MBPS;
|
||||
epic_write_phy_register(sc->iobase,DP83840_BMCR,media);
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
/* read BMSR again to determine link status */
|
||||
epic_read_phy_register(sc->iobase, DP83840_BMSR);
|
||||
i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if (i & BMSR_LINK_STATUS){
|
||||
/* port is linked to the non Auto-Negotiation
|
||||
|
@ -1154,11 +1208,11 @@ epic_autoneg(
|
|||
return EPIC_HALF_DUPLEX;
|
||||
}
|
||||
else {
|
||||
media = epic_read_phy_register (sc->iobase, DP83840_BMCR);
|
||||
media = epic_read_phy_register( sc, DP83840_BMCR);
|
||||
media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX | BMCR_100MBPS);
|
||||
epic_write_phy_register(sc->iobase, DP83840_BMCR, media);
|
||||
epic_read_phy_register(sc->iobase, DP83840_BMSR);
|
||||
i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if (i & BMSR_LINK_STATUS) {
|
||||
/*port is linked to the non
|
||||
|
@ -1186,10 +1240,10 @@ epic_set_mc_table (
|
|||
struct ifnet *ifp = &sc->epic_if;
|
||||
|
||||
if( ifp->if_flags & IFF_MULTICAST ){
|
||||
outl( sc->iobase + MC0, 0xFFFF );
|
||||
outl( sc->iobase + MC1, 0xFFFF );
|
||||
outl( sc->iobase + MC2, 0xFFFF );
|
||||
outl( sc->iobase + MC3, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC0, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC1, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC2, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC3, 0xFFFF );
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -1212,32 +1266,31 @@ static void
|
|||
epic_stop(
|
||||
epic_softc_t * sc)
|
||||
{
|
||||
int iobase = sc->iobase;
|
||||
int i,s;
|
||||
|
||||
s = splimp();
|
||||
sc->epic_if.if_timer = 0;
|
||||
|
||||
/* Disable interrupts, stop processes */
|
||||
outl( iobase + INTMASK, 0 );
|
||||
outl( iobase + GENCTL, 0 );
|
||||
outl( iobase + COMMAND,
|
||||
CSR_WRITE_4( sc, INTMASK, 0 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0 );
|
||||
CSR_WRITE_4( sc, COMMAND,
|
||||
COMMAND_STOP_RX | COMMAND_STOP_RDMA | COMMAND_STOP_TDMA );
|
||||
|
||||
/* Wait RX and TX DMA to stop */
|
||||
for(i=0;i<0x100000;i++){
|
||||
if( (inl(iobase+INTSTAT)&(INTSTAT_RXIDLE|INTSTAT_TXIDLE)) ==
|
||||
if( (CSR_READ_4(sc,INTSTAT)&(INTSTAT_RXIDLE|INTSTAT_TXIDLE)) ==
|
||||
(INTSTAT_RXIDLE|INTSTAT_TXIDLE) ) break;
|
||||
}
|
||||
|
||||
if( !(inl(iobase+INTSTAT)&INTSTAT_RXIDLE) )
|
||||
if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) )
|
||||
printf("tx%d: can't stop RX DMA\n",sc->unit);
|
||||
|
||||
if( !(inl(iobase+INTSTAT)&INTSTAT_TXIDLE) )
|
||||
if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) )
|
||||
printf("tx%d: can't stop TX DMA\n",sc->unit);
|
||||
|
||||
/* Reset chip and phy */
|
||||
outl( iobase + GENCTL, GENCTL_SOFT_RESET );
|
||||
CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
|
||||
|
||||
/* Need to wait for 15 pci ticks to pass before accessing again*/
|
||||
DELAY(1);
|
||||
|
@ -1368,8 +1421,8 @@ epic_init_rings(epic_softc_t * sc){
|
|||
}
|
||||
|
||||
/* Give rings to EPIC */
|
||||
outl( sc->iobase + PRCDAR, vtophys( sc->rx_desc ) );
|
||||
outl( sc->iobase + PTCDAR, vtophys( sc->tx_desc ) );
|
||||
CSR_WRITE_4( sc, PRCDAR, vtophys( sc->rx_desc ) );
|
||||
CSR_WRITE_4( sc, PTCDAR, vtophys( sc->tx_desc ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1377,45 +1430,57 @@ epic_init_rings(epic_softc_t * sc){
|
|||
/*
|
||||
* EEPROM operation functions
|
||||
*/
|
||||
static void epic_write_eepromreg(u_int16_t regaddr, u_int8_t val){
|
||||
static void epic_write_eepromreg __P((
|
||||
epic_softc_t *sc,
|
||||
u_int8_t val))
|
||||
{
|
||||
u_int16_t i;
|
||||
|
||||
outb( regaddr, val );
|
||||
CSR_WRITE_1( sc, EECTL, val );
|
||||
|
||||
for( i=0;i<0xFF; i++)
|
||||
if( !(inb( regaddr ) & 0x20) ) break;
|
||||
if( !(CSR_READ_1( sc, EECTL ) & 0x20) ) break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static u_int8_t epic_read_eepromreg(u_int16_t regaddr){
|
||||
return inb( regaddr );
|
||||
static u_int8_t epic_read_eepromreg __P((
|
||||
epic_softc_t *sc))
|
||||
{
|
||||
return CSR_READ_1( sc,EECTL );
|
||||
}
|
||||
|
||||
static u_int8_t epic_eeprom_clock( u_int16_t ioaddr, u_int8_t val ){
|
||||
|
||||
epic_write_eepromreg( ioaddr + EECTL, val );
|
||||
epic_write_eepromreg( ioaddr + EECTL, (val | 0x4) );
|
||||
epic_write_eepromreg( ioaddr + EECTL, val );
|
||||
static u_int8_t epic_eeprom_clock __P((
|
||||
epic_softc_t *sc,
|
||||
u_int8_t val))
|
||||
{
|
||||
epic_write_eepromreg( sc, val );
|
||||
epic_write_eepromreg( sc, (val | 0x4) );
|
||||
epic_write_eepromreg( sc, val );
|
||||
|
||||
return epic_read_eepromreg( ioaddr + EECTL );
|
||||
return epic_read_eepromreg( sc );
|
||||
}
|
||||
|
||||
static void epic_output_eepromw(u_int16_t ioaddr, u_int16_t val){
|
||||
static void epic_output_eepromw __P((
|
||||
epic_softc_t * sc,
|
||||
u_int16_t val))
|
||||
{
|
||||
int i;
|
||||
for( i = 0xF; i >= 0; i--){
|
||||
if( (val & (1 << i)) ) epic_eeprom_clock( ioaddr, 0x0B );
|
||||
else epic_eeprom_clock( ioaddr, 3);
|
||||
if( (val & (1 << i)) ) epic_eeprom_clock( sc, 0x0B );
|
||||
else epic_eeprom_clock( sc, 3);
|
||||
}
|
||||
}
|
||||
|
||||
static u_int16_t epic_input_eepromw(u_int16_t ioaddr){
|
||||
static u_int16_t epic_input_eepromw __P((
|
||||
epic_softc_t *sc))
|
||||
{
|
||||
int i;
|
||||
int tmp;
|
||||
u_int16_t retval = 0;
|
||||
|
||||
for( i = 0xF; i >= 0; i--) {
|
||||
tmp = epic_eeprom_clock( ioaddr, 0x3 );
|
||||
tmp = epic_eeprom_clock( sc, 0x3 );
|
||||
if( tmp & 0x10 ){
|
||||
retval |= (1 << i);
|
||||
}
|
||||
|
@ -1423,44 +1488,54 @@ static u_int16_t epic_input_eepromw(u_int16_t ioaddr){
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int epic_read_eeprom(u_int16_t ioaddr, u_int16_t loc){
|
||||
static int epic_read_eeprom __P((
|
||||
epic_softc_t *sc,
|
||||
u_int16_t loc))
|
||||
{
|
||||
int i;
|
||||
u_int16_t dataval;
|
||||
u_int16_t read_cmd;
|
||||
|
||||
epic_write_eepromreg(ioaddr + EECTL , 3);
|
||||
epic_write_eepromreg( sc , 3);
|
||||
|
||||
if( epic_read_eepromreg(ioaddr + EECTL) & 0x40 )
|
||||
if( epic_read_eepromreg( sc ) & 0x40 )
|
||||
read_cmd = ( loc & 0x3F ) | 0x180;
|
||||
else
|
||||
read_cmd = ( loc & 0xFF ) | 0x600;
|
||||
|
||||
epic_output_eepromw( ioaddr, read_cmd );
|
||||
epic_output_eepromw( sc, read_cmd );
|
||||
|
||||
dataval = epic_input_eepromw( ioaddr );
|
||||
dataval = epic_input_eepromw( sc );
|
||||
|
||||
epic_write_eepromreg( ioaddr + EECTL, 1 );
|
||||
epic_write_eepromreg( sc, 1 );
|
||||
|
||||
return dataval;
|
||||
}
|
||||
|
||||
static int epic_read_phy_register(u_int16_t iobase, u_int16_t loc){
|
||||
static int epic_read_phy_register __P((
|
||||
epic_softc_t *sc,
|
||||
u_int16_t loc))
|
||||
{
|
||||
int i;
|
||||
|
||||
outl( iobase + MIICTL, ((loc << 4) | 0x0601) );
|
||||
CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0601) );
|
||||
|
||||
for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICTL )&1) ) break;
|
||||
for( i=0;i<0x1000;i++) if( !(CSR_READ_4( sc, MIICTL )&1) ) break;
|
||||
|
||||
return inl( iobase + MIIDATA );
|
||||
return CSR_READ_4( sc, MIIDATA );
|
||||
}
|
||||
|
||||
static void epic_write_phy_register(u_int16_t iobase, u_int16_t loc,u_int16_t val){
|
||||
static void epic_write_phy_register __P((
|
||||
epic_softc_t * sc,
|
||||
u_int16_t loc,
|
||||
u_int16_t val))
|
||||
{
|
||||
int i;
|
||||
|
||||
outl( iobase + MIIDATA, val );
|
||||
outl( iobase + MIICTL, ((loc << 4) | 0x0602) );
|
||||
CSR_WRITE_4( sc, MIIDATA, val );
|
||||
CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0602) );
|
||||
|
||||
for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICTL )&2) ) break;
|
||||
for( i=0;i<0x1000;i++) if( !(CSR_READ_4( sc, MIICTL )&2) ) break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
361
sys/pci/if_tx.c
361
sys/pci/if_tx.c
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* version: stable-167
|
||||
* $Id: $
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -31,8 +31,6 @@
|
|||
* EtherPower II 10/100 Fast Ethernet (tx0)
|
||||
* (aka SMC9432TX based on SMC83c170 EPIC chip)
|
||||
*
|
||||
* Written by Semen Ustimenko.
|
||||
*
|
||||
* TODO:
|
||||
* Deal with TX threshold (probably we should calculate it depending
|
||||
* on processor speed, as did the MS-DOS driver).
|
||||
|
@ -46,6 +44,7 @@
|
|||
|
||||
/* We should define compile time options before smc83c170.h included */
|
||||
/*#define EPIC_NOIFMEDIA 1*/
|
||||
/*#define EPIC_USEIOSPACE 1*/
|
||||
/*#define EPIC_DEBUG 1*/
|
||||
#define RX_TO_MBUF 1 /* Receive directly to mbuf enstead of */
|
||||
/* static allocated buffer */
|
||||
|
@ -105,7 +104,10 @@ DATA_SET ( pcidevice_set, txdevice );
|
|||
* splimp() invoked here
|
||||
*/
|
||||
static int
|
||||
epic_ifioctl(register struct ifnet * ifp, int command, caddr_t data){
|
||||
epic_ifioctl __P((
|
||||
register struct ifnet * ifp,
|
||||
int command, caddr_t data))
|
||||
{
|
||||
epic_softc_t *sc = ifp->if_softc;
|
||||
struct ifreq *ifr = (struct ifreq *) data;
|
||||
int x, error = 0;
|
||||
|
@ -218,6 +220,7 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
|
||||
/* If no more mbuf's to send, return */
|
||||
if( NULL == m ) return;
|
||||
|
||||
/* Save mbuf header */
|
||||
m0 = m;
|
||||
|
||||
|
@ -234,6 +237,36 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
flist->numfrags++;
|
||||
}
|
||||
|
||||
if( NULL != m0 ){
|
||||
/* Copy packet to new allocated mbuf */
|
||||
MGETHDR(m0,M_DONTWAIT,MT_DATA);
|
||||
if( NULL == m0 ) {
|
||||
printf("tx%d: cannot allocate mbuf header\n",sc->unit);
|
||||
sc->epic_if.if_oerrors++;
|
||||
m_freem(m);
|
||||
continue;
|
||||
}
|
||||
MCLGET(m0,M_DONTWAIT);
|
||||
if( NULL == (m0->m_flags & M_EXT) ){
|
||||
printf("tx%d: cannot allocate mbuf cluster\n",sc->unit);
|
||||
m_freem(m0);
|
||||
m_freem(m);
|
||||
sc->epic_if.if_oerrors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (len = 0; m != 0; m = m->m_next) {
|
||||
bcopy( mtod(m, caddr_t), mtod(m0, caddr_t) + len, m->m_len);
|
||||
len += m->m_len;
|
||||
}
|
||||
|
||||
m_freem(buf->mbuf);
|
||||
buf->mbuf = m0;
|
||||
flist->numfrags = 1;
|
||||
flist->frag[0].fraglen = len;
|
||||
flist->frag[0].fragaddr = vtophys( mtod(m0, caddr_t) );
|
||||
}
|
||||
|
||||
/* Does not generate TXC unless ring is full more then a half */
|
||||
desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x05:0x01;
|
||||
#else
|
||||
|
@ -264,7 +297,7 @@ epic_ifstart(struct ifnet * const ifp){
|
|||
m_freem( m );
|
||||
#endif
|
||||
/* Trigger an immediate transmit demand. */
|
||||
outl( sc->iobase + COMMAND, COMMAND_TXQUEUED );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED );
|
||||
|
||||
/* Packet queued successful */
|
||||
sc->pending_txs++;
|
||||
|
@ -531,11 +564,10 @@ epic_intr_normal(
|
|||
void *arg)
|
||||
{
|
||||
epic_softc_t * sc = (epic_softc_t *) arg;
|
||||
int iobase = sc->iobase;
|
||||
int status;
|
||||
|
||||
status = inl(iobase + INTSTAT);
|
||||
outl( iobase + INTSTAT, status & (
|
||||
status = CSR_READ_4( sc, INTSTAT);
|
||||
CSR_WRITE_4( sc, INTSTAT, status & (
|
||||
INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC|
|
||||
INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE|
|
||||
INTSTAT_FATAL|INTSTAT_GP2|
|
||||
|
@ -544,7 +576,7 @@ epic_intr_normal(
|
|||
if( status & (INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC) ) {
|
||||
epic_rx_done( sc );
|
||||
if( status & INTSTAT_RQE )
|
||||
outl( iobase + COMMAND, COMMAND_RXQUEUED );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED );
|
||||
}
|
||||
|
||||
if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) )
|
||||
|
@ -556,23 +588,25 @@ epic_intr_normal(
|
|||
if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) {
|
||||
u_int32_t status;
|
||||
|
||||
status = epic_read_phy_register(sc->iobase,29);
|
||||
status = epic_read_phy_register( sc, QS6612_INTSTAT );
|
||||
|
||||
if( (status & INTSTAT_AN_COMPLETE) &&
|
||||
(epic_autoneg(sc) == EPIC_FULL_DUPLEX) ) {
|
||||
status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
outl( sc->iobase + TXCON,
|
||||
status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc, DP83840_BMCR );
|
||||
CSR_WRITE_4( sc, TXCON,
|
||||
TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT );
|
||||
} else
|
||||
status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
} else {
|
||||
status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc, DP83840_BMCR );
|
||||
CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
|
||||
}
|
||||
|
||||
/* There is apparently QS6612 chip bug: */
|
||||
/* BMCR_FULL_DUPLEX flag is not updated by */
|
||||
/* autonegotiation process, so update manual */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, status);
|
||||
/* autonegotiation process, so update it by hands */
|
||||
epic_write_phy_register( sc, DP83840_BMCR, status);
|
||||
|
||||
/* We should clear GP2 int source after we clear it on PHY */
|
||||
outl( iobase + INTSTAT, INTSTAT_GP2 );
|
||||
/* We should clear GP2 int again after we clear it on PHY */
|
||||
CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 );
|
||||
}
|
||||
|
||||
if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE) ){
|
||||
|
@ -609,9 +643,9 @@ epic_intr_normal(
|
|||
if (status & (INTSTAT_CNT | INTSTAT_TXU | INTSTAT_OVW | INTSTAT_RXE)) {
|
||||
|
||||
/* update dot3 Rx statistics */
|
||||
sc->dot3stats.dot3StatsMissedFrames += inb(iobase + MPCNT);
|
||||
sc->dot3stats.dot3StatsFrameTooLongs += inb(iobase + ALICNT);
|
||||
sc->dot3stats.dot3StatsFCSErrors += inb(iobase + CRCCNT);
|
||||
sc->dot3stats.dot3StatsMissedFrames += CSR_READ_1( sc, MPCNT);
|
||||
sc->dot3stats.dot3StatsFrameTooLongs += CSR_READ_1( sc, ALICNT);
|
||||
sc->dot3stats.dot3StatsFCSErrors += CSR_READ_1( sc, CRCCNT);
|
||||
|
||||
/* Update if Rx statistics */
|
||||
if (status & (INTSTAT_OVW | INTSTAT_RXE))
|
||||
|
@ -624,7 +658,7 @@ epic_intr_normal(
|
|||
sc->epic_if.if_oerrors++;
|
||||
|
||||
/* Restart the transmit process. */
|
||||
outl(iobase + COMMAND, COMMAND_TXUGO);
|
||||
CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,18 +698,14 @@ epic_pci_attach(
|
|||
{
|
||||
struct ifnet * ifp;
|
||||
epic_softc_t *sc;
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
u_int32_t iobase;
|
||||
u_int32_t irq;
|
||||
#else
|
||||
caddr_t pmembase;
|
||||
#endif
|
||||
int i,s,media;
|
||||
u_int32_t pool;
|
||||
|
||||
/*
|
||||
* Get iobase and irq level
|
||||
*/
|
||||
irq = PCI_CONF_READ(PCI_CFIT) & (0xFF);
|
||||
if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &iobase))
|
||||
return;
|
||||
|
||||
/* Allocate memory for softc and hardware descriptors */
|
||||
sc = (epic_softc_t *) malloc(
|
||||
sizeof(epic_softc_t) +
|
||||
|
@ -696,8 +726,20 @@ epic_pci_attach(
|
|||
bzero(sc, sizeof(epic_softc_t));
|
||||
epics[ unit ] = sc;
|
||||
sc->unit = unit;
|
||||
sc->iobase = iobase;
|
||||
sc->irq = irq;
|
||||
|
||||
/* Get iobase or membase */
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) {
|
||||
printf("tx%d: cannot map port\n",unit);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) {
|
||||
printf("tx%d: cannot map memory\n",unit);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(TX_FRAG_LIST)
|
||||
sc->tx_flist = (void *)pool;
|
||||
|
@ -708,14 +750,14 @@ epic_pci_attach(
|
|||
sc->tx_desc = (void *)pool;
|
||||
|
||||
/* Bring the chip out of low-power mode. */
|
||||
outl( iobase + GENCTL, 0x0000 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0x0000 );
|
||||
|
||||
/* Magic?! If we don't set this bit the MII interface won't work. */
|
||||
outl( iobase + TEST1, 0x0008 );
|
||||
CSR_WRITE_4( sc, TEST1, 0x0008 );
|
||||
|
||||
/* Read mac address (may be better is read from EEPROM?) */
|
||||
for (i = 0; i < ETHER_ADDR_LEN / sizeof( u_int16_t); i++)
|
||||
((u_int16_t *)sc->epic_macaddr)[i] = inw(iobase + LAN0 + i*4);
|
||||
((u_int16_t *)sc->epic_macaddr)[i] = CSR_READ_2( sc, LAN0 + i*4 );
|
||||
|
||||
/* Display some info */
|
||||
printf("tx%d: address %02x:%02x:%02x:%02x:%02x:%02x,",sc->unit,
|
||||
|
@ -758,27 +800,27 @@ epic_pci_attach(
|
|||
printf(" type SMC9432TX, ");
|
||||
|
||||
/* Identify PHY */
|
||||
sc->phyid = epic_read_phy_register(iobase,DP83840_PHYIDR1)<<6;
|
||||
sc->phyid|= ((epic_read_phy_register(iobase,DP83840_PHYIDR2)>>10)&0x3F);
|
||||
sc->phyid = epic_read_phy_register( sc, DP83840_PHYIDR1 )<<6;
|
||||
sc->phyid|= (epic_read_phy_register( sc, DP83840_PHYIDR2 )>>10)&0x3F;
|
||||
|
||||
if( QS6612_OUI == sc->phyid ){
|
||||
printf("phy QS6612, ");
|
||||
} else if( DP83840_OUI == sc->phyid ){
|
||||
printf("phy DP83840, ");
|
||||
} else {
|
||||
printf("phy: unknown (%x), ",sc->phyid);
|
||||
printf("phy unknown (%x), ",sc->phyid);
|
||||
sc->phyid = DP83840_OUI;
|
||||
}
|
||||
|
||||
/* Read current config */
|
||||
i = epic_read_phy_register(iobase, DP83840_BMCR);
|
||||
i = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
|
||||
#if defined(_NET_IF_MEDIA_H_)
|
||||
media = IFM_ETHER;
|
||||
#endif
|
||||
|
||||
if( i & BMCR_AUTONEGOTIATION ){
|
||||
i = epic_read_phy_register( iobase, DP83840_LPAR );
|
||||
i = epic_read_phy_register( sc, DP83840_LPAR );
|
||||
|
||||
printf("Auto-Neg ");
|
||||
|
||||
|
@ -833,8 +875,8 @@ epic_pci_attach(
|
|||
#endif
|
||||
|
||||
/* Read MBSR twice to update latched bits */
|
||||
epic_read_phy_register(iobase,DP83840_BMSR);
|
||||
i=epic_read_phy_register(iobase,DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if( !(i & BMSR_LINK_STATUS) )
|
||||
printf("tx%d: WARNING! no link estabilished\n",sc->unit);
|
||||
|
@ -879,20 +921,22 @@ epic_ifmedia_status __P((
|
|||
u_int32_t bmcr;
|
||||
u_int32_t bmsr;
|
||||
|
||||
bmcr = epic_read_phy_register( sc->iobase, DP83840_BMCR );
|
||||
bmcr = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
|
||||
epic_read_phy_register(sc->iobase,DP83840_BMSR);
|
||||
bmsr = epic_read_phy_register(sc->iobase,DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
bmsr = epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
ifmr->ifm_active = IFM_ETHER;
|
||||
ifmr->ifm_status = IFM_AVALID;
|
||||
|
||||
if( !(bmsr & BMSR_LINK_STATUS) ) {
|
||||
ifmr->ifm_active |= bmcr&BMCR_AUTONEGOTIATION?IFM_AUTO:IFM_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
ifmr->ifm_active |= bmcr&BMCR_100MBPS?IFM_100_TX:IFM_10_T;
|
||||
ifmr->ifm_active |= bmcr&BMCR_FULL_DUPLEX?IFM_FDX:0;
|
||||
ifmr->ifm_status |= IFM_ACTIVE;
|
||||
ifmr->ifm_active |= (bmcr&BMCR_100MBPS)?IFM_100_TX:IFM_10_T;
|
||||
ifmr->ifm_active |= (bmcr&BMCR_FULL_DUPLEX)?IFM_FDX:0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -906,22 +950,21 @@ epic_init __P((
|
|||
epic_softc_t * sc))
|
||||
{
|
||||
struct ifnet *ifp = &sc->epic_if;
|
||||
int iobase = sc->iobase;
|
||||
int i,s;
|
||||
|
||||
s = splimp();
|
||||
|
||||
/* Soft reset the chip */
|
||||
outl(iobase + GENCTL, GENCTL_SOFT_RESET );
|
||||
CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
|
||||
|
||||
/* Reset takes 15 pci ticks which depends on processor speed*/
|
||||
DELAY(1);
|
||||
|
||||
/* Wake up */
|
||||
outl( iobase + GENCTL, 0 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0 );
|
||||
|
||||
/* ?????? */
|
||||
outl( iobase + TEST1, 0x0008);
|
||||
CSR_WRITE_4( sc, TEST1, 0x0008);
|
||||
|
||||
/* Initialize rings */
|
||||
if( -1 == epic_init_rings( sc ) ) {
|
||||
|
@ -932,17 +975,18 @@ epic_init __P((
|
|||
}
|
||||
|
||||
/* Put node address to EPIC */
|
||||
outl( iobase + LAN0 + 0x0, ((u_int16_t *)sc->epic_macaddr)[0] );
|
||||
outl( iobase + LAN0 + 0x4, ((u_int16_t *)sc->epic_macaddr)[1] );
|
||||
outl( iobase + LAN0 + 0x8, ((u_int16_t *)sc->epic_macaddr)[2] );
|
||||
CSR_WRITE_4( sc, LAN0, ((u_int16_t *)sc->epic_macaddr)[0] );
|
||||
CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->epic_macaddr)[1] );
|
||||
CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->epic_macaddr)[2] );
|
||||
|
||||
/* Set transmit threshold */
|
||||
outl( iobase + ETXTHR, 0x40 );
|
||||
CSR_WRITE_4( sc, ETXTHR, 0x40 );
|
||||
|
||||
/* Compute and set RXCON. */
|
||||
epic_set_rx_mode( sc );
|
||||
|
||||
/* Set media speed mode */
|
||||
epic_init_phy( sc );
|
||||
epic_set_media_speed( sc );
|
||||
|
||||
/* Set multicast table */
|
||||
|
@ -950,13 +994,13 @@ epic_init __P((
|
|||
|
||||
/* Enable interrupts by setting the interrupt mask. */
|
||||
if( QS6612_OUI == sc->phyid ) {
|
||||
outl( iobase + INTMASK,
|
||||
CSR_WRITE_4( sc, INTMASK,
|
||||
INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
|
||||
INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
|
||||
INTSTAT_CNT | INTSTAT_GP2 | INTSTAT_FATAL |
|
||||
INTSTAT_PTA | INTSTAT_PMA | INTSTAT_APE | INTSTAT_DPE );
|
||||
} else {
|
||||
outl( iobase + INTMASK,
|
||||
CSR_WRITE_4( sc, INTMASK,
|
||||
INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
|
||||
INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
|
||||
INTSTAT_CNT | INTSTAT_FATAL |
|
||||
|
@ -964,12 +1008,12 @@ epic_init __P((
|
|||
}
|
||||
|
||||
/* Enable interrupts, set for PCI read multiple and etc */
|
||||
outl( iobase + GENCTL,
|
||||
CSR_WRITE_4( sc, GENCTL,
|
||||
GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE |
|
||||
GENCTL_ONECOPY | GENCTL_RECEIVE_FIFO_THRESHOLD64 );
|
||||
|
||||
/* Start rx process */
|
||||
outl( iobase + COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX );
|
||||
CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX );
|
||||
|
||||
/* Mark interface running ... */
|
||||
if( ifp->if_flags & IFF_UP ) ifp->if_flags |= IFF_RUNNING;
|
||||
|
@ -1003,11 +1047,39 @@ epic_set_rx_mode(
|
|||
if( sc->epic_if.if_flags & IFF_MULTICAST )
|
||||
rxcon |= RXCON_RECEIVE_MULTICAST_FRAMES;
|
||||
|
||||
outl( sc->iobase + RXCON, rxcon );
|
||||
CSR_WRITE_4( sc, RXCON, rxcon );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
epic_init_phy __P((
|
||||
epic_softc_t * sc))
|
||||
{
|
||||
u_int32_t i;
|
||||
|
||||
/* Reset PHY */
|
||||
epic_write_phy_register( sc, DP83840_BMCR, BMCR_RESET );
|
||||
for(i=0;i<0x100000;i++)
|
||||
if( !(epic_read_phy_register( sc, DP83840_BMCR ) & BMCR_RESET) )
|
||||
break;
|
||||
|
||||
if( epic_read_phy_register( sc, DP83840_BMCR ) & BMCR_RESET )
|
||||
printf("tx%d: WARNING! cannot reset PHY\n",sc->unit);
|
||||
|
||||
switch( sc->phyid ){
|
||||
case QS6612_OUI:
|
||||
/* Init QS6612 to generate interrupt when AutoNeg complete */
|
||||
CSR_WRITE_4( sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
|
||||
epic_read_phy_register( sc, QS6612_INTSTAT );
|
||||
epic_write_phy_register( sc, QS6612_INTMASK,
|
||||
INTMASK_THUNDERLAN|INTSTAT_AN_COMPLETE );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function should set MII to mode specified by IFF_LINK* flags or
|
||||
* ifmedia structure.
|
||||
|
@ -1022,16 +1094,6 @@ epic_set_media_speed __P((
|
|||
struct ifnet *ifp = &sc->epic_if;
|
||||
#endif
|
||||
u_int16_t media;
|
||||
u_int32_t i;
|
||||
|
||||
/* Reset PHY */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, BMCR_RESET );
|
||||
for(i=0;i<0x100000;i++)
|
||||
if( !(epic_read_phy_register(sc->iobase,DP83840_BMCR) & BMCR_RESET) )
|
||||
break;
|
||||
|
||||
if( epic_read_phy_register(sc->iobase, DP83840_BMCR) & BMCR_RESET )
|
||||
printf("tx%d: WARNING! cannot reset PHY\n",sc->unit);
|
||||
|
||||
/* Set media speed */
|
||||
|
||||
|
@ -1039,14 +1101,14 @@ epic_set_media_speed __P((
|
|||
if( IFM_SUBTYPE(tgtmedia) != IFM_AUTO ){
|
||||
/* Set mode */
|
||||
media = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX) ? BMCR_100MBPS : 0;
|
||||
media|= ((tgtmedia&IFM_GMASK)==IFM_FDX) ? BMCR_FULL_DUPLEX : 0;
|
||||
media|= (tgtmedia&IFM_FDX) ? BMCR_FULL_DUPLEX : 0;
|
||||
|
||||
sc->epic_if.if_baudrate =
|
||||
(IFM_SUBTYPE(tgtmedia)==IFM_100_TX)?100000000:10000000;
|
||||
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, media );
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
outl( sc->iobase + TXCON,((tgtmedia&IFM_GMASK)==IFM_FDX)?TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT:TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON,(tgtmedia&IFM_FDX)?TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT:TXCON_DEFAULT );
|
||||
}
|
||||
#else
|
||||
if( ifp->if_flags & IFF_LINK0 ) {
|
||||
|
@ -1057,26 +1119,18 @@ epic_set_media_speed __P((
|
|||
sc->epic_if.if_baudrate =
|
||||
(ifp->if_flags & IFF_LINK2)?100000000:10000000;
|
||||
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR, media );
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
outl( sc->iobase + TXCON, (ifp->if_flags & IFF_LINK2) ? TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT : TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON, (ifp->if_flags & IFF_LINK2) ? TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT : TXCON_DEFAULT );
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Init QS6612 to generate interrupt when AutoNeg complete */
|
||||
if( QS6612_OUI == sc->phyid ) {
|
||||
outl( sc->iobase + NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
|
||||
epic_read_phy_register( sc->iobase, QS6612_INTSTAT );
|
||||
epic_write_phy_register( sc->iobase, QS6612_INTMASK,
|
||||
INTMASK_THUNDERLAN|INTSTAT_AN_COMPLETE );
|
||||
}
|
||||
|
||||
sc->epic_if.if_baudrate = 100000000;
|
||||
|
||||
outl( sc->iobase + TXCON, TXCON_DEFAULT );
|
||||
CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
|
||||
|
||||
/* Set and restart autoneg */
|
||||
epic_write_phy_register( sc->iobase, DP83840_BMCR,
|
||||
epic_write_phy_register( sc, DP83840_BMCR,
|
||||
BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG );
|
||||
|
||||
/* If it is not QS6612 PHY, try to get result of autoneg. */
|
||||
|
@ -1088,7 +1142,7 @@ epic_set_media_speed __P((
|
|||
DELAY(3000000);
|
||||
|
||||
if( epic_autoneg(sc) == EPIC_FULL_DUPLEX )
|
||||
outl( sc->iobase + TXCON,
|
||||
CSR_WRITE_4( sc, TXCON,
|
||||
TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT);
|
||||
}
|
||||
/* Else it will be done when GP2 int occured */
|
||||
|
@ -1114,11 +1168,11 @@ epic_autoneg(
|
|||
/* BMSR must be read twice to update the link status bit
|
||||
* since that bit is a latch bit
|
||||
*/
|
||||
epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
i = epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR);
|
||||
i = epic_read_phy_register( sc, DP83840_BMSR);
|
||||
|
||||
if ((i & BMSR_LINK_STATUS) && (i & BMSR_AUTONEG_COMPLETE)){
|
||||
i = epic_read_phy_register( sc->iobase, DP83840_LPAR );
|
||||
i = epic_read_phy_register( sc, DP83840_LPAR );
|
||||
|
||||
if ( i & (ANAR_100_TX_FD|ANAR_10_FD) )
|
||||
return EPIC_FULL_DUPLEX;
|
||||
|
@ -1133,19 +1187,19 @@ epic_autoneg(
|
|||
/* ANER must be read twice to get the correct reading for the
|
||||
* Multiple link fault bit -- it is a latched bit
|
||||
*/
|
||||
epic_read_phy_register (sc->iobase, DP83840_ANER);
|
||||
i = epic_read_phy_register (sc->iobase, DP83840_ANER);
|
||||
epic_read_phy_register( sc, DP83840_ANER );
|
||||
i = epic_read_phy_register( sc, DP83840_ANER );
|
||||
|
||||
if ( i & ANER_MULTIPLE_LINK_FAULT ) {
|
||||
/* it can be forced to 100Mb/s Half-Duplex */
|
||||
media = epic_read_phy_register(sc->iobase,DP83840_BMCR);
|
||||
media = epic_read_phy_register( sc, DP83840_BMCR );
|
||||
media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX);
|
||||
media |= BMCR_100MBPS;
|
||||
epic_write_phy_register(sc->iobase,DP83840_BMCR,media);
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media );
|
||||
|
||||
/* read BMSR again to determine link status */
|
||||
epic_read_phy_register(sc->iobase, DP83840_BMSR);
|
||||
i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if (i & BMSR_LINK_STATUS){
|
||||
/* port is linked to the non Auto-Negotiation
|
||||
|
@ -1154,11 +1208,11 @@ epic_autoneg(
|
|||
return EPIC_HALF_DUPLEX;
|
||||
}
|
||||
else {
|
||||
media = epic_read_phy_register (sc->iobase, DP83840_BMCR);
|
||||
media = epic_read_phy_register( sc, DP83840_BMCR);
|
||||
media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX | BMCR_100MBPS);
|
||||
epic_write_phy_register(sc->iobase, DP83840_BMCR, media);
|
||||
epic_read_phy_register(sc->iobase, DP83840_BMSR);
|
||||
i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
|
||||
epic_write_phy_register( sc, DP83840_BMCR, media);
|
||||
epic_read_phy_register( sc, DP83840_BMSR );
|
||||
i=epic_read_phy_register( sc, DP83840_BMSR );
|
||||
|
||||
if (i & BMSR_LINK_STATUS) {
|
||||
/*port is linked to the non
|
||||
|
@ -1186,10 +1240,10 @@ epic_set_mc_table (
|
|||
struct ifnet *ifp = &sc->epic_if;
|
||||
|
||||
if( ifp->if_flags & IFF_MULTICAST ){
|
||||
outl( sc->iobase + MC0, 0xFFFF );
|
||||
outl( sc->iobase + MC1, 0xFFFF );
|
||||
outl( sc->iobase + MC2, 0xFFFF );
|
||||
outl( sc->iobase + MC3, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC0, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC1, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC2, 0xFFFF );
|
||||
CSR_WRITE_4( sc, MC3, 0xFFFF );
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -1212,32 +1266,31 @@ static void
|
|||
epic_stop(
|
||||
epic_softc_t * sc)
|
||||
{
|
||||
int iobase = sc->iobase;
|
||||
int i,s;
|
||||
|
||||
s = splimp();
|
||||
sc->epic_if.if_timer = 0;
|
||||
|
||||
/* Disable interrupts, stop processes */
|
||||
outl( iobase + INTMASK, 0 );
|
||||
outl( iobase + GENCTL, 0 );
|
||||
outl( iobase + COMMAND,
|
||||
CSR_WRITE_4( sc, INTMASK, 0 );
|
||||
CSR_WRITE_4( sc, GENCTL, 0 );
|
||||
CSR_WRITE_4( sc, COMMAND,
|
||||
COMMAND_STOP_RX | COMMAND_STOP_RDMA | COMMAND_STOP_TDMA );
|
||||
|
||||
/* Wait RX and TX DMA to stop */
|
||||
for(i=0;i<0x100000;i++){
|
||||
if( (inl(iobase+INTSTAT)&(INTSTAT_RXIDLE|INTSTAT_TXIDLE)) ==
|
||||
if( (CSR_READ_4(sc,INTSTAT)&(INTSTAT_RXIDLE|INTSTAT_TXIDLE)) ==
|
||||
(INTSTAT_RXIDLE|INTSTAT_TXIDLE) ) break;
|
||||
}
|
||||
|
||||
if( !(inl(iobase+INTSTAT)&INTSTAT_RXIDLE) )
|
||||
if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) )
|
||||
printf("tx%d: can't stop RX DMA\n",sc->unit);
|
||||
|
||||
if( !(inl(iobase+INTSTAT)&INTSTAT_TXIDLE) )
|
||||
if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) )
|
||||
printf("tx%d: can't stop TX DMA\n",sc->unit);
|
||||
|
||||
/* Reset chip and phy */
|
||||
outl( iobase + GENCTL, GENCTL_SOFT_RESET );
|
||||
CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
|
||||
|
||||
/* Need to wait for 15 pci ticks to pass before accessing again*/
|
||||
DELAY(1);
|
||||
|
@ -1368,8 +1421,8 @@ epic_init_rings(epic_softc_t * sc){
|
|||
}
|
||||
|
||||
/* Give rings to EPIC */
|
||||
outl( sc->iobase + PRCDAR, vtophys( sc->rx_desc ) );
|
||||
outl( sc->iobase + PTCDAR, vtophys( sc->tx_desc ) );
|
||||
CSR_WRITE_4( sc, PRCDAR, vtophys( sc->rx_desc ) );
|
||||
CSR_WRITE_4( sc, PTCDAR, vtophys( sc->tx_desc ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1377,45 +1430,57 @@ epic_init_rings(epic_softc_t * sc){
|
|||
/*
|
||||
* EEPROM operation functions
|
||||
*/
|
||||
static void epic_write_eepromreg(u_int16_t regaddr, u_int8_t val){
|
||||
static void epic_write_eepromreg __P((
|
||||
epic_softc_t *sc,
|
||||
u_int8_t val))
|
||||
{
|
||||
u_int16_t i;
|
||||
|
||||
outb( regaddr, val );
|
||||
CSR_WRITE_1( sc, EECTL, val );
|
||||
|
||||
for( i=0;i<0xFF; i++)
|
||||
if( !(inb( regaddr ) & 0x20) ) break;
|
||||
if( !(CSR_READ_1( sc, EECTL ) & 0x20) ) break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static u_int8_t epic_read_eepromreg(u_int16_t regaddr){
|
||||
return inb( regaddr );
|
||||
static u_int8_t epic_read_eepromreg __P((
|
||||
epic_softc_t *sc))
|
||||
{
|
||||
return CSR_READ_1( sc,EECTL );
|
||||
}
|
||||
|
||||
static u_int8_t epic_eeprom_clock( u_int16_t ioaddr, u_int8_t val ){
|
||||
|
||||
epic_write_eepromreg( ioaddr + EECTL, val );
|
||||
epic_write_eepromreg( ioaddr + EECTL, (val | 0x4) );
|
||||
epic_write_eepromreg( ioaddr + EECTL, val );
|
||||
static u_int8_t epic_eeprom_clock __P((
|
||||
epic_softc_t *sc,
|
||||
u_int8_t val))
|
||||
{
|
||||
epic_write_eepromreg( sc, val );
|
||||
epic_write_eepromreg( sc, (val | 0x4) );
|
||||
epic_write_eepromreg( sc, val );
|
||||
|
||||
return epic_read_eepromreg( ioaddr + EECTL );
|
||||
return epic_read_eepromreg( sc );
|
||||
}
|
||||
|
||||
static void epic_output_eepromw(u_int16_t ioaddr, u_int16_t val){
|
||||
static void epic_output_eepromw __P((
|
||||
epic_softc_t * sc,
|
||||
u_int16_t val))
|
||||
{
|
||||
int i;
|
||||
for( i = 0xF; i >= 0; i--){
|
||||
if( (val & (1 << i)) ) epic_eeprom_clock( ioaddr, 0x0B );
|
||||
else epic_eeprom_clock( ioaddr, 3);
|
||||
if( (val & (1 << i)) ) epic_eeprom_clock( sc, 0x0B );
|
||||
else epic_eeprom_clock( sc, 3);
|
||||
}
|
||||
}
|
||||
|
||||
static u_int16_t epic_input_eepromw(u_int16_t ioaddr){
|
||||
static u_int16_t epic_input_eepromw __P((
|
||||
epic_softc_t *sc))
|
||||
{
|
||||
int i;
|
||||
int tmp;
|
||||
u_int16_t retval = 0;
|
||||
|
||||
for( i = 0xF; i >= 0; i--) {
|
||||
tmp = epic_eeprom_clock( ioaddr, 0x3 );
|
||||
tmp = epic_eeprom_clock( sc, 0x3 );
|
||||
if( tmp & 0x10 ){
|
||||
retval |= (1 << i);
|
||||
}
|
||||
|
@ -1423,44 +1488,54 @@ static u_int16_t epic_input_eepromw(u_int16_t ioaddr){
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int epic_read_eeprom(u_int16_t ioaddr, u_int16_t loc){
|
||||
static int epic_read_eeprom __P((
|
||||
epic_softc_t *sc,
|
||||
u_int16_t loc))
|
||||
{
|
||||
int i;
|
||||
u_int16_t dataval;
|
||||
u_int16_t read_cmd;
|
||||
|
||||
epic_write_eepromreg(ioaddr + EECTL , 3);
|
||||
epic_write_eepromreg( sc , 3);
|
||||
|
||||
if( epic_read_eepromreg(ioaddr + EECTL) & 0x40 )
|
||||
if( epic_read_eepromreg( sc ) & 0x40 )
|
||||
read_cmd = ( loc & 0x3F ) | 0x180;
|
||||
else
|
||||
read_cmd = ( loc & 0xFF ) | 0x600;
|
||||
|
||||
epic_output_eepromw( ioaddr, read_cmd );
|
||||
epic_output_eepromw( sc, read_cmd );
|
||||
|
||||
dataval = epic_input_eepromw( ioaddr );
|
||||
dataval = epic_input_eepromw( sc );
|
||||
|
||||
epic_write_eepromreg( ioaddr + EECTL, 1 );
|
||||
epic_write_eepromreg( sc, 1 );
|
||||
|
||||
return dataval;
|
||||
}
|
||||
|
||||
static int epic_read_phy_register(u_int16_t iobase, u_int16_t loc){
|
||||
static int epic_read_phy_register __P((
|
||||
epic_softc_t *sc,
|
||||
u_int16_t loc))
|
||||
{
|
||||
int i;
|
||||
|
||||
outl( iobase + MIICTL, ((loc << 4) | 0x0601) );
|
||||
CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0601) );
|
||||
|
||||
for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICTL )&1) ) break;
|
||||
for( i=0;i<0x1000;i++) if( !(CSR_READ_4( sc, MIICTL )&1) ) break;
|
||||
|
||||
return inl( iobase + MIIDATA );
|
||||
return CSR_READ_4( sc, MIIDATA );
|
||||
}
|
||||
|
||||
static void epic_write_phy_register(u_int16_t iobase, u_int16_t loc,u_int16_t val){
|
||||
static void epic_write_phy_register __P((
|
||||
epic_softc_t * sc,
|
||||
u_int16_t loc,
|
||||
u_int16_t val))
|
||||
{
|
||||
int i;
|
||||
|
||||
outl( iobase + MIIDATA, val );
|
||||
outl( iobase + MIICTL, ((loc << 4) | 0x0602) );
|
||||
CSR_WRITE_4( sc, MIIDATA, val );
|
||||
CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0602) );
|
||||
|
||||
for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICTL )&2) ) break;
|
||||
for( i=0;i<0x1000;i++) if( !(CSR_READ_4( sc, MIICTL )&2) ) break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -23,14 +23,10 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* stable-167
|
||||
* $Id: $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* smc83c170.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
|
@ -253,31 +249,31 @@
|
|||
/* NB: to make driver happy, this two structures MUST have thier sizes */
|
||||
/* be divisor of PAGE_SIZE */
|
||||
struct epic_tx_desc {
|
||||
u_int16_t status;
|
||||
u_int16_t txlength;
|
||||
u_int32_t bufaddr;
|
||||
u_int16_t buflength;
|
||||
u_int16_t control;
|
||||
u_int32_t next;
|
||||
volatile u_int16_t status;
|
||||
volatile u_int16_t txlength;
|
||||
volatile u_int32_t bufaddr;
|
||||
volatile u_int16_t buflength;
|
||||
volatile u_int16_t control;
|
||||
volatile u_int32_t next;
|
||||
};
|
||||
struct epic_rx_desc {
|
||||
u_int16_t status;
|
||||
u_int16_t rxlength;
|
||||
u_int32_t bufaddr;
|
||||
u_int32_t buflength;
|
||||
u_int32_t next;
|
||||
volatile u_int16_t status;
|
||||
volatile u_int16_t rxlength;
|
||||
volatile u_int32_t bufaddr;
|
||||
volatile u_int32_t buflength;
|
||||
volatile u_int32_t next;
|
||||
};
|
||||
|
||||
/* This structure defines EPIC's fragment list, maximum number of frags */
|
||||
/* is 63. Let use maximum, becouse size of struct MUST be divisor of */
|
||||
/* PAGE_SIZE, and sometimes come mbufs with more then 30 frags */
|
||||
struct epic_frag_list {
|
||||
u_int32_t numfrags;
|
||||
volatile u_int32_t numfrags;
|
||||
struct {
|
||||
u_int32_t fragaddr;
|
||||
u_int32_t fraglen;
|
||||
volatile u_int32_t fragaddr;
|
||||
volatile u_int32_t fraglen;
|
||||
} frag[63];
|
||||
u_int32_t pad; /* align on 256 bytes */
|
||||
volatile u_int32_t pad; /* align on 256 bytes */
|
||||
};
|
||||
|
||||
/* This is driver's structure to define EPIC descriptors */
|
||||
|
@ -324,13 +320,31 @@ typedef struct {
|
|||
u_int32_t cur_rx;
|
||||
u_int32_t dirty_tx;
|
||||
u_int32_t pending_txs;
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
u_int32_t iobase;
|
||||
u_int32_t irq;
|
||||
#else
|
||||
caddr_t csr;
|
||||
#endif
|
||||
struct ifmib_iso_8802_3 dot3stats;
|
||||
} epic_softc_t;
|
||||
|
||||
#define epic_if epic_ac.ac_if
|
||||
#define epic_macaddr epic_ac.ac_enaddr
|
||||
#if defined(EPIC_USEIOSPACE)
|
||||
#define CSR_WRITE_4(sc,reg,val) outl( (sc)->iobase + (u_int32_t)(reg), (val) )
|
||||
#define CSR_WRITE_2(sc,reg,val) outw( (sc)->iobase + (u_int32_t)(reg), (val) )
|
||||
#define CSR_WRITE_1(sc,reg,val) outb( (sc)->iobase + (u_int32_t)(reg), (val) )
|
||||
#define CSR_READ_4(sc,reg) inl( (sc)->iobase + (u_int32_t)(reg) )
|
||||
#define CSR_READ_2(sc,reg) inw( (sc)->iobase + (u_int32_t)(reg) )
|
||||
#define CSR_READ_1(sc,reg) inb( (sc)->iobase + (u_int32_t)(reg) )
|
||||
#else
|
||||
#define CSR_WRITE_1(sc,reg,val) ((*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int8_t)(val))
|
||||
#define CSR_WRITE_2(sc,reg,val) ((*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int16_t)(val))
|
||||
#define CSR_WRITE_4(sc,reg,val) ((*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int32_t)(val))
|
||||
#define CSR_READ_1(sc,reg) (*(u_int8_t*)((sc)->csr + (u_int32_t)(reg)))
|
||||
#define CSR_READ_2(sc,reg) (*(u_int16_t*)((sc)->csr + (u_int32_t)(reg)))
|
||||
#define CSR_READ_4(sc,reg) (*(u_int32_t*)((sc)->csr + (u_int32_t)(reg)))
|
||||
#endif
|
||||
|
||||
//extern epic_softc_t *epics[];
|
||||
//extern u_long epic_pci_count;
|
||||
|
@ -359,14 +373,15 @@ static void epic_free_rings __P((epic_softc_t *));
|
|||
static void epic_set_rx_mode __P((epic_softc_t *));
|
||||
static void epic_set_mc_table __P((epic_softc_t *));
|
||||
static void epic_set_media_speed __P((epic_softc_t *));
|
||||
static void epic_init_phy __P((epic_softc_t *));
|
||||
static int epic_autoneg __P((epic_softc_t *));
|
||||
|
||||
static int epic_read_eeprom __P((u_int16_t,u_int16_t));
|
||||
static void epic_output_eepromw __P((u_int16_t, u_int16_t));
|
||||
static u_int16_t epic_input_eepromw __P((u_int16_t));
|
||||
static u_int8_t epic_eeprom_clock __P((u_int16_t,u_int8_t));
|
||||
static void epic_write_eepromreg __P((u_int16_t,u_int8_t));
|
||||
static u_int8_t epic_read_eepromreg __P((u_int16_t));
|
||||
static int epic_read_eeprom __P((epic_softc_t *,u_int16_t));
|
||||
static void epic_output_eepromw __P((epic_softc_t *, u_int16_t));
|
||||
static u_int16_t epic_input_eepromw __P((epic_softc_t *));
|
||||
static u_int8_t epic_eeprom_clock __P((epic_softc_t *,u_int8_t));
|
||||
static void epic_write_eepromreg __P((epic_softc_t *,u_int8_t));
|
||||
static u_int8_t epic_read_eepromreg __P((epic_softc_t *));
|
||||
|
||||
static int epic_read_phy_register __P((u_int16_t, u_int16_t));
|
||||
static void epic_write_phy_register __P((u_int16_t, u_int16_t,u_int16_t));
|
||||
static int epic_read_phy_register __P((epic_softc_t *, u_int16_t));
|
||||
static void epic_write_phy_register __P((epic_softc_t *, u_int16_t,u_int16_t));
|
||||
|
|
Loading…
Reference in a new issue