📄 smc91x.c
字号:
/*------------------------------------------------------------------------
. smc91x.c
. This is a driver for SMSC's 9196/91C111 single-chip Ethernet device.
.
. Copyright (C) 2003, Intel corporation (yu.tang@intel.com)
.
. (C) Copyright 2002
. Sysgo Real-Time Solutions, GmbH <www.elinos.com>
. Rolf Offermanns <rof@sysgo.de>
.
. Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
. Developed by Simple Network Magic Corporation (SNMC)
. Copyright (C) 1996 by Erik Stahlman (ES)
.
. This program is free software; you can redistribute it and/or modify
. it under the terms of the GNU General Public License as published by
. the Free Software Foundation; either version 2 of the License, or
. (at your option) any later version.
.
. This program is distributed in the hope that it will be useful,
. but WITHOUT ANY WARRANTY; without even the implied warranty of
. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
. GNU General Public License for more details.
.
. You should have received a copy of the GNU General Public License
. along with this program; if not, write to the Free Software
. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
.
. Information contained in this file was obtained from the LAN91C111
. manual from SMC. To get a copy, if you really want one, you can find
. information under www.smsc.com.
.
.
. "Features" of the SMC chip:
. Integrated PHY/MAC for 10/100BaseT Operation
. Supports internal and external MII
. Integrated 8K packet memory
. EEPROM interface for configuration
.
. Arguments:
. io = for the base address
. irq = for the IRQ
.
. author:
. Erik Stahlman ( erik@vt.edu )
. Daris A Nevil ( dnevil@snmc.com )
.
.
. Hardware multicast code from Peter Cammaert ( pc@denkart.be )
.
. Sources:
. o SMSC LAN91C111 databook (www.smsc.com)
. o smc9194.c by Erik Stahlman
. o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
.
. History:
. 10/17/01 Marco Hasewinkel Modify for DNP/1110
. 07/25/01 Woojung Huh Modify for ADS Bitsy
. 04/25/01 Daris A Nevil Initial public release through SMSC
. 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111
----------------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif
#include <blob/arch.h>
#include <blob/types.h>
#include <blob/init.h>
#include <blob/serial.h>
#include <blob/util.h>
#include <blob/time.h>
#include "net.h"
#include "smc91x.h"
// Use power-down feature of the chip
#define POWER_DOWN 0
#define NO_AUTOPROBE
static const char version[] =
"smc91x.c:v1.0 04/25/01 by Daris A Nevil (dnevil@snmc.com)\n";
#define SMC_DEBUG 0
/*------------------------------------------------------------------------
.
. Configuration options, for the experienced user to change.
.
-------------------------------------------------------------------------*/
/*
. Wait time for memory to be free. This probably shouldn't be
. tuned that much, as waiting for this means nothing else happens
. in the system
*/
#define MEMORY_WAIT_TIME 16
#if (SMC_DEBUG > 2 )
#define PRINTK3(args...) printf(args)
#else
#define PRINTK3(args...)
#endif
#if SMC_DEBUG > 1
#define PRINTK2(args...) printf(args)
#else
#define PRINTK2(args...)
#endif
#ifdef SMC_DEBUG
#define PRINTK(args...) printf(args)
#else
#define PRINTK(args...)
#endif
/*------------------------------------------------------------------------
.
. The internal workings of the driver. If you are changing anything
. here with the SMC stuff, you should have the datasheet and know
. what you are doing.
.
-------------------------------------------------------------------------*/
#define CARDNAME "LAN91X"
// Memory sizing constant
#define LAN91C111_MEMORY_MULTIPLIER (1024*2)
#define SMC_BASE_ADDRESS CONFIG_SMC91X_BASE
#define SMC_DEV_NAME "SMC91X"
#define SMC_PHY_ADDR 0x0000
#define SMC_ALLOC_MAX_TRY 5
#define SMC_TX_TIMEOUT 30
#define SMC_PHY_CLOCK_DELAY 1
#define ETH_ZLEN 60
/*-----------------------------------------------------------------
.
. The driver can be entered at any of the following entry points.
.
.------------------------------------------------------------------ */
extern int eth_init();
extern void eth_halt(void);
extern int eth_rx(void);
extern int eth_xmit(struct mybuf *packet);
/*
. This is called by register_netdev(). It is responsible for
. checking the portlist for the SMC9000 series chipset. If it finds
. one, then it will initialize the device, find the hardware information,
. and sets up the appropriate device parameters.
. NOTE: Interrupts are *OFF* when this procedure is called.
.
. NB:This shouldn't be static since it is referred to externally.
*/
int smc_init(void);
/*
. This is called by unregister_netdev(). It is responsible for
. cleaning up before the driver is finally unregistered and discarded.
*/
void smc_destructor(void);
/*
. The kernel calls this function when someone wants to use the device,
. typically 'ifconfig ethX up'.
*/
static int smc_open(void);
/*
. This is called by the kernel in response to 'ifconfig ethX down'. It
. is responsible for cleaning up everything that the open routine
. does, and maybe putting the card into a powerdown state.
*/
static int smc_close(void);
/*
. Configures the PHY through the MII Management interface
*/
static void smc_phy_configure(void);
/*
. This is a separate procedure to handle the receipt of a packet, to
. leave the interrupt code looking slightly cleaner
*/
static int smc_rcv(void);
/*
------------------------------------------------------------
.
. Internal routines
.
------------------------------------------------------------
*/
/** This is hardcoded for now.
* Once the flash works correctly the mac addr. can be
* fetched from FLASHBLOCK 1 / OFFSET 0x10 using
* smc_get_macaddr( smc_mac_addr );
*/
unsigned char eth_mac_addr[6] = {0x08, 0x00, 0x3e, 0x26, 0x0a, 0x5b};
/*
void smc_get_macaddr( byte *addr ) {
// MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10
unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
int i;
for (i=0; i<6; i++) {
addr[0] = *(dnp1110_mac+0);
addr[1] = *(dnp1110_mac+1);
addr[2] = *(dnp1110_mac+2);
addr[3] = *(dnp1110_mac+3);
addr[4] = *(dnp1110_mac+4);
addr[5] = *(dnp1110_mac+5);
}
}
*/
/***********************************************
* Show available memory *
***********************************************/
void dump_memory_info(void)
{
word mem_info;
word old_bank;
old_bank = SMC_inw(BANK_SELECT)&0xF;
SMC_SELECT_BANK(0);
mem_info = SMC_inw( MIR_REG );
PRINTK2("Memory: %4d available\n", (mem_info >> 8)*2048);
SMC_SELECT_BANK(old_bank);
}
/*
. A rather simple routine to print out a packet for debugging purposes.
*/
#if SMC_DEBUG > 2
static void print_packet( byte *, int );
#endif
#define tx_done(dev) 1
/* this does a soft reset on the device */
static void smc_reset( void );
/* Enable Interrupts, Receive, and Transmit */
static void smc_enable( void );
/* this puts the device in an inactive state */
static void smc_shutdown( void );
/* Routines to Read and Write the PHY Registers across the
MII Management Interface
*/
static word smc_read_phy_register(byte phyreg);
static void smc_write_phy_register(byte phyreg, word phydata);
/*
. Function: smc_reset( void )
. Purpose:
. This sets the SMC9196/91111 chip to its normal state, hopefully from whatever
. mess that any other DOS driver has put it in.
.
. Maybe I should reset more registers to defaults in here? SOFTRST should
. do that for me.
.
. Method:
. 1. send a SOFT RESET
. 2. wait for it to finish
. 3. enable autorelease mode
. 4. reset the memory management unit
. 5. clear all interrupts
.
*/
static void smc_reset( void )
{
PRINTK2("%s:smc_reset\n", SMC_DEV_NAME);
/* This resets the registers mostly to defaults, but doesn't
affect EEPROM. That seems unnecessary */
SMC_SELECT_BANK( 0 );
SMC_outw( RCR_SOFTRST, RCR_REG );
/* Setup the Configuration Register */
/* This is necessary because the CONFIG_REG is not affected */
/* by a soft reset */
SMC_SELECT_BANK( 1 );
//#if defined(CONFIG_SMC91111_EXT_PHY)
// SMC_outw( CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG);
//#else
SMC_outw( CONFIG_DEFAULT, CONFIG_REG);
//#endif
/* Release from possible power-down state */
/* Configuration register is not affected by Soft Reset */
SMC_outw( SMC_inw( CONFIG_REG ) | CONFIG_EPH_POWER_EN, CONFIG_REG );
SMC_SELECT_BANK( 0 );
/* this should pause enough for the chip to be happy */
msleep(1);
/* Disable transmit and receive functionality */
SMC_outw( RCR_CLEAR, RCR_REG );
SMC_outw( TCR_CLEAR, TCR_REG );
/* set the control register */
SMC_SELECT_BANK( 1 );
//SMC_outw( CTL_DEFAULT, CTL_REG );
// Enable AUTO_RELEASE
SMC_outw( SMC_inw(CTL_REG) | CTL_AUTO_RELEASE, CTL_REG);
/* Reset the MMU */
SMC_SELECT_BANK( 2 );
SMC_outw( MC_RESET, MMU_CMD_REG );
while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
msleep(1); // Wait until not busy
/* Note: It doesn't seem that waiting for the MMU busy is needed here,
but this is a place where future chipsets _COULD_ break. Be wary
of issuing another MMU command right after this */
/* Disable all interrupts */
SMC_outb( 0, IM_REG );
}
/*
. Function: smc_enable
. Purpose: let the chip talk to the outside work
. Method:
. 1. Enable the transmitter
. 2. Enable the receiver
. 3. Enable interrupts
*/
static void smc_enable()
{
PRINTK2("%s:smc_enable\n", SMC_DEV_NAME);
SMC_SELECT_BANK( 0 );
/* see the header file for options in TCR/RCR DEFAULT*/
SMC_outw( TCR_DEFAULT, TCR_REG );
SMC_outw( RCR_DEFAULT, RCR_REG );
/* clear MII_DIS */
// smc_write_phy_register(PHY_CNTL_REG, 0x0000);
}
/*
. Function: smc_shutdown
. Purpose: closes down the SMC91xxx chip.
. Method:
. 1. zero the interrupt mask
. 2. clear the enable receive flag
. 3. clear the enable xmit flags
.
. TODO:
. (1) maybe utilize power down mode.
. Why not yet? Because while the chip will go into power down mode,
. the manual says that it will wake up in response to any I/O requests
. in the register space. Empirical results do not show this working.
*/
static void smc_shutdown()
{
PRINTK2(CARDNAME ":smc_shutdown\n");
/* no more interrupts for me */
SMC_SELECT_BANK( 2 );
SMC_outb( 0, IM_REG );
/* and tell the card to stay away from that nasty outside world */
SMC_SELECT_BANK( 0 );
SMC_outb( RCR_CLEAR, RCR_REG );
SMC_outb( TCR_CLEAR, TCR_REG );
}
/*
. Function: smc_hardware_send_packet(struct net_device * )
. Purpose:
. This sends the actual packet to the SMC9xxx chip.
.
. Algorithm:
. First, see if a saved_skb is available.
. ( this should NOT be called if there is no 'saved_skb'
. Now, find the packet number that the chip allocated
. Point the data pointers at it in memory
. Set the length word in the chip's memory
. Dump the packet to chip memory
. Check if a last byte is needed ( odd length packet )
. if so, set the control flag right
. Tell the card to send it
. Enable the transmit interrupt, so I know if it failed
. Free the kernel data if I actually sent it.
*/
static int smc_send_packet(volatile void *packet, int packet_length)
{
byte packet_no;
unsigned long ioaddr;
byte * buf;
int length;
int numPages;
int try = 0;
int time_out;
byte status;
PRINTK3("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);
length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
/* allocate memory
** The MMU wants the number of pages to be the number of 256 bytes
** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
**
** The 91C111 ignores the size bits, but the code is left intact
** for backwards and future compatibility.
**
** Pkt size for allocating is data length +6 (for additional status
** words, length and ctl!)
**
** If odd size then last byte is included in this header.
*/
numPages = ((length & 0xfffe) + 6);
numPages >>= 8; // Divide by 256
if (numPages > 7 ) {
printf("%s: Far too big packet error. \n", SMC_DEV_NAME);
return 0;
}
again:
/* now, try to allocate the memory */
SMC_SELECT_BANK( 2 );
SMC_outw( MC_ALLOC | numPages, MMU_CMD_REG );
try++;
time_out = MEMORY_WAIT_TIME;
do {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -