📄 smc91111.c
字号:
continue; } } while (0); db4_printf(">+Tx packet allocated %x (previous %x)\n", packet, cpd->txpacket); cpd->txpacket = packet; /* ############ assemble packet data ############ */ /* prepare send */ put_reg(cpd, LAN91CXX_PNR, packet); /* Note: Check FIFO state here before continuing? */ put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000); /* Pointer is now set, and the proper bank is selected for */ /* data writes. */ /* Prepare header: */ put_data(cpd, CYG_CPU_TO_LE16(0)); /* reserve space for status word */ /* packet length (includes status, byte-count and control shorts) */ put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6))); /* Always even, always < 15xx(dec) */ /* Put data into buffer */ n = m; while (n) { sdata = (unsigned short *)n->m_data; len = n->m_len; CYG_ASSERT((0 == (len & 1) || !(n->m_next)), "!odd length"); CYG_ASSERT(sdata, "!No sg data pointer here"); while (len >= sizeof(*sdata)) { put_data(cpd, *sdata++); len -= sizeof(*sdata); } n = n->m_next; }#if DEBUG & 64 n = m; while (n) { int lp = 0; unsigned char *start = (unsigned char *)n->m_data; len = n->m_len; while (len > 0) { unsigned char a = *(start++); unsigned char b = *(start++); db64_printf("%02x %02x ", a, b); lp += 2; if (lp >= 16) { db64_printf("\n"); lp = 0; } len -= 2; } n = n->m_next; } db64_printf(" \n");#endif m_freem(m); CYG_ASSERT(sdata, "!No sg data pointer outside"); /* Lay down the control short unconditionally at the end. */ /* (or it might use random memory contents) */ control = 0; if (1 & plen) { /* Need to set ODD flag and insert the data */ unsigned char onebyte = *(unsigned char *)sdata; control = onebyte; control |= LAN91CXX_CONTROLBYTE_ODD; } control |= LAN91CXX_CONTROLBYTE_CRC; /* Just in case... */ put_data(cpd, CYG_CPU_TO_LE16(control)); /* ############ start transmit ############ */ /* Ack TX empty int and unmask it. */ ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00; put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT); put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M); /* notify on error only (Autorelease) */ /* Enqueue the packet */ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet); ints = get_reg(cpd, LAN91CXX_INTERRUPT); db1_printf(">END: ints at TX: %04x\n", ints); dbg_prefix = "";}void smc91111_txDaemon(void *arg){ struct lan91cxx_priv_data *cpd = arg; struct ifnet *ifp = &cpd->arpcom.ac_if; struct mbuf *m; rtems_event_set events; DEBUG_FUNCTION(); for (;;) { /* * Wait for packet */ rtems_bsdnet_event_receive (SMC91111_START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); /*IF_DEQUEUE (&ifp->if_snd, m); if (m) { sendpacket (ifp, m); } */ for (;;) { IF_DEQUEUE(&ifp->if_snd, m); if (!m) break; sendpacket(ifp, m); } ifp->if_flags &= ~IFF_OACTIVE; }}/* start transmit */static void smc91111_start(struct ifnet *ifp){ struct lan91cxx_priv_data *cpd = ifp->if_softc; if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT); ifp->if_flags |= IFF_OACTIVE;}/* called after a tx error interrupt, freet the packet */static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd){ unsigned short packet, tcr; int success = 1; int saved_packet; DEBUG_FUNCTION(); INCR_STAT(cpd, tx_complete); saved_packet = get_reg(cpd, LAN91CXX_PNR); /* Ack and mask TX interrupt set */ /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00; ints |= LAN91CXX_INTERRUPT_TX_SET_ACK; ints &= ~LAN91CXX_INTERRUPT_TX_SET_M; put_reg(cpd, LAN91CXX_INTERRUPT, ints); */ /* Get number of completed packet and read the status word */ packet = get_reg(cpd, LAN91CXX_FIFO_PORTS); db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet); { unsigned short reg; reg = get_reg(cpd, LAN91CXX_EPH_STATUS); /* Covering each bit in turn... */ if (reg & LAN91CXX_STATUS_TX_UNRN) INCR_STAT(cpd, tx_underrun); if (reg & LAN91CXX_STATUS_LOST_CARR) INCR_STAT(cpd, tx_carrier_loss); if (reg & LAN91CXX_STATUS_LATCOL) INCR_STAT(cpd, tx_late_collisions); if (reg & LAN91CXX_STATUS_TX_DEFR) INCR_STAT(cpd, tx_deferred); if (reg & LAN91CXX_STATUS_SQET) INCR_STAT(cpd, tx_sqetesterrors); if (reg & LAN91CXX_STATUS_16COL) INCR_STAT(cpd, tx_max_collisions); if (reg & LAN91CXX_STATUS_MUL_COL) INCR_STAT(cpd, tx_mult_collisions); if (reg & LAN91CXX_STATUS_SNGL_COL) INCR_STAT(cpd, tx_single_collisions); if (reg & LAN91CXX_STATUS_TX_SUC) INCR_STAT(cpd, tx_good); cpd->stats.tx_total_collisions = cpd->stats.tx_late_collisions + cpd->stats.tx_max_collisions + cpd->stats.tx_mult_collisions + cpd->stats.tx_single_collisions; /* We do not need to look in the Counter Register (LAN91CXX_COUNTER) because it just mimics the info we already have above. */ } /* We do not really care about Tx failure. Ethernet is not a reliable medium. But we do care about the TX engine stopping. */ tcr = get_reg(cpd, LAN91CXX_TCR); if (0 == (LAN91CXX_TCR_TXENA & tcr)) { db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr); tcr |= LAN91CXX_TCR_TXENA; put_reg(cpd, LAN91CXX_TCR, tcr); success = 0; /* And treat this as an error... */ } packet &= 0xff; /* and then free the packet */ put_reg(cpd, LAN91CXX_PNR, cpd->txpacket); put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet); while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ; /* Don't change Packet Number Reg until busy bit is cleared */ /* Per LAN91C111 Spec, Page 50 */ put_reg(cpd, LAN91CXX_PNR, saved_packet);}/* \ ------------- Helpers ------------- \ *//* * Show interface statistics */static void smc91111_stats(struct lan91cxx_priv_data *priv){ printf("tx_good :%-8d", priv->stats.tx_good); printf("tx_max_collisions :%-8d", priv->stats.tx_max_collisions); printf("tx_late_collisions :%-8d", priv->stats.tx_late_collisions); printf("tx_underrun :%-8d", priv->stats.tx_underrun); printf("tx_carrier_loss :%-8d", priv->stats.tx_carrier_loss); printf("tx_deferred :%-8d", priv->stats.tx_deferred); printf("tx_sqetesterrors :%-8d", priv->stats.tx_sqetesterrors); printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions); printf("tx_mult_collisions :%-8d", priv->stats.tx_mult_collisions); printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions); printf("rx_good :%-8d", priv->stats.rx_good); printf("rx_crc_errors :%-8d", priv->stats.rx_crc_errors); printf("rx_align_errors :%-8d", priv->stats.rx_align_errors); printf("rx_resource_errors :%-8d", priv->stats.rx_resource_errors); printf("rx_overrun_errors :%-8d", priv->stats.rx_overrun_errors); printf("rx_collisions :%-8d", priv->stats.rx_collisions); printf("rx_short_frames :%-8d", priv->stats.rx_short_frames); printf("rx_too_long_frames :%-8d", priv->stats.rx_too_long_frames); printf("rx_symbol_errors :%-8d", priv->stats.rx_symbol_errors); printf("interrupts :%-8d", priv->stats.interrupts); printf("rx_count :%-8d", priv->stats.rx_count); printf("rx_deliver :%-8d", priv->stats.rx_deliver); printf("rx_resource :%-8d", priv->stats.rx_resource); printf("rx_restart :%-8d", priv->stats.rx_restart); printf("tx_count :%-8d", priv->stats.tx_count); printf("tx_complete :%-8d", priv->stats.tx_complete); printf("tx_dropped :%-8d", priv->stats.tx_dropped);}/* * Driver ioctl handler */static int smc91111_ioctl(struct ifnet *ifp, int command, caddr_t data){ struct lan91cxx_priv_data *cpd = ifp->if_softc; int error = 0; DEBUG_FUNCTION(); switch (command) { case SIOCGIFADDR: case SIOCSIFADDR: db_printf("SIOCSIFADDR\n"); ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: db_printf("SIOCSIFFLAGS\n"); switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { case IFF_RUNNING: smc91111_stop(cpd); break; case IFF_UP: smc91111_init(cpd); break; case IFF_UP | IFF_RUNNING: smc91111_stop(cpd); smc91111_init(cpd); break; default: break; } break; case SIO_RTEMS_SHOW_STATS: db_printf("SIO_RTEMS_SHOW_STATS\n"); smc91111_stats(cpd); break; /* * FIXME: All sorts of multicast commands need to be added here! */ default: error = EINVAL; break; } return error;}/* * Attach an SMC91111 driver to the system */int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config, struct scmv91111_configuration * chip){ struct ifnet *ifp; struct lan91cxx_priv_data *cpd; int unitNumber; char *unitName; int mtu; DEBUG_FUNCTION();/* /\* activate io area *\/ *//* switch (sparc_leon23_get_psr_version()) { *//* case 0: *//* case 2: *//* db_printf("Activating Leon2 io port\n"); *//* /\*configure pio *\/ *//* *((volatile unsigned int *)0x80000000) |= 0x10f80000; *//* *((volatile unsigned int *)0x800000A8) |= *//* (0xe0 | chip->vector) << (8 * (chip->pio - 4)); *//* break; *//* default: *//* { *//* unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl; *//* if ((addr_pio = *//* amba_find_apbslv_addr(VENDOR_GAISLER, *//* GAISLER_PIOPORT, &irq_pio)) *//* && (addr_mctrl = *//* amba_find_apbslv_addr(VENDOR_ESA, *//* ESA_MCTRL, &irq_mctrl))) { *//* LEON3_IOPORT_Regs_Map *io = *//* (LEON3_IOPORT_Regs_Map *) addr_pio; *//* db_printf *//* ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n", *//* (unsigned int)addr_pio, *//* (unsigned int)addr_mctrl); *//* *((volatile unsigned int *)addr_mctrl) |= 0x10f80000; /\*mctrl ctrl 1 *\/ *//* io->irqmask |= (1 << chip->pio); *//* io->irqpol |= (1 << chip->pio); *//* io->irqedge |= (1 << chip->pio); *//* io->iodir &= ~(1 << chip->pio); *//* } else { *//* return 0; *//* } *//* } *//* } */ /* parse driver name */ if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) { db_printf("Unitnumber < 0: %d\n", unitNumber); return 0; } db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr); cpd = &smc91111; ifp = &cpd->arpcom.ac_if; memset(cpd, 0, sizeof(*cpd)); cpd->config = *chip; cpd->base = chip->baseaddr; if (smc_probe(cpd)) { return 0; } if (config->hardware_address) { memcpy(cpd->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); } else { /* dummy default address */ cpd->arpcom.ac_enaddr[0] = 0x12; cpd->arpcom.ac_enaddr[1] = 0x13; cpd->arpcom.ac_enaddr[2] = 0x14; cpd->arpcom.ac_enaddr[3] = 0x15; cpd->arpcom.ac_enaddr[4] = 0x16; cpd->arpcom.ac_enaddr[5] = 0x17; } cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0]; cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1]; cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2]; cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3]; cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4]; cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5]; cpd->rpc_cur_mode = LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK | LAN91CXX_RPCR_ANEG; if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; /* * Set up network interface values */ ifp->if_softc = cpd; ifp->if_unit = unitNumber; ifp->if_name = unitName; ifp->if_mtu = mtu; ifp->if_init = smc91111_init; ifp->if_ioctl = smc91111_ioctl; ifp->if_start = smc91111_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; /* * Attach the interface */ if_attach(ifp); ether_ifattach(ifp);#ifdef DEBUG printf("SMC91111 : driver has been attached\n");#endif return 1;};/* \ ------------- Initialization ------------- \ *//* * Initialize and start the device */static void smc91111_init(void *arg){ struct lan91cxx_priv_data *cpd = arg; struct ifnet *ifp = &cpd->arpcom.ac_if; DEBUG_FUNCTION(); if (cpd->txDaemonTid == 0) { lan91cxx_hardware_init(cpd); lan91cxx_start(ifp); cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096, smc91111_rxDaemon, cpd); cpd->txDaemonTid = rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd); } /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING;}/* * Stop the device */static void smc91111_stop(struct lan91cxx_priv_data *cpd){ struct ifnet *ifp = &cpd->arpcom.ac_if; DEBUG_FUNCTION(); ifp->if_flags &= ~IFF_RUNNING; /* Reset chip */ put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST); put_reg(cpd, LAN91CXX_RCR, 0); cpd->txbusy = cpd->within_send = 0;}int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd){ unsigned short val; int i; DEBUG_FUNCTION(); cpd->txbusy = cpd->within_send = 0; /* install interrupt vector */ db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector); set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1); /* Reset chip */ put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST); put_reg(cpd, LAN91CXX_RCR, 0); HAL_DELAY_US(100000); put_reg(cpd, LAN91CXX_CONFIG, 0x9000); put_reg(cpd, LAN91CXX_RCR, 0); put_reg(cpd, LAN91CXX_TCR, 0); put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu); val = get_reg(cpd, LAN91CXX_EPH_STATUS); /* probe chip by reading the signature in BS register */ val = get_banksel(cpd); db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n", (unsigned int)(cpd->base + LAN91CXX_BS), val); if ((0xff00 & val) != 0x3300) { printf("No 91Cxx signature"); printf("smsc_lan91cxx_init: No 91Cxx signature found\n"); return 0; } val = get_reg(cpd, LAN91CXX_REVISION); db9_printf("LAN91CXX - type: %01x, rev: %01x\n", (val >> 4) & 0xf, val & 0xf); /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */ cpd->c111_reva = (val == 0x3390); /* The controller may provide a function used to set up the ESA */ if (cpd->config_enaddr) (*cpd->config_enaddr) (cpd); db9_printf("LAN91CXX - status: %04x\n", val); /* Use statically configured ESA from the private data */ db9_printf ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -