hp100.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,162 行 · 第 1/5 页
C
2,162 行
spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb_any(skb);#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 net_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 transferred 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 = readl(lp->mem_ptr_virt); else header = isa_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+2); 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_reserve(skb,2); skb->dev = dev; /* ptr to start of the sk_buff data area */ skb_put(skb, pkt_len); ptr = skb->data; /* Now transfer the data from the card into that area */ if (lp->mode == 2) { if (lp->mem_ptr_virt) memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len); /* Note alignment to 32bit transfers */ else isa_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);#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 netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } /* 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 net_device *dev){ int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *) dev->priv; hp100_ring_t *ptr; u_int header; int pkt_len;#ifdef HP100_DEBUG_B hp100_outw(0x4214, TRACE); printk("hp100: %s: rx_bm\n", dev->name);#endif#ifdef HP100_DEBUG if (0 == lp->rxrcommit) { printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name); return; } else /* RX_PKT_CNT states how many PDLs are currently formatted and available to * the cards BM engine */ if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", dev->name, hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit); return; }#endif while ((lp->rxrcommit > hp100_inb(RX_PDL))) { /* * The packet was received into the pdl pointed to by lp->rxrhead ( * the oldest pdl in the ring */ /* First we get the header, which contains information about the */ /* actual length of the received packet. */ ptr = lp->rxrhead; header = *(ptr->pdl - 1); pkt_len = (header & HP100_PKT_LEN_MASK); /* Conversion to new PCI API : NOP */ pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);#ifdef HP100_DEBUG_BM printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", dev->name, (u_int) (ptr->pdl - 1), (u_int) header, pkt_len, (header >> 16) & 0xfff8, (header >> 16) & 7); printk("hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", dev->name, hp100_inb(RX_PDL), hp100_inb(TX_PDL), hp100_inb(RX_PKT_CNT), (u_int) * (ptr->pdl), (u_int) * (ptr->pdl + 3), (u_int) * (ptr->pdl + 4));#endif if ((pkt_len >= MIN_ETHER_SIZE) && (pkt_len <= MAX_ETHER_SIZE)) { if (ptr->skb == NULL) { printk("hp100: %s: rx_bm: skb null\n", dev->name); /* can happen if we only allocated room for the pdh due to memory shortage. */ lp->stats.rx_dropped++; } else { skb_trim(ptr->skb, pkt_len); /* Shorten it */ ptr->skb->protocol = eth_type_trans(ptr->skb, dev); netif_rx(ptr->skb); /* Up and away... */ dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } switch (header & 0x00070000) { case (HP100_MULTI_ADDR_HASH << 16): case (HP100_MULTI_ADDR_NO_HASH << 16): lp->stats.multicast++; break; } } else {#ifdef HP100_DEBUG printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n", dev->name, pkt_len);#endif if (ptr->skb != NULL) dev_kfree_skb_any(ptr->skb); lp->stats.rx_errors++; } lp->rxrhead = lp->rxrhead->next; /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { /* No space for skb, header can still be received. */#ifdef HP100_DEBUG printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name);#endif return; } else { /* successfully allocated new PDL - put it in ringlist at tail. */ hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); lp->rxrtail = lp->rxrtail->next; } }}/* * statistics */static struct net_device_stats *hp100_get_stats(struct net_device *dev){ unsigned long flags; int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *) dev->priv;#ifdef HP100_DEBUG_B hp100_outw(0x4215, TRACE);#endif spin_lock_irqsave(&lp->lock, flags); hp100_ints_off(); /* Useful ? Jean II */ hp100_update_stats(dev); hp100_ints_on(); spin_unlock_irqrestore(&lp->lock, flags); return &(lp->stats);}static void hp100_update_stats(struct net_device *dev){ int ioaddr = dev->base_addr; u_short val; struct hp100_private *lp = (struct hp100_private *) dev->priv;#ifdef HP100_DEBUG_B hp100_outw(0x4216, TRACE); printk("hp100: %s: update-stats\n", dev->name);#endif /* Note: Statistics counters clear when read. */ hp100_page(MAC_CTRL); val = hp100_inw(DROPPED) & 0x0fff; lp->stats.rx_errors += val; lp->stats.rx_over_errors += val; val = hp100_inb(CRC); lp->stats.rx_errors += val; lp->stats.rx_crc_errors += val; val = hp100_inb(ABORT); lp->stats.tx_errors += val; lp->stats.tx_aborted_errors += val; hp100_page(PERFORMANCE);}static void hp100_misc_interrupt(struct net_device *dev){#ifdef HP100_DEBUG_B int ioaddr = dev->base_addr;#endif struct hp100_private *lp = (struct hp100_private *) dev->priv;#ifdef HP100_DEBUG_B int ioaddr = dev->base_addr; hp100_outw(0x4216, TRACE); printk("hp100: %s: misc_interrupt\n", dev->name);#endif /* Note: Statistics counters clear when read. */ lp->stats.rx_errors++; lp->stats.tx_errors++;}static void hp100_clear_stats(struct hp100_private *lp, int ioaddr){ unsigned long flags;#ifdef HP100_DEBUG_B hp100_outw(0x4217, TRACE); printk("hp100: %s: clear_stats\n", dev->name);#endif spin_lock_irqsave(&lp->lock, flags); hp100_page(MAC_CTRL); /* get all statistics bytes */ hp100_inw(DROPPED); hp100_inb(CRC); hp100_inb(ABORT); hp100_page(PERFORMANCE); spin_unlock_irqrestore(&lp->lock, flags);}/* * multicast setup *//* * Set or clear the multicast filter for this adapter. */static void hp100_set_multicast_list(struct net_device *dev){ unsigned long flags; int ioaddr = dev->base_addr; struct hp100_private *lp = (struct hp100_private *) dev->priv;#ifdef HP100_DEBUG_B hp100_outw(0x4218, TRACE); printk("hp100: %s: set_mc_list\n", dev->name);#endif spin_lock_irqsave(&lp->lock, flags); hp100_ints_off(); hp100_page(MAC_CTRL); hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ if (dev->flags & IFF_PROMISC) { lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ memset(&lp->hash_bytes, 0xff, 8); } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ if (dev->flags & IFF_ALLMULTI) { /* set hash filter to receive all multicast packets */ memset(&lp->hash_bytes, 0xff, 8); } else { int i, j, idx; u_char *addrs; struct dev_mc_list *dmi; memset(&lp->hash_bytes, 0x00, 8);#ifdef HP100_DEBUG printk("hp100: %s: computing hash filter - mc_count = %i\n", dev->name, dev->mc_count);#endif for (i = 0, dmi = dev->mc_list; i < dev->mc_count; i++, dmi = dmi->next) { addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */#ifdef HP100_DEBUG printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ", dev->name, addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5]);#endif for (j = idx = 0; j < 6; j++) { idx ^= *addrs++ & 0x3f; printk(":%02x:", idx); }#ifdef HP100_DEBUG printk("idx = %i\n", idx);#endif lp->hash_bytes[idx >> 3] |= (1 << (idx & 7)); } } }#else memset(&lp->hash_bytes, 0xff, 8);#endif } else { lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ memset(&lp->hash_bytes, 0x00, 8); } if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { int i; hp100_outb(lp->mac2_mode, MAC_CFG_2); hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ hp100_page(MAC_ADDRESS); for (i = 0; i < 8; i++) hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i);#ifdef HP100_DEBUG printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, lp->mac1_mode, lp->mac2_mode, lp->hash_bytes[0], lp->hash_bytes[1], lp->hash_bytes[2], lp->hash_bytes[3], lp->hash_bytes[4], lp->hash_bytes[5], lp->hash_bytes[6], lp->hash_bytes[7]);#endif if (lp->lan_type == HP100_LAN_100) {#ifdef HP100_DEBUG printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name);#endif lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */ } } else { int i; u_char old_hash_bytes[8]; hp100_page(MAC_ADDRESS); for (i = 0; i < 8; i++) old_hash_bytes[i] = hp100_inb(HASH_BYTE0 + i); if (memcmp(old_hash_bytes, &lp->hash_bytes, 8)) { for (i = 0; i < 8; i++) hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i);#ifdef HP100_DEBUG printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, lp->hash_bytes[0
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?