at v2.6.24-rc2 268 lines 5.9 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 */ 6 7#define DEBUG 8 9#include <linux/init.h> 10#include <linux/io.h> 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/netdevice.h> 14#include <linux/etherdevice.h> 15#include <linux/platform_device.h> 16#include <asm/mips-boards/simint.h> 17 18#include "mipsnet.h" /* actual device IO mapping */ 19 20#define MIPSNET_VERSION "2005-06-20" 21 22#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) 23 24static char mipsnet_string[] = "mipsnet"; 25 26/* 27 * Copy data from the MIPSNET rx data port 28 */ 29static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, 30 int len) 31{ 32 uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount)); 33 34 if (available_len < len) 35 return -EFAULT; 36 37 for (; len > 0; len--, kdata++) 38 *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); 39 40 return inl(mipsnet_reg_address(dev, rxDataCount)); 41} 42 43static inline ssize_t mipsnet_put_todevice(struct net_device *dev, 44 struct sk_buff *skb) 45{ 46 int count_to_go = skb->len; 47 char *buf_ptr = skb->data; 48 49 outl(skb->len, mipsnet_reg_address(dev, txDataCount)); 50 51 for (; count_to_go; buf_ptr++, count_to_go--) 52 outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); 53 54 dev->stats.tx_packets++; 55 dev->stats.tx_bytes += skb->len; 56 57 return skb->len; 58} 59 60static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) 61{ 62 /* 63 * Only one packet at a time. Once TXDONE interrupt is serviced, the 64 * queue will be restarted. 65 */ 66 netif_stop_queue(dev); 67 mipsnet_put_todevice(dev, skb); 68 69 return 0; 70} 71 72static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) 73{ 74 struct sk_buff *skb; 75 size_t len = count; 76 77 skb = alloc_skb(len + 2, GFP_KERNEL); 78 if (!skb) { 79 dev->stats.rx_dropped++; 80 return -ENOMEM; 81 } 82 83 skb_reserve(skb, 2); 84 if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) 85 return -EFAULT; 86 87 skb->protocol = eth_type_trans(skb, dev); 88 skb->ip_summed = CHECKSUM_UNNECESSARY; 89 90 netif_rx(skb); 91 92 dev->stats.rx_packets++; 93 dev->stats.rx_bytes += len; 94 95 return count; 96} 97 98static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) 99{ 100 struct net_device *dev = dev_id; 101 102 irqreturn_t retval = IRQ_NONE; 103 uint64_t interruptFlags; 104 105 if (irq == dev->irq) { 106 retval = IRQ_HANDLED; 107 108 interruptFlags = 109 inl(mipsnet_reg_address(dev, interruptControl)); 110 111 if (interruptFlags & MIPSNET_INTCTL_TXDONE) { 112 outl(MIPSNET_INTCTL_TXDONE, 113 mipsnet_reg_address(dev, interruptControl)); 114 /* only one packet at a time, we are done. */ 115 netif_wake_queue(dev); 116 } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { 117 mipsnet_get_fromdev(dev, 118 inl(mipsnet_reg_address(dev, rxDataCount))); 119 outl(MIPSNET_INTCTL_RXDONE, 120 mipsnet_reg_address(dev, interruptControl)); 121 122 } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { 123 /* 124 * TESTBIT is cleared on read. 125 * And takes effect after a write with 0 126 */ 127 outl(0, mipsnet_reg_address(dev, interruptControl)); 128 } else { 129 /* Maybe shared IRQ, just ignore, no clearing. */ 130 retval = IRQ_NONE; 131 } 132 133 } else { 134 printk(KERN_INFO "%s: %s(): irq %d for unknown device\n", 135 dev->name, __FUNCTION__, irq); 136 retval = IRQ_NONE; 137 } 138 return retval; 139} 140 141static int mipsnet_open(struct net_device *dev) 142{ 143 int err; 144 145 err = request_irq(dev->irq, &mipsnet_interrupt, 146 IRQF_SHARED, dev->name, (void *) dev); 147 148 if (err) { 149 release_region(dev->base_addr, MIPSNET_IO_EXTENT); 150 return err; 151 } 152 153 netif_start_queue(dev); 154 155 /* test interrupt handler */ 156 outl(MIPSNET_INTCTL_TESTBIT, 157 mipsnet_reg_address(dev, interruptControl)); 158 159 160 return 0; 161} 162 163static int mipsnet_close(struct net_device *dev) 164{ 165 netif_stop_queue(dev); 166 167 return 0; 168} 169 170static void mipsnet_set_mclist(struct net_device *dev) 171{ 172} 173 174static int __init mipsnet_probe(struct device *dev) 175{ 176 struct net_device *netdev; 177 int err; 178 179 netdev = alloc_etherdev(0); 180 if (!netdev) { 181 err = -ENOMEM; 182 goto out; 183 } 184 185 dev_set_drvdata(dev, netdev); 186 187 netdev->open = mipsnet_open; 188 netdev->stop = mipsnet_close; 189 netdev->hard_start_xmit = mipsnet_xmit; 190 netdev->set_multicast_list = mipsnet_set_mclist; 191 192 /* 193 * TODO: probe for these or load them from PARAM 194 */ 195 netdev->base_addr = 0x4200; 196 netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 + 197 inl(mipsnet_reg_address(netdev, interruptInfo)); 198 199 /* Get the io region now, get irq on open() */ 200 if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { 201 err = -EBUSY; 202 goto out_free_netdev; 203 } 204 205 /* 206 * Lacking any better mechanism to allocate a MAC address we use a 207 * random one ... 208 */ 209 random_ether_addr(netdev->dev_addr); 210 211 err = register_netdev(netdev); 212 if (err) { 213 printk(KERN_ERR "MIPSNet: failed to register netdev.\n"); 214 goto out_free_region; 215 } 216 217 return 0; 218 219out_free_region: 220 release_region(netdev->base_addr, MIPSNET_IO_EXTENT); 221 222out_free_netdev: 223 free_netdev(netdev); 224 225out: 226 return err; 227} 228 229static int __devexit mipsnet_device_remove(struct device *device) 230{ 231 struct net_device *dev = dev_get_drvdata(device); 232 233 unregister_netdev(dev); 234 release_region(dev->base_addr, MIPSNET_IO_EXTENT); 235 free_netdev(dev); 236 dev_set_drvdata(device, NULL); 237 238 return 0; 239} 240 241static struct device_driver mipsnet_driver = { 242 .name = mipsnet_string, 243 .bus = &platform_bus_type, 244 .probe = mipsnet_probe, 245 .remove = __devexit_p(mipsnet_device_remove), 246}; 247 248static int __init mipsnet_init_module(void) 249{ 250 int err; 251 252 printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " 253 "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); 254 255 err = driver_register(&mipsnet_driver); 256 if (err) 257 printk(KERN_ERR "Driver registration failed\n"); 258 259 return err; 260} 261 262static void __exit mipsnet_exit_module(void) 263{ 264 driver_unregister(&mipsnet_driver); 265} 266 267module_init(mipsnet_init_module); 268module_exit(mipsnet_exit_module);