📄 sundance.c
字号:
};#define PRIV_ALIGN 15 /* Required alignment mask *//* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment within the structure. */struct netdev_private { /* Descriptor rings first for alignment. */ struct netdev_desc rx_ring[RX_RING_SIZE]; struct netdev_desc tx_ring[TX_RING_SIZE]; struct net_device *next_module; /* Link for devices of this type. */ void *priv_addr; /* Unaligned address for kfree */ const char *product_name; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ int msg_level; int chip_id, drv_flags; struct pci_dev *pci_dev; int max_interrupt_work; /* Note: Group variables for cache line effect. */ struct netdev_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ int rx_copybreak; spinlock_t txlock; /* Group with Tx control cache line. */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */ unsigned int cur_tx, dirty_tx; unsigned int tx_full:1; /* The Tx queue is full. */ /* These values keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port; /* Last dev->if_port value. */ /* Multicast and receive mode. */ spinlock_t mcastlock; /* SMP lock multicast updates. */ u16 mcast_filter[4]; int multicast_filter_limit; /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ int link_status; u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */};/* The station address location in the EEPROM. */#define EEPROM_SA_OFFSET 0x10static int eeprom_read(long ioaddr, int location);static int mdio_read(struct net_device *dev, int phy_id, unsigned int location);static void mdio_write(struct net_device *dev, int phy_id, unsigned int location, int value);static int netdev_open(struct net_device *dev);static void sundance_start(struct net_device *dev);static int change_mtu(struct net_device *dev, int new_mtu);static void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static void init_ring(struct net_device *dev);static int start_tx(struct sk_buff *skb, struct net_device *dev);static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);static void netdev_error(struct net_device *dev, int intr_status);static int netdev_rx(struct net_device *dev);static void netdev_error(struct net_device *dev, int intr_status);static void set_rx_mode(struct net_device *dev);static struct net_device_stats *get_stats(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int netdev_close(struct net_device *dev);/* A list of our installed devices, for removing the driver module. */static struct net_device *root_net_dev = NULL;#ifndef MODULEint sundance_probe(struct net_device *dev){ if (pci_drv_register(&sundance_drv_id, dev) < 0) return -ENODEV; if (debug >= NETIF_MSG_DRV) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); return 0;}#endifstatic void *sundance_probe1(struct pci_dev *pdev, void *init_dev, long ioaddr, int irq, int chip_idx, int card_idx){ struct net_device *dev; struct netdev_private *np; void *priv_mem; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; dev = init_etherdev(init_dev, 0); if (!dev) return NULL; /* Perhaps NETIF_MSG_PROBE */ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); /* Make certain elements e.g. descriptor lists are aligned. */ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL); /* Check for the very unlikely case of no memory. */ if (priv_mem == NULL) return NULL; /* All failure checks before this point. We do a request_region() only to register /proc/ioports info. */#ifdef USE_IO_OPS request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);#endif dev->base_addr = ioaddr; dev->irq = irq; dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); memset(np, 0, sizeof(*np)); np->priv_addr = priv_mem; np->next_module = root_net_dev; root_net_dev = dev; np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->msg_level = (1 << debug) - 1; np->rx_copybreak = rx_copybreak; np->max_interrupt_work = max_interrupt_work; np->multicast_filter_limit = multicast_filter_limit; if (dev->mem_start) option = dev->mem_start; if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->full_duplex = 1; if (np->full_duplex) np->medialock = 1; /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; dev->change_mtu = &change_mtu; if (1) { int phy, phy_idx = 0; np->phys[0] = 1; /* Default setting */ mii_preamble_required++; for (phy = 1; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(dev, phy, 4); if ((mii_status & 0x0040) == 0) mii_preamble_required++; if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x advertising %4.4x.\n", dev->name, phy, mii_status, np->advertising); } } mii_preamble_required--; np->mii_cnt = phy_idx; if (phy_idx == 0) printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", dev->name, (int)readl(ioaddr + ASICCtrl)); } /* Allow forcing the media type. */ if (option > 0) { if (option & 0x220) np->full_duplex = 1; np->default_port = option & 0x3ff; if (np->default_port & 0x330) { np->medialock = 1; if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x300 ? 100 : 10), (np->full_duplex ? "full" : "half")); if (np->mii_cnt) mdio_write(dev, np->phys[0], 0, ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */ } } /* Reset the chip to erase previous misconfiguration. */ if (np->msg_level & NETIF_MSG_MISC) printk("ASIC Control is %x.\n", (int)readl(ioaddr + ASICCtrl)); writel(0x007f0000 | readl(ioaddr + ASICCtrl), ioaddr + ASICCtrl); if (np->msg_level & NETIF_MSG_MISC) printk("ASIC Control is now %x.\n", (int)readl(ioaddr + ASICCtrl)); return dev;}static int change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > 8191)) /* Limited by RxDMAFrameLen */ return -EINVAL; if (netif_running(dev)) return -EBUSY; dev->mtu = new_mtu; return 0;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */static int eeprom_read(long ioaddr, int location){ int boguscnt = 2000; /* Typical 190 ticks. */ writew(0x0200 | (location & 0xff), ioaddr + EECtrl); do { if (! (readw(ioaddr + EECtrl) & 0x8000)) { return readw(ioaddr + EEData); } } while (--boguscnt > 0); return 0;}/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. The maximum data clock rate is 2.5 Mhz. The timing is decoupled from the processor clock by flushing the write from the CPU write buffer with a following read, and using PCI transaction time. */#define mdio_in(mdio_addr) readb(mdio_addr)#define mdio_out(value, mdio_addr) writeb(value, mdio_addr)#define mdio_delay(mdio_addr) readb(mdio_addr)enum mii_reg_bits { MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,};#define MDIO_EnbIn (0)#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and a few older transceivers. */static void mdio_sync(long mdio_addr){ int bits = 32; /* Establish sync by sending at least 32 logic ones. */ while (--bits >= 0) { mdio_out(MDIO_WRITE1, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); }}static int mdio_read(struct net_device *dev, int phy_id, unsigned int location){ long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; if (mii_preamble_required) mdio_sync(mdio_addr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; mdio_out(dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { mdio_out(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) ? 1 : 0); mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, unsigned int location, int value){ long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; if (mii_preamble_required) mdio_sync(mdio_addr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; mdio_out(dataval, mdio_addr); mdio_delay(mdio_addr); mdio_out(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { mdio_out(MDIO_EnbIn, mdio_addr); mdio_delay(mdio_addr); mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(mdio_addr); } return;}static int netdev_open(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; MOD_INC_USE_COUNT; if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { MOD_DEC_USE_COUNT; return -EAGAIN; } if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); init_ring(dev); if (dev->if_port == 0) dev->if_port = np->default_port; np->full_duplex = np->duplex_lock; np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED; sundance_start(dev); netif_start_tx_queue(dev); if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " "MAC Control %x, %4.4x %4.4x.\n", dev->name, (int)readl(ioaddr + RxStatus), (int)readw(ioaddr + TxStatus), (int)readl(ioaddr + MACCtrl0), (int)readw(ioaddr + MACCtrl1), (int)readw(ioaddr + MACCtrl0)); /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + 3*HZ; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); return 0;}static void sundance_start(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int i; /* No reports have indicated that we need to reset the chip. */ writel(virt_to_bus(&np->rx_ring[np->cur_rx % RX_RING_SIZE]), ioaddr + RxListPtr); /* The Tx list pointer is written as packets are queued. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -