URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [eth/] [ns/] [dp83902a/] [current/] [src/] [if_dp83902a.c] - Rev 810
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // dev/if_dp83902a.c // // Ethernet device driver for NS DP83902a ethernet controller // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas, jskov, rsandifo // Date: 2001-06-13 // Purpose: // Description: // // FIXME: Will fail if pinged with large packets (1520 bytes) // Add promisc config // Add SNMP // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/system.h> #include <pkgconf/io_eth_drivers.h> #include <cyg/infra/cyg_type.h> #include <cyg/hal/hal_arch.h> #include <cyg/infra/diag.h> #include <cyg/hal/drv_api.h> #include <cyg/io/eth/eth_drv.h> #include <cyg/io/eth/netdev.h> #include <cyg/io/dp83902a.h> #define __WANT_DEVS #include CYGDAT_DEVS_ETH_NS_DP83902A_INL #undef __WANT_DEVS #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED // This ISR is called when the ethernet interrupt occurs static cyg_uint32 dp83902a_isr(cyg_vector_t vector, cyg_addrword_t data) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)data; DEBUG_FUNCTION(); // INCR_STAT( interrupts ); cyg_drv_interrupt_mask(dp->interrupt); cyg_drv_interrupt_acknowledge(dp->interrupt); return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR } static void dp83902a_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) { // This conditioning out is necessary because of explicit calls to this // DSR - which would not ever be called in the case of a polled mode // usage ie. in RedBoot. #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED dp83902a_priv_data_t* dp = (dp83902a_priv_data_t *)data; struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(dp->tab); struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance); DEBUG_FUNCTION(); // but here, it must be a *sc: eth_drv_dsr( vector, count, (cyg_addrword_t)sc ); #else # ifndef CYGPKG_REDBOOT # error Empty DP83902A ethernet DSR is compiled. Is this what you want? # endif #endif } #endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED // The deliver function (ex-DSR) handles the ethernet [logical] processing static void dp83902a_deliver(struct eth_drv_sc *sc) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; DEBUG_FUNCTION(); // Service the interrupt: dp83902a_poll(sc); // Allow interrupts to happen again cyg_drv_interrupt_unmask(dp->interrupt); } static bool dp83902a_init(struct cyg_netdevtab_entry *tab) { struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; cyg_uint8* base; int i; DEBUG_FUNCTION(); CYGHWR_NS_DP83902A_PLF_INIT(dp); base = dp->base; if (!base) return false; // No device found dp->tab = tab; dp->cr_lock = 0; CYGHWR_NS_DP83902A_PLF_RESET(dp); DEBUG_LINE(); // Prepare ESA DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); // Select page 1 if (dp->hardwired_esa) { // Force the NIC to use the specified ESA for (i = 0; i < 6; i++) DP_OUT(base, DP_P1_PAR0+i, dp->esa[i]); } else { // Use the address from the serial EEPROM for (i = 0; i < 6; i++) DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); } DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); // Select page 0 diag_printf("DP83902A - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", (dp->hardwired_esa) ? "static" : "eeprom", dp->esa[0], dp->esa[1], dp->esa[2], dp->esa[3], dp->esa[4], dp->esa[5] ); #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED cyg_drv_interrupt_create( dp->interrupt, 0, // Priority - unused (cyg_addrword_t)dp,// Data item passed to ISR & DSR dp83902a_isr, // ISR dp83902a_dsr, // DSR &dp->interrupt_handle, // handle to intr obj &dp->interrupt_object ); // space for int obj cyg_drv_interrupt_attach(dp->interrupt_handle); cyg_drv_interrupt_unmask(dp->interrupt); #endif // Initialize upper level driver (sc->funs->eth_drv->init)(sc, dp->esa); return true; } static void dp83902a_stop(struct eth_drv_sc *sc) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; cyg_uint8 *base = dp->base; DEBUG_FUNCTION(); CR_UP(); DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); // Brutal DP_OUT(base, DP_ISR, 0xFF); // Clear any pending interrupts DP_OUT(base, DP_IMR, 0x00); // Disable all interrupts CR_DOWN(); dp->running = false; } // // This function is called to "start up" the interface. It may be called // multiple times, even when the hardware is already running. It will be // called whenever something "hardware oriented" changes and should leave // the hardware ready to send/receive packets. // static void dp83902a_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; cyg_uint8 *base = dp->base; int i; DEBUG_FUNCTION(); CR_UP(); DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); // Brutal DP_OUT(base, DP_DCR, DP_DCR_INIT); DP_OUT(base, DP_RBCH, 0); // Remote byte count DP_OUT(base, DP_RBCL, 0); DP_OUT(base, DP_RCR, DP_RCR_MON); // Accept no packets DP_OUT(base, DP_TCR, DP_TCR_LOCAL); // Transmitter [virtually] off DP_OUT(base, DP_TPSR, dp->tx_buf1); // Transmitter start page dp->tx1 = dp->tx2 = 0; dp->tx_next = dp->tx_buf1; dp->tx_started = false; DP_OUT(base, DP_PSTART, dp->rx_buf_start); // Receive ring start page DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); // Receive ring boundary DP_OUT(base, DP_PSTOP, dp->rx_buf_end); // Receive ring end page dp->rx_next = dp->rx_buf_start-1; DP_OUT(base, DP_ISR, 0xFF); // Clear any pending interrupts DP_OUT(base, DP_IMR, DP_IMR_All); // Enable all interrupts DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); // Select page 1 DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); // Current page - next free page for Rx for (i = 0; i < ETHER_ADDR_LEN; i++) { DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); } // Enable and start device DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // Normal transmit operations DP_OUT(base, DP_RCR, DP_RCR_AB); // Accept broadcast, no errors, no multicast dp->running = true; CR_DOWN(); } // // This routine is called to perform special "control" opertions // static int dp83902a_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_len) { switch (key) { case ETH_DRV_SET_MAC_ADDRESS: return 0; break; default: return 1; break; } } // // This routine is called to see if it is possible to send another packet. // It will return non-zero if a transmit is possible, zero otherwise. // static int dp83902a_can_send(struct eth_drv_sc *sc) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; DEBUG_FUNCTION(); return ((dp->tx1 == 0) || (dp->tx2 == 0)); } // // This routine is called to start the transmitter. It is split out from the // data handling routine so it may be called either when data becomes first // available or when an Tx interrupt occurs // static void dp83902a_start_xmit(struct eth_drv_sc *sc, int start_page, int len) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; cyg_uint8 *base = dp->base; DEBUG_FUNCTION(); #if DEBUG & 1 diag_printf("Tx pkt %d len %d\n", start_page, len); if (dp->tx_started) diag_printf("TX already started?!?\n"); #endif CR_UP(); DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_OUT(base, DP_TBCL, len & 0xFF); DP_OUT(base, DP_TBCH, len >> 8); DP_OUT(base, DP_TPSR, start_page); DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); CR_DOWN(); dp->tx_started = true; } // // This routine is called to send data to the hardware. It is known a-priori // that there is free buffer space (dp->tx_next). // static void dp83902a_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; int i, len, start_page, pkt_len; unsigned char *data; cyg_uint8 isr; #if DEBUG & 4 int dx; #endif DEBUG_FUNCTION(); pkt_len = total_len; if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME; #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA // Make length even when using 16 bit transfers if (pkt_len % 2) pkt_len++; #endif start_page = dp->tx_next; if (dp->tx_next == dp->tx_buf1) { dp->tx1 = start_page; dp->tx1_len = pkt_len; dp->tx1_key = key; dp->tx_next = dp->tx_buf2; } else { dp->tx2 = start_page; dp->tx2_len = pkt_len; dp->tx2_key = key; dp->tx_next = dp->tx_buf1; } CR_UP(); #if DEBUG & 5 diag_printf("TX prep page %d len %d\n", start_page, pkt_len); #endif DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA { // Dummy read. The manual sez something slightly different, // but the code is extended a bit to do what Hitachi's monitor // does (i.e., also read data). cyg_uint16 tmp; #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA int len = 2; #else int len = 1; #endif DP_OUT(base, DP_RSAL, 0x100-len); DP_OUT(base, DP_RSAH, (start_page-1) & 0xff); DP_OUT(base, DP_RBCL, len); DP_OUT(base, DP_RBCH, 0); DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); DP_IN_DATA(dp->data, tmp); } #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA // Stall for a bit before continuing to work around random data // corruption problems on some platforms. CYGACC_CALL_IF_DELAY_US(1); #endif // Send data to device buffer(s) DP_OUT(base, DP_RSAL, 0); DP_OUT(base, DP_RSAH, start_page); DP_OUT(base, DP_RBCL, pkt_len & 0xFF); DP_OUT(base, DP_RBCH, pkt_len >> 8); DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); // Put data into buffer for (i = 0; i < sg_len; i++) { data = (unsigned char *)sg_list[i].buf; len = sg_list[i].len; #if DEBUG & 4 diag_printf(" sg buf %08x len %08x\n ", data, len); dx = 0; #endif while (len > 0) { #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA cyg_uint16 tmp; tmp = *data++ << 8; len -= 2; if (len >= 0) tmp |= *data++; DP_OUT_DATA(dp->data, tmp); #if DEBUG & 4 diag_printf(" %04x", tmp); if (0 == (++dx % 8)) diag_printf("\n "); #endif #else #if DEBUG & 4 diag_printf(" %02x", *data); if (0 == (++dx % 16)) diag_printf("\n "); #endif DP_OUT_DATA(dp->data, *data++); len--; #endif } #if DEBUG & 4 diag_printf("\n"); #endif } if (total_len < pkt_len) { #if DEBUG & 4 diag_printf(" + %d bytes of padding\n", pkt_len - total_len); #endif // Padding to 802.3 length was required for (i = total_len; i < pkt_len;) { #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA i += 2; #else i++; #endif DP_OUT_DATA(dp->data, 0); } } #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA // After last data write, delay for a bit before accessing the // device again, or we may get random data corruption in the last // datum (on some platforms). CYGACC_CALL_IF_DELAY_US(1); #endif // Wait for DMA to complete do { DP_IN(base, DP_ISR, isr); } while ((isr & DP_ISR_RDC) == 0); // Then disable DMA DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); CR_DOWN(); // Start transmit if not already going if (!dp->tx_started) { if (start_page == dp->tx1) { dp->tx_int = 1; // Expecting interrupt from BUF1 } else { dp->tx_int = 2; // Expecting interrupt from BUF2 } dp83902a_start_xmit(sc, start_page, pkt_len); } } // // This function is called when a packet has been received. It's job is // to prepare to unload the packet from the hardware. Once the length of // the packet is known, the upper layer of the driver can be told. When // the upper layer is ready to unload the packet, the internal function // 'dp83902a_recv' will be called to actually fetch it from the hardware. // static void dp83902a_RxEvent(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; unsigned char rsr; unsigned char rcv_hdr[4]; int i, len, pkt, cur; DEBUG_FUNCTION(); DP_IN(base, DP_RSR, rsr); while (true) { CR_UP(); // Read incoming packet header DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); DP_IN(base, DP_P1_CURP, cur); DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_IN(base, DP_BNDRY, pkt); pkt += 1; if (pkt == dp->rx_buf_end) pkt = dp->rx_buf_start; if (pkt == cur) { CR_DOWN(); break; } DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); DP_OUT(base, DP_RBCH, 0); DP_OUT(base, DP_RSAL, 0); DP_OUT(base, DP_RSAH, pkt); if (dp->rx_next == pkt) { if (cur == dp->rx_buf_start) DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); else DP_OUT(base, DP_BNDRY, cur-1); // Update pointer CR_DOWN(); return; } dp->rx_next = pkt; DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA CYGACC_CALL_IF_DELAY_US(10); #endif for (i = 0; i < sizeof(rcv_hdr);) { #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA cyg_uint16 tmp; DP_IN_DATA(dp->data, tmp); rcv_hdr[i++] = (tmp >> 8) & 0xff; rcv_hdr[i++] = tmp & 0xff; #else DP_IN_DATA(dp->data, rcv_hdr[i++]); #endif } CR_DOWN(); #if DEBUG & 5 diag_printf("rx hdr %02x %02x %02x %02x\n", rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); #endif len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); (sc->funs->eth_drv->recv)(sc, len); if (rcv_hdr[1] == dp->rx_buf_start) DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); else DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); // Update pointer } } // // This function is called as a result of the "eth_drv_recv()" call above. // It's job is to actually fetch data for a packet from the hardware once // memory buffers have been allocated for the packet. Note that the buffers // may come in pieces, using a scatter-gather list. This allows for more // efficient processing in the upper layers of the stack. // static void dp83902a_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; int i, mlen, len; unsigned char *data; cyg_uint8 saved_char = 0; bool saved; #if DEBUG & 4 int dx; #endif DEBUG_FUNCTION(); // Compute total packet length len = 0; for (i = 0; i < sg_len; i++) { len += sg_list[i].len; } #if DEBUG & 5 diag_printf("Rx packet %d length %d\n", dp->rx_next, len); #endif CR_UP(); // Read incoming packet data DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_OUT(base, DP_RBCL, len & 0xFF); DP_OUT(base, DP_RBCH, len >> 8); DP_OUT(base, DP_RSAL, 4); // Past header DP_OUT(base, DP_RSAH, dp->rx_next); DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA CYGACC_CALL_IF_DELAY_US(10); #endif saved = false; for (i = 0; i < sg_len; i++) { data = (unsigned char *)sg_list[i].buf; if (data) { mlen = sg_list[i].len; #if DEBUG & 4 diag_printf(" sg buf %08x len %08x \n", data, mlen); dx = 0; #endif while (0 < mlen) { // Saved byte from previous loop? if (saved) { *data++ = saved_char; mlen--; saved = false; continue; } #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA { cyg_uint16 tmp; DP_IN_DATA(dp->data, tmp); #if DEBUG & 4 diag_printf(" %04x", tmp); if (0 == (++dx % 8)) diag_printf("\n "); #endif *data++ = (tmp >> 8) & 0xff; mlen--; if (0 == mlen) { saved_char = tmp & 0xff; saved = true; } else { *data++ = tmp & 0xff; mlen--; } } #else { cyg_uint8 tmp; DP_IN_DATA(dp->data, tmp); #if DEBUG & 4 diag_printf(" %02x", tmp); if (0 == (++dx % 16)) diag_printf("\n "); #endif *data++ = tmp;; mlen--; } #endif } #if DEBUG & 4 diag_printf("\n"); #endif } } CR_DOWN(); } static void dp83902a_TxEvent(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; unsigned char tsr; unsigned long key; DEBUG_FUNCTION(); DP_IN(base, DP_TSR, tsr); if (dp->tx_int == 1) { key = dp->tx1_key; dp->tx1 = 0; } else { key = dp->tx2_key; dp->tx2 = 0; } // Start next packet if one is ready dp->tx_started = false; if (dp->tx1) { dp83902a_start_xmit(sc, dp->tx1, dp->tx1_len); dp->tx_int = 1; } else if (dp->tx2) { dp83902a_start_xmit(sc, dp->tx2, dp->tx2_len); dp->tx_int = 2; } else { dp->tx_int = 0; } // Tell higher level we sent this packet (sc->funs->eth_drv->tx_done)(sc, key, 0); } // Read the tally counters to clear them. Called in response to a CNT // interrupt. static void dp83902a_ClearCounters(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; cyg_uint8 cnt1, cnt2, cnt3; DP_IN(base, DP_FER, cnt1); DP_IN(base, DP_CER, cnt2); DP_IN(base, DP_MISSED, cnt3); DP_OUT(base, DP_ISR, DP_ISR_CNT); } // Deal with an overflow condition. This code follows the procedure set // out in section 7.0 of the datasheet. static void dp83902a_Overflow(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; cyg_uint8 isr; // Issue a stop command and wait 1.6ms for it to complete. CR_UP(); DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); CYGACC_CALL_IF_DELAY_US(1600); // Clear the remote byte counter registers. DP_OUT(base, DP_RBCL, 0); DP_OUT(base, DP_RBCH, 0); // Enter loopback mode while we clear the buffer. DP_OUT(base, DP_TCR, DP_TCR_LOCAL); DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); CR_DOWN(); // Read in as many packets as we can and acknowledge any and receive // interrupts. Since the buffer has overflowed, a receive event of // some kind will have occured. dp83902a_RxEvent(sc); DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); // Clear the overflow condition and leave loopback mode. DP_OUT(base, DP_ISR, DP_ISR_OFLW); DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // If a transmit command was issued, but no transmit event has occured, // restart it here. DP_IN(base, DP_ISR, isr); if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { CR_UP(); DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); CR_DOWN(); } } static void dp83902a_poll(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; cyg_uint8 *base = dp->base; unsigned char isr; // DEBUG_FUNCTION(); CR_UP(); DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); CR_DOWN(); DP_IN(base, DP_ISR, isr); while (0 != isr) { // The CNT interrupt triggers when the MSB of one of the error // counters is set. We don't much care about these counters, but // we should read their values to reset them. if (isr & DP_ISR_CNT) { dp83902a_ClearCounters(sc); } // Check for overflow. It's a special case, since there's a // particular procedure that must be followed to get back into // a running state. if (isr & DP_ISR_OFLW) { dp83902a_Overflow(sc); } else { // Other kinds of interrupts can be acknowledged simply by // clearing the relevant bits of the ISR. Do that now, then // handle the interrupts we care about. DP_OUT(base, DP_ISR, isr); // Clear set bits if (!dp->running) break; // Is this necessary? // Check for tx_started on TX event since these may happen // spuriously it seems. if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { dp83902a_TxEvent(sc); } if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { dp83902a_RxEvent(sc); } } DP_IN(base, DP_ISR, isr); } CYGHWR_NS_DP83902A_PLF_INT_CLEAR(dp); } static int dp83902a_int_vector(struct eth_drv_sc *sc) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; return dp->interrupt; }
Go to most recent revision | Compare with Previous | Blame | View Log