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

📄 dev_sb_mac.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 4 页
字号:
    eth_pkt_t *pkt;    CS_ENTER(sc);    while (1) {	if (sc->rxdscr_onring >= MINRXRING) {	    CS_EXIT(sc);	    break;	    }	CS_EXIT(sc);	pkt = eth_alloc_pkt(sc);	if (pkt == NULL) {	    /* could not allocate a buffer */	    break;	    }	if (bcm4401_add_rcvbuf(sc, pkt) != 0) {	    /* could not add buffer to ring */	    eth_free_pkt(sc, pkt);	    break;	    }	CS_ENTER(sc);	sc->rxdscr_onring++;	}}/*  Receive buffer processing. */static voidbcm4401_rx_callback(bcm4401_softc *sc, eth_pkt_t *pkt){    if (B44_DEBUG) show_packet('>', pkt, PKTBUF_RX_OFFSET);    CS_ENTER(sc);    q_enqueue(&sc->rxqueue, &pkt->next);    CS_EXIT(sc);    sc->inpkts++;}static voidbcm4401_procrxring(bcm4401_softc *sc){    uint32_t rxstat;    volatile rx_dscr *rxcurr;    volatile rx_dscr *rxd;    eth_pkt_t *pkt;    eth_pkt_t *newpkt;    uint32_t hdr0;    rxstat = READCSR(sc, R_RCV_STATUS);    rxcurr = (volatile rx_dscr *)               ((uint8_t *)sc->rxdscr_start + G_RSTAT_CD(rxstat));        for (;;) {	rxd = sc->rxdscr_remove;	if (rxd == rxcurr) {	    /* all packets processed */	    break;	    }	pkt = ETH_PKT_BASE(PCI_TO_PTR(ltoh4(rxd->rxd_bufptr)));	inval_range(pkt->buffer, PKTBUF_RX_OFFSET);	hdr0 = ltoh4(*(uint32_t *)(pkt->buffer));	/* Drop error packets. */	/* The header word apparently reports this (undocumented for 4401,	   but documented in the 4710 manual. */	if (hdr0 & M_RCVHDR0_ERRORS) {	    xprintf("BCM4401: rx error %08X\n", hdr0);	    newpkt = pkt;           /* recycle the buffer */	    }	else {	    /* Pass up the packet */	    pkt->length = G_RCVHDR0_CD(hdr0) - ENET_CRC_SIZE;	    bcm4401_rx_callback(sc, pkt);	    /* put a buffer back on the ring to replace this one */	    newpkt = eth_alloc_pkt(sc);	    }	/* update the pointer, accounting for buffer wrap. */	rxd++;	if (rxd == sc->rxdscr_end)	    rxd = sc->rxdscr_start;	sc->rxdscr_remove = rxd;	if (newpkt) {	    /* The ring must have space now. */	    bcm4401_add_rcvbuf(sc, newpkt);	    }	else {	    CS_ENTER(sc);	    sc->rxdscr_onring--;	    CS_EXIT(sc);	    }	}    /* XXX Check for error stops. */}/*  Transmit ring processing. */static intbcm4401_add_txbuf(bcm4401_softc *sc, eth_pkt_t *pkt){    volatile tx_dscr *txd;    volatile tx_dscr *nexttxd;    uint32_t cmdsts;    txd = sc->txdscr_add;    cmdsts = M_DSCR0_SF | M_DSCR0_EF | M_DSCR0_IC;    nexttxd = (txd+1);    if (nexttxd == sc->txdscr_end) {	cmdsts |= M_DSCR0_ET;	nexttxd = sc->txdscr_start;	}    /* If the next one is the same as our remove pointer, the ring is       considered full.  */    if (nexttxd == sc->txdscr_remove) return -1;    txd->txd_bufptr = htol4(V_DSCR1_DB(PTR_TO_PCI(pkt->buffer)));    cmdsts |= V_DSCR0_BC(pkt->length);    txd->txd_cmdsts = htol4(cmdsts);    sc->txdscr_add = nexttxd;    return 0;}static intbcm4401_transmit(bcm4401_softc *sc, eth_pkt_t *pkt){    int rv;    if (B44_DEBUG) show_packet('<', pkt, 0);    rv = bcm4401_add_txbuf(sc, pkt);    if (rv == 0) {	mips_wbflush();	WRITECSR(sc, R_XMT_PTR, V_XPTR_LD(PTR_TO_PCI(sc->txdscr_add) & 0xFFF));	}     sc->outpkts++;    return rv;}static voidbcm4401_proctxring(bcm4401_softc *sc){    uint32_t txstat;    volatile tx_dscr *txcurr;    volatile tx_dscr *txd;    eth_pkt_t *pkt;    txstat = READCSR(sc, R_XMT_STATUS);    txcurr = (volatile tx_dscr *)               ((uint8_t *)sc->txdscr_start + G_XSTAT_CD(txstat));    for (;;) {	txd = sc->txdscr_remove;	if (txd == txcurr) {	    /* ring is empty, no buffers to process */	    break;	    }	/* Just free the packet */	pkt = ETH_PKT_BASE(PCI_TO_PTR(ltoh4(txd->txd_bufptr)));	eth_free_pkt(sc, pkt);	/* update the pointer, accounting for buffer wrap. */	txd++;	if (txd == sc->txdscr_end)	    txd = sc->txdscr_start;	sc->txdscr_remove = txd;	}    /* XXX Check for error halt. */}static voidbcm4401_initrings(bcm4401_softc *sc){    volatile tx_dscr *txd;    volatile rx_dscr *rxd;    for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++) {        txd->txd_cmdsts = HTOL4(M_DSCR0_SF | M_DSCR0_EF | M_DSCR0_IC);	txd->txd_bufptr = 0;	}    (txd-1)->txd_cmdsts |= HTOL4(M_DSCR0_ET);    for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++) {	rxd->rxd_cmdsts = HTOL4(M_DSCR0_SF | M_DSCR0_EF     /* XXX needed? */				| V_DSCR0_BC(ETH_PKTBUF_LEN));	rxd->rxd_bufptr = 0;	}    (rxd-1)->rxd_cmdsts |= HTOL4(M_DSCR0_ET);    sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start;    sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start;    sc->rxdscr_onring = 0;    /* Precharge the receive ring */    bcm4401_fillrxring(sc);}/* Allocate an integral number of cache lines suitable for DMA access. */static uint8_t *dma_alloc(size_t size, unsigned int align){    uint8_t *base;    size_t len = ALIGN(size, CACHE_ALIGN);    base = KMALLOC(len, ALIGN(align, CACHE_ALIGN));    if (base != NULL)	inval_range(base, len);    return base;}static intbcm4401_init(bcm4401_softc *sc){    /* Allocate descriptor rings */    sc->rxdscrmem = SHARED(dma_alloc(MAXRXDSCR*sizeof(rx_dscr), PAGE_ALIGN));    sc->txdscrmem = SHARED(dma_alloc(MAXTXDSCR*sizeof(tx_dscr), PAGE_ALIGN));    /* Allocate buffer pool (4K aligned to fix apparent DMA alignment bug) */    sc->pktpool = dma_alloc(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, PAGE_ALIGN);    if (sc->pktpool == NULL) {	xprintf("%s: No buffer memory available.\n", bcm4401_devname(sc));	return -1;	}    eth_initfreelist(sc);    q_init(&sc->rxqueue);    /* Fill in pointers to the rings */    sc->rxdscr_start = (volatile rx_dscr *) (sc->rxdscrmem);    sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR;    sc->txdscr_start = (volatile tx_dscr *) (sc->txdscrmem);    sc->txdscr_end = sc->txdscr_start + MAXTXDSCR;    bcm4401_initrings(sc);    return 0;}static voidbcm4401_resetrings(bcm4401_softc *sc){    volatile tx_dscr *txd;    volatile rx_dscr *rxd;    eth_pkt_t *pkt;    /* Free any pending transmit packets (sent and unsent) */    txd = sc->txdscr_remove;    while (txd != sc->txdscr_add) {	pkt = ETH_PKT_BASE(PCI_TO_PTR(ltoh4(txd->txd_bufptr)));	eth_free_pkt(sc, pkt);	txd++;	if (txd == sc->txdscr_end)	    txd = sc->txdscr_start;        }    sc->txdscr_remove = txd;    /* Discard any received packets as well as all free buffers */    rxd = sc->rxdscr_remove;    while (rxd != sc->rxdscr_add) {	pkt = ETH_PKT_BASE(PCI_TO_PTR(ltoh4(rxd->rxd_bufptr)));	eth_free_pkt(sc, pkt);		rxd++;	if (rxd == sc->rxdscr_end)	    rxd = sc->rxdscr_start;	CS_ENTER(sc);	sc->rxdscr_onring--;	CS_EXIT(sc);	}    sc->rxdscr_remove = rxd;    /* Reestablish the initial state. */    bcm4401_initrings(sc);}/* CRC *//* EEPROM access *//* MII access */static voidmii_enable(bcm4401_softc *sc){    uint32_t devctl, enetctl;    devctl = READCSR(sc, R_DEV_CONTROL);    if ((devctl & M_DVCTL_IP) != 0) {	WRITECSR(sc, R_MII_STATUS_CONTROL, M_MIICTL_PR | V_MIICTL_MD(0xD));	devctl = READCSR(sc, R_DEV_CONTROL);	if ((devctl & M_DVCTL_ER) != 0) {	    devctl &= ~M_DVCTL_ER;	    WRITECSR(sc, R_DEV_CONTROL, devctl);	    cfe_usleep(100);	    }	}    else {	WRITECSR(sc, R_MII_STATUS_CONTROL, M_MIICTL_PR | V_MIICTL_MD(0x9));	enetctl = READCSR(sc, R_ENET_CONTROL);	enetctl |= M_ECTL_EP;	WRITECSR(sc, R_ENET_CONTROL, enetctl);	}}static uint16_tmii_read(bcm4401_softc *sc, int reg){    uint32_t cmd, status;    uint32_t data;    int timeout;    WRITECSR(sc, R_ENET_INT_STATUS, M_EINT_MI);    (void)READCSR(sc, R_ENET_INT_STATUS);    cmd = (V_MIIDATA_OP(K_MII_OP_READ) | V_MIIDATA_TA(K_TA_VALID) |           V_MIIDATA_RA(reg) | V_MIIDATA_PM(sc->phy_addr));    WRITECSR(sc, R_MII_DATA, cmd | V_MIIDATA_SB(K_MII_START));    for (timeout = 1000; timeout > 0; timeout -= 100) {	status = READCSR(sc, R_ENET_INT_STATUS);	if ((status & M_EINT_MI) != 0)	    break;	cfe_usleep(100);	}    if (timeout <= 0)	return 0xFFFF;    data = G_MIIDATA_D(READCSR(sc, R_MII_DATA));    return data;}static voidmii_write(bcm4401_softc *sc, int reg, uint16_t value){    uint32_t cmd, status;    int timeout;    WRITECSR(sc, R_ENET_INT_STATUS, M_EINT_MI);    (void)READCSR(sc, R_ENET_INT_STATUS);    cmd = (V_MIIDATA_OP(K_MII_OP_WRITE) | V_MIIDATA_TA(0x2) |           V_MIIDATA_RA(reg) | V_MIIDATA_PM(sc->phy_addr) |	   V_MIIDATA_D(value));    WRITECSR(sc, R_MII_DATA, cmd | V_MIIDATA_SB(K_MII_START));    for (timeout = 1000; timeout > 0; timeout -= 100) {	status = READCSR(sc, R_ENET_INT_STATUS);	if ((status & M_EINT_MI) != 0)	    break;	cfe_usleep(100);	}}/* For an integrated PHY (bcm4401), unimplemented PHY addresses return   id's of 0.  For (some?) external PHYs, unimplmented addresses   appear to return 0x1FFF or 0x3FFF for id1 but reliably (?) return   0xFFFF for id2.  */static intmii_probe(bcm4401_softc *sc){    int i;    uint16_t id1, id2;    int prev = sc->phy_addr;    for (i = 0; i < 32; i++) {        sc->phy_addr = i;        id1 = mii_read(sc, R_PHYIDR1);	id2 = mii_read(sc, R_PHYIDR2);	if (id2 != 0x0000 && id2 != 0xFFFF) {	    sc->phy_vendor = ((uint32_t)id1 << 6) | ((id2 >> 10) & 0x3F);	    sc->phy_device = (id2 >> 4) & 0x3F;	    xprintf("phy %d, vendor %06x part %02x\n",		    i, sc->phy_vendor, sc->phy_device);	    #if 0	    return 0;#endif	    }	}#if 0    xprintf("mii_probe: No PHY found\n");#else    xprintf("mii_probe: Using PHY %d\n", prev);#endif    sc->phy_addr = prev;   /* Expected addr (if any) */    return -1;}#if B44_DEBUGstatic voidmii_dump(bcm4401_softc *sc, const char *label){    int i;    uint16_t  r;    uint32_t  idr, part;    xprintf("%s, MII:\n", label);    idr = part = 0;    /* Common registers */    for (i = 0x0; i <= 0x8; ++i) {	r = mii_read(sc, i);	xprintf(" REG%02X: %04X", i, r);	if (i % 4 == 3) xprintf("\n");	if (i == MII_PHYIDR1) {	    idr |= r << 6;	    }	else if (i == MII_PHYIDR2) {	    idr |= (r >> 10) & 0x3F;	    part = (r >> 4) & 0x3F;	    }	}    xprintf("\nIDR %06x, PART %02x\n", idr, part);        /* Broadcom extensions */    for (i = 0x10; i <= 0x14; ++i) {	r = mii_read(sc, i);	xprintf(" REG%02X: %04X", i, r);	if (i % 4 == 3) xprintf("\n");	}    xprintf("\n");    /* Broadcom extensions (52xx family) */    for (i = 0x18; i <= 0x1F; i++) {	r = mii_read(sc, i);	xprintf(" REG%02X: %04X", i, r);	if (i % 4 == 3) xprintf("\n");	}    xprintf("\n");}#else#define mii_dump(sc,label)#endifstatic voidmii_set_speed(bcm4401_softc *sc, int speed){    /* NYI */}static uint16_tmii_interrupt(bcm4401_softc *sc){    /* The read also clears any interrupt bits. */    return mii_read(sc, R_INTERRUPT);}static voidmii_autonegotiate(bcm4401_softc *sc){    uint16_t  control, status, remote;    unsigned int  timeout;    int linkspeed;

⌨️ 快捷键说明

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