📄 saa9730.c
字号:
return 0;}static int lan_saa9730_restart(struct lan_saa9730_private *lp){ lan_saa9730_stop(lp); lan_saa9730_start(lp); return 0;}static int lan_saa9730_tx(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; unsigned int *pPacket; unsigned int tx_status; if (lan_saa9730_debug > 5) printk("lan_saa9730_tx interrupt\n"); /* Clear interrupt. */ OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); while (1) { pPacket = (unsigned int *) lp->TxmBuffer[lp-> PendingTxmBufferIndex] [lp->PendingTxmPacketIndex]; /* Get status of first packet transmitted. */ tx_status = le32_to_cpu(*pPacket); /* Check ownership. */ if ((tx_status & TX_STAT_CTL_OWNER_MSK) != (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; /* Check for error. */ if (tx_status & TX_STAT_CTL_ERROR_MSK) { if (lan_saa9730_debug > 1) printk("lan_saa9730_tx: tx error = %x\n", tx_status); lp->stats.tx_errors++; if (tx_status & (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) lp->stats.tx_aborted_errors++; if (tx_status & (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) lp->stats. tx_window_errors++; if (tx_status & (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) lp->stats.tx_carrier_errors++; if (tx_status & (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) lp->stats.tx_fifo_errors++; if (tx_status & (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) lp->stats.tx_heartbeat_errors++; lp->stats.collisions += tx_status & TX_STATUS_TX_COLL_MSK; } /* Free buffer. */ *pPacket = cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); /* Update pending index pointer. */ lp->PendingTxmPacketIndex++; if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { lp->PendingTxmPacketIndex = 0; lp->PendingTxmBufferIndex ^= 1; } } /* Make sure A and B are available to hardware. */ OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); if (netif_queue_stopped(dev)) { /* The tx buffer is no longer full. */ netif_wake_queue(dev); } return 0;}static int lan_saa9730_rx(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; int len = 0; struct sk_buff *skb = 0; unsigned int rx_status; int BufferIndex; int PacketIndex; unsigned int *pPacket; unsigned char *pData; if (lan_saa9730_debug > 5) printk("lan_saa9730_rx interrupt\n"); /* Clear receive interrupts. */ OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); /* Address next packet */ if (lp->NextRcvToUseIsA) BufferIndex = 0; else BufferIndex = 1; PacketIndex = lp->NextRcvPacketIndex; pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex]; rx_status = le32_to_cpu(*pPacket); /* Process each packet. */ while ((rx_status & RX_STAT_CTL_OWNER_MSK) == (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { /* Check the rx status. */ if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { /* Received packet is good. */ len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> RX_STAT_CTL_LENGTH_SHF; pData = (unsigned char *) pPacket; pData += 4; skb = dev_alloc_skb(len + 2); if (skb == 0) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; } else { lp->stats.rx_bytes += len; lp->stats.rx_packets++; skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ eth_copy_and_sum(skb, (unsigned char *) pData, len, 0); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } } else { /* We got an error packet. */ if (lan_saa9730_debug > 2) printk ("lan_saa9730_rx: We got an error packet = %x\n", rx_status); lp->stats.rx_errors++; if (rx_status & (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) lp->stats.rx_crc_errors++; if (rx_status & (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) lp->stats. rx_frame_errors++; if (rx_status & (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) lp->stats.rx_fifo_errors++; if (rx_status & (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) lp->stats.rx_length_errors++; } /* Indicate we have processed the buffer. */ *pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); /* Go to next packet in sequence. */ lp->NextRcvPacketIndex++; if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { lp->NextRcvPacketIndex = 0; if (BufferIndex) { lp->NextRcvToUseIsA = 1; } else { lp->NextRcvToUseIsA = 0; } } OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); /* Address next packet */ if (lp->NextRcvToUseIsA) BufferIndex = 0; else BufferIndex = 1; PacketIndex = lp->NextRcvPacketIndex; pPacket = (unsigned int *) lp-> RcvBuffer[BufferIndex][PacketIndex]; rx_status = le32_to_cpu(*pPacket); } /* Make sure A and B are available to hardware. */ OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); return 0;}static void lan_saa9730_interrupt(const int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; if (lan_saa9730_debug > 5) printk("lan_saa9730_interrupt\n"); /* Disable the EVM LAN interrupt. */ evm_saa9730_block_lan_int(lp); /* Clear the EVM LAN interrupt. */ evm_saa9730_clear_lan_int(lp); /* Service pending transmit interrupts. */ if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) lan_saa9730_tx(dev); /* Service pending receive interrupts. */ if (INL(&lp->lan_saa9730_regs->DmaStatus) & (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); /* Enable the EVM LAN interrupt. */ evm_saa9730_unblock_lan_int(lp); return;}static int lan_saa9730_open_fail(struct net_device *dev){ return -ENODEV;}static int lan_saa9730_open(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; /* Associate IRQ with lan_saa9730_interrupt */ if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", dev)) { printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); return -EAGAIN; } /* Enable the Lan interrupt in the event manager. */ evm_saa9730_enable_lan_int(lp); /* Start the LAN controller */ if (lan_saa9730_start(lp)) return -1; netif_start_queue(dev); return 0;}static int lan_saa9730_write(struct lan_saa9730_private *lp, struct sk_buff *skb, int skblen){ unsigned char *pbData = skb->data; unsigned int len = skblen; unsigned char *pbPacketData; unsigned int tx_status; int BufferIndex; int PacketIndex; if (lan_saa9730_debug > 5) printk("lan_saa9730_write: skb=%08x\n", (unsigned int) skb); BufferIndex = lp->NextTxmBufferIndex; PacketIndex = lp->NextTxmPacketIndex; tx_status = le32_to_cpu(*(unsigned int *) lp-> TxmBuffer[BufferIndex][PacketIndex]); if ((tx_status & TX_STAT_CTL_OWNER_MSK) != (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { if (lan_saa9730_debug > 4) printk ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", tx_status); return -1; } lp->NextTxmPacketIndex++; if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { lp->NextTxmPacketIndex = 0; lp->NextTxmBufferIndex ^= 1; } pbPacketData = (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex]; pbPacketData += 4; /* copy the bits */ memcpy(pbPacketData, pbData, len); /* Set transmit status for hardware */ *(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] = cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | (TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF) | (len << TX_STAT_CTL_LENGTH_SHF)); /* Set hardware tx buffer. */ OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); return 0;}static void lan_saa9730_tx_timeout(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; /* Transmitter timeout, serious problems */ lp->stats.tx_errors++; printk("%s: transmit timed out, reset\n", dev->name); /*show_saa9730_regs(lp); */ lan_saa9730_restart(lp); dev->trans_start = jiffies; netif_start_queue(dev);}static int lan_saa9730_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; unsigned long flags; int skblen; int len; if (lan_saa9730_debug > 4) printk("Send packet: skb=%08x\n", (unsigned int) skb); skblen = skb->len; save_and_cli(flags); len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; if (lan_saa9730_write(lp, skb, skblen)) { restore_flags(flags); printk ("Error when writing packet to controller: skb=%08x\n", (unsigned int) skb); netif_stop_queue(dev); return -1; } lp->stats.tx_bytes += len; lp->stats.tx_packets++; dev->trans_start = jiffies; netif_start_queue(dev); dev_kfree_skb(skb); restore_flags(flags); return 0;}static int lan_saa9730_close(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; if (lan_saa9730_debug > 1) printk("lan_saa9730_close:\n"); netif_stop_queue(dev); /* Disable the Lan interrupt in the event manager. */ evm_saa9730_disable_lan_int(lp); /* Stop the controller */ if (lan_saa9730_stop(lp)) return -1; free_irq(dev->irq, (void *) dev); return 0;}static struct net_device_stats *lan_saa9730_get_stats(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; return &lp->stats;}static void lan_saa9730_set_multicast(struct net_device *dev){ struct lan_saa9730_private *lp = (struct lan_saa9730_private *) dev->priv; /* Stop the controller */ lan_saa9730_stop(lp); if (dev->flags & IFF_PROMISC) { /* accept all packets */ OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, &lp->lan_saa9730_regs->CamCtl); } else { if (dev->flags & IFF_ALLMULTI) { /* accept all multicast packets */ OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, &lp->lan_saa9730_regs->CamCtl); } else { /* * Will handle the multicast stuff later. -carstenl */ } } lan_saa9730_restart(lp);}static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq){ struct lan_saa9730_private *lp; unsigned char ethernet_addr[6]; dev = init_etherdev(dev, 0); dev->open = lan_saa9730_open_fail; if (get_ethernet_addr(ethernet_addr)) return -1; memcpy(dev->dev_addr, ethernet_addr, 6); dev->base_addr = ioaddr; dev->irq = irq; /* * Make certain the data structures used by the controller are aligned * and DMAble. */ lp = (struct lan_saa9730_private *) (((unsigned long) kmalloc(sizeof(*lp) + 7, GFP_DMA | GFP_KERNEL) + 7) & ~7); dev->priv = lp; memset(lp, 0, sizeof(*lp)); /* Set SAA9730 LAN base address. */ lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr + SAA9730_LAN_REGS_ADDR); /* Set SAA9730 EVM base address. */ lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr + SAA9730_EVM_REGS_ADDR); /* Allocate LAN RX/TX frame buffer space. */ if (lan_saa9730_allocate_buffers(lp)) return -1; /* Stop LAN controller. */ if (lan_saa9730_stop(lp)) return -1; /* Initialize CAM registers. */ if (lan_saa9730_cam_init(dev)) return -1; /* Initialize MII registers. */ if (lan_saa9730_mii_init(lp)) return -1; /* Initialize control registers. */ if (lan_saa9730_control_init(lp)) return -1; /* Load CAM registers. */ if (lan_saa9730_cam_load(lp)) return -1; /* Initialize DMA context registers. */ if (lan_saa9730_dma_init(lp)) return -1; dev->open = lan_saa9730_open; dev->hard_start_xmit = lan_saa9730_start_xmit; dev->stop = lan_saa9730_close; dev->get_stats = lan_saa9730_get_stats; dev->set_multicast_list = lan_saa9730_set_multicast; dev->tx_timeout = lan_saa9730_tx_timeout; dev->watchdog_timeo = (HZ >> 1); dev->dma = 0; return 0;}static int __init saa9730_probe(void){ struct net_device *dev = NULL; if (pci_present()) { struct pci_dev *pdev = NULL; if (lan_saa9730_debug > 1) printk ("saa9730.c: PCI bios is present, checking for devices...\n"); while ((pdev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, pdev))) { unsigned int pci_ioaddr; pci_irq_line = pdev->irq; /* LAN base address in located at BAR 1. */ pci_ioaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); printk("Found SAA9730 (PCI) at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); if (!lan_saa9730_init (dev, pci_ioaddr, pci_irq_line)) return 0; else printk("Lan init failed.\n"); } } return -ENODEV;}module_init(saa9730_probe);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -