📄 skfddi.c
字号:
PRINTK(" %02x %02x %02x ", dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2]); PRINTK("%02x %02x %02x\n", dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); dmi = dmi->next; } // for } else { // more MC addresses than HW supports mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); } } else { // no MC addresses PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); } /* Update adapter filters */ mac_update_multicast(smc); } return;} // skfp_ctl_set_multicast_list_wo_lock/* * =========================== * = skfp_ctl_set_mac_address = * =========================== * * Overview: * set new mac address on adapter and update dev_addr field in device table. * * Returns: * None * * Arguments: * dev - pointer to device information * addr - pointer to sockaddr structure containing unicast address to set * * Assumptions: * The address pointed to by addr->sa_data is a valid unicast * address and is presented in canonical (LSB) format. */static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr){ struct s_smc *smc = netdev_priv(dev); struct sockaddr *p_sockaddr = (struct sockaddr *) addr; skfddi_priv *bp = &smc->os; unsigned long Flags; memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); spin_lock_irqsave(&bp->DriverLock, Flags); ResetAdapter(smc); spin_unlock_irqrestore(&bp->DriverLock, Flags); return (0); /* always return zero */} // skfp_ctl_set_mac_address/* * ============== * = skfp_ioctl = * ============== * * Overview: * * Perform IOCTL call functions here. Some are privileged operations and the * effective uid is checked in those cases. * * Returns: * status value * 0 - success * other - failure * * Arguments: * dev - pointer to device information * rq - pointer to ioctl request structure * cmd - ? * */static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct s_smc *smc = netdev_priv(dev); skfddi_priv *lp = &smc->os; struct s_skfp_ioctl ioc; int status = 0; if (copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl))) return -EFAULT; switch (ioc.cmd) { case SKFP_GET_STATS: /* Get the driver statistics */ ioc.len = sizeof(lp->MacStat); status = copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len) ? -EFAULT : 0; break; case SKFP_CLR_STATS: /* Zero out the driver statistics */ if (!capable(CAP_NET_ADMIN)) { memset(&lp->MacStat, 0, sizeof(lp->MacStat)); } else { status = -EPERM; } break; default: printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); status = -EOPNOTSUPP; } // switch return status;} // skfp_ioctl/* * ===================== * = skfp_send_pkt = * ===================== * * Overview: * Queues a packet for transmission and try to transmit it. * * Returns: * Condition code * * Arguments: * skb - pointer to sk_buff to queue for transmission * dev - pointer to device information * * Functional Description: * Here we assume that an incoming skb transmit request * is contained in a single physically contiguous buffer * in which the virtual address of the start of packet * (skb->data) can be converted to a physical address * by using pci_map_single(). * * We have an internal queue for packets we can not send * immediately. Packets in this queue can be given to the * adapter if transmit buffers are freed. * * We can't free the skb until after it's been DMA'd * out by the adapter, so we'll keep it in the driver and * return it in mac_drv_tx_complete. * * Return Codes: * 0 - driver has queued and/or sent packet * 1 - caller should requeue the sk_buff for later transmission * * Assumptions: * The entire packet is stored in one physically * contiguous buffer which is not cached and whose * 32-bit physical address can be determined. * * It's vital that this routine is NOT reentered for the * same board and that the OS is not in another section of * code (eg. skfp_interrupt) for the same board on a * different thread. * * Side Effects: * None */static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev){ struct s_smc *smc = netdev_priv(dev); skfddi_priv *bp = &smc->os; PRINTK(KERN_INFO "skfp_send_pkt\n"); /* * Verify that incoming transmit request is OK * * Note: The packet size check is consistent with other * Linux device drivers, although the correct packet * size should be verified before calling the * transmit routine. */ if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { bp->MacStat.gen.tx_errors++; /* bump error counter */ // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); return (0); /* return "success" */ } if (bp->QueueSkb == 0) { // return with tbusy set: queue full netif_stop_queue(dev); return 1; } bp->QueueSkb--; skb_queue_tail(&bp->SendSkbQueue, skb); send_queued_packets(netdev_priv(dev)); if (bp->QueueSkb == 0) { netif_stop_queue(dev); } dev->trans_start = jiffies; return 0;} // skfp_send_pkt/* * ======================= * = send_queued_packets = * ======================= * * Overview: * Send packets from the driver queue as long as there are some and * transmit resources are available. * * Returns: * None * * Arguments: * smc - pointer to smc (adapter) structure * * Functional Description: * Take a packet from queue if there is any. If not, then we are done. * Check if there are resources to send the packet. If not, requeue it * and exit. * Set packet descriptor flags and give packet to adapter. * Check if any send resources can be freed (we do not use the * transmit complete interrupt). */static void send_queued_packets(struct s_smc *smc){ skfddi_priv *bp = &smc->os; struct sk_buff *skb; unsigned char fc; int queue; struct s_smt_fp_txd *txd; // Current TxD. dma_addr_t dma_address; unsigned long Flags; int frame_status; // HWM tx frame status. PRINTK(KERN_INFO "send queued packets\n"); for (;;) { // send first buffer from queue skb = skb_dequeue(&bp->SendSkbQueue); if (!skb) { PRINTK(KERN_INFO "queue empty\n"); return; } // queue empty ! spin_lock_irqsave(&bp->DriverLock, Flags); fc = skb->data[0]; queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0;#ifdef ESS // Check if the frame may/must be sent as a synchronous frame. if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) { // It's an LLC frame. if (!smc->ess.sync_bw_available) fc &= ~FC_SYNC_BIT; // No bandwidth available. else { // Bandwidth is available. if (smc->mib.fddiESSSynchTxMode) { // Send as sync. frame. fc |= FC_SYNC_BIT; } } }#endif // ESS frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue); if ((frame_status & (LOC_TX | LAN_TX)) == 0) { // Unable to send the frame. if ((frame_status & RING_DOWN) != 0) { // Ring is down. PRINTK("Tx attempt while ring down.\n"); } else if ((frame_status & OUT_OF_TXD) != 0) { PRINTK("%s: out of TXDs.\n", bp->dev->name); } else { PRINTK("%s: out of transmit resources", bp->dev->name); } // Note: We will retry the operation as soon as // transmit resources become available. skb_queue_head(&bp->SendSkbQueue, skb); spin_unlock_irqrestore(&bp->DriverLock, Flags); return; // Packet has been queued. } // if (unable to send frame) bp->QueueSkb++; // one packet less in local queue // source address in packet ? CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a); txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue); dma_address = pci_map_single(&bp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (frame_status & LAN_TX) { txd->txd_os.skb = skb; // save skb txd->txd_os.dma_addr = dma_address; // save dma mapping } hwm_tx_frag(smc, skb->data, dma_address, skb->len, frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF); if (!(frame_status & LAN_TX)) { // local only frame pci_unmap_single(&bp->pdev, dma_address, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); } spin_unlock_irqrestore(&bp->DriverLock, Flags); } // for return; // never reached} // send_queued_packets/************************ * * CheckSourceAddress * * Verify if the source address is set. Insert it if necessary. * ************************/void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr){ unsigned char SRBit; if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit return; if ((unsigned short) frame[1 + 10] != 0) return; SRBit = frame[1 + 6] & 0x01; memcpy(&frame[1 + 6], hw_addr, 6); frame[8] |= SRBit;} // CheckSourceAddress/************************ * * ResetAdapter * * Reset the adapter and bring it back to operational mode. * Args * smc - A pointer to the SMT context struct. * Out * Nothing. * ************************/static void ResetAdapter(struct s_smc *smc){ PRINTK(KERN_INFO "[fddi: ResetAdapter]\n"); // Stop the adapter. card_stop(smc); // Stop all activity. // Clear the transmit and receive descriptor queues. mac_drv_clear_tx_queue(smc); mac_drv_clear_rx_queue(smc); // Restart the adapter. smt_reset_defaults(smc, 1); // Initialize the SMT module. init_smt(smc, (smc->os.dev)->dev_addr); // Initialize the hardware. smt_online(smc, 1); // Insert into the ring again. STI_FBI(); // Restore original receive mode (multicasts, promiscuous, etc.). skfp_ctl_set_multicast_list_wo_lock(smc->os.dev);} // ResetAdapter//--------------- functions called by hardware module ----------------/************************ * * llc_restart_tx * * The hardware driver calls this routine when the transmit complete * interrupt bits (end of frame) for the synchronous or asynchronous * queue is set. * * NOTE The hardware driver calls this function also if no packets are queued. * The routine must be able to handle this case. * Args * smc - A pointer to the SMT context struct. * Out * Nothing. * ************************/void llc_restart_tx(struct s_smc *smc){ skfddi_priv *bp = &smc->os; PRINTK(KERN_INFO "[llc_restart_tx]\n"); // Try to send queued packets spin_unlock(&bp->DriverLock); send_queued_packets(smc); spin_lock(&bp->DriverLock); netif_start_queue(bp->dev);// system may send again if it was blocked} // llc_restart_tx/************************ * * mac_drv_get_space * * The hardware module calls this function to allocate the memory * for the SMT MBufs if the define MB_OUTSIDE_SMC is specified. * Args * smc - A pointer to the SMT context struct. * * size - Size of memory in bytes to allocate. * Out * != 0 A pointer to the virtual address of the allocated memory. * == 0 Allocation error. * ************************/void *mac_drv_get_space(struct s_smc *smc, unsigned int size){ void *virt; PRINTK(KERN_INFO "mac_drv_get_space (%d bytes), ", size); virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { printk("Unexpected SMT memory size requested: %d\n", size); return (NULL); } smc->os.SharedMemHeap += size; // Move heap pointer. PRINTK(KERN_INFO "mac_drv_get_space end\n"); PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt); PRINTK(KERN_INFO "bus addr: %lx\n", (ulong) (smc->os.SharedMemDMA + ((char *) virt - (char *)smc->os.SharedMemAddr))); return (virt);} // mac_drv_get_space
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -