📄 hp100.c
字号:
*/static int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct net_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 net_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 net_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 net_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) { 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 { spin_lock_irqsave(&lp->lock, flags); hp100_ints_off(); /* Useful ? Jean II */ i = hp100_sense_lan(dev); hp100_ints_on(); spin_unlock_irqrestore(&lp->lock, flags); 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 */ spin_lock_irqsave(&lp->lock, flags); 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++; spin_unlock_irqrestore(&lp->lock, flags); /* Update statistics */ lp->stats.tx_packets++; lp->stats.tx_bytes += skb->len; 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 net_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 dev_kfree_skb_any(lp->txrhead->skb); 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 net_device *dev){ unsigned long flags; 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) { 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 { spin_lock_irqsave(&lp->lock, flags); hp100_ints_off(); /* Useful ? Jean II */ i = hp100_sense_lan(dev); hp100_ints_on(); spin_unlock_irqrestore(&lp->lock, flags); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -