xref: /openbmc/linux/drivers/net/wan/n2.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * SDL Inc. RISCom/N2 synchronous serial card driver for Linux
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl>
61da177e4SLinus Torvalds  *
7ab274959SAlexander A. Klimov  * For information see <https://www.kernel.org/pub/linux/utils/net/hdlc/>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Note: integrated CSU/DSU/DDS are not supported by this driver
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Sources of information:
121da177e4SLinus Torvalds  *    Hitachi HD64570 SCA User's Manual
131da177e4SLinus Torvalds  *    SDL Inc. PPP/HDLC/CISCO driver
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
1612a3bfefSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1712a3bfefSJoe Perches 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/kernel.h>
2086ae13b0SIngo Molnar #include <linux/capability.h>
211da177e4SLinus Torvalds #include <linux/slab.h>
221da177e4SLinus Torvalds #include <linux/types.h>
231da177e4SLinus Torvalds #include <linux/fcntl.h>
241da177e4SLinus Torvalds #include <linux/in.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/ioport.h>
291da177e4SLinus Torvalds #include <linux/moduleparam.h>
301da177e4SLinus Torvalds #include <linux/netdevice.h>
311da177e4SLinus Torvalds #include <linux/hdlc.h>
321da177e4SLinus Torvalds #include <asm/io.h>
331da177e4SLinus Torvalds #include "hd64570.h"
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds static const char *version = "SDL RISCom/N2 driver version: 1.15";
361da177e4SLinus Torvalds static const char *devname = "RISCom/N2";
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #undef DEBUG_PKT
391da177e4SLinus Torvalds #define DEBUG_RINGS
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #define USE_WINDOWSIZE 16384
421da177e4SLinus Torvalds #define USE_BUS16BITS 1
431da177e4SLinus Torvalds #define CLOCK_BASE 9830400	/* 9.8304 MHz */
441da177e4SLinus Torvalds #define MAX_PAGES      16	/* 16 RAM pages at max */
451da177e4SLinus Torvalds #define MAX_RAM_SIZE 0x80000	/* 512 KB */
461da177e4SLinus Torvalds #if MAX_RAM_SIZE > MAX_PAGES * USE_WINDOWSIZE
471da177e4SLinus Torvalds #undef MAX_RAM_SIZE
481da177e4SLinus Torvalds #define MAX_RAM_SIZE (MAX_PAGES * USE_WINDOWSIZE)
491da177e4SLinus Torvalds #endif
501da177e4SLinus Torvalds #define N2_IOPORTS 0x10
511da177e4SLinus Torvalds #define NEED_DETECT_RAM
521da177e4SLinus Torvalds #define NEED_SCA_MSCI_INTR
531da177e4SLinus Torvalds #define MAX_TX_BUFFERS 10
541da177e4SLinus Torvalds 
5588597364SKrzysztof Hałasa static char *hw;	/* pointer to hw=xxx command line string */
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /* RISCom/N2 Board Registers */
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /* PC Control Register */
601da177e4SLinus Torvalds #define N2_PCR 0
611da177e4SLinus Torvalds #define PCR_RUNSCA 1     /* Run 64570 */
621da177e4SLinus Torvalds #define PCR_VPM    2     /* Enable VPM - needed if using RAM above 1 MB */
631da177e4SLinus Torvalds #define PCR_ENWIN  4     /* Open window */
641da177e4SLinus Torvalds #define PCR_BUS16  8     /* 16-bit bus */
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds /* Memory Base Address Register */
671da177e4SLinus Torvalds #define N2_BAR 2
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /* Page Scan Register  */
701da177e4SLinus Torvalds #define N2_PSR 4
711da177e4SLinus Torvalds #define WIN16K       0x00
721da177e4SLinus Torvalds #define WIN32K       0x20
731da177e4SLinus Torvalds #define WIN64K       0x40
741da177e4SLinus Torvalds #define PSR_WINBITS  0x60
751da177e4SLinus Torvalds #define PSR_DMAEN    0x80
761da177e4SLinus Torvalds #define PSR_PAGEBITS 0x0F
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /* Modem Control Reg */
791da177e4SLinus Torvalds #define N2_MCR 6
801da177e4SLinus Torvalds #define CLOCK_OUT_PORT1 0x80
811da177e4SLinus Torvalds #define CLOCK_OUT_PORT0 0x40
821da177e4SLinus Torvalds #define TX422_PORT1     0x20
831da177e4SLinus Torvalds #define TX422_PORT0     0x10
841da177e4SLinus Torvalds #define DSR_PORT1       0x08
851da177e4SLinus Torvalds #define DSR_PORT0       0x04
861da177e4SLinus Torvalds #define DTR_PORT1       0x02
871da177e4SLinus Torvalds #define DTR_PORT0       0x01
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds typedef struct port_s {
901da177e4SLinus Torvalds 	struct net_device *dev;
911da177e4SLinus Torvalds 	struct card_s *card;
921da177e4SLinus Torvalds 	spinlock_t lock;	/* TX lock */
931da177e4SLinus Torvalds 	sync_serial_settings settings;
941da177e4SLinus Torvalds 	int valid;		/* port enabled */
951da177e4SLinus Torvalds 	int rxpart;		/* partial frame received, next frame invalid*/
961da177e4SLinus Torvalds 	unsigned short encoding;
971da177e4SLinus Torvalds 	unsigned short parity;
981da177e4SLinus Torvalds 	u16 rxin;		/* rx ring buffer 'in' pointer */
991da177e4SLinus Torvalds 	u16 txin;		/* tx ring buffer 'in' and 'last' pointers */
1001da177e4SLinus Torvalds 	u16 txlast;
1011da177e4SLinus Torvalds 	u8 rxs, txs, tmc;	/* SCA registers */
1021da177e4SLinus Torvalds 	u8 phy_node;		/* physical port # - 0 or 1 */
1031da177e4SLinus Torvalds 	u8 log_node;		/* logical port # */
1041da177e4SLinus Torvalds } port_t;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds typedef struct card_s {
1071da177e4SLinus Torvalds 	u8 __iomem *winbase;		/* ISA window base address */
1081da177e4SLinus Torvalds 	u32 phy_winbase;	/* ISA physical base address */
1091da177e4SLinus Torvalds 	u32 ram_size;		/* number of bytes */
1101da177e4SLinus Torvalds 	u16 io;			/* IO Base address */
1111da177e4SLinus Torvalds 	u16 buff_offset;	/* offset of first buffer of first channel */
1121da177e4SLinus Torvalds 	u16 rx_ring_buffers;	/* number of buffers in a ring */
1131da177e4SLinus Torvalds 	u16 tx_ring_buffers;
1141da177e4SLinus Torvalds 	u8 irq;			/* IRQ (3-15) */
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	port_t ports[2];
1171da177e4SLinus Torvalds 	struct card_s *next_card;
1181da177e4SLinus Torvalds } card_t;
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds static card_t *first_card;
1211da177e4SLinus Torvalds static card_t **new_card = &first_card;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds #define sca_reg(reg, card) (0x8000 | (card)->io | \
1241da177e4SLinus Torvalds 			    ((reg) & 0x0F) | (((reg) & 0xF0) << 6))
1251da177e4SLinus Torvalds #define sca_in(reg, card)		inb(sca_reg(reg, card))
1261da177e4SLinus Torvalds #define sca_out(value, reg, card)	outb(value, sca_reg(reg, card))
1271da177e4SLinus Torvalds #define sca_inw(reg, card)		inw(sca_reg(reg, card))
1281da177e4SLinus Torvalds #define sca_outw(value, reg, card)	outw(value, sca_reg(reg, card))
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds #define port_to_card(port)		((port)->card)
1311da177e4SLinus Torvalds #define log_node(port)			((port)->log_node)
1321da177e4SLinus Torvalds #define phy_node(port)			((port)->phy_node)
1331da177e4SLinus Torvalds #define winsize(card)			(USE_WINDOWSIZE)
1341da177e4SLinus Torvalds #define winbase(card)      	     	((card)->winbase)
1351da177e4SLinus Torvalds #define get_port(card, port)		((card)->ports[port].valid ? \
1361da177e4SLinus Torvalds 					 &(card)->ports[port] : NULL)
1371da177e4SLinus Torvalds 
sca_get_page(card_t * card)1381da177e4SLinus Torvalds static __inline__ u8 sca_get_page(card_t *card)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	return inb(card->io + N2_PSR) & PSR_PAGEBITS;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds 
openwin(card_t * card,u8 page)1431da177e4SLinus Torvalds static __inline__ void openwin(card_t *card, u8 page)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds 	u8 psr = inb(card->io + N2_PSR);
1469e7ee10fSPeng Li 
1471da177e4SLinus Torvalds 	outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR);
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds 
1506b40aba3SKrzysztof Hałasa #include "hd64570.c"
1511da177e4SLinus Torvalds 
n2_set_iface(port_t * port)1521da177e4SLinus Torvalds static void n2_set_iface(port_t *port)
1531da177e4SLinus Torvalds {
1541da177e4SLinus Torvalds 	card_t *card = port->card;
1551da177e4SLinus Torvalds 	int io = card->io;
1561da177e4SLinus Torvalds 	u8 mcr = inb(io + N2_MCR);
1571da177e4SLinus Torvalds 	u8 msci = get_msci(port);
1581da177e4SLinus Torvalds 	u8 rxs = port->rxs & CLK_BRG_MASK;
1591da177e4SLinus Torvalds 	u8 txs = port->txs & CLK_BRG_MASK;
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	switch (port->settings.clock_type) {
1621da177e4SLinus Torvalds 	case CLOCK_INT:
1631da177e4SLinus Torvalds 		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
1641da177e4SLinus Torvalds 		rxs |= CLK_BRG_RX; /* BRG output */
1651da177e4SLinus Torvalds 		txs |= CLK_RXCLK_TX; /* RX clock */
1661da177e4SLinus Torvalds 		break;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	case CLOCK_TXINT:
1691da177e4SLinus Torvalds 		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
1701da177e4SLinus Torvalds 		rxs |= CLK_LINE_RX; /* RXC input */
1711da177e4SLinus Torvalds 		txs |= CLK_BRG_TX; /* BRG output */
1721da177e4SLinus Torvalds 		break;
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds 	case CLOCK_TXFROMRX:
1751da177e4SLinus Torvalds 		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
1761da177e4SLinus Torvalds 		rxs |= CLK_LINE_RX; /* RXC input */
1771da177e4SLinus Torvalds 		txs |= CLK_RXCLK_TX; /* RX clock */
1781da177e4SLinus Torvalds 		break;
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	default:		/* Clock EXTernal */
1811da177e4SLinus Torvalds 		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
1821da177e4SLinus Torvalds 		rxs |= CLK_LINE_RX; /* RXC input */
1831da177e4SLinus Torvalds 		txs |= CLK_LINE_TX; /* TXC input */
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	outb(mcr, io + N2_MCR);
1871da177e4SLinus Torvalds 	port->rxs = rxs;
1881da177e4SLinus Torvalds 	port->txs = txs;
1891da177e4SLinus Torvalds 	sca_out(rxs, msci + RXS, card);
1901da177e4SLinus Torvalds 	sca_out(txs, msci + TXS, card);
1911da177e4SLinus Torvalds 	sca_set_port(port);
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
n2_open(struct net_device * dev)1941da177e4SLinus Torvalds static int n2_open(struct net_device *dev)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	port_t *port = dev_to_port(dev);
1971da177e4SLinus Torvalds 	int io = port->card->io;
19830cbb010SPeng Li 	u8 mcr = inb(io + N2_MCR) |
19930cbb010SPeng Li 		(port->phy_node ? TX422_PORT1 : TX422_PORT0);
2001da177e4SLinus Torvalds 	int result;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	result = hdlc_open(dev);
2031da177e4SLinus Torvalds 	if (result)
2041da177e4SLinus Torvalds 		return result;
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */
2071da177e4SLinus Torvalds 	outb(mcr, io + N2_MCR);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
2101da177e4SLinus Torvalds 	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
2111da177e4SLinus Torvalds 	sca_open(dev);
2121da177e4SLinus Torvalds 	n2_set_iface(port);
2131da177e4SLinus Torvalds 	return 0;
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds 
n2_close(struct net_device * dev)2161da177e4SLinus Torvalds static int n2_close(struct net_device *dev)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds 	port_t *port = dev_to_port(dev);
2191da177e4SLinus Torvalds 	int io = port->card->io;
22030cbb010SPeng Li 	u8 mcr = inb(io + N2_MCR) |
22130cbb010SPeng Li 		(port->phy_node ? TX422_PORT1 : TX422_PORT0);
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	sca_close(dev);
2241da177e4SLinus Torvalds 	mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
2251da177e4SLinus Torvalds 	outb(mcr, io + N2_MCR);
2261da177e4SLinus Torvalds 	hdlc_close(dev);
2271da177e4SLinus Torvalds 	return 0;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds 
n2_siocdevprivate(struct net_device * dev,struct ifreq * ifr,void __user * data,int cmd)23073d74f61SArnd Bergmann static int n2_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
23173d74f61SArnd Bergmann 			     void __user *data, int cmd)
23273d74f61SArnd Bergmann {
23373d74f61SArnd Bergmann #ifdef DEBUG_RINGS
23473d74f61SArnd Bergmann 	if (cmd == SIOCDEVPRIVATE) {
23573d74f61SArnd Bergmann 		sca_dump_rings(dev);
23673d74f61SArnd Bergmann 		return 0;
23773d74f61SArnd Bergmann 	}
23873d74f61SArnd Bergmann #endif
23973d74f61SArnd Bergmann 	return -EOPNOTSUPP;
24073d74f61SArnd Bergmann }
24173d74f61SArnd Bergmann 
n2_ioctl(struct net_device * dev,struct if_settings * ifs)242*ad7eab2aSArnd Bergmann static int n2_ioctl(struct net_device *dev, struct if_settings *ifs)
2431da177e4SLinus Torvalds {
2441da177e4SLinus Torvalds 	const size_t size = sizeof(sync_serial_settings);
2451da177e4SLinus Torvalds 	sync_serial_settings new_line;
246*ad7eab2aSArnd Bergmann 	sync_serial_settings __user *line = ifs->ifs_ifsu.sync;
2471da177e4SLinus Torvalds 	port_t *port = dev_to_port(dev);
2481da177e4SLinus Torvalds 
249*ad7eab2aSArnd Bergmann 	switch (ifs->type) {
2501da177e4SLinus Torvalds 	case IF_GET_IFACE:
251*ad7eab2aSArnd Bergmann 		ifs->type = IF_IFACE_SYNC_SERIAL;
252*ad7eab2aSArnd Bergmann 		if (ifs->size < size) {
253*ad7eab2aSArnd Bergmann 			ifs->size = size; /* data size wanted */
2541da177e4SLinus Torvalds 			return -ENOBUFS;
2551da177e4SLinus Torvalds 		}
2561da177e4SLinus Torvalds 		if (copy_to_user(line, &port->settings, size))
2571da177e4SLinus Torvalds 			return -EFAULT;
2581da177e4SLinus Torvalds 		return 0;
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	case IF_IFACE_SYNC_SERIAL:
2611da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
2621da177e4SLinus Torvalds 			return -EPERM;
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 		if (copy_from_user(&new_line, line, size))
2651da177e4SLinus Torvalds 			return -EFAULT;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 		if (new_line.clock_type != CLOCK_EXT &&
2681da177e4SLinus Torvalds 		    new_line.clock_type != CLOCK_TXFROMRX &&
2691da177e4SLinus Torvalds 		    new_line.clock_type != CLOCK_INT &&
2701da177e4SLinus Torvalds 		    new_line.clock_type != CLOCK_TXINT)
2711da177e4SLinus Torvalds 			return -EINVAL;	/* No such clock setting */
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 		if (new_line.loopback != 0 && new_line.loopback != 1)
2741da177e4SLinus Torvalds 			return -EINVAL;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 		memcpy(&port->settings, &new_line, size); /* Update settings */
2771da177e4SLinus Torvalds 		n2_set_iface(port);
2781da177e4SLinus Torvalds 		return 0;
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	default:
281*ad7eab2aSArnd Bergmann 		return hdlc_ioctl(dev, ifs);
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
n2_destroy_card(card_t * card)2851da177e4SLinus Torvalds static void n2_destroy_card(card_t *card)
2861da177e4SLinus Torvalds {
2871da177e4SLinus Torvalds 	int cnt;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	for (cnt = 0; cnt < 2; cnt++)
2901da177e4SLinus Torvalds 		if (card->ports[cnt].card) {
2911da177e4SLinus Torvalds 			struct net_device *dev = port_to_dev(&card->ports[cnt]);
2929e7ee10fSPeng Li 
2931da177e4SLinus Torvalds 			unregister_hdlc_device(dev);
2941da177e4SLinus Torvalds 		}
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	if (card->irq)
2971da177e4SLinus Torvalds 		free_irq(card->irq, card);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	if (card->winbase) {
3001da177e4SLinus Torvalds 		iounmap(card->winbase);
3011da177e4SLinus Torvalds 		release_mem_region(card->phy_winbase, USE_WINDOWSIZE);
3021da177e4SLinus Torvalds 	}
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	if (card->io)
3051da177e4SLinus Torvalds 		release_region(card->io, N2_IOPORTS);
3061da177e4SLinus Torvalds 	if (card->ports[0].dev)
3071da177e4SLinus Torvalds 		free_netdev(card->ports[0].dev);
3081da177e4SLinus Torvalds 	if (card->ports[1].dev)
3091da177e4SLinus Torvalds 		free_netdev(card->ports[1].dev);
3101da177e4SLinus Torvalds 	kfree(card);
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds 
313991990a1SKrzysztof Hałasa static const struct net_device_ops n2_ops = {
314991990a1SKrzysztof Hałasa 	.ndo_open       = n2_open,
315991990a1SKrzysztof Hałasa 	.ndo_stop       = n2_close,
316991990a1SKrzysztof Hałasa 	.ndo_start_xmit = hdlc_start_xmit,
317*ad7eab2aSArnd Bergmann 	.ndo_siocwandev = n2_ioctl,
31873d74f61SArnd Bergmann 	.ndo_siocdevprivate = n2_siocdevprivate,
319991990a1SKrzysztof Hałasa };
3201da177e4SLinus Torvalds 
n2_run(unsigned long io,unsigned long irq,unsigned long winbase,long valid0,long valid1)3211da177e4SLinus Torvalds static int __init n2_run(unsigned long io, unsigned long irq,
3221da177e4SLinus Torvalds 			 unsigned long winbase, long valid0, long valid1)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds 	card_t *card;
3251da177e4SLinus Torvalds 	u8 cnt, pcr;
3261da177e4SLinus Torvalds 	int i;
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) {
32912a3bfefSJoe Perches 		pr_err("invalid I/O port value\n");
3301da177e4SLinus Torvalds 		return -ENODEV;
3311da177e4SLinus Torvalds 	}
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ {
33412a3bfefSJoe Perches 		pr_err("invalid IRQ value\n");
3351da177e4SLinus Torvalds 		return -ENODEV;
3361da177e4SLinus Torvalds 	}
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) {
33912a3bfefSJoe Perches 		pr_err("invalid RAM value\n");
3401da177e4SLinus Torvalds 		return -ENODEV;
3411da177e4SLinus Torvalds 	}
3421da177e4SLinus Torvalds 
343dd00cc48SYoann Padioleau 	card = kzalloc(sizeof(card_t), GFP_KERNEL);
3442aea27baSPeng Li 	if (!card)
3451da177e4SLinus Torvalds 		return -ENOBUFS;
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
3481da177e4SLinus Torvalds 	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
3491da177e4SLinus Torvalds 	if (!card->ports[0].dev || !card->ports[1].dev) {
35012a3bfefSJoe Perches 		pr_err("unable to allocate memory\n");
3511da177e4SLinus Torvalds 		n2_destroy_card(card);
3521da177e4SLinus Torvalds 		return -ENOMEM;
3531da177e4SLinus Torvalds 	}
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	if (!request_region(io, N2_IOPORTS, devname)) {
35612a3bfefSJoe Perches 		pr_err("I/O port region in use\n");
3571da177e4SLinus Torvalds 		n2_destroy_card(card);
3581da177e4SLinus Torvalds 		return -EBUSY;
3591da177e4SLinus Torvalds 	}
3601da177e4SLinus Torvalds 	card->io = io;
3611da177e4SLinus Torvalds 
362a0607fd3SJoe Perches 	if (request_irq(irq, sca_intr, 0, devname, card)) {
36312a3bfefSJoe Perches 		pr_err("could not allocate IRQ\n");
3641da177e4SLinus Torvalds 		n2_destroy_card(card);
365807540baSEric Dumazet 		return -EBUSY;
3661da177e4SLinus Torvalds 	}
3671da177e4SLinus Torvalds 	card->irq = irq;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 	if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) {
37012a3bfefSJoe Perches 		pr_err("could not request RAM window\n");
3711da177e4SLinus Torvalds 		n2_destroy_card(card);
372807540baSEric Dumazet 		return -EBUSY;
3731da177e4SLinus Torvalds 	}
3741da177e4SLinus Torvalds 	card->phy_winbase = winbase;
3751da177e4SLinus Torvalds 	card->winbase = ioremap(winbase, USE_WINDOWSIZE);
3764446065aSKrzysztof Halasa 	if (!card->winbase) {
37712a3bfefSJoe Perches 		pr_err("ioremap() failed\n");
3784446065aSKrzysztof Halasa 		n2_destroy_card(card);
3794446065aSKrzysztof Halasa 		return -EFAULT;
3804446065aSKrzysztof Halasa 	}
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	outb(0, io + N2_PCR);
3831da177e4SLinus Torvalds 	outb(winbase >> 12, io + N2_BAR);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	switch (USE_WINDOWSIZE) {
3861da177e4SLinus Torvalds 	case 16384:
3871da177e4SLinus Torvalds 		outb(WIN16K, io + N2_PSR);
3881da177e4SLinus Torvalds 		break;
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 	case 32768:
3911da177e4SLinus Torvalds 		outb(WIN32K, io + N2_PSR);
3921da177e4SLinus Torvalds 		break;
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds 	case 65536:
3951da177e4SLinus Torvalds 		outb(WIN64K, io + N2_PSR);
3961da177e4SLinus Torvalds 		break;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	default:
39912a3bfefSJoe Perches 		pr_err("invalid window size\n");
4001da177e4SLinus Torvalds 		n2_destroy_card(card);
4011da177e4SLinus Torvalds 		return -ENODEV;
4021da177e4SLinus Torvalds 	}
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0);
4051da177e4SLinus Torvalds 	outb(pcr, io + N2_PCR);
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	card->ram_size = sca_detect_ram(card, card->winbase, MAX_RAM_SIZE);
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 	/* number of TX + RX buffers for one port */
4101da177e4SLinus Torvalds 	i = card->ram_size / ((valid0 + valid1) * (sizeof(pkt_desc) +
4111da177e4SLinus Torvalds 						   HDLC_MAX_MRU));
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
4141da177e4SLinus Torvalds 	card->rx_ring_buffers = i - card->tx_ring_buffers;
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) *
4171da177e4SLinus Torvalds 		(card->tx_ring_buffers + card->rx_ring_buffers);
4181da177e4SLinus Torvalds 
41912a3bfefSJoe Perches 	pr_info("RISCom/N2 %u KB RAM, IRQ%u, using %u TX + %u RX packets rings\n",
42012a3bfefSJoe Perches 		card->ram_size / 1024, card->irq,
42112a3bfefSJoe Perches 		card->tx_ring_buffers, card->rx_ring_buffers);
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	if (card->tx_ring_buffers < 1) {
42412a3bfefSJoe Perches 		pr_err("RAM test failed\n");
4251da177e4SLinus Torvalds 		n2_destroy_card(card);
4261da177e4SLinus Torvalds 		return -EIO;
4271da177e4SLinus Torvalds 	}
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	pcr |= PCR_RUNSCA;		/* run SCA */
4301da177e4SLinus Torvalds 	outb(pcr, io + N2_PCR);
4311da177e4SLinus Torvalds 	outb(0, io + N2_MCR);
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds 	sca_init(card, 0);
4341da177e4SLinus Torvalds 	for (cnt = 0; cnt < 2; cnt++) {
4351da177e4SLinus Torvalds 		port_t *port = &card->ports[cnt];
4361da177e4SLinus Torvalds 		struct net_device *dev = port_to_dev(port);
4371da177e4SLinus Torvalds 		hdlc_device *hdlc = dev_to_hdlc(dev);
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 		if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
4401da177e4SLinus Torvalds 			continue;
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 		port->phy_node = cnt;
4431da177e4SLinus Torvalds 		port->valid = 1;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 		if ((cnt == 1) && valid0)
4461da177e4SLinus Torvalds 			port->log_node = 1;
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 		spin_lock_init(&port->lock);
4491da177e4SLinus Torvalds 		dev->irq = irq;
4501da177e4SLinus Torvalds 		dev->mem_start = winbase;
4511da177e4SLinus Torvalds 		dev->mem_end = winbase + USE_WINDOWSIZE - 1;
4521da177e4SLinus Torvalds 		dev->tx_queue_len = 50;
453991990a1SKrzysztof Hałasa 		dev->netdev_ops = &n2_ops;
4541da177e4SLinus Torvalds 		hdlc->attach = sca_attach;
4551da177e4SLinus Torvalds 		hdlc->xmit = sca_xmit;
4561da177e4SLinus Torvalds 		port->settings.clock_type = CLOCK_EXT;
4571da177e4SLinus Torvalds 		port->card = card;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 		if (register_hdlc_device(dev)) {
46012a3bfefSJoe Perches 			pr_warn("unable to register hdlc device\n");
4611da177e4SLinus Torvalds 			port->card = NULL;
4621da177e4SLinus Torvalds 			n2_destroy_card(card);
4631da177e4SLinus Torvalds 			return -ENOBUFS;
4641da177e4SLinus Torvalds 		}
46588597364SKrzysztof Hałasa 		sca_init_port(port); /* Set up SCA memory */
4661da177e4SLinus Torvalds 
46712a3bfefSJoe Perches 		netdev_info(dev, "RISCom/N2 node %d\n", port->phy_node);
4681da177e4SLinus Torvalds 	}
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds 	*new_card = card;
4711da177e4SLinus Torvalds 	new_card = &card->next_card;
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 	return 0;
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds 
n2_init(void)4761da177e4SLinus Torvalds static int __init n2_init(void)
4771da177e4SLinus Torvalds {
4782aea27baSPeng Li 	if (!hw) {
4791da177e4SLinus Torvalds #ifdef MODULE
48012a3bfefSJoe Perches 		pr_info("no card initialized\n");
4811da177e4SLinus Torvalds #endif
48209669585SAkinobu Mita 		return -EINVAL;	/* no parameters specified, abort */
4831da177e4SLinus Torvalds 	}
4841da177e4SLinus Torvalds 
48512a3bfefSJoe Perches 	pr_info("%s\n", version);
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	do {
4881da177e4SLinus Torvalds 		unsigned long io, irq, ram;
4891da177e4SLinus Torvalds 		long valid[2] = { 0, 0 }; /* Default = both ports disabled */
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 		io = simple_strtoul(hw, &hw, 0);
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 		if (*hw++ != ',')
4941da177e4SLinus Torvalds 			break;
4951da177e4SLinus Torvalds 		irq = simple_strtoul(hw, &hw, 0);
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 		if (*hw++ != ',')
4981da177e4SLinus Torvalds 			break;
4991da177e4SLinus Torvalds 		ram = simple_strtoul(hw, &hw, 0);
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 		if (*hw++ != ',')
5021da177e4SLinus Torvalds 			break;
5031da177e4SLinus Torvalds 		while (1) {
5041da177e4SLinus Torvalds 			if (*hw == '0' && !valid[0])
5051da177e4SLinus Torvalds 				valid[0] = 1; /* Port 0 enabled */
5061da177e4SLinus Torvalds 			else if (*hw == '1' && !valid[1])
5071da177e4SLinus Torvalds 				valid[1] = 1; /* Port 1 enabled */
5081da177e4SLinus Torvalds 			else
5091da177e4SLinus Torvalds 				break;
5101da177e4SLinus Torvalds 			hw++;
5111da177e4SLinus Torvalds 		}
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 		if (!valid[0] && !valid[1])
5141da177e4SLinus Torvalds 			break;	/* at least one port must be used */
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 		if (*hw == ':' || *hw == '\x0')
5171da177e4SLinus Torvalds 			n2_run(io, irq, ram, valid[0], valid[1]);
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 		if (*hw == '\x0')
52009669585SAkinobu Mita 			return first_card ? 0 : -EINVAL;
5211da177e4SLinus Torvalds 	} while (*hw++ == ':');
5221da177e4SLinus Torvalds 
52312a3bfefSJoe Perches 	pr_err("invalid hardware parameters\n");
52409669585SAkinobu Mita 	return first_card ? 0 : -EINVAL;
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds 
n2_cleanup(void)5271da177e4SLinus Torvalds static void __exit n2_cleanup(void)
5281da177e4SLinus Torvalds {
5291da177e4SLinus Torvalds 	card_t *card = first_card;
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 	while (card) {
5321da177e4SLinus Torvalds 		card_t *ptr = card;
5339e7ee10fSPeng Li 
5341da177e4SLinus Torvalds 		card = card->next_card;
5351da177e4SLinus Torvalds 		n2_destroy_card(ptr);
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds module_init(n2_init);
5401da177e4SLinus Torvalds module_exit(n2_cleanup);
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
5431da177e4SLinus Torvalds MODULE_DESCRIPTION("RISCom/N2 serial port driver");
5441da177e4SLinus Torvalds MODULE_LICENSE("GPL v2");
54541b1d174SKrzysztof Halasa module_param(hw, charp, 0444);
54641b1d174SKrzysztof Halasa MODULE_PARM_DESC(hw, "io,irq,ram,ports:io,irq,...");
547