📄 dev_sb1250_ethernet.c
字号:
uint16_t anar, k1ctl, bmcr; uint16_t led_sel1; /* Undo autodetect. */ auto_det = (0x1E << 10); sbeth_mii_write(s, phy_addr, 0x1C, auto_det); auto_det = sbeth_mii_read(s, phy_addr, 0x1C); auto_det |= (0x1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, auto_det); cfe_usleep(100); auto_det &= ~(0x1 << 0); sbeth_mii_write(s, phy_addr, 0x1C, auto_det); cfe_usleep(100); auto_det &= ~(0x1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, auto_det); /* Force copper. */ mode_ctrl = (0x1F << 10); sbeth_mii_write(s, phy_addr, 0x1C, mode_ctrl); mode_ctrl = sbeth_mii_read(s, phy_addr, 0x1C); mode_ctrl |= (1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, mode_ctrl); cfe_usleep(100); mode_ctrl &= ~((0x3 << 1) | (0x1 << 0)); sbeth_mii_write(s, phy_addr, 0x1C, mode_ctrl); cfe_usleep(100); mode_ctrl &= ~(1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, mode_ctrl); cfe_usleep(100); /* Restart autonegotiation. */ anar = sbeth_mii_read(s, phy_addr, MII_ANAR); anar |= (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD); sbeth_mii_write(s, phy_addr, MII_ANAR, anar); k1ctl = sbeth_mii_read(s, phy_addr, MII_K1CTL); k1ctl |= (K1TCR_1000BT_FDX | K1TCR_1000BT_HDX); sbeth_mii_write(s, phy_addr, MII_K1CTL, k1ctl); bmcr = sbeth_mii_read(s, phy_addr, MII_BMCR); bmcr |= (BMCR_ANENABLE | BMCR_RESTARTAN); sbeth_mii_write(s, phy_addr, MII_BMCR, bmcr); /* Remap LINKSPD[1] selector to Link Quality. */ led_sel1 = (0x0D << 10); sbeth_mii_write(s, phy_addr, 0x1C, led_sel1); led_sel1 = sbeth_mii_read(s, phy_addr, 0x1C); led_sel1 |= (1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, mode_ctrl); cfe_usleep(100); led_sel1 &= ~(0xF << 0); led_sel1 |= 0x7; sbeth_mii_write(s, phy_addr, 0x1C, led_sel1); cfe_usleep(100); led_sel1 &= ~(1 << 15); sbeth_mii_write(s, phy_addr, 0x1C, led_sel1); }#endif break; } } return 0;}/* ********************************************************************* * Declarations for CFE Device Driver Interface routines ********************************************************************* */static int sb1250_ether_open(cfe_devctx_t *ctx);static int sb1250_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int sb1250_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);static int sb1250_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int sb1250_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);static int sb1250_ether_close(cfe_devctx_t *ctx);static void sb1250_ether_poll(cfe_devctx_t *ctx,int64_t ticks);static void sb1250_ether_reset(void *softc);/* ********************************************************************* * CFE Device Driver dispatch structure ********************************************************************* */const static cfe_devdisp_t sb1250_ether_dispatch = { sb1250_ether_open, sb1250_ether_read, sb1250_ether_inpstat, sb1250_ether_write, sb1250_ether_ioctl, sb1250_ether_close, sb1250_ether_poll, sb1250_ether_reset};/* ********************************************************************* * CFE Device Driver descriptor ********************************************************************* */const cfe_driver_t sb1250_ether = { "SiByte Ethernet", "eth", CFE_DEV_NETWORK, &sb1250_ether_dispatch, sb1250_ether_probe};/* ********************************************************************* * SB1250_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr) * * Probe and install an Ethernet device driver. This routine * creates a context structure and attaches to the specified * MAC device. * * Input parameters: * drv - driver descriptor * probe_a - base address of MAC to probe * probe_b - not used * probe_ptr - string pointer to hardware address for this * MAC, in the form xx:xx:xx:xx:xx:xx * * Return value: * nothing ********************************************************************* */static void sb1250_ether_probe(cfe_driver_t *drv, unsigned long probe_a, unsigned long probe_b, void *probe_ptr){ sbeth_t *softc; char descr[100]; softc = (sbeth_t *) KMALLOC(sizeof(sbeth_t),0); if (softc) { sbeth_initctx(softc,probe_a,softc); if (probe_ptr) { enet_parse_hwaddr((char *) probe_ptr,softc->sbe_hwaddr); } xsprintf(descr,"%s at 0x%X (%a)",drv->drv_description,probe_a, softc->sbe_hwaddr); sbeth_mii_findphy(softc); sbeth_mii_setup(softc); cfe_attach(drv,softc,NULL,descr); sbeth_setaddr(softc,softc->sbe_hwaddr); }}/* ********************************************************************* * SB1250_ETHER_READENV(ctx) * * Read the environment variable that corresponds to this * interface to pick up the hardware address. Note that the way * we do this is somewhat slimey. * * Input parameters: * ctx - device context * * Return value: * nothing ********************************************************************* */static void sb1250_ether_readenv(cfe_devctx_t *ctx){ sbeth_t *softc = ctx->dev_softc; char envbuf[100]; char *hwaddr; /* * Gross - we should *not* be reaching into these data * structures like this! */ xsprintf(envbuf,"%s_HWADDR",cfe_device_name(ctx)); strupr(envbuf); hwaddr = env_getenv(envbuf); if (hwaddr) { enet_parse_hwaddr(hwaddr,softc->sbe_hwaddr); } }/* ********************************************************************* * SBETH_MII_DUMP(s) * * Dump out the MII registers * * Input parameters: * s - sbeth structure * * Return value: * nothing ********************************************************************* */#if 0static void sbeth_mii_dump(sbeth_t *s){ int idx; printf("---Phy registers---\n"); for (idx = 0; idx < 31; idx++) { printf("Reg %2d = %04X\n", idx, sbeth_mii_read(s,1,idx)); } printf ("\n\n");}#endif/* ********************************************************************* * SB1250_ETHER_OPEN(ctx) * * Open the Ethernet device. The MAC is reset, initialized, and * prepared to receive and send packets. * * Input parameters: * ctx - device context (includes ptr to our softc) * * Return value: * status, 0 = ok ********************************************************************* */static int sb1250_ether_open(cfe_devctx_t *ctx){ sbeth_t *softc = ctx->dev_softc; softc->sbe_devctx = ctx; sbeth_stop(softc); /* * Note: The Phy can take several seconds to become ready! * This gross code pounds on the phy until it says it is * ready, but it still takes 2 more seconds after this * before the link is usable. We're better off letting the * dhcp/arp retries do the right thing here. */#if 0 do { int64_t timer; TIMER_SET(timer,2*CFE_HZ); while (!TIMER_EXPIRED(timer)) { sbeth_mii_poll(softc,FALSE); if (softc->sbe_linkstat != ETHER_SPEED_UNKNOWN) break; } } while (0);#else sbeth_mii_poll(softc,TRUE);#endif sb1250_ether_readenv(ctx); TIMER_SET(softc->sbe_linkstat_timer,SBETH_MIIPOLL_TIMER); softc->sbe_autospeed = TRUE; softc->fifo_mode = FALSE; /* Make sure we see a change with autospeed set */ softc->sbe_phy_oldbmsr &= ~BMSR_ANCOMPLETE; sbeth_start(softc); return 0;}/* ********************************************************************* * SB1250_ETHER_READ(ctx,buffer) * * Read a packet from the Ethernet device. If no packets are * available, the read will succeed but return 0 bytes. * * Input parameters: * ctx - device context (includes ptr to our softc) * buffer - pointer to buffer descriptor. * * Return value: * status, 0 = ok ********************************************************************* */static int sb1250_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer){ sbeth_t *softc = ctx->dev_softc; sbeth_pkt_t *pkt; int blen; if (softc->sbe_state != sbeth_state_on) return -1; sbeth_isr(softc); if (softc->sbe_rxqueue == NULL) { buffer->buf_retlen = 0; return 0; } pkt = softc->sbe_rxqueue; softc->sbe_rxqueue = pkt->next; pkt->next = NULL; blen = buffer->buf_length; if (blen > pkt->length) blen = pkt->length; memcpy(buffer->buf_ptr,pkt->buffer,blen); buffer->buf_retlen = blen; sbeth_free_pkt(softc,pkt); sbeth_fillrxring(softc,0); sbeth_isr(softc); return 0;}/* ********************************************************************* * SB1250_ETHER_INPSTAT(ctx,inpstat) * * Check for received packets on the Ethernet device * * Input parameters: * ctx - device context (includes ptr to our softc) * inpstat - pointer to input status structure * * Return value: * status, 0 = ok ********************************************************************* */static int sb1250_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat){ sbeth_t *softc = ctx->dev_softc; if (softc->sbe_state != sbeth_state_on) return -1; sbeth_isr(softc); inpstat->inp_status = (softc->sbe_rxqueue == NULL) ? 0 : 1; return 0;}/* ********************************************************************* * SB1250_ETHER_WRITE(ctx,buffer) * * Write a packet to the Ethernet device. * * Input parameters: * ctx - device context (includes ptr to our softc) * buffer - pointer to buffer descriptor. * * Return value: * status, 0 = ok ********************************************************************* */static int sb1250_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer){ sbeth_t *softc = ctx->dev_softc; sbeth_pkt_t *pkt; int blen; if (softc->sbe_state != sbeth_state_on) return -1; if (!softc->fifo_mode) { /* Only do a speed check if not packet fifo mode*/ if (softc->sbe_linkstat == ETHER_SPEED_UNKNOWN) { sbeth_mii_poll(softc,1); if (softc->sbe_linkstat == ETHER_SPEED_UNKNOWN) return -1; } } pkt = sbeth_alloc_pkt(softc); if (!pkt) return CFE_ERR_NOMEM; blen = buffer->buf_length; if (blen > pkt->length) blen = pkt->length; memcpy(pkt->buffer,buffer->buf_ptr,blen); pkt->length = blen; sbeth_isr(softc); if (sbeth_transmit(softc,0,pkt->buffer,pkt->length,pkt) != 1) { sbeth_free_pkt(softc,pkt); return CFE_ERR_IOERR; } sbeth_isr(softc); buffer->buf_retlen = blen; return 0;}/* ********************************************************************* * SB1250_ETHER_IOCTL_LOOPBACK(s,loopback) * * Set loopback modes * * Input parameters: * s - sbeth structure * loopback - loopback modes * * Return value: * 0 if ok, else error ********************************************************************* */static int sb1250_ether_ioctl_loopback(sbeth_t *s,int loopback){ unsigned int miireg; uint64_t regval; switch (loopback) { case ETHER_LOOPBACK_OFF: miireg = sbeth_mii_read(s,s->sbe_phyaddr,MII_BMCR); if (miireg & BMCR_LOOPBACK) { miireg &= ~BMCR_LOOPBACK; miireg |= BMCR_RESTARTAN; sbeth_mii_write(s,s->sbe_phyaddr,MII_BMCR,miireg); } regval = SBETH_READCSR(s->sbe_maccfg); if (regval & M_MAC_LOOPBACK_SEL) { regval &= ~M_MAC_LOOPBACK_SEL; SBETH_WRITECSR(s->sbe_maccfg,regval); } break; case ETHER_LOOPBACK_INT: regval = SBETH_READCSR(s->sbe_maccfg); regval |= M_MAC_LOOPBACK_SEL; SBETH_WRITECSR(s->sbe_maccfg,regval); break; case ETHER_LOOPBACK_EXT: regval = SBETH_READCSR(s->sbe_maccfg); if (regval & M_MAC_LOOPBACK_SEL) { regval &= ~M_MAC_LOOPBACK_SEL; SBETH_WRITECSR(s->sbe_maccfg,regval); } miireg = sbeth_mii_read(s,s->sbe_phyaddr,MII_BMCR); miireg |= BMCR_LOOPBACK; sbeth_mii_write(s,s->sbe_phyaddr,MII_BMCR,miireg); break; } s->sbe_loopback = loopback; return 0;}/* ********************************************************************* * SB1250_ETHER_IOCTL_SPEED(s,speed) * * Set speed forcibly via the IOCTL command * * Input parameters: * s - sbeth structure * speed - speed IOCTL setting * * Return value: * 0 if ok, else error ********************************************************************* */static int sb1250_ether_ioctl_speed(sbeth_t *s,int speed)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -