115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek/* 215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * IXP2000 MSF network device driver 315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org> 415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * Dedicated to Marija Kulikova. 515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * 615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * This program is free software; you can redistribute it and/or modify 715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * it under the terms of the GNU General Public License as published by 815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * the Free Software Foundation; either version 2 of the License, or 915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * (at your option) any later version. 1015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek */ 1115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 1215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/module.h> 1315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/kernel.h> 1415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/netdevice.h> 1515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/etherdevice.h> 1615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/init.h> 17a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 1815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <linux/moduleparam.h> 195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 2018ec5c731271939acb414614e964c15c8ef52156Lennert Buytenhek#include <asm/hardware/uengine.h> 2115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include <asm/io.h> 2215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include "ixp2400_rx.ucode" 2315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include "ixp2400_tx.ucode" 2415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include "ixpdev_priv.h" 2515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek#include "ixpdev.h" 26b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders#include "pm3386.h" 2715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 28127477840b9fd205958203648b9fa89860d69a43Lennert Buytenhek#define DRV_MODULE_VERSION "0.2" 29127477840b9fd205958203648b9fa89860d69a43Lennert Buytenhek 3015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int nds_count; 3115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic struct net_device **nds; 3215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int nds_open; 3315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic void (*set_port_admin_status)(int port, int up); 3415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 3515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic struct ixpdev_rx_desc * const rx_desc = 3615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek (struct ixpdev_rx_desc *)(IXP2000_SRAM0_VIRT_BASE + RX_BUF_DESC_BASE); 3715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic struct ixpdev_tx_desc * const tx_desc = 3815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek (struct ixpdev_tx_desc *)(IXP2000_SRAM0_VIRT_BASE + TX_BUF_DESC_BASE); 3915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int tx_pointer; 4015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 4115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 4215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) 4315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 4415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_priv *ip = netdev_priv(dev); 4515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_tx_desc *desc; 4615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int entry; 474871953c0ef2cafeb37bbe186d9d13dcb24fc2c5Dongdong Deng unsigned long flags; 4815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 4915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (unlikely(skb->len > PAGE_SIZE)) { 5015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* @@@ Count drops. */ 5115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek dev_kfree_skb(skb); 526ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 5315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 5415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 5515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek entry = tx_pointer; 5615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek tx_pointer = (tx_pointer + 1) % TX_BUF_COUNT; 5715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 5815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc = tx_desc + entry; 5915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc->pkt_length = skb->len; 6015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc->channel = ip->channel; 6115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 6215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek skb_copy_and_csum_dev(skb, phys_to_virt(desc->buf_addr)); 6315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek dev_kfree_skb(skb); 6415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 6515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_PENDING, 6615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc))); 6715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 684871953c0ef2cafeb37bbe186d9d13dcb24fc2c5Dongdong Deng local_irq_save(flags); 6915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip->tx_queue_entries++; 7015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) 7115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek netif_stop_queue(dev); 724871953c0ef2cafeb37bbe186d9d13dcb24fc2c5Dongdong Deng local_irq_restore(flags); 7315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 746ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 7515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 7615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 7715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 78bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int ixpdev_rx(struct net_device *dev, int processed, int budget) 7915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 80bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger while (processed < budget) { 8115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_rx_desc *desc; 8215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct sk_buff *skb; 8315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek void *buf; 8415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek u32 _desc; 8515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 8615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek _desc = ixp2000_reg_read(RING_RX_DONE); 8715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (_desc == 0) 8815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return 0; 8915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 9015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc = rx_desc + 9115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ((_desc - RX_BUF_DESC_BASE) / sizeof(struct ixpdev_rx_desc)); 9215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek buf = phys_to_virt(desc->buf_addr); 9315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 9415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (desc->pkt_length < 4 || desc->pkt_length > PAGE_SIZE) { 9515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek printk(KERN_ERR "ixp2000: rx err, length %d\n", 9615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc->pkt_length); 9715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek goto err; 9815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 9915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 10015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (desc->channel < 0 || desc->channel >= nds_count) { 10115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek printk(KERN_ERR "ixp2000: rx err, channel %d\n", 10215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc->channel); 10315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek goto err; 10415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 10515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 10615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* @@@ Make FCS stripping configurable. */ 10715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc->pkt_length -= 4; 10815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 10915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (unlikely(!netif_running(nds[desc->channel]))) 11015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek goto err; 11115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 11289d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet skb = netdev_alloc_skb_ip_align(dev, desc->pkt_length); 11315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (likely(skb != NULL)) { 1148c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller skb_copy_to_linear_data(skb, buf, desc->pkt_length); 11515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek skb_put(skb, desc->pkt_length); 1164c13eb6657fe9ef7b4dc8f1a405c902e9e5234e0Arnaldo Carvalho de Melo skb->protocol = eth_type_trans(skb, nds[desc->channel]); 11715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 11815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek netif_receive_skb(skb); 11915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 12015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 12115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekerr: 12215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_PENDING, _desc); 123bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger processed++; 12415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 12515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 126bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return processed; 12715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 12815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 12915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek/* dev always points to nds[0]. */ 130bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int ixpdev_poll(struct napi_struct *napi, int budget) 13115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 132bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi); 133bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct net_device *dev = ip->dev; 134bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger int rx; 135bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger 136bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger rx = 0; 13715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek do { 13815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); 13915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 140bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger rx = ixpdev_rx(dev, rx, budget); 141bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (rx >= budget) 142bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger break; 14315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); 14415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 145288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(napi); 14615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); 14715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 148bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return rx; 14915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 15015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 15115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic void ixpdev_tx_complete(void) 15215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 15315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int channel; 15415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek u32 wake; 15515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 15615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek wake = 0; 15715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek while (1) { 15815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_priv *ip; 15915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek u32 desc; 16015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int entry; 16115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 16215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek desc = ixp2000_reg_read(RING_TX_DONE); 16315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (desc == 0) 16415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek break; 16515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 16615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* @@@ Check whether entries come back in order. */ 16715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek entry = (desc - TX_BUF_DESC_BASE) / sizeof(struct ixpdev_tx_desc); 16815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek channel = tx_desc[entry].channel; 16915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 17015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (channel < 0 || channel >= nds_count) { 17115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek printk(KERN_ERR "ixp2000: txcomp channel index " 17215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek "out of bounds (%d, %.8i, %d)\n", 17315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek channel, (unsigned int)desc, entry); 17415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek continue; 17515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 17615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 17715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip = netdev_priv(nds[channel]); 17815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) 17915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek wake |= 1 << channel; 18015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip->tx_queue_entries--; 18115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 18215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 18315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (channel = 0; wake != 0; channel++) { 18415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (wake & (1 << channel)) { 18515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek netif_wake_queue(nds[channel]); 18615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek wake &= ~(1 << channel); 18715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 18815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 18915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 19015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 1917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ixpdev_interrupt(int irq, void *dev_id) 19215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 19315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek u32 status; 19415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 19515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek status = ixp2000_reg_read(IXP2000_IRQ_THD_STATUS_A_0); 19615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (status == 0) 19715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return IRQ_NONE; 19815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 19915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 20015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * Any of the eight receive units signaled RX? 20115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek */ 20215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (status & 0x00ff) { 203bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct net_device *dev = nds[0]; 204bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct ixpdev_priv *ip = netdev_priv(dev); 205bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger 20615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); 207bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (likely(napi_schedule_prep(&ip->napi))) { 208288379f050284087578b77e04f040b57db3db3f8Ben Hutchings __napi_schedule(&ip->napi); 20915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } else { 21015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek printk(KERN_CRIT "ixp2000: irq while polling!!\n"); 21115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 21215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 21315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 21415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 21515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek * Any of the eight transmit units signaled TXdone? 21615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek */ 21715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (status & 0xff00) { 21815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_wrb(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0xff00); 21915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixpdev_tx_complete(); 22015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 22115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 22215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return IRQ_HANDLED; 22315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 22415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 2258ce51d69b755c39e714826899631629209896b70Lennert Buytenhek#ifdef CONFIG_NET_POLL_CONTROLLER 2268ce51d69b755c39e714826899631629209896b70Lennert Buytenhekstatic void ixpdev_poll_controller(struct net_device *dev) 2278ce51d69b755c39e714826899631629209896b70Lennert Buytenhek{ 2288ce51d69b755c39e714826899631629209896b70Lennert Buytenhek disable_irq(IRQ_IXP2000_THDA0); 2290da2f0f164f098bb4447c714b552ac1681b2d6e8Yoann Padioleau ixpdev_interrupt(IRQ_IXP2000_THDA0, dev); 2308ce51d69b755c39e714826899631629209896b70Lennert Buytenhek enable_irq(IRQ_IXP2000_THDA0); 2318ce51d69b755c39e714826899631629209896b70Lennert Buytenhek} 2328ce51d69b755c39e714826899631629209896b70Lennert Buytenhek#endif 2338ce51d69b755c39e714826899631629209896b70Lennert Buytenhek 23415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int ixpdev_open(struct net_device *dev) 23515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 23615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_priv *ip = netdev_priv(dev); 23715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int err; 23815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 239bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_enable(&ip->napi); 24015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (!nds_open++) { 24115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, 2421fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner IRQF_SHARED, "ixp2000_eth", nds); 24315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (err) { 24415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek nds_open--; 245bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_disable(&ip->napi); 24615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return err; 24715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 24815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 24915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0xffff); 25015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 25115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 25215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek set_port_admin_status(ip->channel, 1); 25315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek netif_start_queue(dev); 25415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 25515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return 0; 25615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 25715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 25815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstatic int ixpdev_close(struct net_device *dev) 25915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 26015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_priv *ip = netdev_priv(dev); 26115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 26215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek netif_stop_queue(dev); 263bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger napi_disable(&ip->napi); 26415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek set_port_admin_status(ip->channel, 0); 26515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 26615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (!--nds_open) { 26715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0xffff); 26815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_irq(IRQ_IXP2000_THDA0, nds); 26915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 27015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 27115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return 0; 27215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 27315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 274b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sandersstatic struct net_device_stats *ixpdev_get_stats(struct net_device *dev) 275b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders{ 276b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders struct ixpdev_priv *ip = netdev_priv(dev); 277b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders 278b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders pm3386_get_stats(ip->channel, &(dev->stats)); 279b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders 280b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders return &(dev->stats); 281b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders} 282b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders 283e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalovstatic const struct net_device_ops ixpdev_netdev_ops = { 284e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_open = ixpdev_open, 285e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_stop = ixpdev_close, 286e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_start_xmit = ixpdev_xmit, 287e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_change_mtu = eth_change_mtu, 288e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_validate_addr = eth_validate_addr, 289e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_set_mac_address = eth_mac_addr, 290b9696ea32533b3353a5390e7c34a4719512fb2a1Vincent Sanders .ndo_get_stats = ixpdev_get_stats, 291e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov#ifdef CONFIG_NET_POLL_CONTROLLER 292e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov .ndo_poll_controller = ixpdev_poll_controller, 293e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov#endif 294e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov}; 295e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov 29615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekstruct net_device *ixpdev_alloc(int channel, int sizeof_priv) 29715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 29815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct net_device *dev; 29915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek struct ixpdev_priv *ip; 30015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 30115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek dev = alloc_etherdev(sizeof_priv); 30215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (dev == NULL) 30315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return NULL; 30415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 305e7090e347ad8bce0de35f9fe2b95e22e4ae8fbabAlexander Beregalov dev->netdev_ops = &ixpdev_netdev_ops; 30615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 30715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; 30815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 30915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip = netdev_priv(dev); 310bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger ip->dev = dev; 311bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger netif_napi_add(dev, &ip->napi, ixpdev_poll, 64); 31215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip->channel = channel; 31315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ip->tx_queue_entries = 0; 31415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 31515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return dev; 31615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 31715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 31815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekint ixpdev_init(int __nds_count, struct net_device **__nds, 31915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek void (*__set_port_admin_status)(int port, int up)) 32015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 32115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int i; 32215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int err; 32315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 3245d4fe2c1ce83c3e967ccc1ba3d580c1a5603a866Lennert Buytenhek BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192); 32515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 326127477840b9fd205958203648b9fa89860d69a43Lennert Buytenhek printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION); 327127477840b9fd205958203648b9fa89860d69a43Lennert Buytenhek 32815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek nds_count = __nds_count; 32915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek nds = __nds; 33015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek set_port_admin_status = __set_port_admin_status; 33115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 33215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < RX_BUF_COUNT; i++) { 33315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek void *buf; 33415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 33515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek buf = (void *)get_zeroed_page(GFP_KERNEL); 33615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (buf == NULL) { 33715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek err = -ENOMEM; 33815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek while (--i >= 0) 33915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); 3400c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek goto err_out; 34115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 34215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek rx_desc[i].buf_addr = virt_to_phys(buf); 34315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek rx_desc[i].buf_length = PAGE_SIZE; 34415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 34515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 34615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* @@@ Maybe we shouldn't be preallocating TX buffers. */ 34715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < TX_BUF_COUNT; i++) { 34815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek void *buf; 34915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 35015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek buf = (void *)get_zeroed_page(GFP_KERNEL); 35115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek if (buf == NULL) { 35215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek err = -ENOMEM; 35315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek while (--i >= 0) 35415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); 35515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek goto err_free_rx; 35615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 35715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek tx_desc[i].buf_addr = virt_to_phys(buf); 35815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 35915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 36015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 256 entries, ring status set means 'empty', base address 0x0000. */ 36115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_PENDING_BASE, 0x44000000); 36215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_PENDING_HEAD, 0x00000000); 36315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_PENDING_TAIL, 0x00000000); 36415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 36515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 256 entries, ring status set means 'full', base address 0x0400. */ 36615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_DONE_BASE, 0x40000400); 36715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_DONE_HEAD, 0x00000000); 36815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_DONE_TAIL, 0x00000000); 36915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 37015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < RX_BUF_COUNT; i++) { 37115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_RX_PENDING, 37215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek RX_BUF_DESC_BASE + (i * sizeof(struct ixpdev_rx_desc))); 37315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek } 37415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 37515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_load(0, &ixp2400_rx); 37615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_start_contexts(0, 0xff); 37715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 37815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 256 entries, ring status set means 'empty', base address 0x0800. */ 37915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_PENDING_BASE, 0x44000800); 38015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_PENDING_HEAD, 0x00000000); 38115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_PENDING_TAIL, 0x00000000); 38215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 38315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* 256 entries, ring status set means 'full', base address 0x0c00. */ 38415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_DONE_BASE, 0x40000c00); 38515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_DONE_HEAD, 0x00000000); 38615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_reg_write(RING_TX_DONE_TAIL, 0x00000000); 38715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 38815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_load(1, &ixp2400_tx); 38915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_start_contexts(1, 0xff); 39015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 3910c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek for (i = 0; i < nds_count; i++) { 3920c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek err = register_netdev(nds[i]); 3930c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek if (err) { 3940c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek while (--i >= 0) 3950c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek unregister_netdev(nds[i]); 3960c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek goto err_free_tx; 3970c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek } 3980c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek } 3990c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek 4007ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek for (i = 0; i < nds_count; i++) { 4017ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), " 4027ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", nds[i]->name, i, 4037ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek nds[i]->dev_addr[0], nds[i]->dev_addr[1], 4047ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek nds[i]->dev_addr[2], nds[i]->dev_addr[3], 4057ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek nds[i]->dev_addr[4], nds[i]->dev_addr[5]); 4067ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek } 4077ed98bfdea45dbdc66261660357659470935a03aLennert Buytenhek 40815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return 0; 40915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 4100c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhekerr_free_tx: 4110c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek for (i = 0; i < TX_BUF_COUNT; i++) 4120c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); 4130c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek 41415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekerr_free_rx: 41515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < RX_BUF_COUNT; i++) 41615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); 41715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 41815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekerr_out: 41915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek return err; 42015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 42115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 42215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhekvoid ixpdev_deinit(void) 42315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek{ 42415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek int i; 42515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 42615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek /* @@@ Flush out pending packets. */ 42715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 4280c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek for (i = 0; i < nds_count; i++) 4290c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek unregister_netdev(nds[i]); 4300c49919a4706cc8c72ff381da7f3ae094e6df03aLennert Buytenhek 43115d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_stop_contexts(1, 0xff); 43215d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_stop_contexts(0, 0xff); 43315d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek ixp2000_uengine_reset(0x3); 43415d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 43515d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < TX_BUF_COUNT; i++) 43615d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); 43715d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek 43815d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek for (i = 0; i < RX_BUF_COUNT; i++) 43915d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); 44015d014d13149aedd76cbff1b5c3bbfe839391457Lennert Buytenhek} 441