3c59x.c
来自「linux 内核源代码」· C语言 代码 · 共 1,988 行 · 第 1/5 页
C
1,988 行
} for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */ while (i < 0x21) checksum ^= eeprom[i++]; checksum = (checksum ^ (checksum >> 8)) & 0xff; } if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) printk(" %s", print_mac(mac, dev->dev_addr)); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { retval = -EINVAL; printk(KERN_ERR "*** EEPROM MAC address is invalid.\n"); goto free_ring; /* With every pack */ } EL3WINDOW(2); for (i = 0; i < 6; i++) iowrite8(dev->dev_addr[i], ioaddr + i); if (print_info) printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= NR_IRQS) printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); EL3WINDOW(4); step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; if (print_info) { printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); } if (pdev && vci->drv_flags & HAS_CB_FNS) { unsigned short n; vp->cb_fn_base = pci_iomap(pdev, 2, 0); if (!vp->cb_fn_base) { retval = -ENOMEM; goto free_ring; } if (print_info) { printk(KERN_INFO "%s: CardBus functions mapped " "%16.16llx->%p\n", print_name, (unsigned long long)pci_resource_start(pdev, 2), vp->cb_fn_base); } EL3WINDOW(2); n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010; if (vp->drv_flags & INVERT_LED_PWR) n |= 0x10; if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; iowrite16(n, ioaddr + Wn2_ResetOptions); if (vp->drv_flags & WNO_XCVR_PWR) { EL3WINDOW(0); iowrite16(0x0800, ioaddr); } } /* Extract our information from the EEPROM data. */ vp->info1 = eeprom[13]; vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; if (vp->info1 & 0x8000) { vp->full_duplex = 1; if (print_info) printk(KERN_INFO "Full duplex capable\n"); } { static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; unsigned int config; EL3WINDOW(3); vp->available_media = ioread16(ioaddr + Wn3_Options); if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */ vp->available_media = 0x40; config = ioread32(ioaddr + Wn3_Config); if (print_info) { printk(KERN_DEBUG " Internal config register is %4.4x, " "transceivers %#x.\n", config, ioread16(ioaddr + Wn3_Options)); printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << RAM_SIZE(config), RAM_WIDTH(config) ? "word" : "byte", ram_split[RAM_SPLIT(config)], AUTOSELECT(config) ? "autoselect/" : "", XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" : media_tbl[XCVR(config)].name); } vp->default_media = XCVR(config); if (vp->default_media == XCVR_NWAY) vp->has_nway = 1; vp->autoselect = AUTOSELECT(config); } if (vp->media_override != 7) { printk(KERN_INFO "%s: Media override to transceiver type %d (%s).\n", print_name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else dev->if_port = vp->default_media; if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) || dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int phy, phy_idx = 0; EL3WINDOW(4); mii_preamble_required++; if (vp->drv_flags & EXTRA_PREAMBLE) mii_preamble_required++; mdio_sync(ioaddr, 32); mdio_read(dev, 24, MII_BMSR); for (phy = 0; phy < 32 && phy_idx < 1; phy++) { int mii_status, phyx; /* * For the 3c905CX we look at index 24 first, because it bogusly * reports an external PHY at all indices */ if (phy == 0) phyx = 24; else if (phy <= 24) phyx = phy - 1; else phyx = phy; mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; if (print_info) { printk(KERN_INFO " MII transceiver found at address %d," " status %4x.\n", phyx, mii_status); } if ((mii_status & 0x0040) == 0) mii_preamble_required++; } } mii_preamble_required--; if (phy_idx == 0) { printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; mdio_write(dev, vp->phys[0], 4, vp->advertising); } } vp->mii.phy_id = vp->phys[0]; } if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; if (print_info) { printk(KERN_INFO " Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); } vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; vp->bus_master = 0; /* AKPM: vortex only */ } /* The 3c59x-specific entries in the device structure. */ dev->open = vortex_open; if (vp->full_bus_master_tx) { dev->hard_start_xmit = boomerang_start_xmit; /* Actually, it still should work with iommu. */ if (card_idx < MAX_UNITS && ((hw_checksums[card_idx] == -1 && (vp->drv_flags & HAS_HWCKSM)) || hw_checksums[card_idx] == 1)) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; } } else { dev->hard_start_xmit = vortex_start_xmit; } if (print_info) { printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", print_name, (dev->features & NETIF_F_SG) ? "en":"dis", (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); } dev->stop = vortex_close; dev->get_stats = vortex_get_stats;#ifdef CONFIG_PCI dev->do_ioctl = vortex_ioctl;#endif dev->ethtool_ops = &vortex_ethtool_ops; dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000;#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = poll_vortex;#endif if (pdev) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp)); acpi_set_WOL(dev); } retval = register_netdev(dev); if (retval == 0) return 0;free_ring: pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, vp->rx_ring, vp->rx_ring_dma);free_region: if (vp->must_free_region) release_region(dev->base_addr, vci->io_size); free_netdev(dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval);out: return retval;}static voidissue_and_wait(struct net_device *dev, int cmd){ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; int i; iowrite16(cmd, ioaddr + EL3_CMD); for (i = 0; i < 2000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) return; } /* OK, that didn't work. Do it the slow way. One second */ for (i = 0; i < 100000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { if (vortex_debug > 1) printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); return; } udelay(10); } printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", dev->name, cmd, ioread16(ioaddr + EL3_STATUS));}static voidvortex_set_duplex(struct net_device *dev){ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; printk(KERN_INFO "%s: setting %s-duplex.\n", dev->name, (vp->full_duplex) ? "full" : "half"); EL3WINDOW(3); /* Set the full-duplex bit. */ iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl);}static void vortex_check_media(struct net_device *dev, unsigned int init){ struct vortex_private *vp = netdev_priv(dev); unsigned int ok_to_print = 0; if (vortex_debug > 3) ok_to_print = 1; if (mii_check_media(&vp->mii, ok_to_print, init)) { vp->full_duplex = vp->mii.full_duplex; vortex_set_duplex(dev); } else if (init) { vortex_set_duplex(dev); }}static intvortex_up(struct net_device *dev){ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned int config; int i, mii_reg1, mii_reg5, err = 0; if (VORTEX_PCI(vp)) { pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ if (vp->pm_state_valid) pci_restore_state(VORTEX_PCI(vp)); err = pci_enable_device(VORTEX_PCI(vp)); if (err) { printk(KERN_WARNING "%s: Could not enable device \n", dev->name); goto err_out; } } /* Before initializing select the active media port. */ EL3WINDOW(3); config = ioread32(ioaddr + Wn3_Config); if (vp->media_override != 7) { printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { if (vp->has_nway) { if (vortex_debug > 1) printk(KERN_INFO "%s: using NWAY device table, not %d\n", dev->name, dev->if_port); dev->if_port = XCVR_NWAY; } else { /* Find first available media type, starting with 100baseTx. */ dev->if_port = XCVR_100baseTx; while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; if (vortex_debug > 1) printk(KERN_INFO "%s: first available media type: %s\n", dev->name, media_tbl[dev->if_port].name); } } else { dev->if_port = vp->default_media; if (vortex_debug > 1) printk(KERN_INFO "%s: using default media %s\n", dev->name, media_tbl[dev->if_port].name); } init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); vp->timer.data = (unsigned long)dev; vp->timer.function = vortex_timer; /* timer handler */ add_timer(&vp->timer); init_timer(&vp->rx_oom_timer); vp->rx_oom_timer.data = (unsigned long)dev; vp->rx_oom_timer.function = rx_oom_timer; if (vortex_debug > 1) printk(KERN_DEBUG "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); vp->full_duplex = vp->mii.force_media; config = BFINS(config, dev->if_port, 20, 4); if (vortex_debug > 6) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { EL3WINDOW(4); mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR); mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); vp->mii.full_duplex = vp->full_duplex; vortex_check_media(dev, 1); } else vortex_set_duplex(dev); issue_and_wait(dev, TxReset); /* * Don't reset the PHY - that upsets autonegotiation during DHCP operations. */ issue_and_wait(dev, RxReset|0x04); iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); if (vortex_debug > 1) { EL3WINDOW(4); printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", dev->name, dev->irq, ioread16(ioaddr + Wn4_Media)); } /* Set the station address and mask in window 2 each time opened. */ EL3WINDOW(2); for (i = 0; i < 6; i++) iowrite8(dev->dev_addr[i], ioaddr + i); for (; i < 12; i+=2) iowrite16(0, ioaddr + i);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?