ep93xx_eth.c
来自「linux 内核源代码」· C语言 代码 · 共 917 行 · 第 1/2 页
C
917 行
ep->descs_dma_addr);}/* * The hardware enforces a sub-2K maximum packet size, so we put * two buffers on every hardware page. */static int ep93xx_alloc_buffers(struct ep93xx_priv *ep){ int i; ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs), &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA); if (ep->descs == NULL) return 1; for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) { void *page; dma_addr_t d; page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (page == NULL) goto err; d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(d)) { free_page((unsigned long)page); goto err; } ep->rx_buf[i] = page; ep->descs->rdesc[i].buf_addr = d; ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE; ep->rx_buf[i + 1] = page + PKT_BUF_SIZE; ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE; } for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) { void *page; dma_addr_t d; page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (page == NULL) goto err; d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(d)) { free_page((unsigned long)page); goto err; } ep->tx_buf[i] = page; ep->descs->tdesc[i].buf_addr = d; ep->tx_buf[i + 1] = page + PKT_BUF_SIZE; ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; } return 0;err: ep93xx_free_buffers(ep); return 1;}static int ep93xx_start_hw(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); unsigned long addr; int i; wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); for (i = 0; i < 10; i++) { if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) break; msleep(1); } if (i == 10) { printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n"); return 1; } wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9)); /* Does the PHY support preamble suppress? */ if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0) wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8)); /* Receive descriptor ring. */ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc); wrl(ep, REG_RXDQBADD, addr); wrl(ep, REG_RXDCURADD, addr); wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc)); /* Receive status ring. */ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat); wrl(ep, REG_RXSTSQBADD, addr); wrl(ep, REG_RXSTSQCURADD, addr); wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat)); /* Transmit descriptor ring. */ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc); wrl(ep, REG_TXDQBADD, addr); wrl(ep, REG_TXDQCURADD, addr); wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc)); /* Transmit status ring. */ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat); wrl(ep, REG_TXSTSQBADD, addr); wrl(ep, REG_TXSTSQCURADD, addr); wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat)); wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX); wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); wrl(ep, REG_GIINTMSK, 0); for (i = 0; i < 10; i++) { if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0) break; msleep(1); } if (i == 10) { printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n"); return 1; } wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES); wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES); wrb(ep, REG_INDAD0, dev->dev_addr[0]); wrb(ep, REG_INDAD1, dev->dev_addr[1]); wrb(ep, REG_INDAD2, dev->dev_addr[2]); wrb(ep, REG_INDAD3, dev->dev_addr[3]); wrb(ep, REG_INDAD4, dev->dev_addr[4]); wrb(ep, REG_INDAD5, dev->dev_addr[5]); wrl(ep, REG_AFP, 0); wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE); wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT); wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE); return 0;}static void ep93xx_stop_hw(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); int i; wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); for (i = 0; i < 10; i++) { if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) break; msleep(1); } if (i == 10) printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");}static int ep93xx_open(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); int err; if (ep93xx_alloc_buffers(ep)) return -ENOMEM; if (is_zero_ether_addr(dev->dev_addr)) { random_ether_addr(dev->dev_addr); printk(KERN_INFO "%s: generated random MAC address " "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); } napi_enable(&ep->napi); if (ep93xx_start_hw(dev)) { napi_disable(&ep->napi); ep93xx_free_buffers(ep); return -EIO; } spin_lock_init(&ep->rx_lock); ep->rx_pointer = 0; ep->tx_clean_pointer = 0; ep->tx_pointer = 0; spin_lock_init(&ep->tx_pending_lock); ep->tx_pending = 0; err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); if (err) { napi_disable(&ep->napi); ep93xx_stop_hw(dev); ep93xx_free_buffers(ep); return err; } wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE); netif_start_queue(dev); return 0;}static int ep93xx_close(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); napi_disable(&ep->napi); netif_stop_queue(dev); wrl(ep, REG_GIINTMSK, 0); free_irq(ep->irq, dev); ep93xx_stop_hw(dev); ep93xx_free_buffers(ep); return 0;}static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct ep93xx_priv *ep = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); return generic_mii_ioctl(&ep->mii, data, cmd, NULL);}static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg){ struct ep93xx_priv *ep = netdev_priv(dev); int data; int i; wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); for (i = 0; i < 10; i++) { if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) break; msleep(1); } if (i == 10) { printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n"); data = 0xffff; } else { data = rdl(ep, REG_MIIDATA); } return data;}static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data){ struct ep93xx_priv *ep = netdev_priv(dev); int i; wrl(ep, REG_MIIDATA, data); wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); for (i = 0; i < 10; i++) { if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) break; msleep(1); } if (i == 10) printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n");}static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_MODULE_NAME); strcpy(info->version, DRV_MODULE_VERSION);}static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct ep93xx_priv *ep = netdev_priv(dev); return mii_ethtool_gset(&ep->mii, cmd);}static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct ep93xx_priv *ep = netdev_priv(dev); return mii_ethtool_sset(&ep->mii, cmd);}static int ep93xx_nway_reset(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); return mii_nway_restart(&ep->mii);}static u32 ep93xx_get_link(struct net_device *dev){ struct ep93xx_priv *ep = netdev_priv(dev); return mii_link_ok(&ep->mii);}static struct ethtool_ops ep93xx_ethtool_ops = { .get_drvinfo = ep93xx_get_drvinfo, .get_settings = ep93xx_get_settings, .set_settings = ep93xx_set_settings, .nway_reset = ep93xx_nway_reset, .get_link = ep93xx_get_link,};struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data){ struct net_device *dev; dev = alloc_etherdev(sizeof(struct ep93xx_priv)); if (dev == NULL) return NULL; memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); dev->get_stats = ep93xx_get_stats; dev->ethtool_ops = &ep93xx_ethtool_ops; dev->hard_start_xmit = ep93xx_xmit; dev->open = ep93xx_open; dev->stop = ep93xx_close; dev->do_ioctl = ep93xx_ioctl; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; return dev;}static int ep93xx_eth_remove(struct platform_device *pdev){ struct net_device *dev; struct ep93xx_priv *ep; dev = platform_get_drvdata(pdev); if (dev == NULL) return 0; platform_set_drvdata(pdev, NULL); ep = netdev_priv(dev); /* @@@ Force down. */ unregister_netdev(dev); ep93xx_free_buffers(ep); if (ep->base_addr != NULL) iounmap(ep->base_addr); if (ep->res != NULL) { release_resource(ep->res); kfree(ep->res); } free_netdev(dev); return 0;}static int ep93xx_eth_probe(struct platform_device *pdev){ struct ep93xx_eth_data *data; struct net_device *dev; struct ep93xx_priv *ep; int err; if (pdev == NULL) return -ENODEV; data = pdev->dev.platform_data; dev = ep93xx_dev_alloc(data); if (dev == NULL) { err = -ENOMEM; goto err_out; } ep = netdev_priv(dev); ep->dev = dev; netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); platform_set_drvdata(pdev, dev); ep->res = request_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1, pdev->dev.bus_id); if (ep->res == NULL) { dev_err(&pdev->dev, "Could not reserve memory region\n"); err = -ENOMEM; goto err_out; } ep->base_addr = ioremap(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start); if (ep->base_addr == NULL) { dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); err = -EIO; goto err_out; } ep->irq = pdev->resource[1].start; ep->mii.phy_id = data->phy_id; ep->mii.phy_id_mask = 0x1f; ep->mii.reg_num_mask = 0x1f; ep->mii.dev = dev; ep->mii.mdio_read = ep93xx_mdio_read; ep->mii.mdio_write = ep93xx_mdio_write; ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); goto err_out; } printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, " "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, ep->irq, data->dev_addr[0], data->dev_addr[1], data->dev_addr[2], data->dev_addr[3], data->dev_addr[4], data->dev_addr[5]); return 0;err_out: ep93xx_eth_remove(pdev); return err;}static struct platform_driver ep93xx_eth_driver = { .probe = ep93xx_eth_probe, .remove = ep93xx_eth_remove, .driver = { .name = "ep93xx-eth", },};static int __init ep93xx_eth_init_module(void){ printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n"); return platform_driver_register(&ep93xx_eth_driver);}static void __exit ep93xx_eth_cleanup_module(void){ platform_driver_unregister(&ep93xx_eth_driver);}module_init(ep93xx_eth_init_module);module_exit(ep93xx_eth_cleanup_module);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?