📄 ethernet_smsc91c111.c
字号:
// Don't overwrite the buffer // Don't bother writing the message for an off-by-one truncation // because it's probably due to us ignoring the odd byte bit. if (data_count-1 > *data_size) { DEBUG_2("%s: Data truncated: %d>%d\r\n", __FUNCTION__, data_count, *data_size); data_count = *data_size; // Throw out truncated packet return 0; } *data_size = data_count; /* * Handle the buffer alignment cases (32,16,8) * Try to read the largest words as we can * in as tight a loop as possible. */ // Read the last 0..3 bytes of data one byte at a time leftovers = data_count % 4; data_count -= leftovers; if (((unsigned int)data % 4) == 0) { // Buffer area is long word aligned data32 = (unsigned int *)data; // Convert count into long words data_count /= 4; // Read as many whole words as we can for( pointer_offset=0; pointer_offset < data_count; ++pointer_offset) { data32[pointer_offset] = REG32(OFFSET_DR); } // Convert pointer_offset into byte offset pointer_offset *= 4; } else if (((unsigned int)data % 4) == 2) { // Buffer area is short word aligned data16 = (unsigned short *)data; // Convert count into short words data_count /= 2; // Read as many short words as we can for( pointer_offset=0; pointer_offset < data_count; pointer_offset += 2) { _temp32 = REG32(OFFSET_DR); data16[pointer_offset] = (_temp32) & 0xFFFF; data16[pointer_offset +1] = (_temp32 >> 16) & 0xFFFF; } // Convert pointer_offset into byte offset pointer_offset *= 2; } else { // Buffer is byte aligned // Read as many short words as we can for( pointer_offset=0; pointer_offset < data_count; pointer_offset += 4) { _temp32 = REG32(OFFSET_DR); data[pointer_offset] = _temp32 & 0xFF; data[pointer_offset + 1] = (_temp32 >> 8) & 0xFF; data[pointer_offset + 2] = (_temp32 >> 16) & 0xFF; data[pointer_offset + 3] = (_temp32 >> 24) & 0xFF; } } // Read the remaining bytes and store as many as requested if (leftovers) { _temp32 = REG32(OFFSET_DR); for (i=0;leftovers--;i++) { data[pointer_offset + i] = (_temp32 >> (i*8)) & 0xFF; } } return 1;} // End of read_mmu_datastatic int release_rx_packet (void){ unsigned short _temp; int counter; counter=MAX_MMUCR_COUNTER; SETUP_BANK(BANK_MMUCR); do { READ_REG16(OFFSET_MMUCR, _temp); } while ((_temp & BIT_MMUCR_BUSY) && --counter); if (!counter) { ERROR ("MMU busy\r\n"); } WRITE_REG16(OFFSET_MMUCR, OPCODE_MMUCR_REM_REL); do { READ_REG16(OFFSET_MMUCR, _temp); } while (_temp & BIT_MMUCR_BUSY); return 1;} // End of release_rx_packet/* * We must release the tx packet passed to us from the MMU. If we do not * do this, then the memory will fill up. */static int release_tx_packet (unsigned char packet_number){ unsigned short _temp; SETUP_BANK (BANK_PNR); WRITE_REG8(OFFSET_PNR,packet_number); SETUP_BANK (BANK_MMUCR); do { READ_REG16 (OFFSET_MMUCR, _temp); } while (_temp & BIT_MMUCR_BUSY); WRITE_REG16 (OFFSET_MMUCR, OPCODE_MMUCR_REL_SPEC); return 1; } // End of release_tx_packetstatic int allocate_tx (unsigned char *packet_number){ unsigned int counter; unsigned short _temp; unsigned char _temp8; int retry=0; // disable retries for now SETUP_BANK(BANK_MIR); /* * We will wait till there is some available memory before * asking for some. */ counter = MAX_TRY; do { READ_REG16(OFFSET_MIR, _temp); } while (((_temp >> 8) == 0) && --counter); /* * For the Case of entering the if condition below... * * Ok, we can't use the SMSC cause all of its memory is used up. * This can be one of 2 cases. * * 1. We have Received Frames there. This does us no good as * we are single threaded. * * 2. We have Transmitted Frames there. * * 3. Both 1 & 2 * * Number 2 is bad, because we should only really ever have one tx * packet in the buffer (we wait for its compeletion). It should not * happen. * * Number 1 can be fixed by removing packets by either reading them * and releasing them, releasing them individually, or flushing them * all. */ if (!counter) { DEBUG_2("%s: Out of MMU Memory; flushing buffers\r\n", __FUNCTION__); flush_ethernet (); //return 0; }allocate: /* * Wait for MMU to become available */ SETUP_BANK(BANK_MMUCR); counter = MAX_TRY; do { READ_REG16(OFFSET_MMUCR, _temp); } while (_temp & BIT_MMUCR_BUSY && --counter); if (!counter) { ERROR ("MMU busy\r\n"); } /* * Give the ALLOCATE TX PACKET command to the MMU */ WRITE_REG16(OFFSET_MMUCR, OPCODE_MMUCR_ALLOC_TX); SETUP_BANK(BANK_ISR); counter=MAX_TRY; do { READ_REG8(OFFSET_ISR, _temp8); } while (!(_temp8 & BIT_ISR_ALLOC_INT) && --counter); if (!counter) { DEBUG_2("%s: Allocation Timeout\r\n", __FUNCTION__); if (!retry++) { goto allocate; } return 0; } /* * If the below fails lets try to flush the ethernet in one last * try to make a go of this. */ SETUP_BANK(BANK_ARR); READ_REG8(OFFSET_ARR, _temp8); if (_temp8 & BIT_ARR_FAILED) { if (!retry++) { // We probably got flooded with received packets // at this point, using up all the buffers. DEBUG_2("%s: Allocation failed; flushing buffers\r\n", __FUNCTION__); flush_ethernet (); goto allocate; } return 0; } *packet_number &= _temp8 & MASK_ARR_PACKET_NUM; return 1;} // End of allocate_tx/* * This function will do the bit-banging neccessary to do the MII transfers * to the PHY itself. Below is a description of how it works. * * The sequence for the Management Interface is * IDLE->START->OPCODE->PHY_ADDR->REG_ADDR->TA->DATA * * IDLE is 32 1's over the MDIO (via MI_IDLE) * START is 01b over the MDIO (via MI_START) * OPCODE is 01b or 10b over the MDIO (via MI_WRITE / MI_READ) * PHY_ADDR is always 00000b (Internal) * REG_ADDR is reg (5 lower bits). * TA is Turnaround time (don't care for write) * DATA is data. * * reg and data both should be clocked out MSB first (Ie. Bit 15 / 4) */static int write_phy_register (unsigned char reg, unsigned short data){ int i; SETUP_BANK(BANK_MI); /* * Lets do the IDLE */ mi_idle(); /* * Lets do that START condition */ mi_start (); /* * Lets tell it we are doing a write */ mi_write_op (); /* * Lets tell it the PHY ADDRESS */ mi_phy_addr (PHY_INT_ADDR); /* * Lets tell it the PHY REG */ mi_phy_addr (reg); /* * Here's The TurnAround time. This is here so that if the * PHY has to switch from Tx or Rx it has time to do so.. */ mi_ta (); for (i=15;i>=0;i--) { WRITE_REG16(OFFSET_MI,((data >> i) & 0x1) | MI_MDOE); udelay (MI_CLK_DELAY); WRITE_REG16(OFFSET_MI,((data >> i) & 0x1) | MI_MDOE | MI_MDCLK); udelay (MI_CLK_DELAY); } return 1;} // End of write_phy_register/* * This does the bit-banging for the MII to the PHY * * The sequence for the Management Interface is * IDLE->START->OPCODE->PHY_ADDR->REG_ADDR->TA->DATA * * IDLE is 32 1's over the MDIO (via MI_IDLE) * START is 01b over the MDIO (via MI_START) * OPCODE is 01b or 10b over the MDIO (via MI_WRITE / MI_READ) * PHY_ADDR is always 00000b (Internal) * REG_ADDR is reg (5 lower bits). * TA is Turnaround time (don't care for write) * DATA is data. * * reg and data both should be clocked out MSB first (Ie. Bit 15 / 4) */static int read_phy_register (unsigned char reg, unsigned short *data){ int i; unsigned short _temp; SETUP_BANK(BANK_MI); /* * Lets do the IDLE */ mi_idle (); /* * Lets do that START condition */ mi_start (); /* * Lets tell it we are doing a write */ mi_read_op (); /* * Lets tell it the PHY ADDRESS */ mi_phy_addr (PHY_INT_ADDR); /* * Lets tell it the PHY REG */ mi_phy_addr(reg); /* * Heres The TurnAround time. This is here so that if the * PHY has to switch from Tx or Rx it has time to do so.. */ mi_ta (); /* * Read the Data in from the PHY */ for (i=15,*data=0;i>=0;i--) { WRITE_REG16(OFFSET_MI, 0); udelay (MI_CLK_DELAY); READ_REG16(OFFSET_MIR, _temp); *data |= ((((_temp >> 1) & 0x1) << i)); WRITE_REG16(OFFSET_MI, MI_MDCLK); udelay (MI_CLK_DELAY); } return 1;} // End of read_phy_register/* * This function may be used to print out the Ethernet Packets. It does * the appropriate byte swapping to make it easier for reading (by humans). * static int print_data (unsigned char *data, unsigned short size){ int i=0,x=0,leftovers; unsigned int data32=0; DEBUG("print_data: Printing %x bytes\r\n", size); for (i=0;i<(size - 3);i+=4) { if ((i % 24)==0) { itc_printf("\r\n\t"); } data32 = data[i] << 24; data32 |= data[i+1] << 16; data32 |= data[i+2] << 8; data32 |= data[i+3]; itc_printf("%x ", data32); } if (i < (size)) { leftovers = size - i; for (data32=0,x=leftovers - 1;x >=0;i++,x--) { data32 |= data[i] << (8*x); } itc_printf("%x (%i bytes valid)", data32, leftovers); } itc_printf("\r\n"); return 1;}*/int rx_ethernet_off (void){ /* * Disable Receive */ SETUP_BANK(BANK_RCR); REG16(OFFSET_RCR) &= ~(BIT_RCR_RXEN); return 1;}int flush_ethernet (void){ unsigned short _temp; int counter; /* * Reset MMU * * This will flush all of Memory (both tx and rx). */ SETUP_BANK (BANK_MMUCR); counter = MAX_TRY; do { READ_REG16(OFFSET_MMUCR, _temp); } while (_temp & BIT_MMUCR_BUSY && --counter); if (!counter) { ERROR ("MMU busy\r\n"); } WRITE_REG16(OFFSET_MMUCR, OPCODE_MMUCR_RESET); do { READ_REG16(OFFSET_MMUCR, _temp); } while (_temp & BIT_MMUCR_BUSY && --counter); //SETUP_BANK(OFFSET_MIR); return 1;}int rx_ethernet_on (void){ SETUP_BANK(BANK_RCR); REG16(OFFSET_RCR) |= BIT_RCR_RXEN; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -