📄 8139too.c
字号:
assert (ioaddr != NULL); addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; dev->poll = rtl8139_poll; dev->weight = 64; dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; dev->do_ioctl = netdev_ioctl; dev->ethtool_ops = &rtl8139_ethtool_ops; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT;#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = rtl8139_poll_controller;#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these * features */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; dev->irq = pdev->irq; /* tp zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); /* note: tp->chipset set in rtl8139_init_board */ tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->mmio_addr = ioaddr; tp->msg_enable = (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); spin_lock_init (&tp->rx_lock); INIT_DELAYED_WORK(&tp->thread, rtl8139_thread); tp->mii.dev = dev; tp->mii.mdio_read = mdio_read; tp->mii.mdio_write = mdio_write; tp->mii.phy_id_mask = 0x3f; tp->mii.reg_num_mask = 0x1f; /* dev is fully set up and ready to use now */ DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); i = register_netdev (dev); if (i) goto err_out; pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes too much time. */#ifdef CONFIG_8139TOO_8129 if (tp->drv_flags & HAS_MII_XCVR) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { u16 advertising = mdio_read(dev, phy, 4); tp->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " "advertising %4.4x.\n", dev->name, phy, mii_status, advertising); } } if (phy_idx == 0) { printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " "transceiver.\n", dev->name); tp->phys[0] = 32; } } else#endif tp->phys[0] = 32; tp->mii.phy_id = tp->phys[0]; /* The lower four bits are the media type. */ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { tp->mii.full_duplex = (option & 0x210) ? 1 : 0; tp->default_port = option & 0xFF; if (tp->default_port) tp->mii.force_media = 1; } if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) tp->mii.full_duplex = full_duplex[board_idx]; if (tp->mii.full_duplex) { printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); /* Changing the MII-advertised media because might prevent re-connection. */ tp->mii.force_media = 1; } if (tp->default_port) { printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); mdio_write(dev, tp->phys[0], 0, ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } /* Put the chip into low-power mode. */ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ return 0;err_out: __rtl8139_cleanup_dev (dev); pci_disable_device (pdev); return i;}static void __devexit rtl8139_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata (pdev); assert (dev != NULL); flush_scheduled_work(); unregister_netdev (dev); __rtl8139_cleanup_dev (dev); pci_disable_device (pdev);}/* Serial EEPROM section. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x08 /* EEPROM chip select. */#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */#define EE_WRITE_0 0x00#define EE_WRITE_1 0x02#define EE_DATA_READ 0x01 /* EEPROM chip data out. */#define EE_ENB (0x80 | EE_CS)/* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay() (void)RTL_R32(Cfg9346)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5)#define EE_READ_CMD (6)#define EE_ERASE_CMD (7)static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len){ int i; unsigned retval = 0; int read_cmd = location | (EE_READ_CMD << addr_len); RTL_W8 (Cfg9346, EE_ENB & ~EE_CS); RTL_W8 (Cfg9346, EE_ENB); eeprom_delay (); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; RTL_W8 (Cfg9346, EE_ENB | dataval); eeprom_delay (); RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK); eeprom_delay (); } RTL_W8 (Cfg9346, EE_ENB); eeprom_delay (); for (i = 16; i > 0; i--) { RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK); eeprom_delay (); retval = (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 : 0); RTL_W8 (Cfg9346, EE_ENB); eeprom_delay (); } /* Terminate the EEPROM access. */ RTL_W8 (Cfg9346, ~EE_CS); eeprom_delay (); return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated serial MDIO protocol. The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues. */#define MDIO_DIR 0x80#define MDIO_DATA_OUT 0x04#define MDIO_DATA_IN 0x02#define MDIO_CLK 0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay() RTL_R8(Config4)static const char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, 0, NWayAdvert, NWayLPAR, NWayExpansion, 0};#ifdef CONFIG_8139TOO_8129/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync (void __iomem *ioaddr){ int i; for (i = 32; i >= 0; i--) { RTL_W8 (Config4, MDIO_WRITE1); mdio_delay (); RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK); mdio_delay (); }}#endifstatic int mdio_read (struct net_device *dev, int phy_id, int location){ struct rtl8139_private *tp = netdev_priv(dev); int retval = 0;#ifdef CONFIG_8139TOO_8129 void __iomem *ioaddr = tp->mmio_addr; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i;#endif if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void __iomem *ioaddr = tp->mmio_addr; return location < 8 && mii_2_8139_map[location] ? RTL_R16 (mii_2_8139_map[location]) : 0; }#ifdef CONFIG_8139TOO_8129 mdio_sync (ioaddr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; RTL_W8 (Config4, MDIO_DIR | dataval); mdio_delay (); RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK); mdio_delay (); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { RTL_W8 (Config4, 0); mdio_delay (); retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0); RTL_W8 (Config4, MDIO_CLK); mdio_delay (); }#endif return (retval >> 1) & 0xffff;}static void mdio_write (struct net_device *dev, int phy_id, int location, int value){ struct rtl8139_private *tp = netdev_priv(dev);#ifdef CONFIG_8139TOO_8129 void __iomem *ioaddr = tp->mmio_addr; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i;#endif if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void __iomem *ioaddr = tp->mmio_addr; if (location == 0) { RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W16 (BasicModeCtrl, value); RTL_W8 (Cfg9346, Cfg9346_Lock); } else if (location < 8 && mii_2_8139_map[location]) RTL_W16 (mii_2_8139_map[location], value); return; }#ifdef CONFIG_8139TOO_8129 mdio_sync (ioaddr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; RTL_W8 (Config4, dataval); mdio_delay (); RTL_W8 (Config4, dataval | MDIO_CLK); mdio_delay (); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { RTL_W8 (Config4, 0); mdio_delay (); RTL_W8 (Config4, MDIO_CLK); mdio_delay (); }#endif}static int rtl8139_open (struct net_device *dev){ struct rtl8139_private *tp = netdev_priv(dev); int retval; void __iomem *ioaddr = tp->mmio_addr; retval = request_irq (dev->irq, rtl8139_interrupt, IRQF_SHARED, dev->name, dev); if (retval) return retval; tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, &tp->tx_bufs_dma); tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, &tp->rx_ring_dma); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { free_irq(dev->irq, dev); if (tp->tx_bufs) pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, tp->tx_bufs, tp->tx_bufs_dma); if (tp->rx_ring) pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); return -ENOMEM; } tp->mii.full_duplex = tp->mii.force_media; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; rtl8139_init_ring (dev); rtl8139_hw_start (dev); netif_start_queue (dev); if (netif_msg_ifup(tp)) printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, (unsigned long long)pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), tp->mii.full_duplex ? "full" : "half"); rtl8139_start_thread(tp); return 0;}static void rtl_check_media (struct net_device *dev, unsigned int init_media){ struct rtl8139_private *tp = netdev_priv(dev); if (tp->phys[0] >= 0) { mii_check_media(&tp->mii, netif_msg_link(tp), init_media); }}/* Start the hardware at open or resume. */static void rtl8139_hw_start (struct net_device *dev){ struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; u32 i; u8 tmp; /* Bring old chips out of low-power mode. */ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'R'); rtl8139_chip_reset (ioaddr); /* unlock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); /* Must enable Tx/Rx before setting transfer thresholds! */ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; RTL_W32 (RxConfig, tp->rx_config); RTL_W32 (TxConfig, rtl8139_tx_config); tp->cur_rx = 0; rtl_check_media (dev, 1); if (tp->chipset >= CH_8139B) { /* Disable magic packet scanning, which is enabled * when PM is enabled in Config1. It can be reenabled * via ETHTOOL_SWOL if desired. */ RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic); } DPRINTK("init buffer addresses\n"); /* Lock Config[01234] and BMCR register writes */ RTL_W8 (Cfg9346, Cfg9346_Lock); /* init Rx ring buffer DMA address */ RTL_W32_F (RxBuf, tp->rx_ring_dma); /* init Tx buffer DMA addresses */ for (i = 0; i < NUM_TX_DESC; i++) RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); RTL_W32 (RxMissed, 0); rtl8139_set_rx_mode (dev); /* no early-rx interrupts */ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); /* make sure RxTx has started */ tmp = RTL_R8 (ChipCmd); if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb))) RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rtl8139_init_ring (struct net_device *dev){ struct rtl8139_private *tp = netdev_priv(dev); int i; tp->cur_rx = 0; tp->cur_tx = 0; tp->dirty_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];}/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */static int next_tick = 3 * HZ;#ifndef CONFIG_8139TOO_TUNE_TWISTERstatic inline void rtl8139_tune_twister (struct net_device *dev, struct rtl8139_private *tp) {}#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -