📄 if_8139.c
字号:
//==========================================================================//// if_8139.c//// RealTek 8139 ethernet driver////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos 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 or (at your option) any later version.//// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD or// other sources, and are covered by the appropriate copyright// disclaimers included herein.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): Eric Doenges// Contributors: Chris Nimmers, Gary Thomas, Andy Dyer// Date: 2003-07-09// Purpose:// Description: hardware driver for RealTek 8139 ethernet// Notes: This is a very basic driver that will send and receive// packets and not much else. A lot of features of the 8139// are not supported (power management, MII interface,// access to the serial eeprom, 'twister tuning', etc.).//// Many of the configuration options (like media type and// speed) the 8139 has are taken directly from the serial// eeprom and are not currently configurable from this driver.//// I've tentatively added some code to handle cache coherency// issues for platforms that do not have a separate address// space for uncached memory access and do not do cache// snooping for PCI bus masters. This code can be activated by// defining CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY// in the platform specific .inl file. Note that if// CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY is// defined, the .inl file is also responsible for making sure// the receive and transmit buffers are located in memory in// such a way that flushing or invalidating cache lines for// these buffers will not affect any other buffers. See the// README in the doc directory for some suggestions on how// to do this.//// Since the official data sheet for this chip is a bit// vague, I had to look at the Linux and OpenBSD drivers to// understand the basic workings of the chip; however, I have// not copied any code from those drivers to avoid tainting// eCos' license.//// FIXME:////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/system.h>#ifdef CYGPKG_IO_ETH_DRIVERS#include <pkgconf/io_eth_drivers.h>#endif#include <pkgconf/devs_eth_rltk_8139.h>#include <cyg/infra/cyg_type.h>#include <cyg/infra/cyg_ass.h>#include <cyg/infra/diag.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_cache.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#include <string.h> /* for memset */#ifdef CYGPKG_IO_PCI#include <cyg/io/pci.h>#else#error "This driver requires the PCI package (CYGPKG_IO_PCI)"#endif#include <cyg/io/pci.h>/* Necessary for memory mapping macros */#include CYGHWR_MEMORY_LAYOUT_H/* Check if we should be dumping debug information or not */#if defined CYGDBG_DEVS_ETH_RLTK_8139_CHATTER \ && (CYGDBG_DEVS_ETH_RLTK_8139_CHATTER > 0)#define DEBUG_RLTK8139_DRIVER#endif#include "if_8139.h"/* Which interrupts we will handle */#define RLTK8139_IRQ (IR_SERR|IR_FOVW|IR_RXOVW|IR_TER|IR_TOK|IR_RER|IR_ROK)/* Allow platform-specific configuration of the driver */#ifndef CYGDAT_DEVS_ETH_RLTK_8139_INL#error "CYGDAT_DEVS_ETH_RLTK_8139_INL not defined"#else#include CYGDAT_DEVS_ETH_RLTK_8139_INL#endif#ifndef CYGHWR_RLTK_8139_PLF_INIT#define CYGHWR_RLTK_8139_PLF_INIT(sc) do {} while(0)#endif/* * If software cache coherency is required, the HAL_DCACHE_INVALIDATE * hal macro must be defined as well. */#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY#if !defined HAL_DCACHE_INVALIDATE || !defined HAL_DCACHE_FLUSH#error "HAL_DCACHE_INVALIDATE/HAL_DCACHE_FLUSH not defined for this platform but CYGPKG_DEVS_ETH_RLTK_8139_CACHE_COHERENCY was defined."#endif#endif/* Local driver function declarations */#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONEstatic cyg_uint32 rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data);#endif#ifdef ETH_DRV_SET_MC_LISTstatic cyg_uint32 ether_crc(cyg_uint8 *data, int length);static void rltk8139_set_multicast_list(Rltk8139_t *rltk8139_info, struct eth_drv_mc_list *mc_list);#endifstatic void rltk8139_reset(struct eth_drv_sc *sc);static bool rltk8139_init(struct cyg_netdevtab_entry *tab);static void rltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags);static void rltk8139_stop(struct eth_drv_sc *sc);static int rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length);static int rltk8139_can_send(struct eth_drv_sc *sc);static void rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key);static void rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len);static void rltk8139_deliver(struct eth_drv_sc *sc);static void rltk8139_poll(struct eth_drv_sc *sc);static int rltk8139_int_vector(struct eth_drv_sc *sc);#ifdef DEBUG_RLTK8139_DRIVERvoid rltk8139_print_state(struct eth_drv_sc *sc);#endif/* * Define inline functions to access the card. This will also handle * endianess issues in one place. This code was lifted from the eCos * i82559 driver. */#if (CYG_BYTEORDER == CYG_MSBFIRST)#define HAL_CTOLE32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff))#define HAL_LE32TOC(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff))#define HAL_CTOLE16(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))#define HAL_LE16TOC(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))static inline voidOUTB(cyg_uint8 value, cyg_uint32 io_address){ HAL_WRITE_UINT8( io_address, value);}static inline voidOUTW(cyg_uint16 value, cyg_uint32 io_address){ HAL_WRITE_UINT16(io_address, (((value & 0xff) << 8) | ((value & 0xff00) >> 8)) );}static inline voidOUTL(cyg_uint32 value, cyg_uint32 io_address){ HAL_WRITE_UINT32(io_address, ((((value) & 0xff) << 24) | (((value) & 0xff00) << 8) | (((value) & 0xff0000) >> 8) | (((value) >> 24) & 0xff)) );}static inline cyg_uint8INB(cyg_uint32 io_address){ cyg_uint8 d; HAL_READ_UINT8(io_address, d); return d;}static inline cyg_uint16INW(cyg_uint32 io_address){ cyg_uint16 d; HAL_READ_UINT16( io_address, d ); return (((d & 0xff) << 8) | ((d & 0xff00) >> 8));}static inline cyg_uint32INL(cyg_uint32 io_address){ cyg_uint32 d; HAL_READ_UINT32(io_address, d); return ((((d) & 0xff) << 24) | (((d) & 0xff00) << 8) | (((d) & 0xff0000) >> 8) | (((d) >> 24) & 0xff));}#else// Maintaining the same styleee as above...#define HAL_CTOLE32(x) ((((x))))#define HAL_LE32TOC(x) ((((x))))#define HAL_CTOLE16(x) ((((x))))#define HAL_LE16TOC(x) ((((x))))static inline void OUTB(cyg_uint8 value, cyg_uint32 io_address){ HAL_WRITE_UINT8( io_address, value ); }static inline void OUTW(cyg_uint16 value, cyg_uint32 io_address){ HAL_WRITE_UINT16( io_address, value ); }static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address){ HAL_WRITE_UINT32( io_address, value ); }static inline cyg_uint8 INB(cyg_uint32 io_address){ cyg_uint8 _t_; HAL_READ_UINT8( io_address, _t_ ); return _t_; }static inline cyg_uint16 INW(cyg_uint32 io_address){ cyg_uint16 _t_; HAL_READ_UINT16( io_address, _t_ ); return _t_; }static inline cyg_uint32 INL(cyg_uint32 io_address){ cyg_uint32 _t_; HAL_READ_UINT32( io_address, _t_ ); return _t_; }#endif // byteorder/* * Table of all known PCI device/vendor ID combinations for the RealTek 8139. * Add them as you get to know them. */#define CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES 2static pci_identifier_tknown_8139_aliases[CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES] = { { 0x10ec, 0x8139, NULL }, /* This is the offical RealTek vendor/device code */ { 0x11db, 0x1234, NULL} /* SEGA DreamCast BroadBandAdapter */};/* * Check if the device description matches a known 8139 alias. */static cyg_boolrltk8139_find_match_func(cyg_uint16 vendor_id, cyg_uint16 device_id, cyg_uint32 class_id, void *p){ int i; for (i = 0; i < CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES; ++i) { if (((known_8139_aliases[i].vendor_id == PCI_ANY_ID) || (known_8139_aliases[i].vendor_id == vendor_id)) && ((known_8139_aliases[i].device_id == PCI_ANY_ID) || (known_8139_aliases[i].device_id == device_id))) return true; } return false;}/* * Find the Nth 8139 device on all attached PCI busses and do some initial * PCI-type initialization. Also setup the interrupt for use in eCos. */static boolrltk8139_find(int n_th, struct eth_drv_sc *sc){ Rltk8139_t *rltk8139_info; cyg_pci_device_id pci_device_id; cyg_pci_device pci_device_info; cyg_uint16 command; int found = -1; /* Go through all PCI devices until we find the Nth 8139 chip */ do { pci_device_id = CYG_PCI_NULL_DEVID; if (!cyg_pci_find_matching(&rltk8139_find_match_func, NULL, &pci_device_id)) return false; else found += 1; } while (found != n_th); /* Save device ID in driver private data in case we ever need it again */ rltk8139_info = (Rltk8139_t *)(sc->driver_private); rltk8139_info->pci_device_id = pci_device_id; /* Now that we have found the device, we can extract some data about it */ cyg_pci_get_device_info(pci_device_id, &pci_device_info); /* Get the assigned interrupt and set up ISR and DSR for it. */ if (cyg_pci_translate_interrupt(&pci_device_info, &rltk8139_info->vector)) {#ifdef DEBUG_RLTK8139_DRIVER diag_printf(" Wired to HAL interrupt vector %d\n", rltk8139_info->vector);#endif#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE /* * Note that we use the generic eth_drv_dsr routine instead of * our own. */ cyg_drv_interrupt_create(rltk8139_info->vector, 0, (CYG_ADDRWORD)sc, rltk8139_isr, eth_drv_dsr, &rltk8139_info->interrupt_handle, &rltk8139_info->interrupt); cyg_drv_interrupt_attach(rltk8139_info->interrupt_handle);#endif } else {#ifdef DEBUG_RLTK8139_DRIVER diag_printf(" Does not generate interrupts.\n");#endif } /* * Call 'cyg_pci_configure_device' for those platforms that do not * configure the PCI bus during HAL initialization. According to Nick * Garnett, there are good reasons to not configure PCI devices during HAL * initialization. Also according to Nick, calling * 'cyg_pci_configure_device' for devices already configured should have no * effect and thus is safe to do. */ if (cyg_pci_configure_device(&pci_device_info)) {#ifdef DEBUG_RLTK8139_DRIVER int i; diag_printf("Found device #%d on bus %d, devfn 0x%02x:\n", n_th, CYG_PCI_DEV_GET_BUS(pci_device_id), CYG_PCI_DEV_GET_DEVFN(pci_device_id)); if (pci_device_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) diag_printf(" Note that board is active. Probed" " sizes and CPU addresses are invalid!\n"); diag_printf(" Vendor 0x%04x", pci_device_info.vendor); diag_printf("\n Device 0x%04x", pci_device_info.device); diag_printf("\n Command 0x%04x, Status 0x%04x\n", pci_device_info.command, pci_device_info.status) ; diag_printf(" Class/Rev 0x%08x", pci_device_info.class_rev); diag_printf("\n Header 0x%02x\n", pci_device_info.header_type); diag_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n", pci_device_info.header.normal.sub_vendor, pci_device_info.header.normal.sub_id); for(i = 0; i < CYG_PCI_MAX_BAR; i++) { diag_printf(" BAR[%d] 0x%08x /", i, pci_device_info.base_address[i]); diag_printf(" probed size 0x%08x / CPU addr 0x%08x\n", pci_device_info.base_size[i], pci_device_info.base_map[i]); }#endif } else {#ifdef DEBUG_RLTK8139_DRIVER diag_printf("Failed to configure 8139 device #%d\n", n_th);#endif return false; } /* * Enable memory mapped and port based I/O and busmastering. We currently * only support IO space accesses; memory mapping is enabled so that bit * DVRLOAD in CONFIG1 is cleared automatically. * * NOTE: it seems that for some configurations/HALs, the device is already * activated at this point, even though eCos' documentation suggests * it shouldn't be. At least in my case, this is not a problem. */ cyg_pci_read_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND, &command); command |= (CYG_PCI_CFG_COMMAND_IO | CYG_PCI_CFG_COMMAND_MEMORY | CYG_PCI_CFG_COMMAND_MASTER); cyg_pci_write_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND, command); /* * This is the base address used to talk to the device. The 8139's IOAR * and MEMAR registers are BAR0 and BAR1, respectively. */ rltk8139_info->base_address = pci_device_info.base_map[0]; /* * Read the MAC address. The RealTek data sheet seems to claim this should * only be read in 4 byte accesses, but the code below works just fine. */ for (found = 0; found < 6; ++found) rltk8139_info->mac[found] = INB(rltk8139_info->base_address + IDR0 + found); /* * This is the indicator for "uses an interrupt". The code was lifted
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -