📄 dev_sb_mac.c
字号:
/* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * Broadcom Silicon Backplane MAC Driver File: dev_sb_mac.c * * Author: Ed Satterthwaite * ********************************************************************* * * Copyright 2001,2002,2003 * Broadcom Corporation. All rights reserved. * * This software is furnished under license and may be used and * copied only in accordance with the following terms and * conditions. Subject to these conditions, you may download, * copy, install, use, modify and distribute modified or unmodified * copies of this software in source and/or binary form. No title * or ownership is transferred hereby. * * 1) Any source code used, modified or distributed must reproduce * and retain this copyright notice and list of conditions * as they appear in the source file. * * 2) No right is granted to use any trade name, trademark, or * logo of Broadcom Corporation. The "Broadcom Corporation" * name may not be used to endorse or promote products derived * from this software without the prior written permission of * Broadcom Corporation. * * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************* *//* local parameterization - should be configuration options. */#define BCM47XX 1#define PCI_HOST 1#include "cfe.h"#define blockcopy memcpy#include "cfe_irq.h"#include "lib_try.h"#include "lib_physio.h"#include "net_enet.h"#include "pcivar.h"#include "pcireg.h"#ifdef BCM47XX#include "sb_bp.h"#include "sb_pci.h"#include "sb_mac.h"extern void bcmcore_sync_range(void *base, int len);extern void bcmcore_inval_range(void *base, int len);/* MII extensions shared by several Broadcom PHYs */#define R_INTERRUPT 0x1A#define M_PHYINT_IS _DD_MAKEMASK1(0) /* InterruptStatus */#define M_PHYINT_LC _DD_MAKEMASK1(1) /* LinkChangeInt */#define M_PHYINT_SP _DD_MAKEMASK1(2) /* SpeedChangeInt */#define M_PHYINT_DC _DD_MAKEMASK1(3) /* DuplexChangeInt */#define M_PHYINT_MI _DD_MAKEMASK1(8) /* MasterIntMask */#define M_PHYINT_LI _DD_MAKEMASK1(9) /* LinkIntMask */#define M_PHYINT_SI _DD_MAKEMASK1(10) /* SpeedIntMask */#define M_PHYINT_FD _DD_MAKEMASK1(11) /* FullDuplexIntMask */#define M_PHYINT_IE _DD_MAKEMASK1(14) /* InterruptEnable */#else#include "bcm4401.h"#endif#include "mii.h"/* This is a driver for the Broadcom 4401 10/100 MAC with integrated PHY as well as for the 10/100 MAC cores used in OCP-based SOCs. This driver takes advantage of DMA coherence in systems that support it (e.g., SB1250). For systems without coherent DMA (e.g, BCM47xx SOCs), packet buffer memory is explicitly flushed, and descriptors are referenced only in uncacheable modes. The BCM4401 does not have a big-endian mode for DMA. On the SB1250, this driver therefore uses "preserve byte lanes" addresses for all DMA accesses that cross the ZBbus-PCI bridge. Descriptors and packets headers as seen by the CPU must be byte-swapped for the DMA engine. For hardware without such a mode, only little-endian operation is supported.*/#define K_PCI_ID_BCM4401 0x4401 /* Rev A0, A1 */#define K_PCI_ID_BCM4401_B 0x170C /* Rev B0 and later */#define K_PCI_ID_BCM4402 0x4402 /* used by HND */#ifndef B44_DEBUG#define B44_DEBUG 0#endif#if ((ENDIAN_BIG + ENDIAN_LITTLE) != 1)#error "dev_sb_mac: system endian not set"#endif/* Set IPOLL to drive processing through the pseudo-interrupt dispatcher. Set XPOLL to drive processing by an external polling agent. Setting both is ok. */#ifndef IPOLL#define IPOLL 0#endif#ifndef XPOLL#define XPOLL 1#endif#define CACHE_ALIGN 32#define PAGE_ALIGN 4096#define ALIGN(n,align) (((n)+((align)-1)) & ~((align)-1))#define MIN_ETHER_PACK (ENET_MIN_PKT+ENET_CRC_SIZE) /* size of min packet */#define MAX_ETHER_PACK (ENET_MAX_PKT+ENET_CRC_SIZE) /* size of max packet *//* Packet buffers. For the BCM4401, an rx packet is preceded by status information written into the rx buffer. The packet itself begins at a programmable offset (PKTBUF_RX_OFFSET), which must be at least 28. The DMA engine allows arbitrary buffer and packet alignment, but aligning to a cache line boundary can reduce lines touched on the copies. */#define PKTBUF_RX_OFFSET CACHE_ALIGN#define ETH_PKTBUF_LEN ALIGN(PKTBUF_RX_OFFSET+MAX_ETHER_PACK, CACHE_ALIGN)#define ETH_PKTPOOL_SIZE 32#if __long64typedef struct eth_pkt_s { queue_t next; /* 16 */ uint8_t *buffer; /* 8 */ uint32_t flags; /* 4 */ int32_t length; /* 4 */ uint8_t data[ETH_PKTBUF_LEN];} eth_pkt_t;#elsetypedef struct eth_pkt_s { queue_t next; /* 8 */ uint8_t *buffer; /* 4 */ uint32_t flags; /* 4 */ int32_t length; /* 4 */ uint32_t unused[3]; /* 12 */ uint8_t data[ETH_PKTBUF_LEN];} eth_pkt_t;#endif/* Work around for apparent alignment problem with DMA *//* #define ETH_PKTBUF_SIZE ALIGN(sizeof(eth_pkt_t), CACHE_ALIGN) */#define ETH_PKTBUF_SIZE 2048#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data))#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET))static voidshow_packet(char c, eth_pkt_t *pkt, int offset){ int i; int n = (pkt->length < 32 ? pkt->length : 32); xprintf("%c[%4d]:", c, pkt->length); for (i = 0; i < n; i++) { if (i % 4 == 0) xprintf(" "); xprintf("%02x", pkt->buffer[offset+i]); } xprintf("\n");}/* Descriptor structures. The descriptor ring must begin on a 4K boundary and cannot exceed 512 entries. Note that descriptors are referenced by the DMA engine using match-bytes addresses. */typedef struct rx_dscr { uint32_t rxd_cmdsts; pci_addr_t rxd_bufptr;} rx_dscr; typedef struct tx_dscr { uint32_t txd_cmdsts; pci_addr_t txd_bufptr;} tx_dscr;/* Driver data structures */typedef enum { eth_state_uninit, eth_state_off, eth_state_on, eth_state_broken} eth_state_t;typedef struct bcm4401_softc { uint32_t membase; uint8_t irq; /* interrupt mapping (used if IPOLL) */ pcitag_t tag; /* tag for configuration registers */ uint8_t hwaddr[ENET_ADDR_LEN]; uint16_t device; /* chip device code */ uint8_t revision; /* chip revision and step */ eth_state_t state; /* current state */ uint32_t intmask; /* interrupt mask */ /* These fields are set before calling bcm4401_hwinit */ int linkspeed; /* encodings from cfe_ioctl */ int loopback; /* Packet free list */ queue_t freelist; uint8_t *pktpool; queue_t rxqueue; /* The descriptor tables */ uint8_t *rxdscrmem; /* receive descriptors */ uint8_t *txdscrmem; /* transmit descriptors */ /* These fields keep track of where we are in tx/rx processing */ volatile rx_dscr *rxdscr_start; /* beginning of ring */ volatile rx_dscr *rxdscr_end; /* end of ring */ volatile rx_dscr *rxdscr_remove; /* oldest one owned by DMA */ volatile rx_dscr *rxdscr_add; /* next place to put a buffer */ int rxdscr_onring; volatile tx_dscr *txdscr_start; /* beginning of ring */ volatile tx_dscr *txdscr_end; /* end of ring */ volatile tx_dscr *txdscr_remove; /* oldest one owned by DMA */ volatile tx_dscr *txdscr_add; /* next place to put a buffer */ cfe_devctx_t *devctx; int phy_addr; uint32_t phy_vendor; uint16_t phy_device; int phy_interrupt; /* bcm5221-like MII interrupt reg */ int slow_poll; /* Statistics */ uint32_t inpkts; uint32_t outpkts; uint32_t interrupts; uint32_t rx_interrupts; uint32_t tx_interrupts;} bcm4401_softc;/* Entry to and exit from critical sections (currently relative to interrupts only, not SMP) */#if CFG_INTERRUPTS#define CS_ENTER(sc) cfe_disable_irq(sc->irq)#define CS_EXIT(sc) cfe_enable_irq(sc->irq)#else#define CS_ENTER(sc) ((void)0)#define CS_EXIT(sc) ((void)0)#endif/* Chip parameterization */#define GP_TIMER_HZ 62500000/* Driver parameterization */#define MAXRXDSCR 32#define MAXTXDSCR 32#define MINRXRING 8/* Prototypes */#if CFG_PCIstatic void bcm4401_ether_probe(cfe_driver_t *drv, unsigned long probe_a, unsigned long probe_b, void *probe_ptr);#endifstatic void sb_ether_probe(cfe_driver_t *drv, unsigned long probe_a, unsigned long probe_b, void *probe_ptr);/* Address mapping macros. Accesses in which the BCM4401 is the target are to registers and use match bits mode. Accesses in which it is the initiator always assume little-endian responses and must use match bytes, per the macros below. For big-endian hosts, the DMA status word must be byte-swapped. *//* Note that PTR_TO_PHYS only works with 32-bit addresses, but then so does the BCM4401. */#define PTR_TO_PHYS(x) (PHYSADDR((uintptr_t)(x)))#define PHYS_TO_PTR(a) ((uint8_t *)KERNADDR(a))/* For non-coherent memory systems, convert all addresses of descriptors to do uncached access. Packet data is flushed as required. */#if CPUCFG_COHERENT_DMA#define SHARED(x) ((uint8_t *)(x))# define sync_range(base,len) ((void)0)# define inval_range(base,len) ((void)0)#else /* XXX need more-generic names */#define SHARED(x) ((uint8_t *)UNCADDR(PHYSADDR((uintptr_t)(x))))# define sync_range(base,len) bcmcore_sync_range(base,len)# define inval_range(base,len) bcmcore_inval_range(base,len)#endif/* The DMA engine does not have a big-endian option for descriptors and data. All its accesses through the host bridge use match bytes mode. The CPU must construct descriptors and headers accordingly. PIO accesses to the configuration and host interface registers use match bits. */#undef PHYS_TO_PCI#undef PCI_TO_PHYS/* XXX This needs cleanup/abstraction. The 47xx SOCs efectively have an endian bit that is used to swap bytes in SDRAM accesses (only). */#if PCI_HOST#if ENDIAN_BIG && defined(BCM47XX)#define PHYS_TO_PCI(a) ((uint32_t) (a) + 0x10000000)#define PCI_TO_PHYS(a) ((uint32_t) (a) - 0x10000000)#else#define PHYS_TO_PCI(a) ((uint32_t) (a))#define PCI_TO_PHYS(a) ((uint32_t) (a))#endif#else#define PHYS_TO_PCI(a) ((uint32_t) (a) + 0x40000000)#define PCI_TO_PHYS(a) ((uint32_t) (a) - 0x40000000)#endif#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a)))#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x)))#if ENDIAN_BIG#define READCSR2(sc,csr) (phys_read16((sc)->membase + ((csr)^2)))#else#define READCSR2(sc,csr) (phys_read16((sc)->membase + (csr)))#endif#define READCSR(sc,csr) (phys_read32((sc)->membase + (csr)))#if ENDIAN_BIG#define WRITECSR2(sc,csr,val) (phys_write16((sc)->membase + ((csr)^2), (val)))#else#define WRITECSR2(sc,csr,val) (phys_write16((sc)->membase + (csr), (val)))#endif#define WRITECSR(sc,csr,val) (phys_write32((sc)->membase + (csr), (val)))/* Byte swap utilities: host to/from little-endian */#if ENDIAN_BIG#define HTOL4(x) \ ((((x) & 0x00FF) << 24) | \ (((x) & 0xFF00) << 8) | \ (((x) >> 8) & 0xFF00) | \ (((x) >> 24) & 0x00FF))static uint32_thtol4(uint32_t x){ uint32_t t; t = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); return (t >> 16) | ((t & 0xFFFF) << 16);}#else#define HTOL4(x) (x)#define htol4(x) (x)#endif#define ltoh4 htol4 /* self-inverse *//* Packet management */static eth_pkt_t *eth_alloc_pkt(bcm4401_softc *sc){ eth_pkt_t *pkt; CS_ENTER(sc); pkt = (eth_pkt_t *) q_deqnext(&sc->freelist); CS_EXIT(sc); if (!pkt) return NULL; pkt->buffer = pkt->data; pkt->length = ETH_PKTBUF_LEN; pkt->flags = 0; return pkt;}static voideth_free_pkt(bcm4401_softc *sc, eth_pkt_t *pkt){ CS_ENTER(sc); q_enqueue(&sc->freelist, &pkt->next); CS_EXIT(sc);}static voideth_initfreelist(bcm4401_softc *sc){ int idx; uint8_t *ptr; eth_pkt_t *pkt; q_init(&sc->freelist); ptr = sc->pktpool; for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) { pkt = (eth_pkt_t *) ptr; eth_free_pkt(sc, pkt); ptr += ETH_PKTBUF_SIZE; }}/* Utilities */static const char *bcm4401_devname(bcm4401_softc *sc){ return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?");}/* Descriptor ring management */static intbcm4401_add_rcvbuf(bcm4401_softc *sc, eth_pkt_t *pkt){ volatile rx_dscr *rxd; volatile rx_dscr *nextrxd; rxd = sc->rxdscr_add; nextrxd = rxd+1; if (nextrxd == sc->rxdscr_end) { nextrxd = sc->rxdscr_start; } /* If the next one is the same as our remove pointer, the ring is considered full. */ if (nextrxd == sc->rxdscr_remove) return -1; /* Only the buffer pointer needs updating. */ rxd->rxd_bufptr = htol4(V_DSCR1_DB(PTR_TO_PCI(pkt->buffer))); sc->rxdscr_add = nextrxd; mips_wbflush(); WRITECSR(sc, R_RCV_PTR, V_RPTR_LD(PTR_TO_PCI(nextrxd) & 0xFFF)); return 0;}static voidbcm4401_fillrxring(bcm4401_softc *sc){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -