?? if_fxp.c
字號:
* zero and must be one bits in this structure and this is the easiest * way to initialize them all to proper values. */ bcopy(fxp_cb_config_template, (void *)&cbp->cb_status, sizeof(fxp_cb_config_template)); cbp->cb_command = htole16(FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL); /* * Start the config command/DMA. */ fxp_scb_wait(sc); CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ for (i = 0; !(cbp->cb_status & htole16(FXP_CB_STATUS_C)) && i < FXP_MAX_STATUS_READS; ++i) DELAY(2); if (i == FXP_MAX_STATUS_READS) { printf("bus congestion, restarting"); return -1; } /* * Now initialize the station address. Temporarily use the TxCB * memory area like we did above for the config CB. */ cb_ias = (struct fxp_cb_ias *) sc->cbl_base; cb_ias->cb_status = htole16(0); cb_ias->cb_command = htole16(FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL); cb_ias->link_addr = htole32(-1); bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr, sizeof(sc->arpcom.ac_enaddr)); /* * Start the IAS (Individual Address Setup) command/DMA. */ fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ for (i = 0; !(cb_ias->cb_status & htole16(FXP_CB_STATUS_C)) && i < FXP_MAX_STATUS_READS; ++i) DELAY(2); if (i == FXP_MAX_STATUS_READS) { printf("bus congestion, restarting"); return -1; } /* * Initialize transmit control block (TxCB) list. */ txp = sc->cbl_base; bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); for (i = 0; i < FXP_NTXCB; i++) { txp[i].cb_status = htole16(FXP_CB_STATUS_C | FXP_CB_STATUS_OK); txp[i].cb_command = htole16(FXP_CB_COMMAND_NOP); txp[i].link_addr = htole32(vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status)); txp[i].tbd_array_addr = htole32(vtophys(&txp[i].tbd[0])); txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; } /* * Set the suspend flag on the first TxCB and start the control * unit. It will execute the NOP and then suspend. */ txp->cb_command = htole16(FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S); sc->cbl_first = sc->cbl_last = txp; sc->tx_queued = 1; fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* * Initialize receiver buffer area - RFA. */ fxp_scb_wait(sc);/* XXXX MIPS: Flush not req. Already done when put on rfa_headm */ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START); /* * Set current media. */ mii_mediachg(&sc->sc_mii); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; splx(s);#ifdef USE_FXP_STATS /* * Start stats updater. */ timeout(fxp_stats_update, sc, hz);#endif return(0);}/* * Change media according to request. */intfxp_mediachange(ifp) struct ifnet *ifp;{ if (ifp->if_flags & IFF_UP) fxp_init(ifp->if_softc); return (0);}/* * Notify the world which media we're using. */voidfxp_mediastatus(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr;{ struct fxp_softc *sc = ifp->if_softc; mii_pollstat(&sc->sc_mii); ifmr->ifm_status = sc->sc_mii.mii_media_status; ifmr->ifm_active = sc->sc_mii.mii_media_active;}/* * Add a buffer to the end of the RFA buffer list. * Return 0 if successful, 1 for failure. A failure results in * adding the 'oldm' (if non-NULL) on to the end of the list - * tossing out its old contents and recycling it. * The RFA struct is stuck at the beginning of mbuf cluster and the * data pointer is fixed up to point just past it. */intfxp_add_rfabuf(sc, oldm) struct fxp_softc *sc; struct mbuf *oldm;{ u_int32_t v; struct mbuf *m; u_int8_t *rfap; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m != NULL) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { m_freem(m); if (oldm == NULL) return 1; m = oldm; m->m_data = m->m_ext.ext_buf; } } else { //printf("m=%x,oldm=%x\n",m,oldm); if (oldm == NULL) return 1; m = oldm; m->m_data = m->m_ext.ext_buf; } /* * Move the data pointer up so that the incoming data packet * will be 32-bit aligned. * Get a pointer to the base of the mbuf cluster and move * data start past it. */#if defined(__mips__) /* * Sync the buffer so we can access it uncached. */ if (m->m_ext.ext_buf!=NULL) { pci_sync_cache(sc->sc_pc, (vm_offset_t)m->m_ext.ext_buf, MCLBYTES, SYNC_R); } m->m_data += RFA_ALIGNMENT_FUDGE; rfap = (u_int8_t *)PHYS_TO_UNCACHED(vtophys(m->m_data)); //printf("rfap=%x\n",rfap);#else m->m_data += RFA_ALIGNMENT_FUDGE; rfap = m->m_data;#endif m->m_data += sizeof(struct fxp_rfa); *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, size)) = htole16(MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE); /* * Initialize the rest of the RFA. Note that since the RFA * is misaligned, we cannot store values directly. Instead, * we use an optimized, inline copy. */ *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_status)) = 0; *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) = htole16(FXP_RFA_CONTROL_EL); *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, actual_size)) = 0; v = -1; fxp_lwcopy(&v, (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr))); fxp_lwcopy(&v, (u_int32_t *)(rfap + offsetof(struct fxp_rfa, rbd_addr))); /* * If there are other buffers already on the list, attach this * one to the end by fixing up the tail to point to this one. */ if (sc->rfa_headm != NULL) { sc->rfa_tailm->m_next = m; v = htole32(vtophys(rfap)); rfap = sc->rfa_tailm->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;#if defined(__mips__) /* Noone should have touched this, so no flush req. */ rfap = (u_int8_t *)PHYS_TO_UNCACHED(vtophys(rfap));#endif /* __mips__ */ fxp_lwcopy(&v, (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr))); *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) &= ~htole16(FXP_RFA_CONTROL_EL); } else { sc->rfa_headm = m; } sc->rfa_tailm = m; return (m == oldm);}volatile intfxp_mdi_read(self, phy, reg) struct device *self; int phy; int reg;{ struct fxp_softc *sc = (struct fxp_softc *)self; int count = 10000; int value; CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21)); while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0 && count--) DELAY(10); if (count <= 0) printf(FXP_FORMAT ": fxp_mdi_read: timed out\n", FXP_ARGS(sc)); return (value & 0xffff);}static voidfxp_statchg(self) struct device *self;{ /* XXX Update ifp->if_baudrate */}voidfxp_mdi_write(self, phy, reg, value) struct device *self; int phy; int reg; int value;{ struct fxp_softc *sc = (struct fxp_softc *)self; int count = 10000; CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) | (value & 0xffff)); while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 && count--) DELAY(10); if (count <= 0) printf(FXP_FORMAT ": fxp_mdi_write: timed out\n", FXP_ARGS(sc));}intfxp_ioctl(ifp, command, data) struct ifnet *ifp; FXP_IOCTLCMD_TYPE command; caddr_t data;{ struct fxp_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splimp(); switch (command) { case SIOCSIFADDR:#if !(defined(__NetBSD__) || defined(__OpenBSD__)) case SIOCGIFADDR: case SIOCSIFMTU:#endif error = ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. * XXX If it's up then re-initialize it. This is so flags * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) { fxp_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) fxp_stop(sc, 1); } break;#ifdef USE_FXP_MCAST case SIOCADDMULTI: case SIOCDELMULTI: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;#if defined(__NetBSD__) || defined(__OpenBSD__)#if defined(__OpenBSD__) error = (command == SIOCADDMULTI) ? ether_addmulti(ifr, &sc->arpcom) : ether_delmulti(ifr, &sc->arpcom);#else error = (command == SIOCADDMULTI) ? ether_addmulti(ifr, &sc->sc_ethercom) : ether_delmulti(ifr, &sc->sc_ethercom);#endif if (error == ENETRESET) { /* * Multicast list has changed; set the hardware * filter accordingly. */ if (!sc->all_mcasts) fxp_mc_setup(sc); /* * fxp_mc_setup() can turn on all_mcasts if we run * out of space, so check it again rather than else {}. */ if (sc->all_mcasts) fxp_init(sc); error = 0; }#else /* __FreeBSD__ */ /* * Multicast list has changed; set the hardware filter * accordingly. */ fxp_init(sc); error = 0;#endif /* __NetBSD__ || __OpenBSD__ */ break;#endif case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command); break; default: error = EINVAL; } (void) splx(s); return (error);}#ifdef USE_FXP_MCAST/* * Program the multicast filter. * * We have an artificial restriction that the multicast setup command * must be the first command in the chain, so we take steps to ensure * this. By requiring this, it allows us to keep up the performance of * the pre-initialized command ring (esp. link pointers) by not actually * inserting the mcsetup command in the ring - i.e. its link pointer * points to the TxCB ring, but the mcsetup descriptor itself is not part * of it. We then can do 'CU_START' on the mcsetup descriptor and have it * lead into the regular TxCB ring when it completes. * * This function must be called at splimp. */voidfxp_mc_setup(sc) struct fxp_softc *sc;{ struct fxp_cb_mcs *mcsp = sc->mcsp; struct ifnet *ifp = &sc->sc_if;#if defined(__OpenBSD__) struct ether_multistep step; struct ether_multi *enm;#else struct ifmultiaddr *ifma;#endif int nmcasts; /* * If there are queued commands, we must wait until they are all * completed. If we are already waiting, then add a NOP command * with interrupt option so that we're notified when all commands * have been completed - fxp_start() ensures that no additional * TX commands will be added when need_mcsetup is true. */ if (sc->tx_queued) { struct fxp_cb_tx *txp; /* * need_mcsetup will be true if we are already waiting for the * NOP command to be completed (see below). In this case, bail. */ if (sc->need_mcsetup) return; sc->need_mcsetup = 1; /* * Add a NOP command with interrupt so that we are notified when all * TX commands have been processed. */ txp = sc->cbl_last->next; txp->mb_head = NULL; txp->cb_status = htole16(0); txp->cb_command = htole16(FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I); /* * Advance the end of list forward. */ sc->cbl_last->cb_command &= htole16(~FXP_CB_COMMAND_S); sc->cbl_last = txp; sc->tx_queued++; /* * Issue a resume in case the CU has just suspended. */ fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); /* * Set a 5 second timer just in case we don't hear from the * card again. */ ifp->if_timer = 5; return; } sc->need_mcsetup = 0; /* * Initialize multicast setup descriptor. */ mcsp->next = sc->cbl_base; mcsp->mb_head = NULL; mcsp->cb_status = htole16(0); mcsp->cb_command = htole16(FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I); mcsp->link_addr = htole32(vtophys(&sc->cbl_base->cb_status)); nmcasts = 0; if (!sc->all_mcasts) {#if defined(__OpenBSD__) ETHER_FIRST_MULTI(step, &sc->arpcom, enm); while (enm != NULL) { if (nmcasts >= MAXMCADDR) { sc->all_mcasts = 1; nmcasts = 0; break; } /* Punt on ranges. */ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, sizeof(enm->enm_addrlo)) != 0) { sc->all_mcasts = 1; nmcasts = 0; break; } bcopy(enm->enm_addrlo, (void *) &sc->mcsp->mc_addr[nmcasts][0], 6); nmcasts++; ETHER_NEXT_MULTI(step, enm); }#else for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (nmcasts >= MAXMCADDR) { sc->all_mcasts = 1; nmcasts = 0; break; } bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (void *) &sc->mcsp->mc_addr[nmcasts][0], 6); nmcasts++; }#endif } mcsp->mc_cnt = htole16(nmcasts * 6); sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp; sc->tx_queued = 1; /* * Wait until command unit is not active. This should never * be the case when nothing is queued, but make sure anyway. */ while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == FXP_SCB_CUS_ACTIVE) ; /* * Start the multicast setup command. */ fxp_scb_wait(sc); CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); ifp->if_timer = 2; return;}#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -