hp100.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,162 行 · 第 1/5 页
C
2,162 行
* 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, 1); } hp100_page(PERFORMANCE); /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ /* Busmaster mode should be shut down now. */}static int hp100_check_lan(struct net_device *dev){ struct hp100_private *lp = (struct hp100_private *) dev->priv; 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, 0); /* relogin */ hp100_start_interface(dev); } return 0;}/* * 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; if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) { skb = skb_padto(skb, ETH_ZLEN); if (skb == NULL) 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 (hp100_check_lan(dev)) return -EIO; 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, 0); 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 settings 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, 0); 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, 0); 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 */ 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 */ } /* Conversion to new PCI API : map skbuf data to PCI bus. * Doc says it's OK for EISA as well - Jean II */ ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE)); /* 1st Frag: Adr. of data */ /* 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 /* Conversion to new PCI API : NOP */ pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE); 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 (hp100_check_lan(dev)) return -EIO; /* 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, 0); 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, 0); 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, 0); 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 } spin_lock_irqsave(&lp->lock, flags); 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_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); if (!ok_flag) memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); } else { /* Note: The J2585B needs alignment to 32bits here! */ isa_memcpy_toio(lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3); if (!ok_flag) isa_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++; lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; hp100_ints_on();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?