📄 if_mahwah.c
字号:
ioaddr = p_i82559->io_address; // get device I/O address if ( p_i82559->tx_queue_full ) {#ifdef KEEP_STATISTICS statistics[p_i82559->index].tx_dropped++;#endif#ifdef DEBUG_82559 os_printf( "i82559_send: Queue full, device %x, key %x\n", p_i82559, key );#endif } else { struct eth_drv_sg *last_sg; volatile cyg_uint8 *to_p; tx_descriptor_add = p_i82559->tx_descriptor_add; p_i82559->tx_keys[tx_descriptor_add] = key; p_txcb = p_i82559->tx_ring[tx_descriptor_add]; CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" ); CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" ); p_txcb->txstatus = 0; p_txcb->command = TxCB_CMD_TRANSMIT | TxCB_CMD_S | TxCB_CMD_I | TxCB_CMD_EL; p_txcb->link = VIRT_TO_BUS((cyg_uint32)p_txcb); p_txcb->tbd_address = 0xFFFFFFFF; p_txcb->tbd_number = 0; p_txcb->tx_threshold = 16; p_txcb->eof = 1; p_txcb->count = total_len; // Copy from the sglist into the txcb to_p = &p_txcb->buffer[0]; CYG_ASSERT( 0 < sg_len, "sg_len underflow" ); CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" ); for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) { cyg_uint8 *from_p; int l; from_p = (cyg_uint8 *)(sg_list->buf); l = sg_list->len; if ( l > total_len ) l = total_len; memcpy( (unsigned char *)to_p, from_p, l ); to_p += l; total_len -= l; if ( 0 > total_len ) break; // Should exit via sg_last normally } CYG_ASSERT( 0 == total_len, "length mismatch in tx" ); CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" ); CYG_ASSERT( &p_txcb->buffer[0] < to_p, "to_p wild in tx" ); CYG_ASSERT( &p_txcb->buffer[0] + MAX_TX_PACKET_SIZE >= to_p, "to_p overflow in tx" ); // Next descriptor if ( ++tx_descriptor_add >= MAX_TX_DESCRIPTORS) tx_descriptor_add = 0; p_i82559->tx_descriptor_add = tx_descriptor_add; // From this instant, interrupts can advance the world and start, // even complete, this tx request... if ( p_i82559->tx_descriptor_remove == tx_descriptor_add ) p_i82559->tx_queue_full = 1; } // Try advancing the Tx Machine regardless // no more interrupts until started ints = Mask82559Interrupt(p_i82559); // Check that either: // tx is already active, there is other stuff queued, // OR this tx just added is the current active one // OR this tx just added is already complete CYG_ASSERT( // The machine is busy: (p_i82559->tx_in_progress == 1) || // or: The machine is idle and this just added is the next one (((p_i82559->tx_descriptor_add-1) == p_i82559->tx_descriptor_active) || ((0 == p_i82559->tx_descriptor_add) && ((MAX_TX_DESCRIPTORS-1) == p_i82559->tx_descriptor_active))) || // or: This tx is already complete (p_i82559->tx_descriptor_add == p_i82559->tx_descriptor_active), "Active/add mismatch" ); // Advance TxMachine atomically TxMachine(p_i82559); Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so PacketRxReady(p_i82559); UnMask82559Interrupt(p_i82559, ints);}// ------------------------------------------------------------------------//// Function : i82559_reset//// ------------------------------------------------------------------------static void i82559_reset(struct i82559* p_i82559){ cyg_uint32 ioaddr; int count; ioaddr = p_i82559->io_address; // make sure no command operating wait_for_cmd_done(ioaddr); OUTL(I82559_SELECTIVE_RESET, ioaddr + SCBPort); for (count = 10 ; count-- ; ) { udelay(1000); } OUTL(I82559_RESET, ioaddr + SCBPort); for (count = 10 ; count-- ; ) { udelay(1000); }}// ------------------------------------------------------------------------//// INTERRUPT HANDLERS//// ------------------------------------------------------------------------static cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data){ struct i82559* p_i82559 = (struct i82559 *)data; cyg_uint16 status; cyg_uint32 ioaddr; IF_BAD_82559( p_i82559 ) {#ifdef DEBUG os_printf( "i82559_isr: Bad device pointer %x\n", p_i82559 );#endif return 0; } ioaddr = p_i82559->io_address; status = INW(ioaddr + SCBStatus); // Acknowledge all INT sources that were active OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus); // (see pages 6-10 & 6-90)#ifdef KEEP_STATISTICS statistics[p_i82559->index].interrupts++; // receiver left ready state ? if ( status & SCB_STATUS_RNR ) statistics[p_i82559->index].rx_resource++; // frame receive interrupt ? if ( status & SCB_STATUS_FR ) statistics[p_i82559->index].rx_count++; // transmit interrupt ? if ( status & SCB_STATUS_CX ) statistics[p_i82559->index].tx_complete++;#endif // Advance the Tx Machine regardless TxMachine(p_i82559); // it should have settled down now... Acknowledge82559Interrupt(p_i82559); return CYG_ISR_CALL_DSR; // schedule DSR}// ------------------------------------------------------------------------static int mux_device_index = 0;static cyg_uint32 eth_mux_isr(cyg_vector_t vector, cyg_addrword_t data){ int device_index = mux_device_index; struct i82559* p_i82559; mux_device_index ^= 1; // look at the other one first next time. do { p_i82559 = &i82559[device_index]; if ( p_i82559->active ) (void)eth_isr( vector, (cyg_addrword_t)p_i82559 ); device_index ^= 1; } while ( device_index == mux_device_index ); return CYG_ISR_CALL_DSR;}// ------------------------------------------------------------------------static void eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ struct i82559* p_i82559 = (struct i82559 *)data; struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance); // but here, it must be a *sc: eth_drv_dsr( vector, count, (cyg_addrword_t)sc );}// ------------------------------------------------------------------------// This is called from the function below (used to be uni-DSR)static inline voiduni_deliver(struct i82559* p_i82559){ // First pass any rx data up the stack PacketRxReady(p_i82559); // Then scan for completed Txen and inform the stack TxDone(p_i82559);}// ------------------------------------------------------------------------void i82559_deliver(struct eth_drv_sc *sc){ struct i82559* p_i82559; int device_index = mux_device_index; // Since this must mux both devices, the incoming arg is ignored. mux_device_index ^= 1; // look at the other one first next time. do { p_i82559 = &i82559[device_index]; if ( p_i82559->active ) uni_deliver( p_i82559 ); device_index ^= 1; } while ( device_index == mux_device_index );}// ------------------------------------------------------------------------// Device table entry to operate the chip in a polled mode.// Only diddle the interface we were asked to!void i82559_poll(struct eth_drv_sc *sc){ struct i82559 *p_i82559; int ints; p_i82559 = (struct i82559 *)sc->driver_private; IF_BAD_82559( p_i82559 ) {#ifdef DEBUG os_printf( "i82559_poll: Bad device pointer %x\n", p_i82559 );#endif return; } // Do these atomically ints = Mask82559Interrupt(p_i82559); // As it happens, this driver always requests the DSR to be called: (void)eth_isr( CYGNUM_HAL_INTERRUPT_PCI_IRQ, (cyg_addrword_t)p_i82559 ); // (no harm in calling this ints-off also, when polled) uni_deliver( p_i82559 ); Acknowledge82559Interrupt(p_i82559); UnMask82559Interrupt(p_i82559, ints);}// ------------------------------------------------------------------------// Determine interrupt vector used by a device - for attaching GDB stubs// packet handler.inti82559_int_vector(struct eth_drv_sc *sc){ struct i82559 *p_i82559; p_i82559 = (struct i82559 *)sc->driver_private; return (p_i82559->vector);}#if 0inti82559_int_op( struct eth_drv_sc *sc, int mask){ struct i82559 *p_i82559; p_i82559 = (struct i82559 *)sc->driver_private; if ( 1 == mask ) return Mask82559Interrupt( p_i82559 ); if ( 0 == mask ) UnMask82559Interrupt( p_i82559, 0x0fffffff ); // enable all return 0;}#endif // ------------------------------------------------------------------------//// Function : pci_init_find_82559s//// This is called exactly once at the start of time to:// o scan the PCI bus for objects// o record them in the device table// o acquire all the info needed for the driver to access them// o instantiate interrupts for them// o attach those interrupts appropriately// ------------------------------------------------------------------------static intpci_init_find_82559s( void ){ cyg_pci_device_id devid; cyg_pci_device dev_info; cyg_uint16 cmd; int device_index; // MUX interrupt - special case when 2 cards share one intr. static cyg_handle_t mux_interrupt_handle = 0; static cyg_interrupt mux_interrupt_object;#ifdef DEBUG db_printf("pci_init_find_82559s()\n");#endif // allocate memory to be used in ioctls later if (mem_reserved_ioctl != (void*)0) {#ifdef DEBUG db_printf("pci_init_find_82559s() called > once\n");#endif return 0; } CYG_ASSERT( CYGMEM_SECTION_pci_window == (char *)CYGHWR_HAL_ARM_PCI_MEM_MAP_BASE, "PCI window configured does not match PCI memory section base" ); CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE == CYGHWR_HAL_ARM_PCI_MEM_MAP_SIZE, "PCI window configured does not match PCI memory section size" ); if ( CYGMEM_SECTION_pci_window != (char *)CYGHWR_HAL_ARM_SA110_PCI_MEM_MAP_BASE || CYGMEM_SECTION_pci_window_SIZE != CYGHWR_HAL_ARM_SA110_PCI_MEM_MAP_SIZE ) {#ifdef DEBUG db_printf("pci_init_find_82559s(): PCI window misconfigured\n");#endif return 0; } // First initialize the heap in PCI window'd memory i82559_heap_size = CYGHWR_HAL_ARM_SA110_PCI_MEM_MAP_SIZE; i82559_heap_base = (cyg_uint8 *)CYGHWR_HAL_ARM_SA110_PCI_MEM_MAP_BASE; i82559_heap_free = i82559_heap_base; mem_reserved_ioctl = pciwindow_mem_alloc(MAX_MEM_RESERVED_IOCTL); cyg_pci_init();#ifdef DEBUG db_printf("Finished cyg_pci_init();\n");#endif devid = CYG_PCI_NULL_DEVID; for (device_index = 0; device_index < MAX_82559; device_index++) { struct i82559 *p_i82559 = &i82559[device_index]; p_i82559->index = device_index; // Intel 82559 and 82557 are virtually identical, with different dev codes if (cyg_pci_find_device(0x8086, 0x1030, &devid) || cyg_pci_find_device(0x8086, 0x1229, &devid) ) {#ifdef DEBUG db_printf("eth%d = 82559\n", device_index);#endif cyg_pci_get_device_info(devid, &dev_info); if (cyg_pci_translate_interrupt(&dev_info, &p_i82559->vector)) {#ifdef DEBUG db_printf(" Wired to HAL vector %d\n", p_i82559->vector);#endif p_i82559->vector = CYGNUM_HAL_INTERRUPT_IRQ_IN_0; diag_printf(" Wired to HAL vector %d\n", p_i82559->vector); cyg_drv_interrupt_create( p_i82559->vector, 0, // Priority - unused (CYG_ADDRWORD)p_i82559, //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -