📄 tulip_core.c
字号:
u16 *data = (u16 *)&rq->ifr_data; int phy = tp->phys[0] & 0x1f; long flags; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; else if (tp->flags & HAS_NWAY) data[0] = 32; else if (tp->chip_id == COMET) data[0] = 1; else return -ENODEV; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ if (data[0] == 32 && (tp->flags & HAS_NWAY)) { int csr12 = inl(ioaddr + CSR12); int csr14 = inl(ioaddr + CSR14); switch (data[1]) { case 0: { data[3] = (csr14<<5) & 0x1000; break; } case 1: data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + (csr12&0x06 ? 0x04 : 0); break; case 4: { data[3] = ((csr14>>9)&0x07C0) + ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; break; } case 5: data[3] = csr12 >> 16; break; default: data[3] = 0; break; } } else { spin_lock_irqsave (&tp->lock, flags); data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); spin_unlock_irqrestore (&tp->lock, flags); } return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (data[0] == 32 && (tp->flags & HAS_NWAY)) { if (data[1] == 5) tp->to_advertise = data[2]; } else { spin_lock_irqsave (&tp->lock, flags); tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); spin_unlock_irqrestore(&tp->lock, flags); } return 0; default: return -EOPNOTSUPP; } return -EOPNOTSUPP;}/* Set or clear the multicast filter for this adaptor. Note that we only use exclusion around actually queueing the new frame, not around filling tp->setup_frame. This is non-deterministic when re-entered but still correct. *//* The little-endian AUTODIN32 ethernet CRC calculation. N.B. Do not use for bulk data, use a table-based routine instead. This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline u32 ether_crc_le(int length, unsigned char *data){ u32 crc = 0xffffffff; /* Initial value. */ while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 8; --bit >= 0; current_octet >>= 1) { if ((crc ^ current_octet) & 1) { crc >>= 1; crc ^= ethernet_polynomial_le; } else crc >>= 1; } } return crc;}static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){ int crc = -1; while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } return crc;}#undef set_bit_le#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; u16 hash_table[32]; struct dev_mc_list *mclist; int i; u16 *eaddrs; memset(hash_table, 0, sizeof(hash_table)); set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff; set_bit_le(index, hash_table); for (i = 0; i < 32; i++) { *setup_frm++ = hash_table[i]; *setup_frm++ = hash_table[i]; } setup_frm = &tp->setup_frame[13*6]; } /* Fill the final entry with our physical address. */ eaddrs = (u16 *)dev->dev_addr; *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];}static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; struct dev_mc_list *mclist; int i; u16 *eaddrs; /* We have <= 14 addresses so we can use the wonderful 16 address perfect filtering of the Tulip. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; } /* Fill the unused entries with the broadcast address. */ memset(setup_frm, 0xff, (15-i)*12); setup_frm = &tp->setup_frame[15*6]; /* Fill the final entry with our physical address. */ eaddrs = (u16 *)dev->dev_addr; *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];}static void set_rx_mode(struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int csr6; DPRINTK("ENTER\n"); csr6 = inl(ioaddr + CSR6) & ~0x00D5; tp->csr6 &= ~0x00D5; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ tp->csr6 |= 0x00C0; csr6 |= 0x00C0; /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= 0x0080; csr6 |= 0x0080; } else if (tp->flags & MC_HASH_ONLY) { /* Some work-alikes have only a 64-entry hash filter table. */ /* Should verify correctness on big-endian/__powerpc__ */ struct dev_mc_list *mclist; int i; u32 mc_filter[2]; /* Multicast hash filter */ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ tp->csr6 |= 0x0080; csr6 |= 0x0080; } else { mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); if (tp->chip_id == AX88140) { outl(2, ioaddr + CSR13); outl(mc_filter[0], ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(mc_filter[1], ioaddr + CSR14); } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ outl(mc_filter[0], ioaddr + 0xAC); outl(mc_filter[1], ioaddr + 0xB0); } } } else { unsigned long flags; /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ if (dev->mc_count > 14) { /* Must use a multicast hash table. */ build_setup_frame_hash(tp->setup_frame, dev); } else { build_setup_frame_perfect(tp->setup_frame, dev); } spin_lock_irqsave(&tp->lock, flags); if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { /* Same setup recently queued, we need not add it. */ } else { u32 tx_flags = 0x08000000 | 192; unsigned int entry; int dummy = -1; /* Now add this frame to the Tx list. */ entry = tp->cur_tx++ % TX_RING_SIZE; if (entry != 0) { /* Avoid a chip errata by prefixing a dummy entry. */ tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; tp->tx_ring[entry].length = (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; tp->tx_ring[entry].buffer1 = 0; /* Must set DescOwned later to avoid race with chip */ dummy = entry; entry = tp->cur_tx++ % TX_RING_SIZE; } tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = pci_map_single(tp->pdev, tp->setup_frame, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); /* Put the setup frame on the Tx list. */ if (entry == TX_RING_SIZE-1) tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ tp->tx_ring[entry].length = cpu_to_le32(tx_flags); tp->tx_ring[entry].buffer1 = cpu_to_le32(tp->tx_buffers[entry].mapping); tp->tx_ring[entry].status = cpu_to_le32(DescOwned); if (dummy >= 0) tp->tx_ring[dummy].status = cpu_to_le32(DescOwned); if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) netif_stop_queue(dev); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); } spin_unlock_irqrestore(&tp->lock, flags); } /* Can someone explain to me what the OR here is supposed to accomplish???? */ tulip_outl_csr(tp, csr6 | 0x0000, CSR6);}static int __devinit tulip_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ static int did_version; /* Already printed version info. */ struct tulip_private *tp; /* See note below on the multiport cards. */ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; static int last_irq; static int multiport_cnt; /* For four-port boards w/one EEPROM */ u8 chip_rev; int i, irq; unsigned short sum; u8 ee_data[EEPROM_SIZE]; struct net_device *dev; long ioaddr; static int board_idx = -1; int chip_idx = ent->driver_data; board_idx++; if (tulip_debug > 0 && did_version++ == 0) printk (KERN_INFO "%s", version); /* * Lan media wire a tulip chip to a wan interface. Needs a very * different driver (lmc driver) */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } /* * Early DM9100's need software CRC and the DMFE driver */ if (pdev->vendor == 0x1282 && pdev->device == 0x9100) { u32 dev_rev; /* Read Chip revision */ pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); if(dev_rev < 0x02000030) { printk(KERN_ERR PFX "skipping early DM9100 with Crc bug (use dmfe)\n"); return -ENODEV; } } /* * Looks for early PCI chipsets where people report hangs * without the workarounds being on. */ /* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned Aries might need this too. The Saturn errata are not pretty reading but thankfully its an old 486 chipset. */ if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) csr0 = 0x00A04800; /* The dreaded SiS496 486 chipset. Same workaround as above. */ if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) csr0 = 0x00A04800; /* * And back to business */ i = pci_enable_device(pdev); if (i) { printk (KERN_ERR PFX "Cannot enable tulip board #%d, aborting\n", board_idx); return i; } ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; /* init_etherdev ensures aligned and zeroed private structures */ dev = init_etherdev (NULL, sizeof (*tp)); if (!dev) { printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); return -ENOMEM; } if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, " "aborting\n", dev->name, pci_resource_len (pdev, 0), pci_resource_start (pdev, 0)); goto err_out_free_netdev; } /* grab all resources from both PIO and MMIO regions, as we * don't want anyone else messing around with our hardware */ if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), dev->name)) { printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) unavailable, " "aborting\n", dev->name, pci_resource_len (pdev, 0), pci_resource_start (pdev, 0)); goto err_out_free_netdev; } if (!request_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1), dev->name)) { printk (KERN_ERR PFX "%s: MMIO region (0x%lx@0x%lx) unavailable, " "aborting\n", dev->name, pci_resource_len (pdev, 1), pci_resource_start (pdev, 1)); goto err_out_free_pio_res; } pci_set_master(pdev); pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); /* * initialize priviate data structure 'tp' * it is zeroed and aligned in init_etherdev */ tp = dev->priv; tp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct tulip_rx_desc) * RX_RING_SIZE + sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -