📄 rcpci45.c
字号:
broadcast_packet (unsigned char *address){ int i; for (i = 0; i < 6; i++) if (address[i] != 0xff) return 0; return 1;}/* * RCrecv_callback() * * The receive packet callback routine. This is called by * RCProcI2OMsgQ() after the adapter posts buffers which have been * filled (one ethernet packet per buffer). */static voidRCrecv_callback (U32 Status, U8 PktCount, U32 BucketsRemain, PU32 PacketDescBlock, struct net_device *dev){ U32 len, count; PDPA pDpa = dev->priv; struct sk_buff *skb; singleTCB tcb; psingleTCB ptcb = &tcb; ptcb->bcount = 1; if ((pDpa->shutdown || pDpa->reboot) && !Status) printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n", dev->name, PktCount); if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { /* * Free whatever buffers the adapter returned, but don't * pass them to the kernel. */ if (!pDpa->shutdown && !pDpa->reboot) printk (KERN_INFO "%s: recv error status = 0x%x\n", dev->name, (uint) Status); else printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n", dev->name, PktCount, (uint) Status); /* * TO DO: check the nature of the failure and put the * adapter in failed mode if it's a hard failure. * Send a reset to the adapter and free all outstanding memory. */ if (PacketDescBlock) { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; dev_kfree_skb (skb); pDpa->numOutRcvBuffers--; /* point to next context field */ PacketDescBlock += BD_SIZE; } } return; } else { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; len = PacketDescBlock[2]; skb->dev = dev; skb_put (skb, len); /* adjust length and tail */ skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); /* send the packet to the kernel */ dev->last_rx = jiffies; pDpa->numOutRcvBuffers--; /* point to next context field */ PacketDescBlock += BD_SIZE; } } /* * Replenish the posted receive buffers. * DO NOT replenish buffers if the driver has already * initiated a reboot or shutdown! */ if (!pDpa->shutdown && !pDpa->reboot) { count = RC_allocate_and_post_buffers (dev, MAX_NMBR_RCV_BUFFERS - pDpa->numOutRcvBuffers); pDpa->numOutRcvBuffers += count; }}/* * RCinterrupt() * * Interrupt handler. * This routine sets up a couple of pointers and calls * RCProcI2OMsgQ(), which in turn process the message and * calls one of our callback functions. */static voidRCinterrupt (int irq, void *dev_id, struct pt_regs *regs){ PDPA pDpa; struct net_device *dev = dev_id; pDpa = dev->priv; if (pDpa->shutdown) printk (KERN_DEBUG "%s: shutdown, service irq\n", dev->name); RCProcI2OMsgQ (dev);}#define REBOOT_REINIT_RETRY_LIMIT 4static voidrc_timer (unsigned long data){ struct net_device *dev = (struct net_device *) data; PDPA pDpa = dev->priv; int init_status; static int retry; int post_buffers = MAX_NMBR_RCV_BUFFERS; int count = 0; int requested = 0; if (pDpa->reboot) { init_status = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, (PFNRXCALLBACK) RCrecv_callback, (PFNCALLBACK) RCreboot_callback); switch (init_status) { case RC_RTN_NO_ERROR: pDpa->reboot = 0; pDpa->shutdown = 0; /* just in case */ RCReportDriverCapability (dev, DriverControlWord); RCEnableI2OInterrupts (dev); if (!(dev->flags & IFF_UP)) { retry = 0; return; } while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; else requested = post_buffers; count = RC_allocate_and_post_buffers (dev, requested); post_buffers -= count; if (count < requested) break; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; printk ("Initialization done.\n"); netif_wake_queue (dev); retry = 0; return; case RC_RTN_FREE_Q_EMPTY: retry++; printk (KERN_WARNING "%s inbound free q empty\n", dev->name); break; default: retry++; printk (KERN_WARNING "%s bad stat after reboot: %d\n", dev->name, init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { printk (KERN_INFO "%s: rescheduling timer...\n", dev->name); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); pDpa->timer.data = (unsigned long) dev; pDpa->timer.function = &rc_timer; add_timer (&pDpa->timer); } } else printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name);}static intRCclose (struct net_device *dev){ PDPA pDpa = dev->priv; printk("RCclose\n"); netif_stop_queue (dev); if (pDpa->reboot) { printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; MOD_DEC_USE_COUNT; return 0; } pDpa->shutdown = 1; /* * We can't allow the driver to be unloaded until the adapter returns * all posted receive buffers. It doesn't hurt to tell the adapter * to return all posted receive buffers and outstanding xmit buffers, * even if there are none. */ RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, (PFNCALLBACK) RCreset_callback); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; return 0;}static struct net_device_stats *RCget_stats (struct net_device *dev){ RCLINKSTATS RCstats; PDPA pDpa = dev->priv; if (!pDpa) { return 0; } else if (!(dev->flags & IFF_UP)) { return 0; } memset (&RCstats, 0, sizeof (RCLINKSTATS)); if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == RC_RTN_NO_ERROR) { /* total packets received */ pDpa->stats.rx_packets = RCstats.Rcv_good /* total packets transmitted */; pDpa->stats.tx_packets = RCstats.TX_good; pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* * This needs improvement. */ pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ pDpa->stats.tx_dropped = 0; /* no space available in linux */ pDpa->stats.multicast = 0; /* multicast packets received */ pDpa->stats.collisions = RCstats.TX_totcol; /* detailed rx_errors: */ pDpa->stats.rx_length_errors = 0; pDpa->stats.rx_over_errors = RCstats.Rcv_orun; pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; pDpa->stats.rx_frame_errors = 0; pDpa->stats.rx_fifo_errors = 0; pDpa->stats.rx_missed_errors = 0; /* detailed tx_errors */ pDpa->stats.tx_aborted_errors = 0; pDpa->stats.tx_carrier_errors = 0; pDpa->stats.tx_fifo_errors = 0; pDpa->stats.tx_heartbeat_errors = 0; pDpa->stats.tx_window_errors = 0; return ((struct net_device_stats *) &(pDpa->stats)); } return 0;}static intRCioctl (struct net_device *dev, struct ifreq *rq, int cmd){ RCuser_struct RCuser; PDPA pDpa = dev->priv; if (!capable (CAP_NET_ADMIN)) return -EPERM; switch (cmd) { case RCU_PROTOCOL_REV: /* * Assign user protocol revision, to tell user-level * controller program whether or not it's in sync. */ rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV; break; case RCU_COMMAND: { if (copy_from_user (&RCuser, rq->ifr_data, sizeof (RCuser))) return -EFAULT; dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); switch (RCuser.cmd) { case RCUC_GETFWVER: RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer (dev, (PU8) & RCUD_GETFWVER-> FirmString, NULL); break; case RCUC_GETINFO: RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO->mem_start = dev->base_addr; RCUD_GETINFO->mem_end = dev->base_addr + pDpa->pci_addr_len; RCUD_GETINFO->base_addr = pDpa->pci_addr; RCUD_GETINFO->irq = dev->irq; break; case RCUC_GETIPANDMASK: RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask (dev, (PU32) & RCUD_GETIPANDMASK->IpAddr, (PU32) & RCUD_GETIPANDMASK-> NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics (dev, (P_RCLINKSTATS) & RCUD_GETLINKSTATISTICS-> StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus (dev, (PU32) & RCUD_GETLINKSTATUS-> ReturnStatus, NULL); break; case RCUC_GETMAC: RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC (dev, NULL); memcpy(RCUD_GETMAC, dev->dev_addr, 8); break; case RCUC_GETPROM: RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode (dev, (PU32) & RCUD_GETPROM-> PromMode, NULL); break; case RCUC_GETBROADCAST: RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode (dev, (PU32) & RCUD_GETBROADCAST-> BroadcastMode, NULL); break; case RCUC_GETSPEED: if (!(dev->flags & IFF_UP)) { return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed (dev, (PU32) & RCUD_GETSPEED-> LinkSpeedCode, NULL); break; case RCUC_SETIPANDMASK: RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; RCSetRavlinIPandMask (dev, (U32) RCUD_SETIPANDMASK-> IpAddr, (U32) RCUD_SETIPANDMASK-> NetMask); break; case RCUC_SETMAC: RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); break; case RCUC_SETSPEED: RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed (dev, (U16) RCUD_SETSPEED-> LinkSpeedCode); break; case RCUC_SETPROM: RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode (dev, (U16) RCUD_SETPROM-> PromMode); break; case RCUC_SETBROADCAST: RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode (dev, (U16) RCUD_SETBROADCAST-> BroadcastMode); break; default: RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT->rc = 0x11223344; break; } if (copy_to_user (rq->ifr_data, &RCuser, sizeof (RCuser))) return -EFAULT; break; } /* RCU_COMMAND */ default: rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; return -EINVAL; } return 0;}static intRCconfig (struct net_device *dev, struct ifmap *map){ /* * To be completed ... */ return 0; if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { printk (KERN_WARNING "%s Change I/O address not implemented\n", dev->name); return -EOPNOTSUPP; } return 0;}static void __exitrcpci_cleanup_module (void){ pci_unregister_driver (&rcpci45_driver);}module_init (rcpci_init_module);module_exit (rcpci_cleanup_module);static intRC_allocate_and_post_buffers (struct net_device *dev, int numBuffers){ int i; PU32 p; psingleB pB; struct sk_buff *skb; RC_RETURN status; U32 res; if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { printk (KERN_ERR "%s: Too many buffers requested!\n", dev->name); numBuffers = 32; } p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!p) { printk (KERN_WARNING "%s unable to allocate TCB\n", dev->name); return 0; } p[0] = 0; /* Buffer Count */ pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */ for (i = 0; i < numBuffers; i++) { skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); if (!skb) { printk (KERN_WARNING "%s: unable to allocate enough skbs!\n", dev->name); if (*p != 0) { /* did we allocate any buffers */ break; } else { kfree (p); /* Free the TCB */ return 0; } } skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ pB->context = (U32) skb; pB->scount = 1; /* segment count */ pB->size = MAX_ETHER_SIZE; pB->addr = virt_to_bus ((void *) skb->data); p[0]++; pB++; } if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n", dev->name, status); /* point to the first buffer */ pB = (psingleB) ((U32) p + sizeof (U32)); while (p[0]) { skb = (struct sk_buff *) pB->context; dev_kfree_skb (skb); p[0]--; pB++; } } res = p[0]; kfree (p); return (res); /* return the number of posted buffers */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -