⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dev_sb_mac.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 4 页
字号:
    linkspeed = ETHER_SPEED_UNKNOWN;    xprintf("%s: Link speed: ", bcm4401_devname(sc));    if (sc->phy_addr == 0x1E) {	/* XXX for SOC parts, this address may indicate a Roboswitch. */	xprintf("100BaseT FDX (switch)\n");	linkspeed = ETHER_SPEED_100FDX;	 	}            else {	/* Read twice to clear latching bits */	status = mii_read(sc, MII_BMSR);	status = mii_read(sc, MII_BMSR);	if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) ==	    (BMSR_AUTONEG | BMSR_LINKSTAT))	    control = mii_read(sc, MII_BMCR);	else {	    for (timeout = 4*CFE_HZ; timeout > 0; timeout -= CFE_HZ/2) {		status = mii_read(sc, MII_BMSR);		if ((status & BMSR_ANCOMPLETE) != 0)		    break;		cfe_sleep(CFE_HZ/2);		}	    }	remote = mii_read(sc, MII_ANLPAR);	if ((status & BMSR_ANCOMPLETE) != 0) {	    /* A link partner was negotiated... */	    if ((remote & ANLPAR_TXFD) != 0) {		xprintf("100BaseT FDX\n");		linkspeed = ETHER_SPEED_100FDX;	 		}	    else if ((remote & ANLPAR_TXHD) != 0) {		xprintf("100BaseT HDX\n");		linkspeed = ETHER_SPEED_100HDX;	 		}	    else if ((remote & ANLPAR_10FD) != 0) {		xprintf("10BaseT FDX\n");		linkspeed = ETHER_SPEED_10FDX;	 		}	    else if ((remote & ANLPAR_10HD) != 0) {		xprintf("10BaseT HDX\n");		linkspeed = ETHER_SPEED_10HDX;	 		}	    }	else {	    /* no link partner convergence */	    xprintf("Unknown\n");	    linkspeed = ETHER_SPEED_UNKNOWN;	    }	sc->linkspeed = linkspeed;	/* clear latching bits */	status = mii_read(sc, MII_BMSR);	}    mii_dump(sc, "final PHY");}static intbcm4401_reset(bcm4401_softc *sc){    return -1;}/* SPROM access routines.  Random read access to the SPROM will   produce a bus error due to PCI timeouts.  As an apparent   (undocumented) side effect, the requested word will be fetched to a   local buffer so that the next access will succeed.  */#define SPROM_SIZE     0x80static intsprom_read_all(bcm4401_softc *sc, uint8_t dest[]){    int i;    uint32_t t;    jmpbuf_t *jb;    jb = exc_initialize_block();    if (jb == NULL)	return -1;    for (i = 0; i < SPROM_SIZE; i += 4) {	if (exc_try(jb) == 0) {	    /* On pass 2 parts, the following read gets a bus error */	    t = READCSR(sc, SPROM_BASE + i);	    cfe_usleep(1000);	    /* the read with valid data (pass 1). */	    t = READCSR(sc, SPROM_BASE + i);	    }	else {	    /* and this one doesn't (pass 2). */	    cfe_usleep(1000);   /* Delay needed; value is empirical. */	    t = READCSR(sc, SPROM_BASE + i);	    }	dest[i+0] = (t >> 8) & 0xFF;  dest[i+1] = (t >> 0) & 0xFF;	t >>= 16;	dest[i+2] = (t >> 8) & 0xFF;  dest[i+3] = (t >> 0) & 0xFF;	/* The following is a kludge, but otherwise setjmp is a one-shot. */	exc_handler.catch_exc = 1;	}    exc_cleanup_block(jb);    return 0;}static voidsprom_dump(uint8_t srom[]){    int  i;    xprintf("BCM4401: SPROM data:");    for (i = 0; i < SPROM_SIZE; i++) {	if (i % 16 == 0)	    xprintf("\n %02x: ", i);	xprintf(" %02x", srom[i]);	}    xprintf("\n");}static intbcm4401_set_hw_addr(bcm4401_softc *sc, uint8_t addr[]){    uint32_t enet_upper, enet_lower;    int timeout;    enet_upper = (addr[0] << 8) | addr[1];    enet_lower = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];        WRITECSR(sc, R_CAM_DATA_H, M_CAM_VB | V_CAM_CD_H(enet_upper));    WRITECSR(sc, R_CAM_DATA_L, V_CAM_CD_L(enet_lower));    WRITECSR(sc, R_CAM_CONTROL, V_CAMCTL_IX(0) | M_CAMCTL_CW);    for (timeout = CFE_HZ; timeout > 0; timeout -= CFE_HZ/10) {	if ((READCSR(sc, R_CAM_CONTROL) & M_CAMCTL_CB) != 0)	    break;	cfe_sleep(1);	}    if (timeout <= 0)        return -1;    return 0;}static voidbcm4401_set_linkspeed(bcm4401_softc *sc){    uint32_t ctrl;    ctrl = READCSR(sc, R_XMT_CONTROL1);    switch (sc->linkspeed) {	case ETHER_SPEED_100FDX:	case ETHER_SPEED_10FDX:	    ctrl |= (M_TCTL_FD | M_TCTL_SB);	    break;	default:	    ctrl &= ~(M_TCTL_FD | M_TCTL_SB);	    break;	}    WRITECSR(sc, R_XMT_CONTROL1, ctrl);}static voidbcm4401_hwinit(bcm4401_softc *sc){    if (sc->state == eth_state_uninit) {	uint32_t ctrl;	bcm4401_reset(sc);	mii_probe(sc);	mii_dump(sc, "initial PHY");	sc->phy_interrupt = 0;	if (sc->phy_vendor == OUI_BCMxx) {	    uint16_t phy_isr;	    switch (sc->phy_device) {		case DEV_BCM5201:  case DEV_BCM5221:		case DEV_BCM4401:		    phy_isr = mii_read(sc, R_INTERRUPT);		    phy_isr &= ~(M_PHYINT_LI | M_PHYINT_SI | M_PHYINT_FD |				M_PHYINT_MI);		    phy_isr |= M_PHYINT_IE;		    mii_write(sc, R_INTERRUPT, phy_isr);		    sc->phy_interrupt = 1;		    break;		default:		    break;		}	    }	mii_autonegotiate(sc);	if (sc->phy_interrupt) {	    (void)mii_read(sc, R_INTERRUPT);  /* clear any pending */  	    }		bcm4401_set_hw_addr(sc, sc->hwaddr);	WRITECSR(sc, R_CAM_CONTROL, M_CAMCTL_CE);	/* XXX Set the transmit watermark here, if needed. */	/* Initialize the receive channel. */	WRITECSR(sc, R_RCV_PTR, 0);	WRITECSR(sc, R_RCV_CONTROL, M_RCTL_RE | V_RCTL_RO(PKTBUF_RX_OFFSET));	WRITECSR(sc, R_RCV_ADDR, PTR_TO_PCI(sc->rxdscrmem));	WRITECSR(sc, R_RCV_PTR, PTR_TO_PCI(sc->rxdscr_add) & 0xFFF);	/* Initialize the transmit channel. */	WRITECSR(sc, R_XMT_PTR, 0);	WRITECSR(sc, R_XMT_CONTROL, M_XCTL_XE);	WRITECSR(sc, R_XMT_ADDR, PTR_TO_PCI(sc->txdscrmem));	/* Modify Ethernet RX MAC settings (probably obsolete). */	WRITECSR(sc, R_EMAC_XMT_MAX_BURST, 32);	WRITECSR(sc, R_EMAC_RCV_MAX_BURST, 32);#if 0	WRITECSR(sc, R_RCV_CONFIG, M_RCFG_AM);   /* All multicast */#else	WRITECSR(sc, R_RCV_CONFIG, 0);#endif	WRITECSR(sc, R_RCV_MAX_LENGTH, MAX_ETHER_PACK);	ctrl = READCSR(sc, R_EMAC_CONTROL);	ctrl |= M_EMCTL_CC;	WRITECSR(sc, R_EMAC_CONTROL, ctrl);	bcm4401_set_linkspeed(sc);	WRITECSR(sc, R_XMT_MAX_LENGTH, MAX_ETHER_PACK);	WRITECSR(sc, R_INT_RECV_LAZY, V_INTLZY_FC(1) | V_INTLZY_TO(100));	/* Enable the MAC */	ctrl = READCSR(sc, R_ENET_CONTROL);	ctrl |= M_ECTL_EE;	WRITECSR(sc, R_ENET_CONTROL, ctrl);	sc->state = eth_state_on;	}}static voidbcm4401_setspeed(bcm4401_softc *sc, int speed){    /* XXX Not yet implemented - autonegotiation only. */    (void)mii_set_speed;}static voidbcm4401_setloopback(bcm4401_softc *sc, int mode){    /* XXX Not yet implemented. */}static voidbcm4401_isr(void *arg){    bcm4401_softc *sc = (bcm4401_softc *)arg;    uint32_t status;#if IPOLL    sc->interrupts++;#endif    for (;;) {	/* Read and clear the interrupt status. */	status = READCSR(sc, R_INT_STATUS);	status &= sc->intmask;	if (status == 0)	    break;	WRITECSR(sc, R_INT_STATUS, status);  /* write-to-clear */	/* XXX Handle SERR, etc. */	if (status & M_INT_RI) {#if IPOLL	    sc->rx_interrupts++;#endif	    bcm4401_procrxring(sc);	    }	if (status & M_INT_XI) {#if IPOLL	    sc->tx_interrupts++;#endif	    bcm4401_proctxring(sc);	    }	if (status & M_INT_TO) {	    sc->slow_poll = 1;	    }	if (status & (M_INT_XU | M_INT_RO)) {	    if (status & M_INT_XU) {		xprintf("BCM4401: tx underrun, %08x\n", status);		/* XXX Try to restart */		}	    if (status & M_INT_RO) {		xprintf("BCM4401: rx overrun, %08x\n", status);		/* XXX Try to restart */		}	    }	}}static voidbcm4401_start(bcm4401_softc *sc){    bcm4401_hwinit(sc);    /* Set up loopback here */    WRITECSR(sc, R_GP_TIMER, 0);             /* stop the timer */    sc->intmask = 0;    WRITECSR(sc, R_INT_MASK, 0);    (void)READCSR(sc, R_INT_STATUS);         /* clear any pending */    sc->intmask =  (M_INT_RI | M_INT_XI);    /* XXX add errors */    if (sc->phy_interrupt)	sc->intmask |=  M_INT_TO;#if IPOLL    cfe_request_irq(sc->irq, bcm4401_isr, sc, CFE_IRQ_FLAGS_SHARED, 0);    WRITECSR(sc, R_INT_MASK, sc->intmask);#endif    sc->slow_poll = 0;    if (sc->phy_interrupt) {	WRITECSR(sc, R_GP_TIMER, GP_TIMER_HZ/4);	}    sc->state = eth_state_on;}static voidbcm4401_stop(bcm4401_softc *sc){    uint32_t ctl, status;    int i;    /* Cancel the timer */    if (sc->phy_interrupt) {	WRITECSR(sc, R_GP_TIMER, 0);	(void)READCSR(sc, R_GP_TIMER);	}    sc->slow_poll = 0;    /* Make sure that no further interrutps will be processed. */    sc->intmask = 0;    WRITECSR(sc, R_INT_MASK, 0);    (void)READCSR(sc, R_INT_MASK);  /* push */    (void)READCSR(sc, R_INT_STATUS);    /* Shut down MAC */    WRITECSR(sc, R_ENET_CONTROL, M_ECTL_ED);    for (i = 1000; i > 0; i--) {	ctl = READCSR(sc, R_ENET_CONTROL);	if ((ctl & M_ECTL_ED) == 0)	    break;	cfe_usleep(100);	}    if (i == 0)	xprintf("%s: cannot clear MAC\n", bcm4401_devname(sc));    /* Shut down DMA engines */    WRITECSR(sc, R_XMT_CONTROL, 0);    for (i = 1000; i > 0; i--) {	status = READCSR(sc, R_XMT_STATUS);	if (G_XSTAT_XS(status) == K_XS_DISABLED)	    break;	cfe_usleep(100);	}    if (i == 0)	xprintf("%s: cannot clear tx DMA\n", bcm4401_devname(sc));    WRITECSR(sc, R_RCV_CONTROL, 0);    for (i = 1000; i > 0; i--) {	status = READCSR(sc, R_RCV_STATUS);	if (G_RSTAT_RS(status) == K_RS_DISABLED)	    break;	cfe_usleep(100);	}    if (i == 0)	xprintf("%s: cannot clear rx DMA\n", bcm4401_devname(sc));    status = READCSR(sc, R_INT_STATUS);    WRITECSR(sc, R_INT_STATUS, status);#if IPOLL    cfe_free_irq(sc->irq, 0);#endif    /* Leave the mii inteface enabled */    mii_enable(sc);}/* Declarations for CFE Device Driver Interface routines */static int bcm4401_ether_open(cfe_devctx_t *ctx);static int bcm4401_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int bcm4401_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);static int bcm4401_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int bcm4401_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int bcm4401_ether_close(cfe_devctx_t *ctx);static void bcm4401_ether_poll(cfe_devctx_t *ctx, int64_t ticks);static void bcm4401_ether_reset(void *softc);/* CFE Device Driver dispatch structure */const static cfe_devdisp_t bcm4401_ether_dispatch = {    bcm4401_ether_open,    bcm4401_ether_read,    bcm4401_ether_inpstat,    bcm4401_ether_write,    bcm4401_ether_ioctl,    bcm4401_ether_close,    bcm4401_ether_poll,    bcm4401_ether_reset};#if CFG_PCI/* CFE Device Driver probe functions for PCI NIC (bcm4401) */const cfe_driver_t bcm4401drv = {    "BCM4401 Ethernet",    "eth",    CFE_DEV_NETWORK,    &bcm4401_ether_dispatch,    bcm4401_ether_probe};static voidbcm4401_pciconfig(bcm4401_softc *sc){    uint32_t oldsb;    uint32_t xlat;    oldsb = pci_conf_read(sc->tag, PCI_PCIBAR0WINDOW_REG);    pci_conf_write(sc->tag, PCI_PCIBAR0WINDOW_REG, SB_PCI_BASE);    (void)pci_conf_read(sc->tag, PCI_PCIBAR0WINDOW_REG);   /* push */    WRITECSR(sc, R_SBINTVEC, V_SBINT_MK(K_SBINT_ENET_MAC));    xlat = READCSR(sc, R_SB_TO_PCI_TRANSLATION2);    xlat |= (M_SBXLAT_PE | M_SBXLAT_WB);    WRITECSR(sc, R_SB_TO_PCI_TRANSLATION2, xlat);    (void)READCSR(sc, R_SB_TO_PCI_TRANSLATION2);           /* push */    pci_conf_write(sc->tag, PCI_PCIBAR0WINDOW_REG, oldsb);    (void)pci_conf_read(sc->tag, PCI_PCIBAR0WINDOW_REG);   /* push */}static intbcm4401_ether_attach(cfe_driver_t *drv, pcitag_t tag){    bcm4401_softc *sc;    uint32_t device;    uint32_t class;    phys_addr_t pa;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -