📄 hp100.c
字号:
hp100_stop_interface( dev ); hp100_hwinit( dev ); hp100_start_interface( dev ); /* sets mac modes, enables interrupts */ return 0;}/* The close function is called when the interface is to be brought down */static int hp100_close( struct device *dev ){ int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *)dev->priv;#ifdef HP100_DEBUG_B hp100_outw( 0x4205, TRACE ); printk("hp100: %s: close\n", dev->name);#endif hp100_page( PERFORMANCE ); hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ hp100_stop_interface( dev ); if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); dev->tbusy = 1; dev->start = 0; free_irq( dev->irq, dev );#ifdef HP100_DEBUG printk( "hp100: %s: close LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) );#endif MOD_DEC_USE_COUNT; return 0;}/* * Configure the PDL Rx rings and LAN */static void hp100_init_pdls( struct device *dev ){ struct hp100_private *lp = (struct hp100_private *)dev->priv; hp100_ring_t *ringptr; u_int *pageptr; int i;#ifdef HP100_DEBUG_B int ioaddr = dev->base_addr;#endif#ifdef HP100_DEBUG_B hp100_outw( 0x4206, TRACE ); printk("hp100: %s: init pdls\n", dev->name);#endif if(0==lp->page_vaddr_algn) printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n",dev->name); else { /* pageptr shall point into the DMA accessible memory region */ /* we use this pointer to status the upper limit of allocated */ /* memory in the allocated page. */ /* note: align the pointers to the pci cache line size */ memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ pageptr=lp->page_vaddr_algn; lp->rxrcommit =0; ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]); /* Initialise Rx Ring */ for (i=MAX_RX_PDL-1; i>=0; i--) { lp->rxring[i].next = ringptr; ringptr=&(lp->rxring[i]); pageptr+=hp100_init_rxpdl(dev, ringptr, pageptr); } /* Initialise Tx Ring */ lp->txrcommit = 0; ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); for (i=MAX_TX_PDL-1; i>=0; i--) { lp->txring[i].next = ringptr; ringptr=&(lp->txring[i]); pageptr+=hp100_init_txpdl(dev, ringptr, pageptr); } }}/* These functions "format" the entries in the pdl structure *//* They return how much memory the fragments need. */static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ){ /* pdlptr is starting address for this pdl */ if( 0!=( ((unsigned)pdlptr) & 0xf) ) printk("hp100: %s: Init rxpdl: 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; /* * 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -