📄 cs8900.c
字号:
}}static voidcs8900_rx_task (void *arg){ cs8900_device *cs = arg; int dev = cs->dev; struct ifnet *ifp = &cs->arpcom.ac_if; rtems_event_set events; struct mbuf *m; struct ether_header *eh; rtems_status_code sc; rtems_interrupt_level level; /* * Turn the receiver and transmitter on. */ mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_TX_ON); /* * Start the software interrupt watchdog. */ rtems_interrupt_disable (level); mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG, CS8900_BUFFER_CONFIG_SW_INT); ++cs->eth_stats.int_swint_req; rtems_interrupt_enable (level); /* * Loop reading packets. */ while (1) { cs8900_rx_refill_queue (cs); sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, TOD_MILLISECONDS_TO_TICKS (250), &events); cs8900_rx_refill_queue (cs); if (sc == RTEMS_TIMEOUT) { /* * We need to check the interrupt hardware in the cs8900a * has not locked up. It seems this occurs if the ISQ * queue fills up. * To test we generate a software interrupt and watch * a counter go up. If the counter does not go for 2 * software interrupts requests we flush the ISQ queue. */ if ((cs->eth_stats.int_swint_req - cs->eth_stats.int_swint_res) > 1) { printf ("cs8900: int lockup, isq flush\n"); mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); while (mem_pp_get_reg (dev, CS8900_PP_ISQ) != 0); cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0; ++cs->eth_stats.int_lockup; mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); } rtems_interrupt_disable (level); mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG, CS8900_BUFFER_CONFIG_SW_INT); ++cs->eth_stats.int_swint_req; rtems_interrupt_enable (level); } cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len); while (cs->rx_loaded_len) { rtems_interrupt_disable (level); m = cs->rx_loaded_head; if (m) { cs->rx_loaded_head = m->m_nextpkt; if (cs->rx_loaded_head == 0) cs->rx_loaded_tail = 0; m->m_nextpkt = 0; cs->rx_loaded_len--; rtems_interrupt_enable (level); m->m_pkthdr.rcvif = ifp; cs->eth_stats.rx_bytes += m->m_pkthdr.len; m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header); eh = mtod (m, struct ether_header *); m->m_data += sizeof (struct ether_header); ++cs->eth_stats.rx_packets; ether_input (ifp, eh, m); } else { rtems_interrupt_enable (level); } } cs8900_trace (cs, CS8900_T_RX_END, cs->rx_loaded_len); }}static voidcs8900_tx_task (void *arg){ cs8900_device *cs = arg; int dev = cs->dev; struct ifnet *ifp = &cs->arpcom.ac_if; rtems_event_set events; struct mbuf *m; rtems_status_code sc; /* * Wait for the link to come up. */ rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (750)); /* * Loop processing the tx queue. */ while (1) { /* * Fetch the mbuf list from the interface's queue. */ IF_DEQUEUE (&ifp->if_snd, m); /* * If something actually is present send it. */ if (!m) { ifp->if_flags &= ~IFF_OACTIVE; rtems_bsdnet_event_receive (CS8900_TX_START_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); } else { if (cs8900_link_active (dev)) { int resending; do { unsigned short buf_status; resending = 0; cs->tx_active = 1; mem_pp_set_reg (dev, CS8900_PP_TxCMD, CS8900_TX_CMD_STATUS_TX_START_ENTIRE | CS8900_TX_CMD_STATUS_FORCE); mem_pp_set_reg (dev, CS8900_PP_TxLength, m->m_pkthdr.len); buf_status = mem_pp_get_reg (dev, CS8900_PP_BusST); /* * If the bid for memory in the device fails trash the * transmit and try again next time. */ if (buf_status & CS8900_BUS_STATUS_TX_BID_ERROR) ++cs->eth_stats.tx_bid_errors; else { /* * If the buffer is not read enable the interrupt and then wait. */ if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0) { cs->eth_stats.tx_wait_for_rdy4tx++; sc = rtems_bsdnet_event_receive (CS8900_TX_WAIT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, TOD_MILLISECONDS_TO_TICKS (750), &events); if (sc == RTEMS_TIMEOUT) { /* * For some reason the wait request has been dropped, * so lets resend from the start. */ printf ("tx resend\n"); ++cs->eth_stats.tx_resends; resending = 1; } } if (!resending) { cs8900_tx_load (dev, m); cs->eth_stats.tx_packets++; cs->eth_stats.tx_bytes += m->m_pkthdr.len; } } } while (resending); m_freem (m); do { rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); } while (cs->tx_active); } else { ++cs->eth_stats.tx_dropped; m_freem (m); } } }}static voidcs8900_start (struct ifnet *ifp){ cs8900_device *cs = ifp->if_softc; /* * Tell the transmit daemon to wake up and send a packet. */ ifp->if_flags |= IFF_OACTIVE; rtems_event_send (cs->tx_task, CS8900_TX_START_EVENT);}static voidcs8900_stop (cs8900_device *cs){ int dev = cs->dev; mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_TX_ON); mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT);}static const char *eth_statistics_labels[] ={ "rx packets", "tx packets", "rx bytes", "tx bytes", "rx interrupts", "tx interrupts", "rx dropped", "rx no mbuf", "rx no custers", "rx oversize errors", "rx crc errors", "rx runt errors", "rx missed errors", "tx ok", "tx collisions", "tx bid errors", "tx wait for rdy4tx", "tx rdy4tx", "tx underrun errors", "tx dropped", "tx resends", "int swint req", "int swint res", "int lockup", "interrupts"};static voidcs8900_stats (cs8900_device *cs){ int dev = cs->dev; int i; int max_label = 0; int len; unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets; cs->eth_stats.rx_missed_errors += mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6; cs->eth_stats.tx_collisions += mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6; printf ("Network Driver Stats for CS8900 :\n"); for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++) { len = strlen (eth_statistics_labels[i]); if (len > max_label) max_label = len; } max_label += 2; printf ("%*s - %10u %*s - %10u\n", max_label, "rx ready len", cs->rx_ready_len, max_label, "rx loaded len", cs->rx_loaded_len); for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++) { printf ("%*s - %10lu", max_label, eth_statistics_labels[i], value[i]); i++; if (i < (sizeof (eth_statistics_labels) / sizeof (const char *))) printf (" %*s - %10lu", max_label, eth_statistics_labels[i], value[i]); printf ("\n"); }#if CS8900_TRACE for (i = 0; i < cs->trace_in; i++) { printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000); if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*)) printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]); else printf ("unknown trace key, %d : ", cs->trace_key[i]); if (cs->trace_key[i] == CS8900_T_INT) { printf ("0x%04lx ", cs->trace_var[i]); if (cs->trace_var[i] == 0) printf ("end"); else { switch (cs->trace_var[i] & 0x1f) { case 0x04: printf ("rx event"); break; case 0x08: printf ("tx event"); break; case 0x0c: printf ("buffer event"); break; case 0x10: printf ("rx missed"); break; case 0x12: printf ("tx collisions"); break; case 0x1f: printf ("tx request"); break; case 0x1e: printf ("tx wait 4 tx"); break; case 0x1d: printf ("tx already active"); break; default: printf ("unknown event"); break; } } } else printf ("0x%08lx", cs->trace_var[i]); printf ("\n"); } cs->trace_in = 0; #endif}static voidcs8900_init (void *arg){ cs8900_device *cs = arg; int dev = cs->dev; struct ifnet *ifp = &cs->arpcom.ac_if; if (cs->rx_task == 0) { /* * Set up the hardware. */ cs8900_hardware_init (cs); /* * Start driver task. We have only one task. */ cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs); cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs); }#ifdef todo /* * Set flags appropriately */ if (ifp->if_flags & IFF_PROMISC) else#endif /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING; /* * Set the Line Control to bring the receive and transmitter online. */ mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_TX_ON); mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT);}static intcs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data){ cs8900_device *cs = ifp->if_softc; int error = 0; switch (cmd) { case SIOCGIFADDR: case SIOCSIFADDR: error = ether_ioctl (ifp, cmd, data); break; case SIOCSIFFLAGS: switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { case IFF_RUNNING: cs8900_stop (cs); break; case IFF_UP: cs8900_init (cs); break; case IFF_UP | IFF_RUNNING: cs8900_stop (cs); cs8900_init (cs); break; default: break; } break; case SIO_RTEMS_SHOW_STATS: cs8900_stats (cs); break; /* FIXME: Multicast commands must be added here. */ default: error = EINVAL; break; } return error;}intcs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching){ cs8900_device *cs; struct ifnet *ifp; int mtu; int unit; char *name; /* * Parse driver name */ if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0) return 0; /* * Is driver free? */ if (unit >= CS8900_DEVICES) { printf ("Bad CS8900 unit number for device `%s'.\n", config->name); return 0; } cs = &cs8900[unit]; cs->dev = unit; ifp = &cs->arpcom.ac_if; if (attaching) { if (ifp->if_softc) { printf ("Driver `%s' already in use.\n", config->name); return 0; } /* * Process options */ if (config->hardware_address) memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); else cs8900_get_mac_addr (unit, cs->arpcom.ac_enaddr); if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; cs->accept_bcast = !config->ignore_broadcast; /* * Set up network interface values. */ ifp->if_softc = cs; ifp->if_unit = unit; ifp->if_name = name; ifp->if_mtu = mtu; ifp->if_init = cs8900_init; ifp->if_ioctl = cs8900_ioctl; ifp->if_start = cs8900_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 to the stack. */ if_attach (ifp); ether_ifattach (ifp); } else { if (!ifp->if_softc) { printf ("Driver `%s' not found.\n", config->name); return 0; } cs8900_stop (cs); cs8900_detach_interrupt (unit); } return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -