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