📄 hp100.c
字号:
hp100_stop_interface( dev ); lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } else { hp100_ints_off(); i = hp100_sense_lan( dev ); hp100_ints_on(); if ( i == HP100_LAN_ERR ) printk( "hp100: %s: link down detected\n", dev->name ); else if ( lp->lan_type != i ) /* cable change! */ { /* it's very hard - all network setting must be changed!!! */ printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); lp->lan_type = i; hp100_stop_interface( dev ); if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } else { printk( "hp100: %s: interface reset\n", dev->name ); hp100_stop_interface( dev ); if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } } dev->trans_start = jiffies; return -EAGAIN; } /* * we have to turn int's off before modifying this, otherwise * a tx_pdl_cleanup could occur at the same time */ save_flags( flags ); cli(); ringptr=lp->txrtail; lp->txrtail=ringptr->next; /* Check whether packet has minimal packet size */ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; ringptr->skb=skb; ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */ ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ if(lp->chip==HP100_CHIPID_SHASTA) { /* TODO:Could someone who has the EISA card please check if this works? */ ringptr->pdl[2]=i; } else /* Lassen */ { /* In the PDL, don't use the padded size but the real packet size: */ ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */ } /* Hand this PDL to the card. */ hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ lp->txrcommit++; restore_flags( flags ); /* Update statistics */ lp->stats.tx_packets++;#ifdef LINUX_2_1 lp->stats.tx_bytes += skb->len;#endif dev->trans_start = jiffies; return 0;}/* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the * number of commited packets. It then frees the skb's of the packets that * obviously have been sent to the network. * * Needs the PERFORMANCE page selected. */static void hp100_clean_txring( struct device *dev ){ struct hp100_private *lp = (struct hp100_private *)dev->priv; int ioaddr = dev->base_addr; int donecount;#ifdef HP100_DEBUG_B hp100_outw( 0x4211, TRACE ); printk("hp100: %s: clean txring\n", dev->name);#endif /* How many PDLs have been transmitted? */ donecount=(lp->txrcommit)-hp100_inb(TX_PDL);#ifdef HP100_DEBUG if(donecount>MAX_TX_PDL) printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n",dev->name);#endif for( ; 0!=donecount; donecount-- ) {#ifdef HP100_DEBUG_BM printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", dev->name, (u_int) lp->txrhead->skb->data, lp->txrcommit, hp100_inb(TX_PDL), donecount);#endif#ifdef LINUX_2_1 dev_kfree_skb( lp->txrhead->skb );#else dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );#endif lp->txrhead->skb=(void *)NULL; lp->txrhead=lp->txrhead->next; lp->txrcommit--; }}/* tx function for slave modes */static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ){ int i, ok_flag; int ioaddr = dev->base_addr; u_short val; struct hp100_private *lp = (struct hp100_private *)dev->priv;#ifdef HP100_DEBUG_B hp100_outw( 0x4212, TRACE ); printk("hp100: %s: start_xmit\n", dev->name);#endif if ( skb==NULL ) {#ifndef LINUX_2_1 dev_tint( dev );#endif return 0; } if ( skb->len <= 0 ) return 0; if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ { hp100_stop_interface( dev ); if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) { printk( "hp100: %s: no connection found - check wire\n", dev->name ); hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ return -EIO; } if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ hp100_start_interface( dev ); } /* If there is not enough free memory on the card... */ i=hp100_inl(TX_MEM_FREE)&0x7fffffff; if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) ) {#ifdef HP100_DEBUG printk( "hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i );#endif /* not waited long enough since last failed tx try? */ if ( jiffies - dev->trans_start < HZ ) {#ifdef HP100_DEBUG printk("hp100: %s: trans_start timing problem\n", dev->name);#endif return -EAGAIN; } if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) /* we have a 100Mb/s adapter but it isn't connected to hub */ { printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name ); hp100_stop_interface( dev ); lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } else { hp100_ints_off(); i = hp100_sense_lan( dev ); hp100_ints_on(); if ( i == HP100_LAN_ERR ) printk( "hp100: %s: link down detected\n", dev->name ); else if ( lp->lan_type != i ) /* cable change! */ { /* it's very hard - all network setting must be changed!!! */ printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); lp->lan_type = i; hp100_stop_interface( dev ); if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } else { printk( "hp100: %s: interface reset\n", dev->name ); hp100_stop_interface( dev ); if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); mdelay(1); } } dev->trans_start = jiffies; return -EAGAIN; } for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ ) {#ifdef HP100_DEBUG_TX printk( "hp100: %s: start_xmit: busy\n", dev->name );#endif } hp100_ints_off(); val = hp100_inw( IRQ_STATUS ); /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set * when the current packet being transmitted on the wire is completed. */ hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); #ifdef HP100_DEBUG_TX printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",dev->name,val,hp100_inw(IRQ_MASK),(int)skb->len );#endif ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; hp100_outw( i, DATA32 ); /* tell card the total packet length */ hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */ if ( lp->mode==2 ) /* memory mapped */ { if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ { /* Note: The J2585B needs alignment to 32bits here! */ memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 ); if ( !ok_flag ) memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); } else { /* Note: The J2585B needs alignment to 32bits here! */ memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 ); if ( !ok_flag ) memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); } } else /* programmed i/o */ { outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 ); if ( !ok_flag ) for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) hp100_outl( 0, DATA32 ); } hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ lp->stats.tx_packets++;#ifdef LINUX_2_1 lp->stats.tx_bytes += skb->len;#endif dev->trans_start=jiffies; hp100_ints_on(); #ifdef LINUX_2_1 dev_kfree_skb( skb );#else dev_kfree_skb( skb, FREE_WRITE );#endif #ifdef HP100_DEBUG_TX printk( "hp100: %s: start_xmit: end\n", dev->name );#endif return 0;}/* * Receive Function (Non-Busmaster mode) * Called when an "Receive Packet" interrupt occurs, i.e. the receive * packet counter is non-zero. * For non-busmaster, this function does the whole work of transfering * the packet to the host memory and then up to higher layers via skb * and netif_rx. */static void hp100_rx( struct device *dev ){ int packets, pkt_len; int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *)dev->priv; u_int header; struct sk_buff *skb;#ifdef DEBUG_B hp100_outw( 0x4213, TRACE ); printk("hp100: %s: rx\n", dev->name);#endif /* First get indication of received lan packet */ /* RX_PKT_CND indicates the number of packets which have been fully */ /* received onto the card but have not been fully transfered of the card */ packets = hp100_inb( RX_PKT_CNT );#ifdef HP100_DEBUG_RX if ( packets > 1 ) printk( "hp100: %s: rx: waiting packets = %d\n", dev->name,packets );#endif while ( packets-- > 0 ) { /* If ADV_NXT_PKT is still set, we have to wait until the card has */ /* really advanced to the next packet. */ for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT); pkt_len++ ) {#ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets );#endif } /* First we get the header, which contains information about the */ /* actual length of the received packet. */ if( lp->mode==2 ) /* memory mapped mode */ { if ( lp->mem_ptr_virt ) /* if memory was remapped */ header = *(__u32 *)lp->mem_ptr_virt; else header = readl( lp->mem_ptr_phys ); } else /* programmed i/o */ header = hp100_inl( DATA32 ); pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3;#ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", dev->name, header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8, (header>>16)&7);#endif /* Now we allocate the skb and transfer the data into it. */ skb = dev_alloc_skb( pkt_len ); if ( skb == NULL ) /* Not enough memory->drop packet */ {#ifdef HP100_DEBUG printk( "hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", dev->name, pkt_len );#endif lp->stats.rx_dropped++; } else /* skb successfully allocated */ { u_char *ptr; skb->dev = dev; /* ptr to start of the sk_buff data area */ ptr = (u_char *)skb_put( skb, pkt_len ); /* Now transfer the data from the card into that area */ if ( lp->mode==2 ) { if ( lp->mem_ptr_virt ) memcpy( ptr, lp->mem_ptr_virt, pkt_len ); /* Note alignment to 32bit transfers */ else memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); } else /* io mapped */ insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); lp->stats.rx_packets++;#ifdef LINUX_2_1 lp->stats.rx_bytes += skb->len;#endif #ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", dev->name, ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );#endif } /* Indicate the card that we have got the packet */ hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); switch ( header & 0x00070000 ) { case (HP100_MULTI_ADDR_HASH<<16): case (HP100_MULTI_ADDR_NO_HASH<<16): lp->stats.multicast++; break; } } /* end of while(there are packets) loop */#ifdef HP100_DEBUG_RX printk( "hp100_rx: %s: end\n", dev->name );#endif}/* * Receive Function for Busmaster Mode */static void hp100_rx_bm( struct device *dev ){ int ioaddr = dev->base_add
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -