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