📄 smc91111.c
字号:
static intcrc32(char *s, int length){ /* indices */ int perByte; int perBit; /* crc polynomial for Ethernet */ const unsigned long poly = 0xedb88320; /* crc value - preinitialized to all 1's */ unsigned long crc_value = 0xffffffff; for (perByte = 0; perByte < length; perByte++) { unsigned char c; c = *(s++); for (perBit = 0; perBit < 8; perBit++) { crc_value = (crc_value >> 1) ^ (((crc_value ^ c) & 0x01) ? poly : 0); c >>= 1; } } return crc_value;}/* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct device * ) . Purpose: . Attempt to allocate memory for a packet, if chip-memory is not . available, then tell the card to generate an interrupt when it . is available. . . Algorithm: . . o if the saved_skb is not currently null, then drop this packet . on the floor. This should never happen, because of TBUSY. . o if the saved_skb is null, then replace it with the current packet, . o See if I can sending it now. . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now.*/static intsmc_wait_to_send_packet(struct sk_buff *skb, struct net_device *dev){ struct smc_local *lp = (struct smc_local *) dev->priv; unsigned int ioaddr = dev->base_addr; u16 length; unsigned short numPages;#ifdef USE_AUTO_RELEASE u16 time_out; u16 status;#endif PRINTK3("%s:smc_wait_to_send_packet\n", dev->name); if (lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ lp->stats.tx_aborted_errors++; printk("%s: Bad Craziness - sent packet while busy.\n", dev->name); return 1; } lp->saved_skb = skb; length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;#if 0 /* ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** The 91C111 ignores the size bits, but the code is left intact ** for backwards and future compatibility. ** ** Pkt size for allocating is data length +6 (for additional status ** words, length and ctl!) ** ** If odd size then last byte is included in this header. */ numPages = ((length & 0xfffe) + 6); numPages >>= 8; // Divide by 256 if (numPages > 7) { printk("%s: Far too big packet error. \n", dev->name); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ dev_kfree_skb(skb); lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); return 0; }#else numPages = 0;#endif /* either way, a packet is waiting now */ lp->packets_waiting++; /* now, try to allocate the memory */ SMC_SELECT_BANK(2);#ifdef USE_AUTO_RELEASE smc_wait_mmu_release_complete( ioaddr); SMC_outw((MC_ALLOC | numPages), ioaddr, MMU_CMD_REG); /* . Performance Hack . . wait a short amount of time.. if I can send a packet now, I send . it now. Otherwise, I enable an interrupt and wait for one to be . available. . . I could have handled this a slightly different way, by checking to . see if any memory was available in the FREE MEMORY register. However, . either way, I need to generate an allocation, and the allocation works . no matter what, so I saw no point in checking free memory. */ time_out = MEMORY_WAIT_TIME; do { status = SMC_inb(ioaddr, INT_REG); if (status & IM_ALLOC_INT) { /* acknowledge the interrupt */ SMC_outb(IM_ALLOC_INT, ioaddr, INT_REG); break; } } while (--time_out); if (!time_out) { netif_stop_queue (dev); /* oh well, wait until the chip finds memory later */ SMC_ENABLE_INT(IM_ALLOC_INT); /* Check the status bit one more time just in case */ /* it snuk in between the time we last checked it */ /* and when we set the interrupt bit */ status = SMC_inb(ioaddr, INT_REG); if (!(status & IM_ALLOC_INT)) { PRINTK2("%s: memory allocation deferred. \n", dev->name); /* it's deferred, but I'll handle it later */ return 0; } /* Looks like it did sneak in, so disable */ /* the interrupt */ SMC_DISABLE_INT(IM_ALLOC_INT); } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev);#else /* dont use performance hack */ /* stop the queue and wait for alloc interrupt */ netif_stop_queue (dev); spin_lock_irq(&lp->mmu_lock); SMC_ENABLE_INT( IM_ALLOC_INT ); smc_wait_mmu_release_complete( ioaddr); SMC_outw((MC_ALLOC | numPages), ioaddr, MMU_CMD_REG); spin_unlock_irq(&lp->mmu_lock);#endif return 0;}/* . Function: smc_hardware_send_packet(struct device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it.*/static voidsmc_hardware_send_packet(struct net_device *dev){ struct smc_local *lp = (struct smc_local *) dev->priv; u8 packet_no; struct sk_buff *skb = lp->saved_skb; u16 length; unsigned int ioaddr; unsigned char *buf; PRINTK3("%s:smc_hardware_send_packet\n", dev->name); ioaddr = dev->base_addr; if (!skb) { PRINTK("%s: In XMIT with no packet to send \n", dev->name); return; } length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buf = skb->data; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = SMC_inb(ioaddr, AR_REG); if (packet_no & AR_FAILED) { /* or isn't there? BAD CHIP! */ printk(KERN_INFO "%s: Memory allocation failed. \n", dev->name); dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; } /* we have a packet address, so tell the card to use it */ SMC_outb(packet_no, ioaddr, PN_REG); /* point to the beginning of the packet */ SMC_outw(PTR_AUTOINC, ioaddr, PTR_REG); PRINTK3("%s: Trying to xmit packet of length %x\n", dev->name, length);#if SMC_DEBUG > 2 printk("Transmitting Packet\n"); print_packet(buf, length);#endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */ if( lp->use_32bit) SMC_outl((length + 6) << 16, ioaddr, DATA_REG); else { SMC_outw(0, ioaddr, DATA_REG); /* send the packet length ( +6 for status words, length, and ctl */ SMC_outb((length + 6) & 0xFF, ioaddr, DATA_REG); SMC_outb((length + 6) >> 8, ioaddr, DATA_REG); } /* send the actual data . I _think_ it's faster to send the longs first, and then . mop up by sending the last word. It depends heavily . on alignment, at least on the 486. Maybe it would be . a good idea to check which is optimal? But that could take . almost as much time as is saved? . Well, the data fifo is dword aligned, hopefully buf ptr is . dword aligned, so sending longs is definitely a win... [jws] */ if( lp->use_32bit) { if((unsigned int)buf & 2) { //gah, the sk buff is misaligned... SMC_outw(*((u16 *) buf)++, ioaddr, DATA_REG); length -=2; } SMC_outsl(ioaddr, DATA_REG, buf, length); if (length & 0x2) SMC_outw(*((u16 *) (buf + (length & ~3))), ioaddr, DATA_REG); } else SMC_outsw(ioaddr, DATA_REG, buf, length); /* Send the last byte, if there is one. */ if ((length & 1) == 0) { SMC_outw(0, ioaddr, DATA_REG); } else { SMC_outb(buf[length - 1], ioaddr, DATA_REG); SMC_outb(0x20, ioaddr, DATA_REG); // Set odd bit in CONTROL BYTE } /* enable the interrupts */#ifdef USE_AUTO_RELEASE SMC_ENABLE_INT((IM_TX_INT | IM_TX_EMPTY_INT));#else SMC_ENABLE_INT( (IM_TX_INT) ); SMC_SELECT_BANK( 0 ); SMC_outw( SMC_inw( ioaddr , TCR_REG ) | TCR_ENABLE, ioaddr , TCR_REG ); SMC_SELECT_BANK( 2 );#endif /* and let the chipset deal with it */ SMC_outw(MC_ENQUEUE, ioaddr, MMU_CMD_REG); PRINTK2("%s: Sent packet of length %d \n", dev->name, length); lp->tx_bytes += length; lp->saved_skb = NULL; dev_kfree_skb_any(skb); dev->trans_start = jiffies; /* we can send another packet */ /* but let's give the receiver some more time by waiting */// netif_wake_queue(dev); return;}/*------------------------------------------------------------------------- | | smc_init( struct device * dev ) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code | dev->base_addr == 2, always allocate space, and return success | dev->base_addr == <anything else> this is the address to check | | Output: | 0 --> there is a device | anything else, error | ---------------------------------------------------------------------------*/int __initsmc_init(struct net_device *dev){ #ifdef CONFIG_ARCH_S3C2410 unsigned long base_addr = dev->base_addr; SET_MODULE_OWNER(dev); PRINTK2("%s: smc_init\n", dev->name); /* try a specific location... */ if (base_addr) return smc_probe(dev, base_addr);#endif /* couldn't find anything */ return -ENODEV;}/*------------------------------------------------------------------------- | | smc_destructor( struct device * dev ) | Input parameters: | dev, pointer to the device structure | | Output: | None. | ---------------------------------------------------------------------------*/voidsmc_destructor(struct net_device *dev){ PRINTK2("%s: smc_destructor\n", dev->name);}#ifndef NO_AUTOPROBE/*---------------------------------------------------------------------- . smc_findirq . . This routine has a simple purpose -- make the SMC chip generate an . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------*/int __initsmc_findirq(unsigned int ioaddr){ int timeout = 20; unsigned long cookie; PRINTK2("%s:smc_findirq\n", CARDNAME); /* I have to do a STI() here, because this is called from a routine that does an CLI during this process, making it rather difficult to get interrupts for auto detection */ sti(); cookie = probe_irq_on(); /* * What I try to do here is trigger an ALLOC_INT. This is done * by allocating a small chunk of memory, which will give an interrupt * when done. */ SMC_SELECT_BANK(2); /* enable ALLOCation interrupts ONLY */ SMC_outb(IM_ALLOC_INT, ioaddr, IM_REG); /* . Allocate 512 bytes of memory. Note that the chip was just . reset so all the memory is available */ SMC_outw(MC_ALLOC | 1, ioaddr, MMU_CMD_REG); /* . Wait until positive that the interrupt has been generated */ while (timeout) { u8 int_status; int_status = SMC_inb(ioaddr, INT_REG); if (int_status & IM_ALLOC_INT) break; /* got the interrupt */ timeout--; } /* there is really nothing that I can do here if timeout fails, as autoirq_report will return a 0 anyway, which is what I want in this case. Plus, the clean up is needed in both cases. */ /* DELAY HERE! On a fast machine, the status might change before the interrupt is given to the processor. This means that the interrupt was never detected, and autoirq_report fails to report anything. This should fix autoirq_* problems. */ mdelay(10); /* and disable all interrupts again */ SMC_outb(0, ioaddr, IM_REG); /* clear hardware interrupts again, because that's how it was when I was called... */ cli(); /* and return what I found */ return probe_irq_off(cookie);}#endif/*---------------------------------------------------------------------- . Function: smc_probe( int ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC91111 chip. . Returns a 0 on success . . Algorithm: . (1) see if the high byte of BANK_SELECT is 0x33 . (2) compare the ioaddr with the base register's address . (3) see if I recognize the chip ID in the appropriate register . .--------------------------------------------------------------------- *//*--------------------------------------------------------------- . Here I do typical initialization tasks. . . o Initialize the structure if needed . o print out my vanity message if not done so already . o print out what type of hardware is detected . o print out the ethernet address . o find the IRQ . o set up my private data . o configure the dev structure with my subroutines . o actually GRAB the irq. . o GRAB the region .-----------------------------------------------------------------*/static int __initsmc_probe(struct net_device *dev, unsigned int ioaddr){ int i, memory, retval; static unsigned version_printed = 0; unsigned int bank; const char *version_string; int interface; /*registers */ u16 revision_register; u16 base_address_register; u16 memory_info_register; /*=> Pramod */ struct smc_local *lp; /*<= Pramod */ /* find the interface numbed */ for (interface = 0; interface < MAX_NETWORK_INTERFACE_COUNT; interface++) { if ( smc_config[interface].port == dev->base_addr) { break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -