📄 xirc2ps_cs.c
字号:
unsigned bytes_rcvd; unsigned int_status, eth_status, rx_status, tx_status; unsigned rsr, pktlen; ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days * is this something to worry about? * -- on a laptop? */ if (!netif_device_present(dev)) return IRQ_HANDLED; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ PutByte(XIRCREG_CR, 0); } DEBUG(6, "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); saved_page = GetByte(XIRCREG_PR); /* Read the ISR to see whats the cause for the interrupt. * This also clears the interrupt flags on CE2 cards */ int_status = GetByte(XIRCREG_ISR); bytes_rcvd = 0; loop_entry: if (int_status == 0xff) { /* card may be ejected */ DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq); goto leave; } eth_status = GetByte(XIRCREG_ESR); SelectPage(0x40); rx_status = GetByte(XIRCREG40_RXST0); PutByte(XIRCREG40_RXST0, (~rx_status & 0xff)); tx_status = GetByte(XIRCREG40_TXST0); tx_status |= GetByte(XIRCREG40_TXST1) << 8; PutByte(XIRCREG40_TXST0, 0); PutByte(XIRCREG40_TXST1, 0); DEBUG(3, "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", dev->name, int_status, eth_status, rx_status, tx_status); /***** receive section ******/ SelectPage(0); while (eth_status & FullPktRcvd) { rsr = GetByte(XIRCREG0_RSR); if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) { /* too many bytes received during this int, drop the rest of the * packets */ lp->stats.rx_dropped++; DEBUG(2, "%s: RX drop, too much done\n", dev->name); } else if (rsr & PktRxOk) { struct sk_buff *skb; pktlen = GetWord(XIRCREG0_RBC); bytes_rcvd += pktlen; DEBUG(5, "rsr=%#02x packet_length=%u\n", rsr, pktlen); skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */ if (!skb) { printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n", pktlen); lp->stats.rx_dropped++; } else { /* okay get the packet */ skb_reserve(skb, 2); if (lp->silicon == 0 ) { /* work around a hardware bug */ unsigned rhsa; /* receive start address */ SelectPage(5); rhsa = GetWord(XIRCREG5_RHSA0); SelectPage(0); rhsa += 3; /* skip control infos */ if (rhsa >= 0x8000) rhsa = 0; if (rhsa + pktlen > 0x8000) { unsigned i; u_char *buf = skb_put(skb, pktlen); for (i=0; i < pktlen ; i++, rhsa++) { buf[i] = GetByte(XIRCREG_EDP); if (rhsa == 0x8000) { rhsa = 0; i--; } } } else { insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), (pktlen+1)>>1); } } #if 0 else if (lp->mohawk) { /* To use this 32 bit access we should use * a manual optimized loop * Also the words are swapped, we can get more * performance by using 32 bit access and swapping * the words in a register. Will need this for cardbus * * Note: don't forget to change the ALLOC_SKB to .. +3 */ unsigned i; u_long *p = skb_put(skb, pktlen); register u_long a; kio_addr_t edpreg = ioaddr+XIRCREG_EDP-2; for (i=0; i < len ; i += 4, p++) { a = inl(edpreg); __asm__("rorl $16,%0\n\t" :"=q" (a) : "0" (a)); *p = a; } } #endif else { insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), (pktlen+1)>>1); } skb->protocol = eth_type_trans(skb, dev); skb->dev = dev; netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) lp->stats.multicast++; } } else { /* bad packet */ DEBUG(5, "rsr=%#02x\n", rsr); } if (rsr & PktTooLong) { lp->stats.rx_frame_errors++; DEBUG(3, "%s: Packet too long\n", dev->name); } if (rsr & CRCErr) { lp->stats.rx_crc_errors++; DEBUG(3, "%s: CRC error\n", dev->name); } if (rsr & AlignErr) { lp->stats.rx_fifo_errors++; /* okay ? */ DEBUG(3, "%s: Alignment error\n", dev->name); } /* clear the received/dropped/error packet */ PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ /* get the new ethernet status */ eth_status = GetByte(XIRCREG_ESR); } if (rx_status & 0x10) { /* Receive overrun */ lp->stats.rx_over_errors++; PutByte(XIRCREG_CR, ClearRxOvrun); DEBUG(3, "receive overrun cleared\n"); } /***** transmit section ******/ if (int_status & PktTxed) { unsigned n, nn; n = lp->last_ptr_value; nn = GetByte(XIRCREG0_PTR); lp->last_ptr_value = nn; if (nn < n) /* rollover */ lp->stats.tx_packets += 256 - n; else if (n == nn) { /* happens sometimes - don't know why */ DEBUG(0, "PTR not changed?\n"); } else lp->stats.tx_packets += lp->last_ptr_value - n; netif_wake_queue(dev); } if (tx_status & 0x0002) { /* Execessive collissions */ DEBUG(0, "tx restarted due to execssive collissions\n"); PutByte(XIRCREG_CR, RestartTx); /* restart transmitter process */ } if (tx_status & 0x0040) lp->stats.tx_aborted_errors++; /* recalculate our work chunk so that we limit the duration of this * ISR to about 1/10 of a second. * Calculate only if we received a reasonable amount of bytes. */ if (bytes_rcvd > 1000) { u_long duration = jiffies - start_ticks; if (duration >= HZ/10) { /* if more than about 1/10 second */ maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration; if (maxrx_bytes < 2000) maxrx_bytes = 2000; else if (maxrx_bytes > 22000) maxrx_bytes = 22000; DEBUG(1, "set maxrx=%u (rcvd=%u ticks=%lu)\n", maxrx_bytes, bytes_rcvd, duration); } else if (!duration && maxrx_bytes < 22000) { /* now much faster */ maxrx_bytes += 2000; if (maxrx_bytes > 22000) maxrx_bytes = 22000; DEBUG(1, "set maxrx=%u\n", maxrx_bytes); } } leave: if (lockup_hack) { if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0) goto loop_entry; } SelectPage(saved_page); PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */ /* Instead of dropping packets during a receive, we could * force an interrupt with this command: * PutByte(XIRCREG_CR, EnableIntr|ForceIntr); */ return IRQ_HANDLED;} /* xirc2ps_interrupt *//*====================================================================*/static voiddo_tx_timeout(struct net_device *dev){ local_info_t *lp = netdev_priv(dev); printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); lp->stats.tx_errors++; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; netif_wake_queue(dev);}static intdo_start_xmit(struct sk_buff *skb, struct net_device *dev){ local_info_t *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; int okay; unsigned freespace; unsigned pktlen = skb? skb->len : 0; DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", skb, dev, pktlen); /* adjust the packet length to min. required * and hope that the buffer is large enough * to provide some random data. * fixme: For Mohawk we can change this by sending * a larger packetlen than we actually have; the chip will * pad this in his buffer with random bytes */ if (pktlen < ETH_ZLEN) { skb = skb_padto(skb, ETH_ZLEN); if (skb == NULL) return 0; pktlen = ETH_ZLEN; } netif_stop_queue(dev); SelectPage(0); PutWord(XIRCREG0_TRS, (u_short)pktlen+2); freespace = GetWord(XIRCREG0_TSO); okay = freespace & 0x8000; freespace &= 0x7fff; /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ okay = pktlen +2 < freespace; DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ return 1; /* upper layer may decide to requeue this packet */ } /* send the packet */ PutWord(XIRCREG_EDP, (u_short)pktlen); outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1); if (pktlen & 1) PutByte(XIRCREG_EDP, skb->data[pktlen-1]); if (lp->mohawk) PutByte(XIRCREG_CR, TransmitPacket|EnableIntr); dev_kfree_skb (skb); dev->trans_start = jiffies; lp->stats.tx_bytes += pktlen; netif_start_queue(dev); return 0;}static struct net_device_stats *do_get_stats(struct net_device *dev){ local_info_t *lp = netdev_priv(dev); /* lp->stats.rx_missed_errors = GetByte(?) */ return &lp->stats;}/**************** * Set all addresses: This first one is the individual address, * the next 9 addresses are taken from the multicast list and * the rest is filled with the individual address. */static voidset_addresses(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; local_info_t *lp = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; char *addr; int i,j,k,n; SelectPage(k=0x50); for (i=0,j=8,n=0; ; i++, j++) { if (i > 5) { if (++n > 9) break; i = 0; } if (j > 15) { j = 8; k++; SelectPage(k); } if (n && n <= dev->mc_count && dmi) { addr = dmi->dmi_addr; dmi = dmi->next; } else addr = dev->dev_addr; if (lp->mohawk) PutByte(j, addr[5-i]); else PutByte(j, addr[i]); } SelectPage(0);}/**************** * Set or clear the multicast filter for this adaptor. * We can filter up to 9 addresses, if more are requested we set * multicast promiscuous mode. */static voidset_multicast_list(struct net_device *dev){ kio_addr_t ioaddr = dev->base_addr; SelectPage(0x42); if (dev->flags & IFF_PROMISC) { /* snoop */ PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */ } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) { PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */ } else if (dev->mc_count) { /* the chip can filter 9 addresses perfectly */ PutByte(XIRCREG42_SWC1, 0x00); SelectPage(0x40); PutByte(XIRCREG40_CMD0, Offline); set_addresses(dev); SelectPage(0x40); PutByte(XIRCREG40_CMD0, EnableRecv | Online); } else { /* standard usage */ PutByte(XIRCREG42_SWC1, 0x00); } SelectPage(0);}static intdo_config(struct net_device *dev, struct ifmap *map){ local_info_t *local = netdev_priv(dev); DEBUG(0, "do_config(%p)\n", dev); if (map->port != 255 && map->port != dev->if_port) { if (map->port > 4) return -EINVAL; if (!map->port) { local->probe_port = 1; dev->if_port = 1; } else { local->probe_port = 0; dev->if_port = map->port; } printk(KERN_INFO "%s: switching to %s port\n", dev->name, if_names[dev->if_port]); do_reset(dev,1); /* not the fine way :-) */ } return 0;}/**************** * Open the driver */static intdo_open(struct net_device *dev){ local_info_t *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(0, "do_open(%p)\n", dev); /* Check that the PCMCIA card is still here. */ /* Physical device present signature. */ if (!DEV_OK(link)) return -ENODEV; /* okay */ link->open++; netif_start_queue(dev); do_reset(dev,1); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -