12d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* 22d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * SGI IOC3 master driver and IRQ demuxer 32d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * 42d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org> 52d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Heavily based on similar work by: 62d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver 72d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer 82d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre */ 92d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/errno.h> 112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/module.h> 122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/pci.h> 1356b146d36db933844011d5026c6f55593037c7b8Tobias Klauser#include <linux/dma-mapping.h> 142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/interrupt.h> 152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/spinlock.h> 162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/delay.h> 172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/ioc3.h> 182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#include <linux/rwsem.h> 195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#define IOC3_PCI_SIZE 0x100000 222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic LIST_HEAD(ioc3_devices); 242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic int ioc3_counter; 252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic DECLARE_RWSEM(ioc3_devices_rwsem); 262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES]; 282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic struct ioc3_submodule *ioc3_ethernet; 2934af946a22724c4e2b204957f2b24b22a0fb121cIngo Molnarstatic DEFINE_RWLOCK(ioc3_submodules_lock); 302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* NIC probing code */ 322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#define GPCR_MLAN_EN 0x00200000 /* enable MCR to pin 8 */ 342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic inline unsigned mcr_pack(unsigned pulse, unsigned sample) 362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return (pulse << 10) | (sample << 2); 382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic int nic_wait(struct ioc3_driver_data *idd) 412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 42d656101009d76000b8fc0998a33d592100334d52Al Viro unsigned mcr; 432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre do { 45d656101009d76000b8fc0998a33d592100334d52Al Viro mcr = readl(&idd->vma->mcr); 462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } while (!(mcr & 2)); 472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return mcr & 1; 492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic int nic_reset(struct ioc3_driver_data *idd) 522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int presence; 542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre local_irq_save(flags); 57d656101009d76000b8fc0998a33d592100334d52Al Viro writel(mcr_pack(500, 65), &idd->vma->mcr); 582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre presence = nic_wait(idd); 592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre local_irq_restore(flags); 602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre udelay(500); 622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return presence; 642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6615b370c95cbc1553eec30a99a5ffb3ac3c8d7b81Pat Gefrestatic int nic_read_bit(struct ioc3_driver_data *idd) 672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int result; 692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre local_irq_save(flags); 72d656101009d76000b8fc0998a33d592100334d52Al Viro writel(mcr_pack(6, 13), &idd->vma->mcr); 732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre result = nic_wait(idd); 742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre local_irq_restore(flags); 752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre udelay(500); 772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return result; 792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8115b370c95cbc1553eec30a99a5ffb3ac3c8d7b81Pat Gefrestatic void nic_write_bit(struct ioc3_driver_data *idd, int bit) 822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (bit) 84d656101009d76000b8fc0998a33d592100334d52Al Viro writel(mcr_pack(6, 110), &idd->vma->mcr); 852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre else 86d656101009d76000b8fc0998a33d592100334d52Al Viro writel(mcr_pack(80, 30), &idd->vma->mcr); 872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_wait(idd); 892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic unsigned nic_read_byte(struct ioc3_driver_data *idd) 922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned result = 0; 942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i; 952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for (i = 0; i < 8; i++) 972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre result = (result >> 1) | (nic_read_bit(idd) << 7); 982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return result; 1002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void nic_write_byte(struct ioc3_driver_data *idd, int byte) 1032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i, bit; 1052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for (i = 8; i; i--) { 1072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre bit = byte & 1; 1082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre byte >>= 1; 1092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_bit(idd, bit); 1112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic unsigned long 1152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrenic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr) 1162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int a, b, index, disc; 1182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_reset(idd); 1202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Search ROM. */ 1222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0xF0); 1232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Algorithm from ``Book of iButton Standards''. */ 1252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for (index = 0, disc = 0; index < 64; index++) { 1262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre a = nic_read_bit(idd); 1272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre b = nic_read_bit(idd); 1282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (a && b) { 1302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING "IOC3 NIC search failed.\n"); 1312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *last = 0; 1322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return 0; 1332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!a && !b) { 1362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (index == *last) { 1372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr |= 1UL << index; 1382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else if (index > *last) { 1392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr &= ~(1UL << index); 1402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre disc = index; 1412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else if ((addr & (1UL << index)) == 0) 1422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre disc = index; 1432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_bit(idd, (addr>>index)&1); 1442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre continue; 1452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else { 1462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (a) 1472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr |= 1UL << index; 1482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre else 1492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr &= ~(1UL << index); 1502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_bit(idd, a); 1512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre continue; 1522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *last = disc; 1552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return addr; 1562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void nic_addr(struct ioc3_driver_data *idd, unsigned long addr) 1592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int index; 1612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_reset(idd); 1632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0xF0); 1642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for (index = 0; index < 64; index++) { 1652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_read_bit(idd); 1662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_read_bit(idd); 1672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_bit(idd, (addr>>index)&1); 1682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void crc16_byte(unsigned int *crc, unsigned char db) 1722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i; 1742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<8;i++) { 1762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc <<= 1; 1772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if((db^(*crc>>16)) & 1) 1782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc ^= 0x8005; 1792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre db >>= 1; 1802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 1812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc &= 0xFFFF; 1822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc) 1852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(size--) 1872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc16_byte(&crc, *(dbs++)); 1882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return crc; 1892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 1902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void crc8_byte(unsigned int *crc, unsigned char db) 1922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 1932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i,f; 1942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 1952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<8;i++) { 1962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre f = (*crc ^ db) & 1; 1972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc >>= 1; 1982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre db >>= 1; 1992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(f) 2002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc ^= 0x8c; 2012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *crc &= 0xff; 2032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 2042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic unsigned int crc8_addr(unsigned long addr) 2062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 2072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i; 2082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned int crc = 0x00; 2092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<8;i++) 2112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc8_byte(&crc, addr>>(i<<3)); 2122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return crc; 2132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 2142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void 2162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreread_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page, 2172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned char *redir, unsigned char *data) 2182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 2192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int loops = 16, i; 2202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(redir[page] != 0xFF) { 2222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre page = redir[page]^0xFF; 2232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops--; 2242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(loops<0) { 2252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_ERR "IOC3: NIC circular redirection\n"); 2262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 2272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops = 3; 2302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(loops>0) { 2312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_addr(idd, addr); 2322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0xF0); 2332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, (page << 5) & 0xE0); 2342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, (page >> 3) & 0x1F); 2352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<0x20;i++) 2362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre data[i] = nic_read_byte(idd); 2372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(crc16_area(data, 0x20, 0x0000) == 0x800d) 2382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 2392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops--; 2402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_ERR "IOC3: CRC error in data page\n"); 2422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<0x20;i++) 2432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre data[i] = 0x00; 2442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 2452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void 2472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreread_redir_map(struct ioc3_driver_data *idd, unsigned long addr, 2482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned char *redir) 2492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 2502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i,j,loops = 3,crc_ok; 2512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned int crc; 2522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(loops>0) { 2542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc_ok = 1; 2552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_addr(idd, addr); 2562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0xAA); 2572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0x00); 2582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0x01); 2592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<64;i+=8) { 2602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(j=0;j<8;j++) 2612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre redir[i+j] = nic_read_byte(idd); 2622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000); 2632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc16_byte(&crc, nic_read_byte(idd)); 2642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc16_byte(&crc, nic_read_byte(idd)); 2652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(crc != 0x800d) 2662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre crc_ok = 0; 2672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(crc_ok) 2692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 2702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops--; 2712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 2722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_ERR "IOC3: CRC error in redirection page\n"); 2732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<64;i++) 2742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre redir[i] = 0xFF; 2752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 2762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void read_nic(struct ioc3_driver_data *idd, unsigned long addr) 2782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 2792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned char redir[64]; 2802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned char data[64],part[32]; 2812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i,j; 2822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 2832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* read redirections */ 2842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_redir_map(idd, addr, redir); 2852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* read data pages */ 2862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_redir_page(idd, addr, 0, redir, data); 2872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_redir_page(idd, addr, 1, redir, data+32); 2882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* assemble the part # */ 2892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre j=0; 2902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<19;i++) 2912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(data[i+11] != ' ') 2922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre part[j++] = data[i+11]; 2932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<6;i++) 2942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(data[i+32] != ' ') 2952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre part[j++] = data[i+32]; 2962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre part[j] = 0; 2972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* skip Octane power supplies */ 2982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(part, "060-0035-", 9)) 2992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 3002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(part, "060-0038-", 9)) 3012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 3022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre strcpy(idd->nic_part, part); 3032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* assemble the serial # */ 3042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre j=0; 3052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<10;i++) 3062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(data[i+1] != ' ') 3072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_serial[j++] = data[i+1]; 3082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_serial[j] = 0; 3092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 3102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void read_mac(struct ioc3_driver_data *idd, unsigned long addr) 3122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 3132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i, loops = 3; 3142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned char data[13]; 3152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(loops>0) { 3172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_addr(idd, addr); 3182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0xF0); 3192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0x00); 3202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_write_byte(idd, 0x00); 3212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre nic_read_byte(idd); 3222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<13;i++) 3232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre data[i] = nic_read_byte(idd); 3242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(crc16_area(data, 13, 0x0000) == 0x800d) { 3252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=10;i>4;i--) 3262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_mac[10-i] = data[i]; 3272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 3282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops--; 3302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_ERR "IOC3: CRC error in MAC address\n"); 3322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<6;i++) 3332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_mac[i] = 0x00; 3342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 3352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic void probe_nic(struct ioc3_driver_data *idd) 3372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 3382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int save = 0, loops = 3; 3392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long first, addr; 3402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 341d656101009d76000b8fc0998a33d592100334d52Al Viro writel(GPCR_MLAN_EN, &idd->vma->gpcr_s); 3422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(loops>0) { 3442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_part[0] = 0; 3452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_serial[0] = 0; 3462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr = first = nic_find(idd, &save, 0); 3472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!first) 3482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 3492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre while(1) { 3502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(crc8_addr(addr)) 3512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre break; 3522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre else { 3532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre switch(addr & 0xFF) { 3542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case 0x0B: 3552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_nic(idd, addr); 3562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre break; 3572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case 0x09: 3582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case 0x89: 3592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case 0x91: 3602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_mac(idd, addr); 3612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre break; 3622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre addr = nic_find(idd, &save, addr); 3652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(addr == first) 3662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return; 3672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre loops--; 3692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_ERR "IOC3: CRC error in NIC address\n"); 3712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 3722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Interrupts */ 3742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 37515b370c95cbc1553eec30a99a5ffb3ac3c8d7b81Pat Gefrestatic void write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which) 3762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 3772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 3782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_lock_irqsave(&idd->ir_lock, flags); 3802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre switch (which) { 3812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case IOC3_W_IES: 3822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(val, &idd->vma->sio_ies); 3832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre break; 3842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre case IOC3_W_IEC: 3852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(val, &idd->vma->sio_iec); 3862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre break; 3872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 3882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_unlock_irqrestore(&idd->ir_lock, flags); 3892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 3902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd) 3912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 3922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flag; 3932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre uint32_t intrs = 0; 3942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 3952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_lock_irqsave(&idd->ir_lock, flag); 3962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre intrs = readl(&idd->vma->sio_ir); 3972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre intrs &= readl(&idd->vma->sio_ies); 3982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_unlock_irqrestore(&idd->ir_lock, flag); 3992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return intrs; 4002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4027d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ioc3_intr_io(int irq, void *arg) 4032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 405c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzik struct ioc3_driver_data *idd = arg; 4062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int handled = 1, id; 4072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned int pending; 4082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_lock_irqsave(&ioc3_submodules_lock, flags); 4102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 411d656101009d76000b8fc0998a33d592100334d52Al Viro if(idd->dual_irq && readb(&idd->vma->eisr)) { 4122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* send Ethernet IRQ to the driver */ 4132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_ethernet && idd->active[ioc3_ethernet->id] && 4142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ioc3_ethernet->intr) { 4152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, 4167d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells idd, 0); 4172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 4182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 4192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pending = get_pending_intrs(idd); /* look at the IO IRQs */ 4202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(id=0;id<IOC3_MAX_SUBMODULES;id++) { 4222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(idd->active[id] && ioc3_submodules[id] 4232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre && (pending & ioc3_submodules[id]->irq_mask) 4242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre && ioc3_submodules[id]->intr) { 4252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, ioc3_submodules[id]->irq_mask, 4262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre IOC3_W_IEC); 4272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!ioc3_submodules[id]->intr(ioc3_submodules[id], 4287d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells idd, pending & ioc3_submodules[id]->irq_mask)) 4292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pending &= ~ioc3_submodules[id]->irq_mask; 4302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (ioc3_submodules[id]->reset_mask) 4312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, ioc3_submodules[id]->irq_mask, 4322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre IOC3_W_IES); 4332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 4342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 4352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_unlock_irqrestore(&ioc3_submodules_lock, flags); 4362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(pending) { 4372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 4382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending); 4392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, pending, IOC3_W_IEC); 4402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre handled = 1; 4412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 4422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return handled?IRQ_HANDLED:IRQ_NONE; 4432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4457d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ioc3_intr_eth(int irq, void *arg) 4462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 4482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg; 4492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int handled = 1; 4502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!idd->dual_irq) 4522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return IRQ_NONE; 4532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_lock_irqsave(&ioc3_submodules_lock, flags); 4542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_ethernet && idd->active[ioc3_ethernet->id] 4552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre && ioc3_ethernet->intr) 4567d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0); 4572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre read_unlock_irqrestore(&ioc3_submodules_lock, flags); 4582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return handled?IRQ_HANDLED:IRQ_NONE; 4592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrevoid ioc3_enable(struct ioc3_submodule *is, 4622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd, unsigned int irqs) 4632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, irqs & is->irq_mask, IOC3_W_IES); 4652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrevoid ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd, 4682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned int irqs) 4692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(irqs & is->irq_mask, &idd->vma->sio_ir); 4712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrevoid ioc3_disable(struct ioc3_submodule *is, 4742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd, unsigned int irqs) 4752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC); 4772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrevoid ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val) 4802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 4822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_lock_irqsave(&idd->gpio_lock, flags); 4832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(val, &idd->vma->gpcr_s); 4842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_unlock_irqrestore(&idd->gpio_lock, flags); 4852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Keep it simple, stupid! */ 4882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic int find_slot(void **tab, int max) 4892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 4902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int i; 4912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(i=0;i<max;i++) 4922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!(tab[i])) 4932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return i; 4942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return -1; 4952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 4962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 4972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Register an IOC3 submodule */ 4982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreint ioc3_register_submodule(struct ioc3_submodule *is) 4992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 5002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd; 5012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int alloc_id; 5022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 5032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_lock_irqsave(&ioc3_submodules_lock, flags); 5052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES); 5062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(alloc_id != -1) { 5072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ioc3_submodules[alloc_id] = is; 5082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(is->ethernet) { 5092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_ethernet==NULL) 5102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ioc3_ethernet=is; 5112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre else 5122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 5132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "IOC3 Ethernet module already registered!\n"); 5142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 5152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 5162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_unlock_irqrestore(&ioc3_submodules_lock, flags); 5172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(alloc_id == -1) { 5192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING "Increase IOC3_MAX_SUBMODULES!\n"); 5202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return -ENOMEM; 5212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 5222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre is->id=alloc_id; 5242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Initialize submodule for each IOC3 */ 5262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!is->probe) 5272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return 0; 5282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre down_read(&ioc3_devices_rwsem); 5302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre list_for_each_entry(idd, &ioc3_devices, list) { 5312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* set to 1 for IRQs in probe */ 5322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[alloc_id] = 1; 5332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[alloc_id] = !is->probe(is, idd); 5342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 5352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre up_read(&ioc3_devices_rwsem); 5362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return 0; 5382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 5392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Unregister an IOC3 submodule */ 5412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrevoid ioc3_unregister_submodule(struct ioc3_submodule *is) 5422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 5432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd; 5442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre unsigned long flags; 5452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_lock_irqsave(&ioc3_submodules_lock, flags); 5472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_submodules[is->id]==is) 5482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ioc3_submodules[is->id]=NULL; 5492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre else 5502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 5512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "IOC3 submodule %s has wrong ID.\n",is->name); 5522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_ethernet==is) 5532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ioc3_ethernet = NULL; 5542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_unlock_irqrestore(&ioc3_submodules_lock, flags); 5552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Remove submodule for each IOC3 */ 5572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre down_read(&ioc3_devices_rwsem); 5582d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre list_for_each_entry(idd, &ioc3_devices, list) 5592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(idd->active[is->id]) { 5602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(is->remove) 5612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(is->remove(is, idd)) 5622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 5632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: IOC3 submodule %s remove failed " 5642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for pci_dev %s.\n", 5659150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, module_name(is->owner), 5662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_name(idd->pdev)); 5672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[is->id] = 0; 5682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(is->irq_mask) 5692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, is->irq_mask, IOC3_W_IEC); 5702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 5712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre up_read(&ioc3_devices_rwsem); 5722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 5732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/********************* 5752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Device management * 5762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *********************/ 5772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5782ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic char * __devinitdata 5792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreioc3_class_names[]={"unknown", "IP27 BaseIO", "IP30 system", "MENET 1/2/3", 5802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "MENET 4", "CADduo", "Altix Serial"}; 5812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 5822ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic int __devinit ioc3_class(struct ioc3_driver_data *idd) 5832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 5842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int res = IOC3_CLASS_NONE; 5852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* NIC-based logic */ 5862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(idd->nic_part, "030-0891-", 9)) 5872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre res = IOC3_CLASS_BASE_IP30; 5882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(idd->nic_part, "030-1155-", 9)) 5892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre res = IOC3_CLASS_CADDUO; 5902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(idd->nic_part, "030-1657-", 9)) 5912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre res = IOC3_CLASS_SERIAL; 5922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!strncmp(idd->nic_part, "030-1664-", 9)) 5932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre res = IOC3_CLASS_SERIAL; 5942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* total random heuristics */ 5952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#ifdef CONFIG_SGI_IP27 5962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(!idd->nic_part[0]) 5972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre res = IOC3_CLASS_BASE_IP27; 5982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#endif 5992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* print educational message */ 6002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_INFO "IOC3 part: [%s], serial: [%s] => class %s\n", 6012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->nic_part, idd->nic_serial, ioc3_class_names[res]); 6022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return res; 6032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 6042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Adds a new instance of an IOC3 card */ 6052ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic int __devinit 6062ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvareioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) 6072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 6082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd; 6092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre uint32_t pcmd; 6102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int ret, id; 6112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Enable IOC3 and take ownership of it */ 6132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if ((ret = pci_enable_device(pdev))) { 6142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 6152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: Failed to enable IOC3 device for pci_dev %s.\n", 6169150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pci_name(pdev)); 6172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre goto out; 6182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_set_master(pdev); 6202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#ifdef USE_64BIT_DMA 6226a35528a8346f6e6fd32ed7e51f04d1fa4ca2c01Yang Hongyang ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 6232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!ret) { 6246a35528a8346f6e6fd32ed7e51f04d1fa4ca2c01Yang Hongyang ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 6252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (ret < 0) { 6262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA " 6272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for consistent allocations\n", 6289150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__); 6292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre#endif 6322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Set up per-IOC3 data */ 634dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL); 6352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!idd) { 6362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 6372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: Failed to allocate IOC3 data for pci_dev %s.\n", 6389150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pci_name(pdev)); 6392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ret = -ENODEV; 6402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre goto out_idd; 6412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_lock_init(&idd->ir_lock); 6432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre spin_lock_init(&idd->gpio_lock); 6442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->pdev = pdev; 6452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Map all IOC3 registers. These are shared between subdevices 6472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * so the main IOC3 module manages them. 6482d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre */ 6492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->pma = pci_resource_start(pdev, 0); 6502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!idd->pma) { 6512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 6522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: Unable to find IOC3 resource " 6532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for pci_dev %s.\n", 6549150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pci_name(pdev)); 6552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ret = -ENODEV; 6562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre goto out_pci; 6572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 65852c9ae0ac7576c94f6a2371b44039e7ba12a0439Brent Casavant if (!request_mem_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) { 6592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 6602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: Unable to request IOC3 region " 6612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for pci_dev %s.\n", 6629150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pci_name(pdev)); 6632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ret = -ENODEV; 6642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre goto out_pci; 6652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->vma = ioremap(idd->pma, IOC3_PCI_SIZE); 6672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (!idd->vma) { 6682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 6692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: Unable to remap IOC3 region " 6702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for pci_dev %s.\n", 6719150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pci_name(pdev)); 6722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre ret = -ENODEV; 6732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre goto out_misc_region; 6742d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 6752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Track PCI-device specific data */ 6772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_set_drvdata(pdev, idd); 6782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre down_write(&ioc3_devices_rwsem); 6792c43630fb0ff3f01c29367248ffa4a851e2c9b34Pat Gefre list_add_tail(&idd->list, &ioc3_devices); 6802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->id = ioc3_counter++; 6812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre up_write(&ioc3_devices_rwsem); 6822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 683d656101009d76000b8fc0998a33d592100334d52Al Viro idd->gpdr_shadow = readl(&idd->vma->gpdr); 6842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Read IOC3 NIC contents */ 6862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre probe_nic(idd); 6872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Detect IOC3 class */ 6892d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->class = ioc3_class(idd); 6902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Initialize IOC3 */ 6922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_read_config_dword(pdev, PCI_COMMAND, &pcmd); 6932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_write_config_dword(pdev, PCI_COMMAND, 6942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pcmd | PCI_COMMAND_MEMORY | 6952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre PCI_COMMAND_PARITY | PCI_COMMAND_SERR | 6962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre PCI_SCR_DROP_MODE_EN); 6972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 6982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, ~0, IOC3_W_IEC); 6992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(~0, &idd->vma->sio_ir); 7002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Set up IRQs */ 7022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(idd->class == IOC3_CLASS_BASE_IP30 7032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre || idd->class == IOC3_CLASS_BASE_IP27) { 7042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(0, &idd->vma->eier); 7052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(~0, &idd->vma->eisr); 7062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->dual_irq = 1; 708dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner if (!request_irq(pdev->irq, ioc3_intr_eth, IRQF_SHARED, 7092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "ioc3-eth", (void *)idd)) { 7102d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->irq_eth = pdev->irq; 7112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else { 7122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 7132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s : request_irq fails for IRQ 0x%x\n ", 7149150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pdev->irq); 7152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 716dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner if (!request_irq(pdev->irq+2, ioc3_intr_io, IRQF_SHARED, 7172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "ioc3-io", (void *)idd)) { 7182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->irq_io = pdev->irq+2; 7192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else { 7202d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 7212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s : request_irq fails for IRQ 0x%x\n ", 7229150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pdev->irq+2); 7232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 7242d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else { 725dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED, 7262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "ioc3", (void *)idd)) { 7272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->irq_io = pdev->irq; 7282d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } else { 7292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 7302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s : request_irq fails for IRQ 0x%x\n ", 7319150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, pdev->irq); 7322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 7332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 7342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Add this IOC3 to all submodules */ 7362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(id=0;id<IOC3_MAX_SUBMODULES;id++) 7372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_submodules[id] && ioc3_submodules[id]->probe) { 7382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[id] = 1; 7392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[id] = !ioc3_submodules[id]->probe 7402d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre (ioc3_submodules[id], idd); 7412d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 7422d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7432d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev)); 7442d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7452d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return 0; 7462d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7472d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreout_misc_region: 74852c9ae0ac7576c94f6a2371b44039e7ba12a0439Brent Casavant release_mem_region(idd->pma, IOC3_PCI_SIZE); 7492d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreout_pci: 7502d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre kfree(idd); 7512d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreout_idd: 7522d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_disable_device(pdev); 7532d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefreout: 7542d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return ret; 7552d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 7562d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7572d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Removes a particular instance of an IOC3 card. */ 7582ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic void __devexit ioc3_remove(struct pci_dev *pdev) 7592d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 7602d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre int id; 7612d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre struct ioc3_driver_data *idd; 7622d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7632d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd = pci_get_drvdata(pdev); 7642d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7652d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Remove this IOC3 from all submodules */ 7662d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre for(id=0;id<IOC3_MAX_SUBMODULES;id++) 7672d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(idd->active[id]) { 7682d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_submodules[id] && ioc3_submodules[id]->remove) 7692d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(ioc3_submodules[id]->remove(ioc3_submodules[id], 7702d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd)) 7712d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre printk(KERN_WARNING 7722d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "%s: IOC3 submodule 0x%s remove failed " 7732d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre "for pci_dev %s.\n", 7749150c979cee012eeee853d4041e133d2801c699eHarvey Harrison __func__, 7752d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre module_name(ioc3_submodules[id]->owner), 7762d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_name(pdev)); 7772d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre idd->active[id] = 0; 7782d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre } 7792d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7802d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Clear and disable all IRQs */ 7812d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre write_ireg(idd, ~0, IOC3_W_IEC); 7822d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre writel(~0, &idd->vma->sio_ir); 7832d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7842d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Release resources */ 7852d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre free_irq(idd->irq_io, (void *)idd); 7862d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if(idd->dual_irq) 7872d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre free_irq(idd->irq_eth, (void *)idd); 7882d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre iounmap(idd->vma); 78952c9ae0ac7576c94f6a2371b44039e7ba12a0439Brent Casavant release_mem_region(idd->pma, IOC3_PCI_SIZE); 7902d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7912d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Disable IOC3 and relinquish */ 7922d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_disable_device(pdev); 7932d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 7942d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre /* Remove and free driver data */ 7952d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre down_write(&ioc3_devices_rwsem); 7962d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre list_del(&idd->list); 7972d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre up_write(&ioc3_devices_rwsem); 7982d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre kfree(idd); 7992d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 8002d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8012d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic struct pci_device_id ioc3_id_table[] = { 8022d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID}, 8032d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre {0} 8042d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre}; 8052d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8062d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefrestatic struct pci_driver ioc3_driver = { 8072d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre .name = "IOC3", 8082d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre .id_table = ioc3_id_table, 8092d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre .probe = ioc3_probe, 8102ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvare .remove = __devexit_p(ioc3_remove), 8112d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre}; 8122d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8132d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick GefreMODULE_DEVICE_TABLE(pci, ioc3_id_table); 8142d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8152d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/********************* 8162d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre * Module management * 8172d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre *********************/ 8182d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8192d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Module load */ 8202ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic int __init ioc3_init(void) 8212d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 8222d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre if (ia64_platform_is("sn2")) 8232d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre return pci_register_driver(&ioc3_driver); 8249385565e20c4acf97cd8e2fd7155750e578edcc4Jean Delvare return -ENODEV; 8252d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 8262d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8272d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre/* Module unload */ 8282ea5d35a49f5c89d1d2d677fe90c71ad5a6278b6Jean Delvarestatic void __exit ioc3_exit(void) 8292d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre{ 8302d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre pci_unregister_driver(&ioc3_driver); 8312d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre} 8322d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8332d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefremodule_init(ioc3_init); 8342d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefremodule_exit(ioc3_exit); 8352d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 8362d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick GefreMODULE_AUTHOR("Stanislaw Skowronek <skylark@linux-mips.org>"); 8372d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick GefreMODULE_DESCRIPTION("PCI driver for SGI IOC3"); 8382d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick GefreMODULE_LICENSE("GPL"); 8392d0cfb527944c2cfee2cffab14f52d483e329fcfPatrick Gefre 84053d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_register_submodule); 84153d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_unregister_submodule); 84253d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_ack); 84353d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_gpcr_set); 84453d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_disable); 84553d8be5c144ece5d48745810b14248968e73eaf2Pat GefreEXPORT_SYMBOL_GPL(ioc3_enable); 846