?? if_fxp.c
字號:
bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif#endif /* * Add shutdown hook so that DMA is disabled prior to reboot. Not * doing do could allow DMA to corrupt kernel memory during the * reboot before the driver initializes. */ shutdownhook_establish(fxp_shutdown, sc);#ifndef PMON /* * Add suspend hook, for similiar reasons.. */ powerhook_establish(fxp_power, sc);#endif}/* * Device shutdown routine. Called at system shutdown after sync. The * main purpose of this routine is to shut off receiver DMA so that * kernel memory doesn't get clobbered during warmboot. */static voidfxp_shutdown(sc) void *sc;{ fxp_stop((struct fxp_softc *) sc, 0);}#ifndef PMON/* * Power handler routine. Called when the system is transitioning * into/out of power save modes. As with fxp_shutdown, the main * purpose of this routine is to shut off receiver DMA so it doesn't * clobber kernel memory at the wrong time. */voidfxp_power(why, arg) int why; void *arg;{ struct fxp_softc *sc = arg; struct ifnet *ifp; int s; s = splnet(); if (why != PWR_RESUME) fxp_stop(sc, 0); else { ifp = &sc->arpcom.ac_if; if (ifp->if_flags & IFF_UP) fxp_init(sc); } splx(s);}#endifstatic intfxp_ether_ioctl(ifp, cmd, data) struct ifnet *ifp; FXP_IOCTLCMD_TYPE cmd; caddr_t data;{ struct ifaddr *ifa = (struct ifaddr *) data; struct fxp_softc *sc = ifp->if_softc; int error = 0; switch (cmd) {#ifdef PMON case SIOCPOLL: break;#endif case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: error = fxp_init(sc); if(error == -1) return(error);#ifdef __OpenBSD__ arp_ifinit(&sc->arpcom, ifa);#else arp_ifinit(ifp, ifa);#endif break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *) LLADDR(ifp->if_sadl); else bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), ifp->if_addrlen); /* Set new address. */ fxp_init(sc); break; }#endif default: fxp_init(sc); break; } break; default: return (EINVAL); } return (error);}/************************************************************* * End of operating system-specific autoconfiguration glue *************************************************************//* * Do generic parts of attach. */static intfxp_attach_common(sc, enaddr) struct fxp_softc *sc; u_int8_t *enaddr;{ u_int16_t data; int i; /* * Reset to a stable state. */ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); DELAY(100); sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, M_DEVBUF, M_NOWAIT); if (sc->cbl_base == NULL) goto fail;#if defined(__mips__) /* * Due to MIPS processor cache behaviour we change to uncached * addresses to access control structure areas. */ pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->cbl_base, sizeof(struct fxp_cb_tx) * FXP_NTXCB, SYNC_W); sc->cbl_base = (void *)PHYS_TO_UNCACHED(vtophys(sc->cbl_base));#endif /*__mips__*/ sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT); if (sc->fxp_stats == NULL) goto fail; bzero(sc->fxp_stats, sizeof(struct fxp_stats));#if defined(__mips__) pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->fxp_stats, sizeof(struct fxp_stats), SYNC_W); sc->fxp_stats = (void *)PHYS_TO_UNCACHED(vtophys(sc->fxp_stats));#endif /*__mips__*/ sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT); if (sc->mcsp == NULL) goto fail;#if defined(__mips__) pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->mcsp, sizeof(struct fxp_cb_mcs), SYNC_W); sc->mcsp = (void *)PHYS_TO_UNCACHED(vtophys(sc->mcsp));#endif /*__mips__*/ /* * Pre-allocate our receive buffers. */ for (i = 0; i < FXP_NRFABUFS; i++) { if (fxp_add_rfabuf(sc, NULL) != 0) { goto fail; } } /* * Find out how large of an SEEPROM we have. */ fxp_autosize_eeprom(sc); /* * Get info about the primary PHY */#if defined(GODSONEV1) data=0x4701;#else fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);#endif sc->phy_primary_addr = data & 0xff; sc->phy_primary_device = (data >> 8) & 0x3f; sc->phy_10Mbps_only = data >> 15; /* * Read MAC address. */#if defined(GODSONEV1) enaddr[0]=0x12; enaddr[1]=0x34; enaddr[2]=0x56; enaddr[3]=0x78; enaddr[4]=0x9a; enaddr[5]=0xbc;#else fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);#endif return (0); fail: printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc)); if (sc->cbl_base) free(sc->cbl_base, M_DEVBUF); if (sc->fxp_stats) free(sc->fxp_stats, M_DEVBUF); if (sc->mcsp) free(sc->mcsp, M_DEVBUF); /* frees entire chain */ if (sc->rfa_headm) m_freem(sc->rfa_headm); return (ENOMEM);}/* * From NetBSD: * * Figure out EEPROM size. * * 559's can have either 64-word or 256-word EEPROMs, the 558 * datasheet only talks about 64-word EEPROMs, and the 557 datasheet * talks about the existance of 16 to 256 word EEPROMs. * * The only known sizes are 64 and 256, where the 256 version is used * by CardBus cards to store CIS information. * * The address is shifted in msb-to-lsb, and after the last * address-bit the EEPROM is supposed to output a `dummy zero' bit, * after which follows the actual data. We try to detect this zero, by * probing the data-out bit in the EEPROM control register just after * having shifted in a bit. If the bit is zero, we assume we've * shifted enough address bits. The data-out should be tri-state, * before this, which should translate to a logical one. * * Other ways to do this would be to try to read a register with known * contents with a varying number of address bits, but no such * register seem to be available. The high bits of register 10 are 01 * on the 558 and 559, but apparently not on the 557. * * The Linux driver computes a checksum on the EEPROM data, but the * value of this checksum is not very well documented. */static voidfxp_autosize_eeprom(sc) struct fxp_softc *sc;{ u_int16_t reg; int x; CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); /* * Shift in read opcode. */ for (x = 3; x > 0; x--) { if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); } /* * Shift in address. * Wait for the dummy zero following a correct address shift. */ for (x = 1; x <= 8; x++) { CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS | FXP_EEPROM_EESK); DELAY(1); if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0) break; CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); DELAY(1); } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); sc->eeprom_size = x;}/* * Read from the serial EEPROM. Basically, you manually shift in * the read opcode (one bit at a time) and then shift in the address, * and then you shift out the data (all of this one bit at a time). * The word size is 16 bits, so you have to provide the address for * every 16 bits of data. */voidfxp_read_eeprom(sc, data, offset, words) struct fxp_softc *sc; u_short *data; int offset; int words;{ u_int16_t reg; int i, x; for (i = 0; i < words; i++) { CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); /* * Shift in read opcode. */ for (x = 3; x > 0; x--) { if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); } /* * Shift in address. */ for (x = sc->eeprom_size; x > 0; x--) { if ((i + offset) & (1 << (x - 1))) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); } reg = FXP_EEPROM_EECS; data[i] = 0; /* * Shift out data. */ for (x = 16; x > 0; x--) { CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) data[i] |= (1 << (x - 1)); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); }#if BYTE_ORDER == BIG_ENDIAN data[i] = swap16(data[i]);#endif CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); }}#if 0/* * Write to the serial EEPROM. This is not intended to be used * uncautiosly(?). The main intention is to privide a means to * initiate an uninitialized EEPROM during production test. */voidfxp_write_eeprom(sc, data, offset, words) struct fxp_softc *sc; u_short *data; int offset; int words;{ u_int16_t reg; int i, x; int d; /* * Enable writing. */ d = (FXP_EEPROM_OPC_WRITENB << 4); x = 0x100; while (x != 0) { if (d & x) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); x >>= 1; }/* XXXX Need data sheet to verify if raise CS is enough! (pefo) */ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); /* * Now write the data words. */ for (i = 0; i < words; i++) {#if BYTE_ORDER == BIG_ENDIAN data[i] = swap16(data[i]);#endif CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); /* * Shift in write command, address and data. */ d = (FXP_EEPROM_OPC_WRITE << 6) | ((i + offset) & 0x3f); d = d << 16 | data[i]; x = 0x1000000; while (x != 0) { if (d & x) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); x >>= 1; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); DELAY(200000); /* Let write settle */ } /* * Disable writing. */ d = (FXP_EEPROM_OPC_WRITDIS << 4); x = 0x100; while (x != 0) { if (d & x) { reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; } else { reg = FXP_EEPROM_EECS; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); DELAY(1); x >>= 1; } CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK); DELAY(1); CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); DELAY(1);}#endif/* * Start packet transmission on the interface. */static voidfxp_start(ifp) struct ifnet *ifp;{ struct fxp_softc *sc = ifp->if_softc; struct fxp_cb_tx *txp;#ifdef USE_FXP_MCAST /* * See if we need to suspend xmit until the multicast filter * has been reprogrammed (which can only be done at the head * of the command chain). */ if (sc->need_mcsetup) return;#endif txp = NULL; /* * We're finished if there is nothing more to add to the list or if * we're all filled up with buffers to transmit. * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add * a NOP command when needed. */ while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) { struct mbuf *m, *mb_head; int segment; /* * Grab a packet to transmit. */ IF_DEQUEUE(&ifp->if_snd, mb_head); /* * Get pointer to next available tx desc. */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -