Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29 463 lines 11 kB view raw
1/* 2 * abyss.c: Network driver for the Madge Smart 16/4 PCI Mk2 token ring card. 3 * 4 * Written 1999-2000 by Adam Fritzler 5 * 6 * This software may be used and distributed according to the terms 7 * of the GNU General Public License, incorporated herein by reference. 8 * 9 * This driver module supports the following cards: 10 * - Madge Smart 16/4 PCI Mk2 11 * 12 * Maintainer(s): 13 * AF Adam Fritzler 14 * 15 * Modification History: 16 * 30-Dec-99 AF Split off from the tms380tr driver. 17 * 22-Jan-00 AF Updated to use indirect read/writes 18 * 23-Nov-00 JG New PCI API, cleanups 19 * 20 * 21 * TODO: 22 * 1. See if we can use MMIO instead of inb/outb/inw/outw 23 * 2. Add support for Mk1 (has AT24 attached to the PCI 24 * config registers) 25 * 26 */ 27 28#include <linux/module.h> 29#include <linux/kernel.h> 30#include <linux/errno.h> 31#include <linux/pci.h> 32#include <linux/init.h> 33#include <linux/netdevice.h> 34#include <linux/trdevice.h> 35 36#include <asm/system.h> 37#include <asm/io.h> 38#include <asm/irq.h> 39 40#include "tms380tr.h" 41#include "abyss.h" /* Madge-specific constants */ 42 43static char version[] __devinitdata = 44"abyss.c: v1.02 23/11/2000 by Adam Fritzler\n"; 45 46#define ABYSS_IO_EXTENT 64 47 48static struct pci_device_id abyss_pci_tbl[] = { 49 { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2, 50 PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, }, 51 { } /* Terminating entry */ 52}; 53MODULE_DEVICE_TABLE(pci, abyss_pci_tbl); 54 55MODULE_LICENSE("GPL"); 56 57static int abyss_open(struct net_device *dev); 58static int abyss_close(struct net_device *dev); 59static void abyss_enable(struct net_device *dev); 60static int abyss_chipset_init(struct net_device *dev); 61static void abyss_read_eeprom(struct net_device *dev); 62static unsigned short abyss_setnselout_pins(struct net_device *dev); 63 64static void at24_writedatabyte(unsigned long regaddr, unsigned char byte); 65static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr); 66static int at24_sendcmd(unsigned long regaddr, unsigned char cmd); 67static unsigned char at24_readdatabit(unsigned long regaddr); 68static unsigned char at24_readdatabyte(unsigned long regaddr); 69static int at24_waitforack(unsigned long regaddr); 70static int at24_waitfornack(unsigned long regaddr); 71static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data); 72static void at24_start(unsigned long regaddr); 73static unsigned char at24_readb(unsigned long regaddr, unsigned char addr); 74 75static unsigned short abyss_sifreadb(struct net_device *dev, unsigned short reg) 76{ 77 return inb(dev->base_addr + reg); 78} 79 80static unsigned short abyss_sifreadw(struct net_device *dev, unsigned short reg) 81{ 82 return inw(dev->base_addr + reg); 83} 84 85static void abyss_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) 86{ 87 outb(val, dev->base_addr + reg); 88} 89 90static void abyss_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) 91{ 92 outw(val, dev->base_addr + reg); 93} 94 95static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_id *ent) 96{ 97 static int versionprinted; 98 struct net_device *dev; 99 struct net_local *tp; 100 int ret, pci_irq_line; 101 unsigned long pci_ioaddr; 102 103 if (versionprinted++ == 0) 104 printk("%s", version); 105 106 if (pci_enable_device(pdev)) 107 return -EIO; 108 109 /* Remove I/O space marker in bit 0. */ 110 pci_irq_line = pdev->irq; 111 pci_ioaddr = pci_resource_start (pdev, 0); 112 113 /* At this point we have found a valid card. */ 114 115 dev = alloc_trdev(sizeof(struct net_local)); 116 if (!dev) 117 return -ENOMEM; 118 119 if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) { 120 ret = -EBUSY; 121 goto err_out_trdev; 122 } 123 124 ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED, 125 dev->name, dev); 126 if (ret) 127 goto err_out_region; 128 129 dev->base_addr = pci_ioaddr; 130 dev->irq = pci_irq_line; 131 132 printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name); 133 printk("%s: IO: %#4lx IRQ: %d\n", 134 dev->name, pci_ioaddr, dev->irq); 135 /* 136 * The TMS SIF registers lay 0x10 above the card base address. 137 */ 138 dev->base_addr += 0x10; 139 140 ret = tmsdev_init(dev, &pdev->dev); 141 if (ret) { 142 printk("%s: unable to get memory for dev->priv.\n", 143 dev->name); 144 goto err_out_irq; 145 } 146 147 abyss_read_eeprom(dev); 148 149 printk("%s: Ring Station Address: %pM\n", dev->name, dev->dev_addr); 150 151 tp = netdev_priv(dev); 152 tp->setnselout = abyss_setnselout_pins; 153 tp->sifreadb = abyss_sifreadb; 154 tp->sifreadw = abyss_sifreadw; 155 tp->sifwriteb = abyss_sifwriteb; 156 tp->sifwritew = abyss_sifwritew; 157 158 memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1); 159 160 dev->open = abyss_open; 161 dev->stop = abyss_close; 162 163 pci_set_drvdata(pdev, dev); 164 SET_NETDEV_DEV(dev, &pdev->dev); 165 166 ret = register_netdev(dev); 167 if (ret) 168 goto err_out_tmsdev; 169 return 0; 170 171err_out_tmsdev: 172 pci_set_drvdata(pdev, NULL); 173 tmsdev_term(dev); 174err_out_irq: 175 free_irq(pdev->irq, dev); 176err_out_region: 177 release_region(pci_ioaddr, ABYSS_IO_EXTENT); 178err_out_trdev: 179 free_netdev(dev); 180 return ret; 181} 182 183static unsigned short abyss_setnselout_pins(struct net_device *dev) 184{ 185 unsigned short val = 0; 186 struct net_local *tp = netdev_priv(dev); 187 188 if(tp->DataRate == SPEED_4) 189 val |= 0x01; /* Set 4Mbps */ 190 else 191 val |= 0x00; /* Set 16Mbps */ 192 193 return val; 194} 195 196/* 197 * The following Madge boards should use this code: 198 * - Smart 16/4 PCI Mk2 (Abyss) 199 * - Smart 16/4 PCI Mk1 (PCI T) 200 * - Smart 16/4 Client Plus PnP (Big Apple) 201 * - Smart 16/4 Cardbus Mk2 202 * 203 * These access an Atmel AT24 SEEPROM using their glue chip registers. 204 * 205 */ 206static void at24_writedatabyte(unsigned long regaddr, unsigned char byte) 207{ 208 int i; 209 210 for (i = 0; i < 8; i++) { 211 at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); 212 at24_setlines(regaddr, 1, (byte >> (7-i))&0x01); 213 at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); 214 } 215} 216 217static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr) 218{ 219 if (at24_sendcmd(regaddr, cmd)) { 220 at24_writedatabyte(regaddr, addr); 221 return at24_waitforack(regaddr); 222 } 223 return 0; 224} 225 226static int at24_sendcmd(unsigned long regaddr, unsigned char cmd) 227{ 228 int i; 229 230 for (i = 0; i < 10; i++) { 231 at24_start(regaddr); 232 at24_writedatabyte(regaddr, cmd); 233 if (at24_waitforack(regaddr)) 234 return 1; 235 } 236 return 0; 237} 238 239static unsigned char at24_readdatabit(unsigned long regaddr) 240{ 241 unsigned char val; 242 243 at24_setlines(regaddr, 0, 1); 244 at24_setlines(regaddr, 1, 1); 245 val = (inb(regaddr) & AT24_DATA)?1:0; 246 at24_setlines(regaddr, 1, 1); 247 at24_setlines(regaddr, 0, 1); 248 return val; 249} 250 251static unsigned char at24_readdatabyte(unsigned long regaddr) 252{ 253 unsigned char data = 0; 254 int i; 255 256 for (i = 0; i < 8; i++) { 257 data <<= 1; 258 data |= at24_readdatabit(regaddr); 259 } 260 261 return data; 262} 263 264static int at24_waitforack(unsigned long regaddr) 265{ 266 int i; 267 268 for (i = 0; i < 10; i++) { 269 if ((at24_readdatabit(regaddr) & 0x01) == 0x00) 270 return 1; 271 } 272 return 0; 273} 274 275static int at24_waitfornack(unsigned long regaddr) 276{ 277 int i; 278 for (i = 0; i < 10; i++) { 279 if ((at24_readdatabit(regaddr) & 0x01) == 0x01) 280 return 1; 281 } 282 return 0; 283} 284 285static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data) 286{ 287 unsigned char val = AT24_ENABLE; 288 if (clock) 289 val |= AT24_CLOCK; 290 if (data) 291 val |= AT24_DATA; 292 293 outb(val, regaddr); 294 tms380tr_wait(20); /* Very necessary. */ 295} 296 297static void at24_start(unsigned long regaddr) 298{ 299 at24_setlines(regaddr, 0, 1); 300 at24_setlines(regaddr, 1, 1); 301 at24_setlines(regaddr, 1, 0); 302 at24_setlines(regaddr, 0, 1); 303} 304 305static unsigned char at24_readb(unsigned long regaddr, unsigned char addr) 306{ 307 unsigned char data = 0xff; 308 309 if (at24_sendfullcmd(regaddr, AT24_WRITE, addr)) { 310 if (at24_sendcmd(regaddr, AT24_READ)) { 311 data = at24_readdatabyte(regaddr); 312 if (!at24_waitfornack(regaddr)) 313 data = 0xff; 314 } 315 } 316 return data; 317} 318 319 320/* 321 * Enable basic functions of the Madge chipset needed 322 * for initialization. 323 */ 324static void abyss_enable(struct net_device *dev) 325{ 326 unsigned char reset_reg; 327 unsigned long ioaddr; 328 329 ioaddr = dev->base_addr; 330 reset_reg = inb(ioaddr + PCIBM2_RESET_REG); 331 reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; 332 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 333 tms380tr_wait(100); 334} 335 336/* 337 * Enable the functions of the Madge chipset needed for 338 * full working order. 339 */ 340static int abyss_chipset_init(struct net_device *dev) 341{ 342 unsigned char reset_reg; 343 unsigned long ioaddr; 344 345 ioaddr = dev->base_addr; 346 347 reset_reg = inb(ioaddr + PCIBM2_RESET_REG); 348 349 reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; 350 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 351 352 reset_reg &= ~(PCIBM2_RESET_REG_CHIP_NRES | 353 PCIBM2_RESET_REG_FIFO_NRES | 354 PCIBM2_RESET_REG_SIF_NRES); 355 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 356 357 tms380tr_wait(100); 358 359 reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; 360 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 361 362 reset_reg |= PCIBM2_RESET_REG_SIF_NRES; 363 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 364 365 reset_reg |= PCIBM2_RESET_REG_FIFO_NRES; 366 outb(reset_reg, ioaddr + PCIBM2_RESET_REG); 367 368 outb(PCIBM2_INT_CONTROL_REG_SINTEN | 369 PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE, 370 ioaddr + PCIBM2_INT_CONTROL_REG); 371 372 outb(30, ioaddr + PCIBM2_FIFO_THRESHOLD); 373 374 return 0; 375} 376 377static inline void abyss_chipset_close(struct net_device *dev) 378{ 379 unsigned long ioaddr; 380 381 ioaddr = dev->base_addr; 382 outb(0, ioaddr + PCIBM2_RESET_REG); 383} 384 385/* 386 * Read configuration data from the AT24 SEEPROM on Madge cards. 387 * 388 */ 389static void abyss_read_eeprom(struct net_device *dev) 390{ 391 struct net_local *tp; 392 unsigned long ioaddr; 393 unsigned short val; 394 int i; 395 396 tp = netdev_priv(dev); 397 ioaddr = dev->base_addr; 398 399 /* Must enable glue chip first */ 400 abyss_enable(dev); 401 402 val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, 403 PCIBM2_SEEPROM_RING_SPEED); 404 tp->DataRate = val?SPEED_4:SPEED_16; /* set open speed */ 405 printk("%s: SEEPROM: ring speed: %dMb/sec\n", dev->name, tp->DataRate); 406 407 val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, 408 PCIBM2_SEEPROM_RAM_SIZE) * 128; 409 printk("%s: SEEPROM: adapter RAM: %dkb\n", dev->name, val); 410 411 dev->addr_len = 6; 412 for (i = 0; i < 6; i++) 413 dev->dev_addr[i] = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, 414 PCIBM2_SEEPROM_BIA+i); 415} 416 417static int abyss_open(struct net_device *dev) 418{ 419 abyss_chipset_init(dev); 420 tms380tr_open(dev); 421 return 0; 422} 423 424static int abyss_close(struct net_device *dev) 425{ 426 tms380tr_close(dev); 427 abyss_chipset_close(dev); 428 return 0; 429} 430 431static void __devexit abyss_detach (struct pci_dev *pdev) 432{ 433 struct net_device *dev = pci_get_drvdata(pdev); 434 435 BUG_ON(!dev); 436 unregister_netdev(dev); 437 release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT); 438 free_irq(dev->irq, dev); 439 tmsdev_term(dev); 440 free_netdev(dev); 441 pci_set_drvdata(pdev, NULL); 442} 443 444static struct pci_driver abyss_driver = { 445 .name = "abyss", 446 .id_table = abyss_pci_tbl, 447 .probe = abyss_attach, 448 .remove = __devexit_p(abyss_detach), 449}; 450 451static int __init abyss_init (void) 452{ 453 return pci_register_driver(&abyss_driver); 454} 455 456static void __exit abyss_rmmod (void) 457{ 458 pci_unregister_driver (&abyss_driver); 459} 460 461module_init(abyss_init); 462module_exit(abyss_rmmod); 463