📄 hp100.c
字号:
ringptr->pdl = pdlptr+1; ringptr->pdl_paddr = virt_to_bus(pdlptr+1); ringptr->skb = (void *) NULL; /* * Write address and length of first PDL Fragment (which is used for * storing the RX-Header * We use the 4 bytes _before_ the PDH in the pdl memory area to * store this information. (PDH is at offset 0x04) */ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ *(pdlptr+3) = 4; /* Length Frag 1 */ return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 );}static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ){ if( 0!=( ((unsigned)pdlptr) & 0xf) ) printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned) pdlptr); ringptr->pdl = pdlptr; /* +1; */ ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ ringptr->skb = (void *) NULL; return((((MAX_TX_FRAG*2+2)+3)/4)*4);}/* * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes * for possible odd word alignment rounding up to next dword and set PDL * address for fragment#2 * Returns: 0 if unable to allocate skb_buff * 1 if successful */int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev ){#ifdef HP100_DEBUG_B int ioaddr = dev->base_addr;#endif#ifdef HP100_DEBUG_BM u_int *p;#endif#ifdef HP100_DEBUG_B hp100_outw( 0x4207, TRACE ); printk("hp100: %s: build rx pdl\n", dev->name);#endif /* Allocate skb buffer of maximum size */ /* Note: This depends on the alloc_skb functions allocating more * space than requested, i.e. aligning to 16bytes */ ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 ); if(NULL!=ringptr->skb) { /* * Reserve 2 bytes at the head of the buffer to land the IP header * on a long word boundary (According to the Network Driver section * in the Linux KHG, this should help to increase performance.) */ skb_reserve(ringptr->skb, 2); ringptr->skb->dev=dev; ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE ); /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ /* Note: 1st Fragment is used for the 4 byte packet status * (receive header). Its PDL entries are set up by init_rxpdl. So * here we only have to set up the PDL fragment entries for the data * part. Those 4 bytes will be stored in the DMA memory region * directly before the PDL. */#ifdef HP100_DEBUG_BM printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", dev->name, (u_int) ringptr->pdl, ((MAX_ETHER_SIZE+2+3)/4)*4, (unsigned int) ringptr->skb->data);#endif ringptr->pdl[0] = 0x00020000; /* Write PDH */ ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ #ifdef HP100_DEBUG_BM for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++) printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n",dev->name,(u_int) p,(u_int) *p );#endif return(1); } /* else: */ /* alloc_skb failed (no memory) -> still can receive the header * fragment into PDL memory. make PDL safe by clearing msgptr and * making the PDL only 1 fragment (i.e. the 4 byte packet status) */#ifdef HP100_DEBUG_BM printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", dev->name, (u_int) ringptr->pdl);#endif ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */ return(0);}/* * hp100_rxfill - attempt to fill the Rx Ring will empty skb's * * Makes assumption that skb's are always contiguous memory areas and * therefore PDLs contain only 2 physical fragments. * - While the number of Rx PDLs with buffers is less than maximum * a. Get a maximum packet size skb * b. Put the physical address of the buffer into the PDL. * c. Output physical address of PDL to adapter. */static void hp100_rxfill( struct device *dev ){ int ioaddr=dev->base_addr; struct hp100_private *lp = (struct hp100_private *)dev->priv; hp100_ring_t *ringptr;#ifdef HP100_DEBUG_B hp100_outw( 0x4208, TRACE ); printk("hp100: %s: rxfill\n",dev->name);#endif hp100_page( PERFORMANCE ); while (lp->rxrcommit < MAX_RX_PDL) { /* ** Attempt to get a buffer and build a Rx PDL. */ ringptr = lp->rxrtail; if (0 == hp100_build_rx_pdl( ringptr, dev )) { return; /* None available, return */ } /* Hand this PDL over to the card */ /* Note: This needs performance page selected! */#ifdef HP100_DEBUG_BM printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", dev->name, lp->rxrcommit, (u_int)ringptr->pdl, (u_int)ringptr->pdl_paddr, (u_int)ringptr->pdl[3]);#endif hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); lp->rxrcommit += 1; lp->rxrtail = ringptr->next; }}/* * BM_shutdown - shutdown bus mastering and leave chip in reset state */static void hp100_BM_shutdown( struct device *dev ){ int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *)dev->priv; unsigned long time;#ifdef HP100_DEBUG_B hp100_outw( 0x4209, TRACE ); printk("hp100: %s: bm shutdown\n",dev->name);#endif hp100_page( PERFORMANCE ); hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */ /* Ensure Interrupts are off */ hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW ); /* Disable all MAC activity */ hp100_page( MAC_CTRL ); hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ /* If cascade MMU is not already in reset */ if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) ) { /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so * MMU pointers will not be reset out from underneath */ hp100_page( MAC_CTRL ); for(time=0; time<5000; time++) { if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))== (HP100_TX_IDLE|HP100_RX_IDLE) ) break; } /* Shutdown algorithm depends on the generation of Cascade */ if( lp->chip==HP100_CHIPID_LASSEN ) { /* ETR shutdown/reset */ /* Disable Busmaster mode and wait for bit to go to zero. */ hp100_page(HW_MAP); hp100_andb( ~HP100_BM_MASTER, BM ); /* 100 ms timeout */ for(time=0; time<32000; time++) { if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break; } } else { /* Shasta or Rainier Shutdown/Reset */ /* To ensure all bus master inloading activity has ceased, * wait for no Rx PDAs or no Rx packets on card. */ hp100_page( PERFORMANCE ); /* 100 ms timeout */ for(time=0; time<10000; time++) { /* RX_PDL: PDLs not executed. */ /* RX_PKT_CNT: RX'd packets on card. */ if ( (hp100_inb( RX_PDL ) == 0) && (hp100_inb( RX_PKT_CNT ) == 0) ) break; } if(time>=10000) printk("hp100: %s: BM shutdown error.\n", dev->name); /* To ensure all bus master outloading activity has ceased, * wait until the Tx PDA count goes to zero or no more Tx space * available in the Tx region of the card. */ /* 100 ms timeout */ for(time=0; time<10000; time++) { if ( (0 == hp100_inb( TX_PKT_CNT )) && (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break; } /* Disable Busmaster mode */ hp100_page(HW_MAP); hp100_andb( ~HP100_BM_MASTER, BM ); } /* end of shutdown procedure for non-etr parts */ hp100_cascade_reset( dev, TRUE ); } hp100_page( PERFORMANCE ); /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ /* Busmaster mode should be shut down now. */}/* * transmit functions *//* tx function for busmaster mode */static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ){ unsigned long flags; int i, ok_flag; int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *)dev->priv; hp100_ring_t *ringptr;#ifdef HP100_DEBUG_B hp100_outw( 0x4210, TRACE ); printk("hp100: %s: start_xmit_bm\n",dev->name);#endif if ( skb==NULL ) {#ifndef LINUX_2_1 dev_tint( dev );#endif return 0; } if ( skb->len <= 0 ) return 0; /* Get Tx ring tail pointer */ if( lp->txrtail->next==lp->txrhead ) { /* No memory. */#ifdef HP100_DEBUG printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);#endif /* not waited long enough since last tx? */ if ( jiffies - dev->trans_start < HZ ) return -EAGAIN; 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 pkts 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 ( 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 ); } } 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-- ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -