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

📄 dev_sb_mac.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 4 页
字号:
    uint8_t sprom[SPROM_SIZE];    char descr[100];    device = pci_conf_read(tag, PCI_ID_REG);    class = pci_conf_read(tag, PCI_CLASS_REG);    /* Use memory space for the CSRs */    pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &pa);    sc = (bcm4401_softc *) KMALLOC(sizeof(bcm4401_softc), 0);    if (sc == NULL) {	xprintf("BCM4401: No memory to complete probe\n");	return 0;	}    memset(sc, 0, sizeof(*sc));    sc->membase = (uint32_t)pa;    sc->irq = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG) & 0xFF;    sc->tag = tag;    sc->device = PCI_PRODUCT(device);    sc->revision = PCI_REVISION(class);    sc->devctx = NULL;#if 1    sc->linkspeed = ETHER_SPEED_AUTO;    /* select autonegotiation */#else    sc->linkspeed = ETHER_SPEED_100FDX;  /* 100 Mbps, full duplex */#endif    sc->loopback = ETHER_LOOPBACK_OFF;    /* Enable the core by enabling the core clocks and then clearing       RESET.  The backplane mapping registers have been initialized       from the SPROM, but a more paranoid implementation would       reconfigure at this point. */    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_RS | M_SBTS_CE | M_SBTS_FC);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    /* "PR3158 workaround - not fixed in any chip yet" */    if ((READCSR(sc, R_SBTMSTATEHI) & M_SBTS_SE) != 0) {	WRITECSR(sc, R_SBTMSTATEHI, 0);	}    if ((READCSR(sc, R_SBIMSTATE) & (M_SBIS_IE | M_SBIS_TO)) != 0) {	uint32_t sbis;	sbis = READCSR(sc, R_SBIMSTATE);	sbis &= ~(M_SBIS_IE | M_SBIS_TO);	WRITECSR(sc, R_SBIMSTATE, sbis);	}    /* End of workaround */    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_CE | M_SBTS_FC);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_CE);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    bcm4401_pciconfig(sc);    mii_enable(sc);    bcm4401_init(sc);    sprom_read_all(sc, sprom);    if (B44_DEBUG) sprom_dump(sprom);    /* Use the address in EEPROM.  */    memcpy(sc->hwaddr, &sprom[SPROM_MAC_ADDR], ENET_ADDR_LEN);    sc->phy_addr = sprom[SPROM_PHY_ADDR] & 0x1F;    sc->state = eth_state_uninit;    xsprintf(descr, "%s at 0x%X (%a)",	     drv->drv_description, sc->membase, sc->hwaddr);    cfe_attach(drv, sc, NULL, descr);    return 1;}static voidbcm4401_ether_probe(cfe_driver_t *drv,		    unsigned long probe_a, unsigned long probe_b, 		    void *probe_ptr){    int index;    index = 0;    for (;;) {	pcitag_t tag;	pcireg_t device;	if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0)	    break;	index++;	device = pci_conf_read(tag, PCI_ID_REG);	if (PCI_VENDOR(device) == K_PCI_VENDOR_BROADCOM) {	    switch (PCI_PRODUCT(device)) {		case K_PCI_ID_BCM4401:	        case K_PCI_ID_BCM4401_B:		case K_PCI_ID_BCM4402:		    bcm4401_ether_attach(drv, tag);		    break;		default:		    break;		}	    }	}}#endif/* CFE Device Driver probe functions for SOC core. */const cfe_driver_t sb_mac = {    "BCM47xx Ethernet",    "eth",    CFE_DEV_NETWORK,    &bcm4401_ether_dispatch,    sb_ether_probe};static voidsb_pciconfig(bcm4401_softc *sc){    /* XXX Anything MAC-specific to do here? */}static intsb_ether_attach(cfe_driver_t *drv,		     int unit, const char *mac_addr, int phy_addr){    bcm4401_softc *sc;    phys_addr_t pa;    uint32_t flag, id;    char descr[100];    /* XXX The map of enumeration space should be discovered by scanning. */#ifdef SB_ENET1_BASE    static const phys_addr_t enet_base[2] = {SB_ENET0_BASE, SB_ENET1_BASE};#else    static const phys_addr_t enet_base[1] = {SB_ENET0_BASE};#endif    /* Use memory space for the CSRs */    pa = enet_base[unit];    sc = (bcm4401_softc *) KMALLOC(sizeof(bcm4401_softc), CACHE_ALIGN);    if (sc == NULL) {	xprintf("BCM4xxx MAC: No memory to complete probe\n");	return 0;	}    memset(sc, 0, sizeof(*sc));    sc->membase = (uint32_t)pa;    flag = READCSR(sc, R_SBTPSFLAG);    sc->irq = G_SBTSF_FN(flag);    sc->tag = 0;    id = READCSR(sc, R_SBIDHIGH);    sc->device = G_SBID_CR(id);    sc->revision = G_SBID_RV(id);    sc->devctx = NULL;#if 1    sc->linkspeed = ETHER_SPEED_AUTO;    /* select autonegotiation */#else    sc->linkspeed = ETHER_SPEED_100FDX;  /* 100 Mbps, full duplex */#endif    sc->loopback = ETHER_LOOPBACK_OFF;    /* Enable the core by enabling the core clocks and then clearing       RESET.  The backplane mapping registers are fixed but vary       among the various 47xx SOCs. */    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_RS | M_SBTS_CE | M_SBTS_FC);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    /* From Linux driver "PR3158 workaround - not fixed in any chip yet" */    if ((READCSR(sc, R_SBTMSTATEHI) & M_SBTS_SE) != 0) {	WRITECSR(sc, R_SBTMSTATEHI, 0);	}    if ((READCSR(sc, R_SBIMSTATE) & (M_SBIS_IE | M_SBIS_TO)) != 0) {	uint32_t sbis;	sbis = READCSR(sc, R_SBIMSTATE);	sbis &= ~(M_SBIS_IE | M_SBIS_TO);	WRITECSR(sc, R_SBIMSTATE, sbis);	}    /* End of workaround */    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_CE | M_SBTS_FC);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    WRITECSR(sc, R_SBTMSTATELOW, M_SBTS_CE);    (void)READCSR(sc, R_SBTMSTATELOW);   /* push */    cfe_usleep(100);    sb_pciconfig(sc);    mii_enable(sc);    bcm4401_init(sc);    /* XXX How should 47xx SOCs get their MAC addresses? */    (void)sprom_read_all;    (void)sprom_dump;    if (mac_addr) {	enet_parse_hwaddr(mac_addr, sc->hwaddr);	}    else {	sc->hwaddr[0] = 0x02; sc->hwaddr[1] = 0x00; sc->hwaddr[2] = 0x00;	sc->hwaddr[3] = 0x47; sc->hwaddr[4] = 0x10; sc->hwaddr[5] = 0x10+unit;	}    sc->phy_addr = phy_addr;    sc->state = eth_state_uninit;    xsprintf(descr, "%s at 0x%X (%a)",	     drv->drv_description, sc->membase, sc->hwaddr);    cfe_attach(drv, sc, NULL, descr);    return 1;}/* *  Probe arguments: *         probe_a - index of the MAC to probe *         probe_b - PHY address for MII *         probe_ptr - string pointer to hardware address for this *                     MAC, in the form xx:xx:xx:xx:xx:xx. */static voidsb_ether_probe(cfe_driver_t *drv,		    unsigned long probe_a, unsigned long probe_b, 		    void *probe_ptr){    int index = probe_a;    int phy_addr = probe_b;    const char *mac_addr = probe_ptr;    if (index == 0 || index == 1)	sb_ether_attach(drv, index, mac_addr, phy_addr);}/* The functions below are called via the dispatch vector for the 4401. */static intbcm4401_ether_open(cfe_devctx_t *ctx){    bcm4401_softc *sc = ctx->dev_softc;    if (sc->state == eth_state_on)	bcm4401_stop(sc);    sc->devctx = ctx;    sc->inpkts = sc->outpkts = 0;    sc->interrupts = 0;    sc->rx_interrupts = sc->tx_interrupts = 0;    bcm4401_start(sc);#if XPOLL    bcm4401_isr(sc);#endif    return 0;}static intbcm4401_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer){    bcm4401_softc *sc = ctx->dev_softc;    eth_pkt_t *pkt;    int blen;#if XPOLL    bcm4401_isr(sc);#endif    if (sc->state != eth_state_on) return -1;    CS_ENTER(sc);    pkt = (eth_pkt_t *) q_deqnext(&(sc->rxqueue));    CS_EXIT(sc);    if (pkt == NULL) {	buffer->buf_retlen = 0;	return 0;	}    blen = buffer->buf_length;    if (blen > pkt->length) blen = pkt->length;    inval_range(pkt->buffer+PKTBUF_RX_OFFSET, blen);    blockcopy(buffer->buf_ptr, pkt->buffer+PKTBUF_RX_OFFSET, blen);    buffer->buf_retlen = blen;    eth_free_pkt(sc, pkt);    bcm4401_fillrxring(sc);#if XPOLL    bcm4401_isr(sc);#endif    return 0;}static intbcm4401_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat){    bcm4401_softc *sc = ctx->dev_softc;#if XPOLL    bcm4401_isr(sc);#endif    if (sc->state != eth_state_on) return -1;    /* We avoid an interlock here because the result is a hint and an       interrupt cannot turn a non-empty queue into an empty one. */    inpstat->inp_status = (q_isempty(&(sc->rxqueue))) ? 0 : 1;    return 0;}static intbcm4401_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer){    bcm4401_softc *sc = ctx->dev_softc;    eth_pkt_t *pkt;    int blen;#if XPOLL    bcm4401_isr(sc);#endif    if (sc->state != eth_state_on) return -1;    pkt = eth_alloc_pkt(sc);    if (!pkt) return CFE_ERR_NOMEM;    blen = buffer->buf_length;    if (blen > pkt->length) blen = pkt->length;    blockcopy(pkt->buffer, buffer->buf_ptr, blen);    pkt->length = blen;    sync_range(pkt->buffer, blen);    if (bcm4401_transmit(sc, pkt) != 0) {	eth_free_pkt(sc,pkt);	return CFE_ERR_IOERR;	}#if XPOLL    bcm4401_isr(sc);#endif    return 0;}static intbcm4401_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) {    bcm4401_softc *sc = ctx->dev_softc;    int  *argp;    int   mode;    int   speed;    switch ((int)buffer->buf_ioctlcmd) {	case IOCTL_ETHER_GETHWADDR:	    memcpy(buffer->buf_ptr, sc->hwaddr, sizeof(sc->hwaddr));	    return 0;	case IOCTL_ETHER_SETHWADDR:	    return -1;    /* not supported */	case IOCTL_ETHER_GETSPEED:	    argp = (int *) buffer->buf_ptr;	    *argp = sc->linkspeed;	    return 0;	case IOCTL_ETHER_SETSPEED:	    speed = *((int *) buffer->buf_ptr);	    bcm4401_setspeed(sc, speed);	    return -1;    /* not supported yet */	case IOCTL_ETHER_GETLINK:	    argp = (int *) buffer->buf_ptr;	    *argp = sc->linkspeed;	    return 0;	case IOCTL_ETHER_GETLOOPBACK:	    *((int *) buffer) = sc->loopback;	    return 0;	case IOCTL_ETHER_SETLOOPBACK:	    mode = *((int *) buffer->buf_ptr);	    sc->loopback = ETHER_LOOPBACK_OFF;  /* default */	    if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) {		bcm4401_setloopback(sc, mode);		}	    return -1;    /* not supported yet */	default:	    return -1;	}}static intbcm4401_ether_close(cfe_devctx_t *ctx){    bcm4401_softc *sc = ctx->dev_softc;    sc->state = eth_state_off;    bcm4401_stop(sc);    xprintf("%s: %d sent, %d received, %d interrupts\n",	    bcm4401_devname(sc), sc->outpkts, sc->inpkts, sc->interrupts);    if (IPOLL) {	xprintf("  %d tx interrupts, %d rx interrupts\n",		sc->tx_interrupts, sc->rx_interrupts);	}    /* resynchronize descriptor rings */    bcm4401_resetrings(sc);    sc->devctx = NULL;#if 1 /* XXX Redo partitioning among hwinit, start and stop */    sc->state = eth_state_uninit;#endif    return 0;}static voidbcm4401_ether_poll(cfe_devctx_t *ctx, int64_t ticks){    bcm4401_softc *sc = (bcm4401_softc *)ctx->dev_softc;    uint16_t phy_isr;    /* The PHY Interrupt register appears to work as claimed with       respect to link status changes, but I've had no luck clearing       the MIIInt bit in the EnetIntStatus register.  We therefore use       polling but reduce the frequency since reading MII registers is       expensive.  */    if (sc->slow_poll) {	sc->slow_poll = 0;	if (sc->phy_interrupt) {	    phy_isr = mii_interrupt(sc);	    if ((phy_isr & (M_PHYINT_LC | M_PHYINT_SP | M_PHYINT_DC)) != 0) {		mii_autonegotiate(sc);		bcm4401_set_linkspeed(sc);		}	    }	}}static voidbcm4401_ether_reset(void *softc){    bcm4401_softc *sc = (bcm4401_softc *)softc;    /* Turn off the Ethernet interface. */    if (sc->state == eth_state_on)	bcm4401_stop(sc);    bcm4401_reset(sc);    sc->state = eth_state_uninit;}

⌨️ 快捷键说明

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