mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
Merge branch 'for-david' of git://git.kernel.org/pub/scm/linux/kernel/git/chris/linux-2.6
This commit is contained in:
commit
c46920dadb
14 changed files with 1397 additions and 2084 deletions
|
@ -6,7 +6,7 @@
|
|||
# To add a new book the only step required is to add the book to the
|
||||
# list of DOCBOOKS.
|
||||
|
||||
DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml \
|
||||
DOCBOOKS := z8530book.xml mcabook.xml \
|
||||
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
|
||||
procfs-guide.xml writing_usb_driver.xml networking.xml \
|
||||
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
||||
|
|
|
@ -98,9 +98,6 @@
|
|||
X!Enet/core/wireless.c
|
||||
</sect1>
|
||||
-->
|
||||
<sect1><title>Synchronous PPP</title>
|
||||
!Edrivers/net/wan/syncppp.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
</book>
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||
|
||||
<book id="WANGuide">
|
||||
<bookinfo>
|
||||
<title>Synchronous PPP and Cisco HDLC Programming Guide</title>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Alan</firstname>
|
||||
<surname>Cox</surname>
|
||||
<affiliation>
|
||||
<address>
|
||||
<email>alan@lxorguk.ukuu.org.uk</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2000</year>
|
||||
<holder>Alan Cox</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
This documentation is free software; you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This program is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
MA 02111-1307 USA
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more details see the file COPYING in the source
|
||||
distribution of Linux.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The syncppp drivers in Linux provide a fairly complete
|
||||
implementation of Cisco HDLC and a minimal implementation of
|
||||
PPP. The longer term goal is to switch the PPP layer to the
|
||||
generic PPP interface that is new in Linux 2.3.x. The API should
|
||||
remain unchanged when this is done, but support will then be
|
||||
available for IPX, compression and other PPP features
|
||||
</para>
|
||||
</chapter>
|
||||
<chapter id="bugs">
|
||||
<title>Known Bugs And Assumptions</title>
|
||||
<para>
|
||||
<variablelist>
|
||||
<varlistentry><term>PPP is minimal</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The current PPP implementation is very basic, although sufficient
|
||||
for most wan usages.
|
||||
</para>
|
||||
</listitem></varlistentry>
|
||||
|
||||
<varlistentry><term>Cisco HDLC Quirks</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Currently we do not end all packets with the correct Cisco multicast
|
||||
or unicast flags. Nothing appears to mind too much but this should
|
||||
be corrected.
|
||||
</para>
|
||||
</listitem></varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="pubfunctions">
|
||||
<title>Public Functions Provided</title>
|
||||
!Edrivers/net/wan/syncppp.c
|
||||
</chapter>
|
||||
|
||||
</book>
|
|
@ -3,15 +3,15 @@ Krzysztof Halasa <khc@pm.waw.pl>
|
|||
|
||||
|
||||
Generic HDLC layer currently supports:
|
||||
1. Frame Relay (ANSI, CCITT, Cisco and no LMI).
|
||||
1. Frame Relay (ANSI, CCITT, Cisco and no LMI)
|
||||
- Normal (routed) and Ethernet-bridged (Ethernet device emulation)
|
||||
interfaces can share a single PVC.
|
||||
- ARP support (no InARP support in the kernel - there is an
|
||||
experimental InARP user-space daemon available on:
|
||||
http://www.kernel.org/pub/linux/utils/net/hdlc/).
|
||||
2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation.
|
||||
3. Cisco HDLC.
|
||||
4. PPP (uses syncppp.c).
|
||||
2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation
|
||||
3. Cisco HDLC
|
||||
4. PPP
|
||||
5. X.25 (uses X.25 routines).
|
||||
|
||||
Generic HDLC is a protocol driver only - it needs a low-level driver
|
||||
|
|
|
@ -14,7 +14,7 @@ obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
|
|||
obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
|
||||
obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
|
||||
obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
|
||||
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
|
||||
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
|
||||
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
|
||||
|
||||
pc300-y := pc300_drv.o
|
||||
|
|
|
@ -88,7 +88,7 @@ static card_t **new_card = &first_card;
|
|||
/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */
|
||||
#define sca_outw(value, reg, card) do { \
|
||||
writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \
|
||||
writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg+1));\
|
||||
writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
|
||||
} while(0)
|
||||
|
||||
#define port_to_card(port) (port)
|
||||
|
@ -113,7 +113,7 @@ static inline void openwin(card_t *card, u8 page)
|
|||
}
|
||||
|
||||
|
||||
#include "hd6457x.c"
|
||||
#include "hd64570.c"
|
||||
|
||||
|
||||
static inline void set_carrier(port_t *port)
|
||||
|
@ -381,7 +381,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
|
|||
return result;
|
||||
}
|
||||
|
||||
sca_init_sync_port(card); /* Set up C101 memory */
|
||||
sca_init_port(card); /* Set up C101 memory */
|
||||
set_carrier(card);
|
||||
|
||||
printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Hitachi SCA HD64570 and HD64572 common driver for Linux
|
||||
* Hitachi SCA HD64570 driver for Linux
|
||||
*
|
||||
* Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
|
@ -7,9 +7,7 @@
|
|||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* Sources of information:
|
||||
* Hitachi HD64570 SCA User's Manual
|
||||
* Hitachi HD64572 SCA-II User's Manual
|
||||
* Source of information: Hitachi HD64570 SCA User's Manual
|
||||
*
|
||||
* We use the following SCA memory map:
|
||||
*
|
||||
|
@ -26,33 +24,26 @@
|
|||
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/hdlc.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/hdlc.h>
|
||||
|
||||
#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \
|
||||
(defined (__HD64570_H) && defined (__HD64572_H))
|
||||
#error Either hd64570.h or hd64572.h must be included
|
||||
#endif
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "hd64570.h"
|
||||
|
||||
#define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET)
|
||||
#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
|
||||
|
@ -62,16 +53,6 @@
|
|||
#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02)
|
||||
#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04)
|
||||
|
||||
#ifdef __HD64570_H /* HD64570 */
|
||||
#define sca_outa(value, reg, card) sca_outw(value, reg, card)
|
||||
#define sca_ina(reg, card) sca_inw(reg, card)
|
||||
#define writea(value, ptr) writew(value, ptr)
|
||||
|
||||
#else /* HD64572 */
|
||||
#define sca_outa(value, reg, card) sca_outl(value, reg, card)
|
||||
#define sca_ina(reg, card) sca_inl(reg, card)
|
||||
#define writea(value, ptr) writel(value, ptr)
|
||||
#endif
|
||||
|
||||
static inline struct net_device *port_to_dev(port_t *port)
|
||||
{
|
||||
|
@ -81,8 +62,6 @@ static inline struct net_device *port_to_dev(port_t *port)
|
|||
static inline int sca_intr_status(card_t *card)
|
||||
{
|
||||
u8 result = 0;
|
||||
|
||||
#ifdef __HD64570_H /* HD64570 */
|
||||
u8 isr0 = sca_in(ISR0, card);
|
||||
u8 isr1 = sca_in(ISR1, card);
|
||||
|
||||
|
@ -93,18 +72,6 @@ static inline int sca_intr_status(card_t *card)
|
|||
if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
|
||||
if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
|
||||
|
||||
#else /* HD64572 */
|
||||
u32 isr0 = sca_inl(ISR0, card);
|
||||
|
||||
if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
|
||||
if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
|
||||
if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1);
|
||||
if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1);
|
||||
if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
|
||||
if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
|
||||
|
||||
#endif /* HD64570 vs HD64572 */
|
||||
|
||||
if (!(result & SCA_INTR_DMAC_TX(0)))
|
||||
if (sca_in(DSR_TX(0), card) & DSR_EOM)
|
||||
result |= SCA_INTR_DMAC_TX(0);
|
||||
|
@ -127,7 +94,6 @@ static inline u16 next_desc(port_t *port, u16 desc, int transmit)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
u16 rx_buffs = port_to_card(port)->rx_ring_buffers;
|
||||
|
@ -139,28 +105,26 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
/* Descriptor offset always fits in 16 bytes */
|
||||
/* Descriptor offset always fits in 16 bits */
|
||||
return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, int transmit)
|
||||
static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
|
||||
int transmit)
|
||||
{
|
||||
#ifdef PAGE0_ALWAYS_MAPPED
|
||||
return (pkt_desc __iomem *)(win0base(port_to_card(port))
|
||||
+ desc_offset(port, desc, transmit));
|
||||
+ desc_offset(port, desc, transmit));
|
||||
#else
|
||||
return (pkt_desc __iomem *)(winbase(port_to_card(port))
|
||||
+ desc_offset(port, desc, transmit));
|
||||
+ desc_offset(port, desc, transmit));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
return port_to_card(port)->buff_offset +
|
||||
|
@ -186,7 +150,7 @@ static inline void sca_set_carrier(port_t *port)
|
|||
}
|
||||
|
||||
|
||||
static void sca_init_sync_port(port_t *port)
|
||||
static void sca_init_port(port_t *port)
|
||||
{
|
||||
card_t *card = port_to_card(port);
|
||||
int transmit, i;
|
||||
|
@ -195,7 +159,7 @@ static void sca_init_sync_port(port_t *port)
|
|||
port->txin = 0;
|
||||
port->txlast = 0;
|
||||
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
#ifndef PAGE0_ALWAYS_MAPPED
|
||||
openwin(card, 0);
|
||||
#endif
|
||||
|
||||
|
@ -209,7 +173,7 @@ static void sca_init_sync_port(port_t *port)
|
|||
u16 chain_off = desc_offset(port, i + 1, transmit);
|
||||
u32 buff_off = buffer_offset(port, i, transmit);
|
||||
|
||||
writea(chain_off, &desc->cp);
|
||||
writew(chain_off, &desc->cp);
|
||||
writel(buff_off, &desc->bp);
|
||||
writew(0, &desc->len);
|
||||
writeb(0, &desc->stat);
|
||||
|
@ -222,16 +186,14 @@ static void sca_init_sync_port(port_t *port)
|
|||
sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) :
|
||||
DCR_RX(phy_node(port)), card);
|
||||
|
||||
#ifdef __HD64570_H
|
||||
sca_out(0, dmac + CPB, card); /* pointer base */
|
||||
#endif
|
||||
/* current desc addr */
|
||||
sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card);
|
||||
sca_out(0, dmac + CPB, card); /* pointer base */
|
||||
sca_outw(desc_offset(port, 0, transmit), dmac + CDAL, card);
|
||||
if (!transmit)
|
||||
sca_outa(desc_offset(port, buffs - 1, transmit),
|
||||
sca_outw(desc_offset(port, buffs - 1, transmit),
|
||||
dmac + EDAL, card);
|
||||
else
|
||||
sca_outa(desc_offset(port, 0, transmit), dmac + EDAL,
|
||||
sca_outw(desc_offset(port, 0, transmit), dmac + EDAL,
|
||||
card);
|
||||
|
||||
/* clear frame end interrupt counter */
|
||||
|
@ -258,7 +220,6 @@ static void sca_init_sync_port(port_t *port)
|
|||
}
|
||||
|
||||
|
||||
|
||||
#ifdef NEED_SCA_MSCI_INTR
|
||||
/* MSCI interrupt service */
|
||||
static inline void sca_msci_intr(port_t *port)
|
||||
|
@ -282,17 +243,15 @@ static inline void sca_msci_intr(port_t *port)
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u16 rxin)
|
||||
static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
|
||||
u16 rxin)
|
||||
{
|
||||
struct net_device *dev = port_to_dev(port);
|
||||
struct sk_buff *skb;
|
||||
u16 len;
|
||||
u32 buff;
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
u32 maxlen;
|
||||
u8 page;
|
||||
#endif
|
||||
|
||||
len = readw(&desc->len);
|
||||
skb = dev_alloc_skb(len);
|
||||
|
@ -302,7 +261,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
|
|||
}
|
||||
|
||||
buff = buffer_offset(port, rxin, 0);
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
page = buff / winsize(card);
|
||||
buff = buff % winsize(card);
|
||||
maxlen = winsize(card) - buff;
|
||||
|
@ -314,12 +272,10 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
|
|||
openwin(card, page + 1);
|
||||
memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen);
|
||||
} else
|
||||
#endif
|
||||
memcpy_fromio(skb->data, winbase(card) + buff, len);
|
||||
memcpy_fromio(skb->data, winbase(card) + buff, len);
|
||||
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
/* select pkt_desc table page back */
|
||||
openwin(card, 0);
|
||||
#ifndef PAGE0_ALWAYS_MAPPED
|
||||
openwin(card, 0); /* select pkt_desc table page back */
|
||||
#endif
|
||||
skb_put(skb, len);
|
||||
#ifdef DEBUG_PKT
|
||||
|
@ -333,7 +289,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Receive DMA interrupt service */
|
||||
static inline void sca_rx_intr(port_t *port)
|
||||
{
|
||||
|
@ -353,7 +308,7 @@ static inline void sca_rx_intr(port_t *port)
|
|||
while (1) {
|
||||
u32 desc_off = desc_offset(port, port->rxin, 0);
|
||||
pkt_desc __iomem *desc;
|
||||
u32 cda = sca_ina(dmac + CDAL, card);
|
||||
u32 cda = sca_inw(dmac + CDAL, card);
|
||||
|
||||
if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
|
||||
break; /* No frame received */
|
||||
|
@ -377,7 +332,7 @@ static inline void sca_rx_intr(port_t *port)
|
|||
sca_rx(card, port, desc, port->rxin);
|
||||
|
||||
/* Set new error descriptor address */
|
||||
sca_outa(desc_off, dmac + EDAL, card);
|
||||
sca_outw(desc_off, dmac + EDAL, card);
|
||||
port->rxin = next_desc(port, port->rxin, 0);
|
||||
}
|
||||
|
||||
|
@ -386,7 +341,6 @@ static inline void sca_rx_intr(port_t *port)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Transmit DMA interrupt service */
|
||||
static inline void sca_tx_intr(port_t *port)
|
||||
{
|
||||
|
@ -407,7 +361,7 @@ static inline void sca_tx_intr(port_t *port)
|
|||
pkt_desc __iomem *desc;
|
||||
|
||||
u32 desc_off = desc_offset(port, port->txlast, 1);
|
||||
u32 cda = sca_ina(dmac + CDAL, card);
|
||||
u32 cda = sca_inw(dmac + CDAL, card);
|
||||
if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
|
||||
break; /* Transmitter is/will_be sending this frame */
|
||||
|
||||
|
@ -423,17 +377,13 @@ static inline void sca_tx_intr(port_t *port)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static irqreturn_t sca_intr(int irq, void* dev_id)
|
||||
{
|
||||
card_t *card = dev_id;
|
||||
int i;
|
||||
u8 stat;
|
||||
int handled = 0;
|
||||
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
u8 page = sca_get_page(card);
|
||||
#endif
|
||||
|
||||
while((stat = sca_intr_status(card)) != 0) {
|
||||
handled = 1;
|
||||
|
@ -452,14 +402,11 @@ static irqreturn_t sca_intr(int irq, void* dev_id)
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
openwin(card, page); /* Restore original page */
|
||||
#endif
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sca_set_port(port_t *port)
|
||||
{
|
||||
card_t* card = port_to_card(port);
|
||||
|
@ -497,12 +444,7 @@ static void sca_set_port(port_t *port)
|
|||
port->tmc = tmc;
|
||||
|
||||
/* baud divisor - time constant*/
|
||||
#ifdef __HD64570_H
|
||||
sca_out(port->tmc, msci + TMC, card);
|
||||
#else
|
||||
sca_out(port->tmc, msci + TMCR, card);
|
||||
sca_out(port->tmc, msci + TMCT, card);
|
||||
#endif
|
||||
|
||||
/* Set BRG bits */
|
||||
sca_out(port->rxs, msci + RXS, card);
|
||||
|
@ -518,7 +460,6 @@ static void sca_set_port(port_t *port)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static void sca_open(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
|
@ -540,11 +481,7 @@ static void sca_open(struct net_device *dev)
|
|||
switch(port->parity) {
|
||||
case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break;
|
||||
case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break;
|
||||
#ifdef __HD64570_H
|
||||
case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
|
||||
#else
|
||||
case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
|
||||
#endif
|
||||
case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break;
|
||||
default: md0 = MD0_HDLC | MD0_CRC_NONE;
|
||||
}
|
||||
|
@ -554,35 +491,20 @@ static void sca_open(struct net_device *dev)
|
|||
sca_out(0x00, msci + MD1, card); /* no address field check */
|
||||
sca_out(md2, msci + MD2, card);
|
||||
sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
|
||||
#ifdef __HD64570_H
|
||||
sca_out(CTL_IDLE, msci + CTL, card);
|
||||
#else
|
||||
/* Skip the rest of underrun frame */
|
||||
sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
|
||||
#endif
|
||||
|
||||
#ifdef __HD64570_H
|
||||
/* Allow at least 8 bytes before requesting RX DMA operation */
|
||||
/* TX with higher priority and possibly with shorter transfers */
|
||||
sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/
|
||||
sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/
|
||||
sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
|
||||
#else
|
||||
sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
|
||||
sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
|
||||
sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
|
||||
sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
|
||||
sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
|
||||
#endif
|
||||
|
||||
/* We're using the following interrupts:
|
||||
- TXINT (DMAC completed all transmisions, underrun or DCD change)
|
||||
- all DMA interrupts
|
||||
*/
|
||||
|
||||
sca_set_carrier(port);
|
||||
|
||||
#ifdef __HD64570_H
|
||||
/* MSCI TX INT and RX INT A IRQ enable */
|
||||
sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card);
|
||||
sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card);
|
||||
|
@ -591,21 +513,8 @@ static void sca_open(struct net_device *dev)
|
|||
/* enable DMA IRQ */
|
||||
sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
|
||||
IER1, card);
|
||||
#else
|
||||
/* MSCI TXINT and RXINTA interrupt enable */
|
||||
sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0,
|
||||
card);
|
||||
/* DMA & MSCI IRQ enable */
|
||||
sca_outl(sca_inl(IER0, card) |
|
||||
(phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card);
|
||||
#endif
|
||||
|
||||
#ifdef __HD64570_H
|
||||
sca_out(port->tmc, msci + TMC, card); /* Restore registers */
|
||||
#else
|
||||
sca_out(port->tmc, msci + TMCR, card);
|
||||
sca_out(port->tmc, msci + TMCT, card);
|
||||
#endif
|
||||
sca_out(port->rxs, msci + RXS, card);
|
||||
sca_out(port->txs, msci + TXS, card);
|
||||
sca_out(CMD_TX_ENABLE, msci + CMD, card);
|
||||
|
@ -615,7 +524,6 @@ static void sca_open(struct net_device *dev)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static void sca_close(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
|
@ -623,23 +531,17 @@ static void sca_close(struct net_device *dev)
|
|||
|
||||
/* reset channel */
|
||||
sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
|
||||
#ifdef __HD64570_H
|
||||
/* disable MSCI interrupts */
|
||||
sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0),
|
||||
IER0, card);
|
||||
/* disable DMA interrupts */
|
||||
sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0),
|
||||
IER1, card);
|
||||
#else
|
||||
/* disable DMA & MSCI IRQ */
|
||||
sca_outl(sca_inl(IER0, card) &
|
||||
(phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card);
|
||||
#endif
|
||||
|
||||
netif_stop_queue(dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int sca_attach(struct net_device *dev, unsigned short encoding,
|
||||
unsigned short parity)
|
||||
{
|
||||
|
@ -653,11 +555,7 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
|
|||
if (parity != PARITY_NONE &&
|
||||
parity != PARITY_CRC16_PR0 &&
|
||||
parity != PARITY_CRC16_PR1 &&
|
||||
#ifdef __HD64570_H
|
||||
parity != PARITY_CRC16_PR0_CCITT &&
|
||||
#else
|
||||
parity != PARITY_CRC32_PR1_CCITT &&
|
||||
#endif
|
||||
parity != PARITY_CRC16_PR1_CCITT)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -667,34 +565,30 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
|
|||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_RINGS
|
||||
static void sca_dump_rings(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
card_t *card = port_to_card(port);
|
||||
u16 cnt;
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
u8 page;
|
||||
#endif
|
||||
#ifndef PAGE0_ALWAYS_MAPPED
|
||||
u8 page = sca_get_page(card);
|
||||
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
page = sca_get_page(card);
|
||||
openwin(card, 0);
|
||||
#endif
|
||||
|
||||
printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive",
|
||||
sca_ina(get_dmac_rx(port) + CDAL, card),
|
||||
sca_ina(get_dmac_rx(port) + EDAL, card),
|
||||
sca_inw(get_dmac_rx(port) + CDAL, card),
|
||||
sca_inw(get_dmac_rx(port) + EDAL, card),
|
||||
sca_in(DSR_RX(phy_node(port)), card), port->rxin,
|
||||
sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in");
|
||||
sca_in(DSR_RX(phy_node(port)), card) & DSR_DE ? "" : "in");
|
||||
for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++)
|
||||
printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
|
||||
|
||||
printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
|
||||
"last=%u %sactive",
|
||||
sca_ina(get_dmac_tx(port) + CDAL, card),
|
||||
sca_ina(get_dmac_tx(port) + EDAL, card),
|
||||
sca_inw(get_dmac_tx(port) + CDAL, card),
|
||||
sca_inw(get_dmac_tx(port) + EDAL, card),
|
||||
sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast,
|
||||
sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in");
|
||||
|
||||
|
@ -702,12 +596,8 @@ static void sca_dump_rings(struct net_device *dev)
|
|||
printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
|
||||
printk("\n");
|
||||
|
||||
printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, "
|
||||
"ST: %02x %02x %02x %02x"
|
||||
#ifdef __HD64572_H
|
||||
" %02x"
|
||||
#endif
|
||||
", FST: %02x CST: %02x %02x\n",
|
||||
printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, ST: %02x %02x %02x %02x,"
|
||||
" FST: %02x CST: %02x %02x\n",
|
||||
sca_in(get_msci(port) + MD0, card),
|
||||
sca_in(get_msci(port) + MD1, card),
|
||||
sca_in(get_msci(port) + MD2, card),
|
||||
|
@ -715,52 +605,33 @@ static void sca_dump_rings(struct net_device *dev)
|
|||
sca_in(get_msci(port) + ST1, card),
|
||||
sca_in(get_msci(port) + ST2, card),
|
||||
sca_in(get_msci(port) + ST3, card),
|
||||
#ifdef __HD64572_H
|
||||
sca_in(get_msci(port) + ST4, card),
|
||||
#endif
|
||||
sca_in(get_msci(port) + FST, card),
|
||||
sca_in(get_msci(port) + CST0, card),
|
||||
sca_in(get_msci(port) + CST1, card));
|
||||
|
||||
#ifdef __HD64572_H
|
||||
printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card),
|
||||
sca_inl(ISR0, card), sca_inl(ISR1, card));
|
||||
#else
|
||||
printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card),
|
||||
sca_in(ISR1, card), sca_in(ISR2, card));
|
||||
#endif
|
||||
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
#ifndef PAGE0_ALWAYS_MAPPED
|
||||
openwin(card, page); /* Restore original page */
|
||||
#endif
|
||||
}
|
||||
#endif /* DEBUG_RINGS */
|
||||
|
||||
|
||||
|
||||
static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
card_t *card = port_to_card(port);
|
||||
pkt_desc __iomem *desc;
|
||||
u32 buff, len;
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
u8 page;
|
||||
u32 maxlen;
|
||||
#endif
|
||||
|
||||
spin_lock_irq(&port->lock);
|
||||
|
||||
desc = desc_address(port, port->txin + 1, 1);
|
||||
if (readb(&desc->stat)) { /* allow 1 packet gap */
|
||||
/* should never happen - previous xmit should stop queue */
|
||||
#ifdef DEBUG_PKT
|
||||
printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
|
||||
#endif
|
||||
netif_stop_queue(dev);
|
||||
spin_unlock_irq(&port->lock);
|
||||
return 1; /* request packet to be queued */
|
||||
}
|
||||
BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */
|
||||
|
||||
#ifdef DEBUG_PKT
|
||||
printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
|
||||
|
@ -770,7 +641,6 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
desc = desc_address(port, port->txin, 1);
|
||||
buff = buffer_offset(port, port->txin, 1);
|
||||
len = skb->len;
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
page = buff / winsize(card);
|
||||
buff = buff % winsize(card);
|
||||
maxlen = winsize(card) - buff;
|
||||
|
@ -780,12 +650,10 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
memcpy_toio(winbase(card) + buff, skb->data, maxlen);
|
||||
openwin(card, page + 1);
|
||||
memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
} else
|
||||
memcpy_toio(winbase(card) + buff, skb->data, len);
|
||||
|
||||
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
|
||||
#ifndef PAGE0_ALWAYS_MAPPED
|
||||
openwin(card, 0); /* select pkt_desc table page back */
|
||||
#endif
|
||||
writew(len, &desc->len);
|
||||
|
@ -793,7 +661,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
dev->trans_start = jiffies;
|
||||
|
||||
port->txin = next_desc(port, port->txin, 1);
|
||||
sca_outa(desc_offset(port, port->txin, 1),
|
||||
sca_outw(desc_offset(port, port->txin, 1),
|
||||
get_dmac_tx(port) + EDAL, card);
|
||||
|
||||
sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */
|
||||
|
@ -809,40 +677,29 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
|
||||
|
||||
|
||||
#ifdef NEED_DETECT_RAM
|
||||
static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
|
||||
static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase,
|
||||
u32 ramsize)
|
||||
{
|
||||
/* Round RAM size to 32 bits, fill from end to start */
|
||||
u32 i = ramsize &= ~3;
|
||||
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
u32 size = winsize(card);
|
||||
|
||||
openwin(card, (i - 4) / size); /* select last window */
|
||||
#endif
|
||||
|
||||
do {
|
||||
i -= 4;
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
if ((i + 4) % size == 0)
|
||||
openwin(card, i / size);
|
||||
writel(i ^ 0x12345678, rambase + i % size);
|
||||
#else
|
||||
writel(i ^ 0x12345678, rambase + i);
|
||||
#endif
|
||||
}while (i > 0);
|
||||
} while (i > 0);
|
||||
|
||||
for (i = 0; i < ramsize ; i += 4) {
|
||||
#ifndef ALL_PAGES_ALWAYS_MAPPED
|
||||
if (i % size == 0)
|
||||
openwin(card, i / size);
|
||||
|
||||
if (readl(rambase + i % size) != (i ^ 0x12345678))
|
||||
break;
|
||||
#else
|
||||
if (readl(rambase + i) != (i ^ 0x12345678))
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return i;
|
||||
|
@ -850,7 +707,6 @@ static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsi
|
|||
#endif /* NEED_DETECT_RAM */
|
||||
|
||||
|
||||
|
||||
static void __devinit sca_init(card_t *card, int wait_states)
|
||||
{
|
||||
sca_out(wait_states, WCRL, card); /* Wait Control */
|
640
drivers/net/wan/hd64572.c
Normal file
640
drivers/net/wan/hd64572.c
Normal file
|
@ -0,0 +1,640 @@
|
|||
/*
|
||||
* Hitachi (now Renesas) SCA-II HD64572 driver for Linux
|
||||
*
|
||||
* Copyright (C) 1998-2008 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* Source of information: HD64572 SCA-II User's Manual
|
||||
*
|
||||
* We use the following SCA memory map:
|
||||
*
|
||||
* Packet buffer descriptor rings - starting from card->rambase:
|
||||
* rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring
|
||||
* tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring
|
||||
* rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used)
|
||||
* tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used)
|
||||
*
|
||||
* Packet data buffers - starting from card->rambase + buff_offset:
|
||||
* rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers
|
||||
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers
|
||||
* rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used)
|
||||
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used)
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/hdlc.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "hd64572.h"
|
||||
|
||||
#define NAPI_WEIGHT 16
|
||||
|
||||
#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET)
|
||||
#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
|
||||
#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
|
||||
|
||||
#define sca_in(reg, card) readb(card->scabase + (reg))
|
||||
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
|
||||
#define sca_inw(reg, card) readw(card->scabase + (reg))
|
||||
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
|
||||
#define sca_inl(reg, card) readl(card->scabase + (reg))
|
||||
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
|
||||
|
||||
static int sca_poll(struct napi_struct *napi, int budget);
|
||||
|
||||
static inline port_t* dev_to_port(struct net_device *dev)
|
||||
{
|
||||
return dev_to_hdlc(dev)->priv;
|
||||
}
|
||||
|
||||
static inline void enable_intr(port_t *port)
|
||||
{
|
||||
/* enable DMIB and MSCI RXINTA interrupts */
|
||||
sca_outl(sca_inl(IER0, port->card) |
|
||||
(port->chan ? 0x08002200 : 0x00080022), IER0, port->card);
|
||||
}
|
||||
|
||||
static inline void disable_intr(port_t *port)
|
||||
{
|
||||
sca_outl(sca_inl(IER0, port->card) &
|
||||
(port->chan ? 0x00FF00FF : 0xFF00FF00), IER0, port->card);
|
||||
}
|
||||
|
||||
static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
u16 rx_buffs = port->card->rx_ring_buffers;
|
||||
u16 tx_buffs = port->card->tx_ring_buffers;
|
||||
|
||||
desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc.
|
||||
return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc;
|
||||
}
|
||||
|
||||
|
||||
static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
/* Descriptor offset always fits in 16 bits */
|
||||
return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
|
||||
}
|
||||
|
||||
|
||||
static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
|
||||
int transmit)
|
||||
{
|
||||
return (pkt_desc __iomem *)(port->card->rambase +
|
||||
desc_offset(port, desc, transmit));
|
||||
}
|
||||
|
||||
|
||||
static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
|
||||
{
|
||||
return port->card->buff_offset +
|
||||
desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU;
|
||||
}
|
||||
|
||||
|
||||
static inline void sca_set_carrier(port_t *port)
|
||||
{
|
||||
if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) {
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "%s: sca_set_carrier on\n",
|
||||
port->netdev.name);
|
||||
#endif
|
||||
netif_carrier_on(port->netdev);
|
||||
} else {
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "%s: sca_set_carrier off\n",
|
||||
port->netdev.name);
|
||||
#endif
|
||||
netif_carrier_off(port->netdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sca_init_port(port_t *port)
|
||||
{
|
||||
card_t *card = port->card;
|
||||
u16 dmac_rx = get_dmac_rx(port), dmac_tx = get_dmac_tx(port);
|
||||
int transmit, i;
|
||||
|
||||
port->rxin = 0;
|
||||
port->txin = 0;
|
||||
port->txlast = 0;
|
||||
|
||||
for (transmit = 0; transmit < 2; transmit++) {
|
||||
u16 buffs = transmit ? card->tx_ring_buffers
|
||||
: card->rx_ring_buffers;
|
||||
|
||||
for (i = 0; i < buffs; i++) {
|
||||
pkt_desc __iomem *desc = desc_address(port, i, transmit);
|
||||
u16 chain_off = desc_offset(port, i + 1, transmit);
|
||||
u32 buff_off = buffer_offset(port, i, transmit);
|
||||
|
||||
writel(chain_off, &desc->cp);
|
||||
writel(buff_off, &desc->bp);
|
||||
writew(0, &desc->len);
|
||||
writeb(0, &desc->stat);
|
||||
}
|
||||
}
|
||||
|
||||
/* DMA disable - to halt state */
|
||||
sca_out(0, DSR_RX(port->chan), card);
|
||||
sca_out(0, DSR_TX(port->chan), card);
|
||||
|
||||
/* software ABORT - to initial state */
|
||||
sca_out(DCR_ABORT, DCR_RX(port->chan), card);
|
||||
sca_out(DCR_ABORT, DCR_TX(port->chan), card);
|
||||
|
||||
/* current desc addr */
|
||||
sca_outl(desc_offset(port, 0, 0), dmac_rx + CDAL, card);
|
||||
sca_outl(desc_offset(port, card->tx_ring_buffers - 1, 0),
|
||||
dmac_rx + EDAL, card);
|
||||
sca_outl(desc_offset(port, 0, 1), dmac_tx + CDAL, card);
|
||||
sca_outl(desc_offset(port, 0, 1), dmac_tx + EDAL, card);
|
||||
|
||||
/* clear frame end interrupt counter */
|
||||
sca_out(DCR_CLEAR_EOF, DCR_RX(port->chan), card);
|
||||
sca_out(DCR_CLEAR_EOF, DCR_TX(port->chan), card);
|
||||
|
||||
/* Receive */
|
||||
sca_outw(HDLC_MAX_MRU, dmac_rx + BFLL, card); /* set buffer length */
|
||||
sca_out(0x14, DMR_RX(port->chan), card); /* Chain mode, Multi-frame */
|
||||
sca_out(DIR_EOME, DIR_RX(port->chan), card); /* enable interrupts */
|
||||
sca_out(DSR_DE, DSR_RX(port->chan), card); /* DMA enable */
|
||||
|
||||
/* Transmit */
|
||||
sca_out(0x14, DMR_TX(port->chan), card); /* Chain mode, Multi-frame */
|
||||
sca_out(DIR_EOME, DIR_TX(port->chan), card); /* enable interrupts */
|
||||
|
||||
sca_set_carrier(port);
|
||||
netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT);
|
||||
}
|
||||
|
||||
|
||||
/* MSCI interrupt service */
|
||||
static inline void sca_msci_intr(port_t *port)
|
||||
{
|
||||
u16 msci = get_msci(port);
|
||||
card_t* card = port->card;
|
||||
|
||||
if (sca_in(msci + ST1, card) & ST1_CDCD) {
|
||||
/* Reset MSCI CDCD status bit */
|
||||
sca_out(ST1_CDCD, msci + ST1, card);
|
||||
sca_set_carrier(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
|
||||
u16 rxin)
|
||||
{
|
||||
struct net_device *dev = port->netdev;
|
||||
struct sk_buff *skb;
|
||||
u16 len;
|
||||
u32 buff;
|
||||
|
||||
len = readw(&desc->len);
|
||||
skb = dev_alloc_skb(len);
|
||||
if (!skb) {
|
||||
dev->stats.rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
buff = buffer_offset(port, rxin, 0);
|
||||
memcpy_fromio(skb->data, card->rambase + buff, len);
|
||||
|
||||
skb_put(skb, len);
|
||||
#ifdef DEBUG_PKT
|
||||
printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len);
|
||||
debug_frame(skb);
|
||||
#endif
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += skb->len;
|
||||
skb->protocol = hdlc_type_trans(skb, dev);
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
|
||||
/* Receive DMA service */
|
||||
static inline int sca_rx_done(port_t *port, int budget)
|
||||
{
|
||||
struct net_device *dev = port->netdev;
|
||||
u16 dmac = get_dmac_rx(port);
|
||||
card_t *card = port->card;
|
||||
u8 stat = sca_in(DSR_RX(port->chan), card); /* read DMA Status */
|
||||
int received = 0;
|
||||
|
||||
/* Reset DSR status bits */
|
||||
sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
|
||||
DSR_RX(port->chan), card);
|
||||
|
||||
if (stat & DSR_BOF)
|
||||
/* Dropped one or more frames */
|
||||
dev->stats.rx_over_errors++;
|
||||
|
||||
while (received < budget) {
|
||||
u32 desc_off = desc_offset(port, port->rxin, 0);
|
||||
pkt_desc __iomem *desc;
|
||||
u32 cda = sca_inl(dmac + CDAL, card);
|
||||
|
||||
if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
|
||||
break; /* No frame received */
|
||||
|
||||
desc = desc_address(port, port->rxin, 0);
|
||||
stat = readb(&desc->stat);
|
||||
if (!(stat & ST_RX_EOM))
|
||||
port->rxpart = 1; /* partial frame received */
|
||||
else if ((stat & ST_ERROR_MASK) || port->rxpart) {
|
||||
dev->stats.rx_errors++;
|
||||
if (stat & ST_RX_OVERRUN)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
else if ((stat & (ST_RX_SHORT | ST_RX_ABORT |
|
||||
ST_RX_RESBIT)) || port->rxpart)
|
||||
dev->stats.rx_frame_errors++;
|
||||
else if (stat & ST_RX_CRC)
|
||||
dev->stats.rx_crc_errors++;
|
||||
if (stat & ST_RX_EOM)
|
||||
port->rxpart = 0; /* received last fragment */
|
||||
} else {
|
||||
sca_rx(card, port, desc, port->rxin);
|
||||
received++;
|
||||
}
|
||||
|
||||
/* Set new error descriptor address */
|
||||
sca_outl(desc_off, dmac + EDAL, card);
|
||||
port->rxin = (port->rxin + 1) % card->rx_ring_buffers;
|
||||
}
|
||||
|
||||
/* make sure RX DMA is enabled */
|
||||
sca_out(DSR_DE, DSR_RX(port->chan), card);
|
||||
return received;
|
||||
}
|
||||
|
||||
|
||||
/* Transmit DMA service */
|
||||
static inline void sca_tx_done(port_t *port)
|
||||
{
|
||||
struct net_device *dev = port->netdev;
|
||||
card_t* card = port->card;
|
||||
u8 stat;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
stat = sca_in(DSR_TX(port->chan), card); /* read DMA Status */
|
||||
|
||||
/* Reset DSR status bits */
|
||||
sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
|
||||
DSR_TX(port->chan), card);
|
||||
|
||||
while (1) {
|
||||
pkt_desc __iomem *desc = desc_address(port, port->txlast, 1);
|
||||
u8 stat = readb(&desc->stat);
|
||||
|
||||
if (!(stat & ST_TX_OWNRSHP))
|
||||
break; /* not yet transmitted */
|
||||
if (stat & ST_TX_UNDRRUN) {
|
||||
dev->stats.tx_errors++;
|
||||
dev->stats.tx_fifo_errors++;
|
||||
} else {
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += readw(&desc->len);
|
||||
}
|
||||
writeb(0, &desc->stat); /* Free descriptor */
|
||||
port->txlast = (port->txlast + 1) % card->tx_ring_buffers;
|
||||
}
|
||||
|
||||
netif_wake_queue(dev);
|
||||
spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
|
||||
static int sca_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
port_t *port = container_of(napi, port_t, napi);
|
||||
u32 isr0 = sca_inl(ISR0, port->card);
|
||||
int received = 0;
|
||||
|
||||
if (isr0 & (port->chan ? 0x08000000 : 0x00080000))
|
||||
sca_msci_intr(port);
|
||||
|
||||
if (isr0 & (port->chan ? 0x00002000 : 0x00000020))
|
||||
sca_tx_done(port);
|
||||
|
||||
if (isr0 & (port->chan ? 0x00000200 : 0x00000002))
|
||||
received = sca_rx_done(port, budget);
|
||||
|
||||
if (received < budget) {
|
||||
netif_rx_complete(port->netdev, napi);
|
||||
enable_intr(port);
|
||||
}
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
static irqreturn_t sca_intr(int irq, void *dev_id)
|
||||
{
|
||||
card_t *card = dev_id;
|
||||
u32 isr0 = sca_inl(ISR0, card);
|
||||
int i, handled = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
port_t *port = get_port(card, i);
|
||||
if (port && (isr0 & (i ? 0x08002200 : 0x00080022))) {
|
||||
handled = 1;
|
||||
disable_intr(port);
|
||||
netif_rx_schedule(port->netdev, &port->napi);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
||||
static void sca_set_port(port_t *port)
|
||||
{
|
||||
card_t* card = port->card;
|
||||
u16 msci = get_msci(port);
|
||||
u8 md2 = sca_in(msci + MD2, card);
|
||||
unsigned int tmc, br = 10, brv = 1024;
|
||||
|
||||
|
||||
if (port->settings.clock_rate > 0) {
|
||||
/* Try lower br for better accuracy*/
|
||||
do {
|
||||
br--;
|
||||
brv >>= 1; /* brv = 2^9 = 512 max in specs */
|
||||
|
||||
/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
|
||||
tmc = CLOCK_BASE / brv / port->settings.clock_rate;
|
||||
}while (br > 1 && tmc <= 128);
|
||||
|
||||
if (tmc < 1) {
|
||||
tmc = 1;
|
||||
br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */
|
||||
brv = 1;
|
||||
} else if (tmc > 255)
|
||||
tmc = 256; /* tmc=0 means 256 - low baud rates */
|
||||
|
||||
port->settings.clock_rate = CLOCK_BASE / brv / tmc;
|
||||
} else {
|
||||
br = 9; /* Minimum clock rate */
|
||||
tmc = 256; /* 8bit = 0 */
|
||||
port->settings.clock_rate = CLOCK_BASE / (256 * 512);
|
||||
}
|
||||
|
||||
port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
|
||||
port->txs = (port->txs & ~CLK_BRG_MASK) | br;
|
||||
port->tmc = tmc;
|
||||
|
||||
/* baud divisor - time constant*/
|
||||
sca_out(port->tmc, msci + TMCR, card);
|
||||
sca_out(port->tmc, msci + TMCT, card);
|
||||
|
||||
/* Set BRG bits */
|
||||
sca_out(port->rxs, msci + RXS, card);
|
||||
sca_out(port->txs, msci + TXS, card);
|
||||
|
||||
if (port->settings.loopback)
|
||||
md2 |= MD2_LOOPBACK;
|
||||
else
|
||||
md2 &= ~MD2_LOOPBACK;
|
||||
|
||||
sca_out(md2, msci + MD2, card);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void sca_open(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
card_t* card = port->card;
|
||||
u16 msci = get_msci(port);
|
||||
u8 md0, md2;
|
||||
|
||||
switch(port->encoding) {
|
||||
case ENCODING_NRZ: md2 = MD2_NRZ; break;
|
||||
case ENCODING_NRZI: md2 = MD2_NRZI; break;
|
||||
case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break;
|
||||
case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break;
|
||||
default: md2 = MD2_MANCHESTER;
|
||||
}
|
||||
|
||||
if (port->settings.loopback)
|
||||
md2 |= MD2_LOOPBACK;
|
||||
|
||||
switch(port->parity) {
|
||||
case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break;
|
||||
case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break;
|
||||
case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
|
||||
case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break;
|
||||
default: md0 = MD0_HDLC | MD0_CRC_NONE;
|
||||
}
|
||||
|
||||
sca_out(CMD_RESET, msci + CMD, card);
|
||||
sca_out(md0, msci + MD0, card);
|
||||
sca_out(0x00, msci + MD1, card); /* no address field check */
|
||||
sca_out(md2, msci + MD2, card);
|
||||
sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
|
||||
/* Skip the rest of underrun frame */
|
||||
sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
|
||||
sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
|
||||
sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
|
||||
sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
|
||||
sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
|
||||
sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
|
||||
|
||||
/* We're using the following interrupts:
|
||||
- RXINTA (DCD changes only)
|
||||
- DMIB (EOM - single frame transfer complete)
|
||||
*/
|
||||
sca_outl(IE0_RXINTA | IE0_CDCD, msci + IE0, card);
|
||||
|
||||
sca_out(port->tmc, msci + TMCR, card);
|
||||
sca_out(port->tmc, msci + TMCT, card);
|
||||
sca_out(port->rxs, msci + RXS, card);
|
||||
sca_out(port->txs, msci + TXS, card);
|
||||
sca_out(CMD_TX_ENABLE, msci + CMD, card);
|
||||
sca_out(CMD_RX_ENABLE, msci + CMD, card);
|
||||
|
||||
sca_set_carrier(port);
|
||||
enable_intr(port);
|
||||
napi_enable(&port->napi);
|
||||
netif_start_queue(dev);
|
||||
}
|
||||
|
||||
|
||||
static void sca_close(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
|
||||
/* reset channel */
|
||||
sca_out(CMD_RESET, get_msci(port) + CMD, port->card);
|
||||
disable_intr(port);
|
||||
napi_disable(&port->napi);
|
||||
netif_stop_queue(dev);
|
||||
}
|
||||
|
||||
|
||||
static int sca_attach(struct net_device *dev, unsigned short encoding,
|
||||
unsigned short parity)
|
||||
{
|
||||
if (encoding != ENCODING_NRZ &&
|
||||
encoding != ENCODING_NRZI &&
|
||||
encoding != ENCODING_FM_MARK &&
|
||||
encoding != ENCODING_FM_SPACE &&
|
||||
encoding != ENCODING_MANCHESTER)
|
||||
return -EINVAL;
|
||||
|
||||
if (parity != PARITY_NONE &&
|
||||
parity != PARITY_CRC16_PR0 &&
|
||||
parity != PARITY_CRC16_PR1 &&
|
||||
parity != PARITY_CRC32_PR1_CCITT &&
|
||||
parity != PARITY_CRC16_PR1_CCITT)
|
||||
return -EINVAL;
|
||||
|
||||
dev_to_port(dev)->encoding = encoding;
|
||||
dev_to_port(dev)->parity = parity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_RINGS
|
||||
static void sca_dump_rings(struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
card_t *card = port->card;
|
||||
u16 cnt;
|
||||
|
||||
printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive",
|
||||
sca_inl(get_dmac_rx(port) + CDAL, card),
|
||||
sca_inl(get_dmac_rx(port) + EDAL, card),
|
||||
sca_in(DSR_RX(port->chan), card), port->rxin,
|
||||
sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in");
|
||||
for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++)
|
||||
printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
|
||||
|
||||
printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
|
||||
"last=%u %sactive",
|
||||
sca_inl(get_dmac_tx(port) + CDAL, card),
|
||||
sca_inl(get_dmac_tx(port) + EDAL, card),
|
||||
sca_in(DSR_TX(port->chan), card), port->txin, port->txlast,
|
||||
sca_in(DSR_TX(port->chan), card) & DSR_DE ? "" : "in");
|
||||
|
||||
for (cnt = 0; cnt < port->card->tx_ring_buffers; cnt++)
|
||||
printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
|
||||
printk("\n");
|
||||
|
||||
printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x,"
|
||||
" ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x\n",
|
||||
sca_in(get_msci(port) + MD0, card),
|
||||
sca_in(get_msci(port) + MD1, card),
|
||||
sca_in(get_msci(port) + MD2, card),
|
||||
sca_in(get_msci(port) + ST0, card),
|
||||
sca_in(get_msci(port) + ST1, card),
|
||||
sca_in(get_msci(port) + ST2, card),
|
||||
sca_in(get_msci(port) + ST3, card),
|
||||
sca_in(get_msci(port) + ST4, card),
|
||||
sca_in(get_msci(port) + FST, card),
|
||||
sca_in(get_msci(port) + CST0, card),
|
||||
sca_in(get_msci(port) + CST1, card));
|
||||
|
||||
printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card),
|
||||
sca_inl(ISR0, card), sca_inl(ISR1, card));
|
||||
}
|
||||
#endif /* DEBUG_RINGS */
|
||||
|
||||
|
||||
static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
port_t *port = dev_to_port(dev);
|
||||
card_t *card = port->card;
|
||||
pkt_desc __iomem *desc;
|
||||
u32 buff, len;
|
||||
|
||||
spin_lock_irq(&port->lock);
|
||||
|
||||
desc = desc_address(port, port->txin + 1, 1);
|
||||
BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */
|
||||
|
||||
#ifdef DEBUG_PKT
|
||||
printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
|
||||
debug_frame(skb);
|
||||
#endif
|
||||
|
||||
desc = desc_address(port, port->txin, 1);
|
||||
buff = buffer_offset(port, port->txin, 1);
|
||||
len = skb->len;
|
||||
memcpy_toio(card->rambase + buff, skb->data, len);
|
||||
|
||||
writew(len, &desc->len);
|
||||
writeb(ST_TX_EOM, &desc->stat);
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
port->txin = (port->txin + 1) % card->tx_ring_buffers;
|
||||
sca_outl(desc_offset(port, port->txin, 1),
|
||||
get_dmac_tx(port) + EDAL, card);
|
||||
|
||||
sca_out(DSR_DE, DSR_TX(port->chan), card); /* Enable TX DMA */
|
||||
|
||||
desc = desc_address(port, port->txin + 1, 1);
|
||||
if (readb(&desc->stat)) /* allow 1 packet gap */
|
||||
netif_stop_queue(dev);
|
||||
|
||||
spin_unlock_irq(&port->lock);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase,
|
||||
u32 ramsize)
|
||||
{
|
||||
/* Round RAM size to 32 bits, fill from end to start */
|
||||
u32 i = ramsize &= ~3;
|
||||
|
||||
do {
|
||||
i -= 4;
|
||||
writel(i ^ 0x12345678, rambase + i);
|
||||
} while (i > 0);
|
||||
|
||||
for (i = 0; i < ramsize ; i += 4) {
|
||||
if (readl(rambase + i) != (i ^ 0x12345678))
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static void __devinit sca_init(card_t *card, int wait_states)
|
||||
{
|
||||
sca_out(wait_states, WCRL, card); /* Wait Control */
|
||||
sca_out(wait_states, WCRM, card);
|
||||
sca_out(wait_states, WCRH, card);
|
||||
|
||||
sca_out(0, DMER, card); /* DMA Master disable */
|
||||
sca_out(0x03, PCR, card); /* DMA priority */
|
||||
sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */
|
||||
sca_out(0, DSR_TX(0), card);
|
||||
sca_out(0, DSR_RX(1), card);
|
||||
sca_out(0, DSR_TX(1), card);
|
||||
sca_out(DMER_DME, DMER, card); /* DMA Master enable */
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* Generic HDLC support routines for Linux
|
||||
* Point-to-point protocol support
|
||||
*
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
|
@ -18,87 +18,632 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/syncppp.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct ppp_state {
|
||||
struct ppp_device pppdev;
|
||||
struct ppp_device *syncppp_ptr;
|
||||
int (*old_change_mtu)(struct net_device *dev, int new_mtu);
|
||||
#define DEBUG_CP 0 /* also bytes# to dump */
|
||||
#define DEBUG_STATE 0
|
||||
#define DEBUG_HARD_HEADER 0
|
||||
|
||||
#define HDLC_ADDR_ALLSTATIONS 0xFF
|
||||
#define HDLC_CTRL_UI 0x03
|
||||
|
||||
#define PID_LCP 0xC021
|
||||
#define PID_IP 0x0021
|
||||
#define PID_IPCP 0x8021
|
||||
#define PID_IPV6 0x0057
|
||||
#define PID_IPV6CP 0x8057
|
||||
|
||||
enum {IDX_LCP = 0, IDX_IPCP, IDX_IPV6CP, IDX_COUNT};
|
||||
enum {CP_CONF_REQ = 1, CP_CONF_ACK, CP_CONF_NAK, CP_CONF_REJ, CP_TERM_REQ,
|
||||
CP_TERM_ACK, CP_CODE_REJ, LCP_PROTO_REJ, LCP_ECHO_REQ, LCP_ECHO_REPLY,
|
||||
LCP_DISC_REQ, CP_CODES};
|
||||
#if DEBUG_CP
|
||||
static const char *const code_names[CP_CODES] = {
|
||||
"0", "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq",
|
||||
"TermAck", "CodeRej", "ProtoRej", "EchoReq", "EchoReply", "Discard"
|
||||
};
|
||||
static char debug_buffer[64 + 3 * DEBUG_CP];
|
||||
#endif
|
||||
|
||||
enum {LCP_OPTION_MRU = 1, LCP_OPTION_ACCM, LCP_OPTION_MAGIC = 5};
|
||||
|
||||
struct hdlc_header {
|
||||
u8 address;
|
||||
u8 control;
|
||||
__be16 protocol;
|
||||
};
|
||||
|
||||
struct cp_header {
|
||||
u8 code;
|
||||
u8 id;
|
||||
__be16 len;
|
||||
};
|
||||
|
||||
|
||||
struct proto {
|
||||
struct net_device *dev;
|
||||
struct timer_list timer;
|
||||
unsigned long timeout;
|
||||
u16 pid; /* protocol ID */
|
||||
u8 state;
|
||||
u8 cr_id; /* ID of last Configuration-Request */
|
||||
u8 restart_counter;
|
||||
};
|
||||
|
||||
struct ppp {
|
||||
struct proto protos[IDX_COUNT];
|
||||
spinlock_t lock;
|
||||
unsigned long last_pong;
|
||||
unsigned int req_timeout, cr_retries, term_retries;
|
||||
unsigned int keepalive_interval, keepalive_timeout;
|
||||
u8 seq; /* local sequence number for requests */
|
||||
u8 echo_id; /* ID of last Echo-Request (LCP) */
|
||||
};
|
||||
|
||||
enum {CLOSED = 0, STOPPED, STOPPING, REQ_SENT, ACK_RECV, ACK_SENT, OPENED,
|
||||
STATES, STATE_MASK = 0xF};
|
||||
enum {START = 0, STOP, TO_GOOD, TO_BAD, RCR_GOOD, RCR_BAD, RCA, RCN, RTR, RTA,
|
||||
RUC, RXJ_GOOD, RXJ_BAD, EVENTS};
|
||||
enum {INV = 0x10, IRC = 0x20, ZRC = 0x40, SCR = 0x80, SCA = 0x100,
|
||||
SCN = 0x200, STR = 0x400, STA = 0x800, SCJ = 0x1000};
|
||||
|
||||
#if DEBUG_STATE
|
||||
static const char *const state_names[STATES] = {
|
||||
"Closed", "Stopped", "Stopping", "ReqSent", "AckRecv", "AckSent",
|
||||
"Opened"
|
||||
};
|
||||
static const char *const event_names[EVENTS] = {
|
||||
"Start", "Stop", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN",
|
||||
"RTR", "RTA", "RUC", "RXJ+", "RXJ-"
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct sk_buff_head tx_queue; /* used when holding the spin lock */
|
||||
|
||||
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
|
||||
static inline struct ppp_state* state(hdlc_device *hdlc)
|
||||
static inline struct ppp* get_ppp(struct net_device *dev)
|
||||
{
|
||||
return(struct ppp_state *)(hdlc->state);
|
||||
return (struct ppp *)dev_to_hdlc(dev)->state;
|
||||
}
|
||||
|
||||
|
||||
static int ppp_open(struct net_device *dev)
|
||||
static inline struct proto* get_proto(struct net_device *dev, u16 pid)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
int (*old_ioctl)(struct net_device *, struct ifreq *, int);
|
||||
int result;
|
||||
struct ppp *ppp = get_ppp(dev);
|
||||
|
||||
dev->ml_priv = &state(hdlc)->syncppp_ptr;
|
||||
state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
|
||||
state(hdlc)->pppdev.dev = dev;
|
||||
|
||||
old_ioctl = dev->do_ioctl;
|
||||
state(hdlc)->old_change_mtu = dev->change_mtu;
|
||||
sppp_attach(&state(hdlc)->pppdev);
|
||||
/* sppp_attach nukes them. We don't need syncppp's ioctl */
|
||||
dev->do_ioctl = old_ioctl;
|
||||
state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
|
||||
dev->type = ARPHRD_PPP;
|
||||
result = sppp_open(dev);
|
||||
if (result) {
|
||||
sppp_detach(dev);
|
||||
return result;
|
||||
switch (pid) {
|
||||
case PID_LCP:
|
||||
return &ppp->protos[IDX_LCP];
|
||||
case PID_IPCP:
|
||||
return &ppp->protos[IDX_IPCP];
|
||||
case PID_IPV6CP:
|
||||
return &ppp->protos[IDX_IPV6CP];
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ppp_close(struct net_device *dev)
|
||||
static inline const char* proto_name(u16 pid)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
|
||||
sppp_close(dev);
|
||||
sppp_detach(dev);
|
||||
|
||||
dev->change_mtu = state(hdlc)->old_change_mtu;
|
||||
dev->mtu = HDLC_MAX_MTU;
|
||||
dev->hard_header_len = 16;
|
||||
switch (pid) {
|
||||
case PID_LCP:
|
||||
return "LCP";
|
||||
case PID_IPCP:
|
||||
return "IPCP";
|
||||
case PID_IPV6CP:
|
||||
return "IPV6CP";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
return __constant_htons(ETH_P_WAN_PPP);
|
||||
struct hdlc_header *data = (struct hdlc_header*)skb->data;
|
||||
|
||||
if (skb->len < sizeof(struct hdlc_header))
|
||||
return htons(ETH_P_HDLC);
|
||||
if (data->address != HDLC_ADDR_ALLSTATIONS ||
|
||||
data->control != HDLC_CTRL_UI)
|
||||
return htons(ETH_P_HDLC);
|
||||
|
||||
switch (data->protocol) {
|
||||
case __constant_htons(PID_IP):
|
||||
skb_pull(skb, sizeof(struct hdlc_header));
|
||||
return htons(ETH_P_IP);
|
||||
|
||||
case __constant_htons(PID_IPV6):
|
||||
skb_pull(skb, sizeof(struct hdlc_header));
|
||||
return htons(ETH_P_IPV6);
|
||||
|
||||
default:
|
||||
return htons(ETH_P_HDLC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
u16 type, const void *daddr, const void *saddr,
|
||||
unsigned int len)
|
||||
{
|
||||
struct hdlc_header *data;
|
||||
#if DEBUG_HARD_HEADER
|
||||
printk(KERN_DEBUG "%s: ppp_hard_header() called\n", dev->name);
|
||||
#endif
|
||||
|
||||
skb_push(skb, sizeof(struct hdlc_header));
|
||||
data = (struct hdlc_header*)skb->data;
|
||||
|
||||
data->address = HDLC_ADDR_ALLSTATIONS;
|
||||
data->control = HDLC_CTRL_UI;
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
data->protocol = htons(PID_IP);
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
data->protocol = htons(PID_IPV6);
|
||||
break;
|
||||
case PID_LCP:
|
||||
case PID_IPCP:
|
||||
case PID_IPV6CP:
|
||||
data->protocol = htons(type);
|
||||
break;
|
||||
default: /* unknown protocol */
|
||||
data->protocol = 0;
|
||||
}
|
||||
return sizeof(struct hdlc_header);
|
||||
}
|
||||
|
||||
|
||||
static void ppp_tx_flush(void)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
while ((skb = skb_dequeue(&tx_queue)) != NULL)
|
||||
dev_queue_xmit(skb);
|
||||
}
|
||||
|
||||
static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code,
|
||||
u8 id, unsigned int len, const void *data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct cp_header *cp;
|
||||
unsigned int magic_len = 0;
|
||||
static u32 magic;
|
||||
|
||||
#if DEBUG_CP
|
||||
int i;
|
||||
char *ptr;
|
||||
#endif
|
||||
|
||||
if (pid == PID_LCP && (code == LCP_ECHO_REQ || code == LCP_ECHO_REPLY))
|
||||
magic_len = sizeof(magic);
|
||||
|
||||
skb = dev_alloc_skb(sizeof(struct hdlc_header) +
|
||||
sizeof(struct cp_header) + magic_len + len);
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING "%s: out of memory in ppp_tx_cp()\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
skb_reserve(skb, sizeof(struct hdlc_header));
|
||||
|
||||
cp = (struct cp_header *)skb_put(skb, sizeof(struct cp_header));
|
||||
cp->code = code;
|
||||
cp->id = id;
|
||||
cp->len = htons(sizeof(struct cp_header) + magic_len + len);
|
||||
|
||||
if (magic_len)
|
||||
memcpy(skb_put(skb, magic_len), &magic, magic_len);
|
||||
if (len)
|
||||
memcpy(skb_put(skb, len), data, len);
|
||||
|
||||
#if DEBUG_CP
|
||||
BUG_ON(code >= CP_CODES);
|
||||
ptr = debug_buffer;
|
||||
*ptr = '\x0';
|
||||
for (i = 0; i < min_t(unsigned int, magic_len + len, DEBUG_CP); i++) {
|
||||
sprintf(ptr, " %02X", skb->data[sizeof(struct cp_header) + i]);
|
||||
ptr += strlen(ptr);
|
||||
}
|
||||
printk(KERN_DEBUG "%s: TX %s [%s id 0x%X]%s\n", dev->name,
|
||||
proto_name(pid), code_names[code], id, debug_buffer);
|
||||
#endif
|
||||
|
||||
ppp_hard_header(skb, dev, pid, NULL, NULL, 0);
|
||||
|
||||
skb->priority = TC_PRIO_CONTROL;
|
||||
skb->dev = dev;
|
||||
skb_reset_network_header(skb);
|
||||
skb_queue_tail(&tx_queue, skb);
|
||||
}
|
||||
|
||||
|
||||
/* State transition table (compare STD-51)
|
||||
Events Actions
|
||||
TO+ = Timeout with counter > 0 irc = Initialize-Restart-Count
|
||||
TO- = Timeout with counter expired zrc = Zero-Restart-Count
|
||||
|
||||
RCR+ = Receive-Configure-Request (Good) scr = Send-Configure-Request
|
||||
RCR- = Receive-Configure-Request (Bad)
|
||||
RCA = Receive-Configure-Ack sca = Send-Configure-Ack
|
||||
RCN = Receive-Configure-Nak/Rej scn = Send-Configure-Nak/Rej
|
||||
|
||||
RTR = Receive-Terminate-Request str = Send-Terminate-Request
|
||||
RTA = Receive-Terminate-Ack sta = Send-Terminate-Ack
|
||||
|
||||
RUC = Receive-Unknown-Code scj = Send-Code-Reject
|
||||
RXJ+ = Receive-Code-Reject (permitted)
|
||||
or Receive-Protocol-Reject
|
||||
RXJ- = Receive-Code-Reject (catastrophic)
|
||||
or Receive-Protocol-Reject
|
||||
*/
|
||||
static int cp_table[EVENTS][STATES] = {
|
||||
/* CLOSED STOPPED STOPPING REQ_SENT ACK_RECV ACK_SENT OPENED
|
||||
0 1 2 3 4 5 6 */
|
||||
{IRC|SCR|3, INV , INV , INV , INV , INV , INV }, /* START */
|
||||
{ INV , 0 , 0 , 0 , 0 , 0 , 0 }, /* STOP */
|
||||
{ INV , INV ,STR|2, SCR|3 ,SCR|3, SCR|5 , INV }, /* TO+ */
|
||||
{ INV , INV , 1 , 1 , 1 , 1 , INV }, /* TO- */
|
||||
{ STA|0 ,IRC|SCR|SCA|5, 2 , SCA|5 ,SCA|6, SCA|5 ,SCR|SCA|5}, /* RCR+ */
|
||||
{ STA|0 ,IRC|SCR|SCN|3, 2 , SCN|3 ,SCN|4, SCN|3 ,SCR|SCN|3}, /* RCR- */
|
||||
{ STA|0 , STA|1 , 2 , IRC|4 ,SCR|3, 6 , SCR|3 }, /* RCA */
|
||||
{ STA|0 , STA|1 , 2 ,IRC|SCR|3,SCR|3,IRC|SCR|5, SCR|3 }, /* RCN */
|
||||
{ STA|0 , STA|1 ,STA|2, STA|3 ,STA|3, STA|3 ,ZRC|STA|2}, /* RTR */
|
||||
{ 0 , 1 , 1 , 3 , 3 , 5 , SCR|3 }, /* RTA */
|
||||
{ SCJ|0 , SCJ|1 ,SCJ|2, SCJ|3 ,SCJ|4, SCJ|5 , SCJ|6 }, /* RUC */
|
||||
{ 0 , 1 , 2 , 3 , 3 , 5 , 6 }, /* RXJ+ */
|
||||
{ 0 , 1 , 1 , 1 , 1 , 1 ,IRC|STR|2}, /* RXJ- */
|
||||
};
|
||||
|
||||
|
||||
/* SCA: RCR+ must supply id, len and data
|
||||
SCN: RCR- must supply code, id, len and data
|
||||
STA: RTR must supply id
|
||||
SCJ: RUC must supply CP packet len and data */
|
||||
static void ppp_cp_event(struct net_device *dev, u16 pid, u16 event, u8 code,
|
||||
u8 id, unsigned int len, void *data)
|
||||
{
|
||||
int old_state, action;
|
||||
struct ppp *ppp = get_ppp(dev);
|
||||
struct proto *proto = get_proto(dev, pid);
|
||||
|
||||
old_state = proto->state;
|
||||
BUG_ON(old_state >= STATES);
|
||||
BUG_ON(event >= EVENTS);
|
||||
|
||||
#if DEBUG_STATE
|
||||
printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) %s ...\n", dev->name,
|
||||
proto_name(pid), event_names[event], state_names[proto->state]);
|
||||
#endif
|
||||
|
||||
action = cp_table[event][old_state];
|
||||
|
||||
proto->state = action & STATE_MASK;
|
||||
if (action & (SCR | STR)) /* set Configure-Req/Terminate-Req timer */
|
||||
mod_timer(&proto->timer, proto->timeout =
|
||||
jiffies + ppp->req_timeout * HZ);
|
||||
if (action & ZRC)
|
||||
proto->restart_counter = 0;
|
||||
if (action & IRC)
|
||||
proto->restart_counter = (proto->state == STOPPING) ?
|
||||
ppp->term_retries : ppp->cr_retries;
|
||||
|
||||
if (action & SCR) /* send Configure-Request */
|
||||
ppp_tx_cp(dev, pid, CP_CONF_REQ, proto->cr_id = ++ppp->seq,
|
||||
0, NULL);
|
||||
if (action & SCA) /* send Configure-Ack */
|
||||
ppp_tx_cp(dev, pid, CP_CONF_ACK, id, len, data);
|
||||
if (action & SCN) /* send Configure-Nak/Reject */
|
||||
ppp_tx_cp(dev, pid, code, id, len, data);
|
||||
if (action & STR) /* send Terminate-Request */
|
||||
ppp_tx_cp(dev, pid, CP_TERM_REQ, ++ppp->seq, 0, NULL);
|
||||
if (action & STA) /* send Terminate-Ack */
|
||||
ppp_tx_cp(dev, pid, CP_TERM_ACK, id, 0, NULL);
|
||||
if (action & SCJ) /* send Code-Reject */
|
||||
ppp_tx_cp(dev, pid, CP_CODE_REJ, ++ppp->seq, len, data);
|
||||
|
||||
if (old_state != OPENED && proto->state == OPENED) {
|
||||
printk(KERN_INFO "%s: %s up\n", dev->name, proto_name(pid));
|
||||
if (pid == PID_LCP) {
|
||||
netif_dormant_off(dev);
|
||||
ppp_cp_event(dev, PID_IPCP, START, 0, 0, 0, NULL);
|
||||
ppp_cp_event(dev, PID_IPV6CP, START, 0, 0, 0, NULL);
|
||||
ppp->last_pong = jiffies;
|
||||
mod_timer(&proto->timer, proto->timeout =
|
||||
jiffies + ppp->keepalive_interval * HZ);
|
||||
}
|
||||
}
|
||||
if (old_state == OPENED && proto->state != OPENED) {
|
||||
printk(KERN_INFO "%s: %s down\n", dev->name, proto_name(pid));
|
||||
if (pid == PID_LCP) {
|
||||
netif_dormant_on(dev);
|
||||
ppp_cp_event(dev, PID_IPCP, STOP, 0, 0, 0, NULL);
|
||||
ppp_cp_event(dev, PID_IPV6CP, STOP, 0, 0, 0, NULL);
|
||||
}
|
||||
}
|
||||
if (old_state != CLOSED && proto->state == CLOSED)
|
||||
del_timer(&proto->timer);
|
||||
|
||||
#if DEBUG_STATE
|
||||
printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) ... %s\n", dev->name,
|
||||
proto_name(pid), event_names[event], state_names[proto->state]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
|
||||
unsigned int len, u8 *data)
|
||||
{
|
||||
static u8 const valid_accm[6] = { LCP_OPTION_ACCM, 6, 0, 0, 0, 0 };
|
||||
u8 *opt, *out;
|
||||
unsigned int nak_len = 0, rej_len = 0;
|
||||
|
||||
if (!(out = kmalloc(len, GFP_ATOMIC))) {
|
||||
dev->stats.rx_dropped++;
|
||||
return; /* out of memory, ignore CR packet */
|
||||
}
|
||||
|
||||
for (opt = data; len; len -= opt[1], opt += opt[1]) {
|
||||
if (len < 2 || len < opt[1]) {
|
||||
dev->stats.rx_errors++;
|
||||
return; /* bad packet, drop silently */
|
||||
}
|
||||
|
||||
if (pid == PID_LCP)
|
||||
switch (opt[0]) {
|
||||
case LCP_OPTION_MRU:
|
||||
continue; /* MRU always OK and > 1500 bytes? */
|
||||
|
||||
case LCP_OPTION_ACCM: /* async control character map */
|
||||
if (!memcmp(opt, valid_accm,
|
||||
sizeof(valid_accm)))
|
||||
continue;
|
||||
if (!rej_len) { /* NAK it */
|
||||
memcpy(out + nak_len, valid_accm,
|
||||
sizeof(valid_accm));
|
||||
nak_len += sizeof(valid_accm);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case LCP_OPTION_MAGIC:
|
||||
if (opt[1] != 6 || (!opt[2] && !opt[3] &&
|
||||
!opt[4] && !opt[5]))
|
||||
break; /* reject invalid magic number */
|
||||
continue;
|
||||
}
|
||||
/* reject this option */
|
||||
memcpy(out + rej_len, opt, opt[1]);
|
||||
rej_len += opt[1];
|
||||
}
|
||||
|
||||
if (rej_len)
|
||||
ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_REJ, id, rej_len, out);
|
||||
else if (nak_len)
|
||||
ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_NAK, id, nak_len, out);
|
||||
else
|
||||
ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, len, data);
|
||||
|
||||
kfree(out);
|
||||
}
|
||||
|
||||
static int ppp_rx(struct sk_buff *skb)
|
||||
{
|
||||
struct hdlc_header *hdr = (struct hdlc_header*)skb->data;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct ppp *ppp = get_ppp(dev);
|
||||
struct proto *proto;
|
||||
struct cp_header *cp;
|
||||
unsigned long flags;
|
||||
unsigned int len;
|
||||
u16 pid;
|
||||
#if DEBUG_CP
|
||||
int i;
|
||||
char *ptr;
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&ppp->lock, flags);
|
||||
/* Check HDLC header */
|
||||
if (skb->len < sizeof(struct hdlc_header))
|
||||
goto rx_error;
|
||||
cp = (struct cp_header*)skb_pull(skb, sizeof(struct hdlc_header));
|
||||
if (hdr->address != HDLC_ADDR_ALLSTATIONS ||
|
||||
hdr->control != HDLC_CTRL_UI)
|
||||
goto rx_error;
|
||||
|
||||
pid = ntohs(hdr->protocol);
|
||||
proto = get_proto(dev, pid);
|
||||
if (!proto) {
|
||||
if (ppp->protos[IDX_LCP].state == OPENED)
|
||||
ppp_tx_cp(dev, PID_LCP, LCP_PROTO_REJ,
|
||||
++ppp->seq, skb->len + 2, &hdr->protocol);
|
||||
goto rx_error;
|
||||
}
|
||||
|
||||
len = ntohs(cp->len);
|
||||
if (len < sizeof(struct cp_header) /* no complete CP header? */ ||
|
||||
skb->len < len /* truncated packet? */)
|
||||
goto rx_error;
|
||||
skb_pull(skb, sizeof(struct cp_header));
|
||||
len -= sizeof(struct cp_header);
|
||||
|
||||
/* HDLC and CP headers stripped from skb */
|
||||
#if DEBUG_CP
|
||||
if (cp->code < CP_CODES)
|
||||
sprintf(debug_buffer, "[%s id 0x%X]", code_names[cp->code],
|
||||
cp->id);
|
||||
else
|
||||
sprintf(debug_buffer, "[code %u id 0x%X]", cp->code, cp->id);
|
||||
ptr = debug_buffer + strlen(debug_buffer);
|
||||
for (i = 0; i < min_t(unsigned int, len, DEBUG_CP); i++) {
|
||||
sprintf(ptr, " %02X", skb->data[i]);
|
||||
ptr += strlen(ptr);
|
||||
}
|
||||
printk(KERN_DEBUG "%s: RX %s %s\n", dev->name, proto_name(pid),
|
||||
debug_buffer);
|
||||
#endif
|
||||
|
||||
/* LCP only */
|
||||
if (pid == PID_LCP)
|
||||
switch (cp->code) {
|
||||
case LCP_PROTO_REJ:
|
||||
pid = ntohs(*(__be16*)skb->data);
|
||||
if (pid == PID_LCP || pid == PID_IPCP ||
|
||||
pid == PID_IPV6CP)
|
||||
ppp_cp_event(dev, pid, RXJ_BAD, 0, 0,
|
||||
0, NULL);
|
||||
goto out;
|
||||
|
||||
case LCP_ECHO_REQ: /* send Echo-Reply */
|
||||
if (len >= 4 && proto->state == OPENED)
|
||||
ppp_tx_cp(dev, PID_LCP, LCP_ECHO_REPLY,
|
||||
cp->id, len - 4, skb->data + 4);
|
||||
goto out;
|
||||
|
||||
case LCP_ECHO_REPLY:
|
||||
if (cp->id == ppp->echo_id)
|
||||
ppp->last_pong = jiffies;
|
||||
goto out;
|
||||
|
||||
case LCP_DISC_REQ: /* discard */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* LCP, IPCP and IPV6CP */
|
||||
switch (cp->code) {
|
||||
case CP_CONF_REQ:
|
||||
ppp_cp_parse_cr(dev, pid, cp->id, len, skb->data);
|
||||
goto out;
|
||||
|
||||
case CP_CONF_ACK:
|
||||
if (cp->id == proto->cr_id)
|
||||
ppp_cp_event(dev, pid, RCA, 0, 0, 0, NULL);
|
||||
goto out;
|
||||
|
||||
case CP_CONF_REJ:
|
||||
case CP_CONF_NAK:
|
||||
if (cp->id == proto->cr_id)
|
||||
ppp_cp_event(dev, pid, RCN, 0, 0, 0, NULL);
|
||||
goto out;
|
||||
|
||||
case CP_TERM_REQ:
|
||||
ppp_cp_event(dev, pid, RTR, 0, cp->id, 0, NULL);
|
||||
goto out;
|
||||
|
||||
case CP_TERM_ACK:
|
||||
ppp_cp_event(dev, pid, RTA, 0, 0, 0, NULL);
|
||||
goto out;
|
||||
|
||||
case CP_CODE_REJ:
|
||||
ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, 0, NULL);
|
||||
goto out;
|
||||
|
||||
default:
|
||||
len += sizeof(struct cp_header);
|
||||
if (len > dev->mtu)
|
||||
len = dev->mtu;
|
||||
ppp_cp_event(dev, pid, RUC, 0, 0, len, cp);
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
|
||||
rx_error:
|
||||
dev->stats.rx_errors++;
|
||||
out:
|
||||
spin_unlock_irqrestore(&ppp->lock, flags);
|
||||
dev_kfree_skb_any(skb);
|
||||
ppp_tx_flush();
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
|
||||
static void ppp_timer(unsigned long arg)
|
||||
{
|
||||
struct proto *proto = (struct proto *)arg;
|
||||
struct ppp *ppp = get_ppp(proto->dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ppp->lock, flags);
|
||||
switch (proto->state) {
|
||||
case STOPPING:
|
||||
case REQ_SENT:
|
||||
case ACK_RECV:
|
||||
case ACK_SENT:
|
||||
if (proto->restart_counter) {
|
||||
ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
|
||||
0, NULL);
|
||||
proto->restart_counter--;
|
||||
} else
|
||||
ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0,
|
||||
0, NULL);
|
||||
break;
|
||||
|
||||
case OPENED:
|
||||
if (proto->pid != PID_LCP)
|
||||
break;
|
||||
if (time_after(jiffies, ppp->last_pong +
|
||||
ppp->keepalive_timeout * HZ)) {
|
||||
printk(KERN_INFO "%s: Link down\n", proto->dev->name);
|
||||
ppp_cp_event(proto->dev, PID_LCP, STOP, 0, 0, 0, NULL);
|
||||
ppp_cp_event(proto->dev, PID_LCP, START, 0, 0, 0, NULL);
|
||||
} else { /* send keep-alive packet */
|
||||
ppp->echo_id = ++ppp->seq;
|
||||
ppp_tx_cp(proto->dev, PID_LCP, LCP_ECHO_REQ,
|
||||
ppp->echo_id, 0, NULL);
|
||||
proto->timer.expires = jiffies +
|
||||
ppp->keepalive_interval * HZ;
|
||||
add_timer(&proto->timer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ppp->lock, flags);
|
||||
ppp_tx_flush();
|
||||
}
|
||||
|
||||
|
||||
static void ppp_start(struct net_device *dev)
|
||||
{
|
||||
struct ppp *ppp = get_ppp(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IDX_COUNT; i++) {
|
||||
struct proto *proto = &ppp->protos[i];
|
||||
proto->dev = dev;
|
||||
init_timer(&proto->timer);
|
||||
proto->timer.function = ppp_timer;
|
||||
proto->timer.data = (unsigned long)proto;
|
||||
proto->state = CLOSED;
|
||||
}
|
||||
ppp->protos[IDX_LCP].pid = PID_LCP;
|
||||
ppp->protos[IDX_IPCP].pid = PID_IPCP;
|
||||
ppp->protos[IDX_IPV6CP].pid = PID_IPV6CP;
|
||||
|
||||
ppp_cp_event(dev, PID_LCP, START, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
static void ppp_stop(struct net_device *dev)
|
||||
{
|
||||
ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
static struct hdlc_proto proto = {
|
||||
.open = ppp_open,
|
||||
.close = ppp_close,
|
||||
.start = ppp_start,
|
||||
.stop = ppp_stop,
|
||||
.type_trans = ppp_type_trans,
|
||||
.ioctl = ppp_ioctl,
|
||||
.netif_rx = ppp_rx,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct header_ops ppp_header_ops = {
|
||||
.create = ppp_hard_header,
|
||||
};
|
||||
|
||||
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
struct ppp *ppp;
|
||||
int result;
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
|
@ -109,25 +654,35 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
|||
return 0; /* return protocol only, no settable parameters */
|
||||
|
||||
case IF_PROTO_PPP:
|
||||
if(!capable(CAP_NET_ADMIN))
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if(dev->flags & IFF_UP)
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
/* no settable parameters */
|
||||
|
||||
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
|
||||
result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = attach_hdlc_protocol(dev, &proto,
|
||||
sizeof(struct ppp_state));
|
||||
result = attach_hdlc_protocol(dev, &proto, sizeof(struct ppp));
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
ppp = get_ppp(dev);
|
||||
spin_lock_init(&ppp->lock);
|
||||
ppp->req_timeout = 2;
|
||||
ppp->cr_retries = 10;
|
||||
ppp->term_retries = 2;
|
||||
ppp->keepalive_interval = 10;
|
||||
ppp->keepalive_timeout = 60;
|
||||
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header_len = sizeof(struct hdlc_header);
|
||||
dev->header_ops = &ppp_header_ops;
|
||||
dev->type = ARPHRD_PPP;
|
||||
netif_dormant_off(dev);
|
||||
netif_dormant_on(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -137,12 +692,11 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
|||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
skb_queue_head_init(&tx_queue);
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
|
|
|
@ -53,7 +53,7 @@ static const char* devname = "RISCom/N2";
|
|||
#define NEED_SCA_MSCI_INTR
|
||||
#define MAX_TX_BUFFERS 10
|
||||
|
||||
static char *hw = NULL; /* pointer to hw=xxx command line string */
|
||||
static char *hw; /* pointer to hw=xxx command line string */
|
||||
|
||||
/* RISCom/N2 Board Registers */
|
||||
|
||||
|
@ -145,7 +145,6 @@ static card_t **new_card = &first_card;
|
|||
&(card)->ports[port] : NULL)
|
||||
|
||||
|
||||
|
||||
static __inline__ u8 sca_get_page(card_t *card)
|
||||
{
|
||||
return inb(card->io + N2_PSR) & PSR_PAGEBITS;
|
||||
|
@ -159,9 +158,7 @@ static __inline__ void openwin(card_t *card, u8 page)
|
|||
}
|
||||
|
||||
|
||||
|
||||
#include "hd6457x.c"
|
||||
|
||||
#include "hd64570.c"
|
||||
|
||||
|
||||
static void n2_set_iface(port_t *port)
|
||||
|
@ -478,7 +475,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
|
|||
n2_destroy_card(card);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
sca_init_sync_port(port); /* Set up SCA memory */
|
||||
sca_init_port(port); /* Set up SCA memory */
|
||||
|
||||
printk(KERN_INFO "%s: RISCom/N2 node %d\n",
|
||||
dev->name, port->phy_node);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Cyclades PC300 synchronous serial card driver for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 2000-2008 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
* Sources of information:
|
||||
* Hitachi HD64572 SCA-II User's Manual
|
||||
* Cyclades PC300 Linux driver
|
||||
* Original Cyclades PC300 Linux driver
|
||||
*
|
||||
* This driver currently supports only PC300/RSV (V.24/V.35) and
|
||||
* PC300/X21 cards.
|
||||
|
@ -37,17 +37,11 @@
|
|||
|
||||
#include "hd64572.h"
|
||||
|
||||
static const char* version = "Cyclades PC300 driver version: 1.17";
|
||||
static const char* devname = "PC300";
|
||||
|
||||
#undef DEBUG_PKT
|
||||
#define DEBUG_RINGS
|
||||
|
||||
#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */
|
||||
#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */
|
||||
#define ALL_PAGES_ALWAYS_MAPPED
|
||||
#define NEED_DETECT_RAM
|
||||
#define NEED_SCA_MSCI_INTR
|
||||
#define MAX_TX_BUFFERS 10
|
||||
|
||||
static int pci_clock_freq = 33000000;
|
||||
|
@ -81,7 +75,8 @@ typedef struct {
|
|||
|
||||
|
||||
typedef struct port_s {
|
||||
struct net_device *dev;
|
||||
struct napi_struct napi;
|
||||
struct net_device *netdev;
|
||||
struct card_s *card;
|
||||
spinlock_t lock; /* TX lock */
|
||||
sync_serial_settings settings;
|
||||
|
@ -93,7 +88,7 @@ typedef struct port_s {
|
|||
u16 txin; /* tx ring buffer 'in' and 'last' pointers */
|
||||
u16 txlast;
|
||||
u8 rxs, txs, tmc; /* SCA registers */
|
||||
u8 phy_node; /* physical port # - 0 or 1 */
|
||||
u8 chan; /* physical port # - 0 or 1 */
|
||||
}port_t;
|
||||
|
||||
|
||||
|
@ -114,21 +109,10 @@ typedef struct card_s {
|
|||
}card_t;
|
||||
|
||||
|
||||
#define sca_in(reg, card) readb(card->scabase + (reg))
|
||||
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
|
||||
#define sca_inw(reg, card) readw(card->scabase + (reg))
|
||||
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
|
||||
#define sca_inl(reg, card) readl(card->scabase + (reg))
|
||||
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
|
||||
|
||||
#define port_to_card(port) (port->card)
|
||||
#define log_node(port) (port->phy_node)
|
||||
#define phy_node(port) (port->phy_node)
|
||||
#define winbase(card) (card->rambase)
|
||||
#define get_port(card, port) ((port) < (card)->n_ports ? \
|
||||
(&(card)->ports[port]) : (NULL))
|
||||
|
||||
#include "hd6457x.c"
|
||||
#include "hd64572.c"
|
||||
|
||||
|
||||
static void pc300_set_iface(port_t *port)
|
||||
|
@ -139,8 +123,8 @@ static void pc300_set_iface(port_t *port)
|
|||
u8 rxs = port->rxs & CLK_BRG_MASK;
|
||||
u8 txs = port->txs & CLK_BRG_MASK;
|
||||
|
||||
sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
|
||||
port_to_card(port));
|
||||
sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
|
||||
port->card);
|
||||
switch(port->settings.clock_type) {
|
||||
case CLOCK_INT:
|
||||
rxs |= CLK_BRG; /* BRG output */
|
||||
|
@ -172,10 +156,10 @@ static void pc300_set_iface(port_t *port)
|
|||
if (port->card->type == PC300_RSV) {
|
||||
if (port->iface == IF_IFACE_V35)
|
||||
writel(card->init_ctrl_value |
|
||||
PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
|
||||
PC300_CHMEDIA_MASK(port->chan), init_ctrl);
|
||||
else
|
||||
writel(card->init_ctrl_value &
|
||||
~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
|
||||
~PC300_CHMEDIA_MASK(port->chan), init_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,10 +264,8 @@ static void pc300_pci_remove_one(struct pci_dev *pdev)
|
|||
card_t *card = pci_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (card->ports[i].card) {
|
||||
struct net_device *dev = port_to_dev(&card->ports[i]);
|
||||
unregister_hdlc_device(dev);
|
||||
}
|
||||
if (card->ports[i].card)
|
||||
unregister_hdlc_device(card->ports[i].netdev);
|
||||
|
||||
if (card->irq)
|
||||
free_irq(card->irq, card);
|
||||
|
@ -298,10 +280,10 @@ static void pc300_pci_remove_one(struct pci_dev *pdev)
|
|||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
if (card->ports[0].dev)
|
||||
free_netdev(card->ports[0].dev);
|
||||
if (card->ports[1].dev)
|
||||
free_netdev(card->ports[1].dev);
|
||||
if (card->ports[0].netdev)
|
||||
free_netdev(card->ports[0].netdev);
|
||||
if (card->ports[1].netdev)
|
||||
free_netdev(card->ports[1].netdev);
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
|
@ -318,12 +300,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
u32 scaphys; /* SCA memory base */
|
||||
u32 plxphys; /* PLX registers memory base */
|
||||
|
||||
#ifndef MODULE
|
||||
static int printed_version;
|
||||
if (!printed_version++)
|
||||
printk(KERN_INFO "%s\n", version);
|
||||
#endif
|
||||
|
||||
i = pci_enable_device(pdev);
|
||||
if (i)
|
||||
return i;
|
||||
|
@ -343,6 +319,35 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
}
|
||||
pci_set_drvdata(pdev, card);
|
||||
|
||||
if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
|
||||
pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
|
||||
pci_resource_len(pdev, 3) < 16384) {
|
||||
printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
|
||||
pc300_pci_remove_one(pdev);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
plxphys = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
|
||||
|
||||
scaphys = pci_resource_start(pdev, 2) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
|
||||
|
||||
ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->rambase = pci_ioremap_bar(pdev, 3);
|
||||
|
||||
if (card->plxbase == NULL ||
|
||||
card->scabase == NULL ||
|
||||
card->rambase == NULL) {
|
||||
printk(KERN_ERR "pc300: ioremap() failed\n");
|
||||
pc300_pci_remove_one(pdev);
|
||||
}
|
||||
|
||||
/* PLX PCI 9050 workaround for local configuration register read bug */
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
|
||||
card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
|
||||
|
||||
if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
|
||||
pdev->device == PCI_DEVICE_ID_PC300_TE_2)
|
||||
card->type = PC300_TE; /* not fully supported */
|
||||
|
@ -358,41 +363,12 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
card->n_ports = 2;
|
||||
|
||||
for (i = 0; i < card->n_ports; i++)
|
||||
if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
|
||||
if (!(card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]))) {
|
||||
printk(KERN_ERR "pc300: unable to allocate memory\n");
|
||||
pc300_pci_remove_one(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
|
||||
pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
|
||||
pci_resource_len(pdev, 3) < 16384) {
|
||||
printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
|
||||
pc300_pci_remove_one(pdev);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
|
||||
|
||||
scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
|
||||
|
||||
ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
card->rambase = pci_ioremap_bar(pdev, 3);
|
||||
|
||||
if (card->plxbase == NULL ||
|
||||
card->scabase == NULL ||
|
||||
card->rambase == NULL) {
|
||||
printk(KERN_ERR "pc300: ioremap() failed\n");
|
||||
pc300_pci_remove_one(pdev);
|
||||
}
|
||||
|
||||
/* PLX PCI 9050 workaround for local configuration register read bug */
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
|
||||
card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
|
||||
|
||||
/* Reset PLX */
|
||||
p = &card->plxbase->init_ctrl;
|
||||
writel(card->init_ctrl_value | 0x40000000, p);
|
||||
|
@ -446,7 +422,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
writew(0x0041, &card->plxbase->intr_ctrl_stat);
|
||||
|
||||
/* Allocate IRQ */
|
||||
if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
|
||||
if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pc300", card)) {
|
||||
printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
|
||||
pdev->irq);
|
||||
pc300_pci_remove_one(pdev);
|
||||
|
@ -463,9 +439,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
|
||||
for (i = 0; i < card->n_ports; i++) {
|
||||
port_t *port = &card->ports[i];
|
||||
struct net_device *dev = port_to_dev(port);
|
||||
struct net_device *dev = port->netdev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
port->phy_node = i;
|
||||
port->chan = i;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
dev->irq = card->irq;
|
||||
|
@ -484,6 +460,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
else
|
||||
port->iface = IF_IFACE_V35;
|
||||
|
||||
sca_init_port(port);
|
||||
if (register_hdlc_device(dev)) {
|
||||
printk(KERN_ERR "pc300: unable to register hdlc "
|
||||
"device\n");
|
||||
|
@ -491,10 +468,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
|
|||
pc300_pci_remove_one(pdev);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
sca_init_sync_port(port); /* Set up SCA memory */
|
||||
|
||||
printk(KERN_INFO "%s: PC300 node %d\n",
|
||||
dev->name, port->phy_node);
|
||||
printk(KERN_INFO "%s: PC300 channel %d\n",
|
||||
dev->name, port->chan);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -524,9 +500,6 @@ static struct pci_driver pc300_pci_driver = {
|
|||
|
||||
static int __init pc300_init_module(void)
|
||||
{
|
||||
#ifdef MODULE
|
||||
printk(KERN_INFO "%s\n", version);
|
||||
#endif
|
||||
if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
|
||||
printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Goramo PCI200SYN synchronous serial card driver for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 2002-2008 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
|
@ -33,17 +33,11 @@
|
|||
|
||||
#include "hd64572.h"
|
||||
|
||||
static const char* version = "Goramo PCI200SYN driver version: 1.16";
|
||||
static const char* devname = "PCI200SYN";
|
||||
|
||||
#undef DEBUG_PKT
|
||||
#define DEBUG_RINGS
|
||||
|
||||
#define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */
|
||||
#define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */
|
||||
#define ALL_PAGES_ALWAYS_MAPPED
|
||||
#define NEED_DETECT_RAM
|
||||
#define NEED_SCA_MSCI_INTR
|
||||
#define MAX_TX_BUFFERS 10
|
||||
|
||||
static int pci_clock_freq = 33000000;
|
||||
|
@ -68,7 +62,8 @@ typedef struct {
|
|||
|
||||
|
||||
typedef struct port_s {
|
||||
struct net_device *dev;
|
||||
struct napi_struct napi;
|
||||
struct net_device *netdev;
|
||||
struct card_s *card;
|
||||
spinlock_t lock; /* TX lock */
|
||||
sync_serial_settings settings;
|
||||
|
@ -79,7 +74,7 @@ typedef struct port_s {
|
|||
u16 txin; /* tx ring buffer 'in' and 'last' pointers */
|
||||
u16 txlast;
|
||||
u8 rxs, txs, tmc; /* SCA registers */
|
||||
u8 phy_node; /* physical port # - 0 or 1 */
|
||||
u8 chan; /* physical port # - 0 or 1 */
|
||||
}port_t;
|
||||
|
||||
|
||||
|
@ -97,17 +92,6 @@ typedef struct card_s {
|
|||
}card_t;
|
||||
|
||||
|
||||
#define sca_in(reg, card) readb(card->scabase + (reg))
|
||||
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
|
||||
#define sca_inw(reg, card) readw(card->scabase + (reg))
|
||||
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
|
||||
#define sca_inl(reg, card) readl(card->scabase + (reg))
|
||||
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
|
||||
|
||||
#define port_to_card(port) (port->card)
|
||||
#define log_node(port) (port->phy_node)
|
||||
#define phy_node(port) (port->phy_node)
|
||||
#define winbase(card) (card->rambase)
|
||||
#define get_port(card, port) (&card->ports[port])
|
||||
#define sca_flush(card) (sca_in(IER0, card));
|
||||
|
||||
|
@ -127,7 +111,7 @@ static inline void new_memcpy_toio(char __iomem *dest, char *src, int length)
|
|||
#undef memcpy_toio
|
||||
#define memcpy_toio new_memcpy_toio
|
||||
|
||||
#include "hd6457x.c"
|
||||
#include "hd64572.c"
|
||||
|
||||
|
||||
static void pci200_set_iface(port_t *port)
|
||||
|
@ -137,8 +121,8 @@ static void pci200_set_iface(port_t *port)
|
|||
u8 rxs = port->rxs & CLK_BRG_MASK;
|
||||
u8 txs = port->txs & CLK_BRG_MASK;
|
||||
|
||||
sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
|
||||
port_to_card(port));
|
||||
sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
|
||||
port->card);
|
||||
switch(port->settings.clock_type) {
|
||||
case CLOCK_INT:
|
||||
rxs |= CLK_BRG; /* BRG output */
|
||||
|
@ -180,7 +164,7 @@ static int pci200_open(struct net_device *dev)
|
|||
|
||||
sca_open(dev);
|
||||
pci200_set_iface(port);
|
||||
sca_flush(port_to_card(port));
|
||||
sca_flush(port->card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -189,7 +173,7 @@ static int pci200_open(struct net_device *dev)
|
|||
static int pci200_close(struct net_device *dev)
|
||||
{
|
||||
sca_close(dev);
|
||||
sca_flush(port_to_card(dev_to_port(dev)));
|
||||
sca_flush(dev_to_port(dev)->card);
|
||||
hdlc_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -242,7 +226,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
|
||||
memcpy(&port->settings, &new_line, size); /* Update settings */
|
||||
pci200_set_iface(port);
|
||||
sca_flush(port_to_card(port));
|
||||
sca_flush(port->card);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
@ -258,10 +242,8 @@ static void pci200_pci_remove_one(struct pci_dev *pdev)
|
|||
card_t *card = pci_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (card->ports[i].card) {
|
||||
struct net_device *dev = port_to_dev(&card->ports[i]);
|
||||
unregister_hdlc_device(dev);
|
||||
}
|
||||
if (card->ports[i].card)
|
||||
unregister_hdlc_device(card->ports[i].netdev);
|
||||
|
||||
if (card->irq)
|
||||
free_irq(card->irq, card);
|
||||
|
@ -276,10 +258,10 @@ static void pci200_pci_remove_one(struct pci_dev *pdev)
|
|||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
if (card->ports[0].dev)
|
||||
free_netdev(card->ports[0].dev);
|
||||
if (card->ports[1].dev)
|
||||
free_netdev(card->ports[1].dev);
|
||||
if (card->ports[0].netdev)
|
||||
free_netdev(card->ports[0].netdev);
|
||||
if (card->ports[1].netdev)
|
||||
free_netdev(card->ports[1].netdev);
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
|
@ -296,12 +278,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
u32 scaphys; /* SCA memory base */
|
||||
u32 plxphys; /* PLX registers memory base */
|
||||
|
||||
#ifndef MODULE
|
||||
static int printed_version;
|
||||
if (!printed_version++)
|
||||
printk(KERN_INFO "%s\n", version);
|
||||
#endif
|
||||
|
||||
i = pci_enable_device(pdev);
|
||||
if (i)
|
||||
return i;
|
||||
|
@ -320,9 +296,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
return -ENOBUFS;
|
||||
}
|
||||
pci_set_drvdata(pdev, card);
|
||||
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
|
||||
card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
|
||||
if (!card->ports[0].dev || !card->ports[1].dev) {
|
||||
card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]);
|
||||
card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]);
|
||||
if (!card->ports[0].netdev || !card->ports[1].netdev) {
|
||||
printk(KERN_ERR "pci200syn: unable to allocate memory\n");
|
||||
pci200_pci_remove_one(pdev);
|
||||
return -ENOMEM;
|
||||
|
@ -398,7 +374,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
writew(readw(p) | 0x0040, p);
|
||||
|
||||
/* Allocate IRQ */
|
||||
if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
|
||||
if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) {
|
||||
printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n",
|
||||
pdev->irq);
|
||||
pci200_pci_remove_one(pdev);
|
||||
|
@ -410,9 +386,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
|
||||
for (i = 0; i < 2; i++) {
|
||||
port_t *port = &card->ports[i];
|
||||
struct net_device *dev = port_to_dev(port);
|
||||
struct net_device *dev = port->netdev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
port->phy_node = i;
|
||||
port->chan = i;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
dev->irq = card->irq;
|
||||
|
@ -426,6 +402,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
hdlc->xmit = sca_xmit;
|
||||
port->settings.clock_type = CLOCK_EXT;
|
||||
port->card = card;
|
||||
sca_init_port(port);
|
||||
if (register_hdlc_device(dev)) {
|
||||
printk(KERN_ERR "pci200syn: unable to register hdlc "
|
||||
"device\n");
|
||||
|
@ -433,10 +410,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
|
|||
pci200_pci_remove_one(pdev);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
sca_init_sync_port(port); /* Set up SCA memory */
|
||||
|
||||
printk(KERN_INFO "%s: PCI200SYN node %d\n",
|
||||
dev->name, port->phy_node);
|
||||
printk(KERN_INFO "%s: PCI200SYN channel %d\n",
|
||||
dev->name, port->chan);
|
||||
}
|
||||
|
||||
sca_flush(card);
|
||||
|
@ -464,9 +440,6 @@ static struct pci_driver pci200_pci_driver = {
|
|||
|
||||
static int __init pci200_init_module(void)
|
||||
{
|
||||
#ifdef MODULE
|
||||
printk(KERN_INFO "%s\n", version);
|
||||
#endif
|
||||
if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
|
||||
printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
|
||||
return -EINVAL;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Defines for synchronous PPP/Cisco link level subroutines.
|
||||
*
|
||||
* Copyright (C) 1994 Cronyx Ltd.
|
||||
* Author: Serge Vakulenko, <vak@zebub.msk.su>
|
||||
*
|
||||
* This software is distributed with NO WARRANTIES, not even the implied
|
||||
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Authors grant any other persons or organizations permission to use
|
||||
* or modify this software as long as this message is kept with the software,
|
||||
* all derivative works or modified versions.
|
||||
*
|
||||
* Version 1.7, Wed Jun 7 22:12:02 MSD 1995
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SYNCPPP_H_
|
||||
#define _SYNCPPP_H_ 1
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct slcp {
|
||||
u16 state; /* state machine */
|
||||
u32 magic; /* local magic number */
|
||||
u_char echoid; /* id of last keepalive echo request */
|
||||
u_char confid; /* id of last configuration request */
|
||||
};
|
||||
|
||||
struct sipcp {
|
||||
u16 state; /* state machine */
|
||||
u_char confid; /* id of last configuration request */
|
||||
};
|
||||
|
||||
struct sppp
|
||||
{
|
||||
struct sppp * pp_next; /* next interface in keepalive list */
|
||||
u32 pp_flags; /* use Cisco protocol instead of PPP */
|
||||
u16 pp_alivecnt; /* keepalive packets counter */
|
||||
u16 pp_loopcnt; /* loopback detection counter */
|
||||
u32 pp_seq; /* local sequence number */
|
||||
u32 pp_rseq; /* remote sequence number */
|
||||
struct slcp lcp; /* LCP params */
|
||||
struct sipcp ipcp; /* IPCP params */
|
||||
struct timer_list pp_timer;
|
||||
struct net_device *pp_if;
|
||||
char pp_link_state; /* Link status */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct ppp_device
|
||||
{
|
||||
struct net_device *dev; /* Network device pointer */
|
||||
struct sppp sppp; /* Synchronous PPP */
|
||||
};
|
||||
|
||||
static inline struct sppp *sppp_of(struct net_device *dev)
|
||||
{
|
||||
struct ppp_device **ppp = dev->ml_priv;
|
||||
BUG_ON((*ppp)->dev != dev);
|
||||
return &(*ppp)->sppp;
|
||||
}
|
||||
|
||||
#define PP_KEEPALIVE 0x01 /* use keepalive protocol */
|
||||
#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */
|
||||
#define PP_TIMO 0x04 /* cp_timeout routine active */
|
||||
#define PP_DEBUG 0x08
|
||||
|
||||
#define PPP_MTU 1500 /* max. transmit unit */
|
||||
|
||||
#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */
|
||||
#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */
|
||||
#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */
|
||||
#define LCP_STATE_OPENED 3 /* LCP state: opened */
|
||||
|
||||
#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */
|
||||
#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */
|
||||
#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */
|
||||
#define IPCP_STATE_OPENED 3 /* IPCP state: opened */
|
||||
|
||||
#define SPPP_LINK_DOWN 0 /* link down - no keepalive */
|
||||
#define SPPP_LINK_UP 1 /* link is up - keepalive ok */
|
||||
|
||||
void sppp_attach (struct ppp_device *pd);
|
||||
void sppp_detach (struct net_device *dev);
|
||||
int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
struct sk_buff *sppp_dequeue (struct net_device *dev);
|
||||
int sppp_isempty (struct net_device *dev);
|
||||
void sppp_flush (struct net_device *dev);
|
||||
int sppp_open (struct net_device *dev);
|
||||
int sppp_reopen (struct net_device *dev);
|
||||
int sppp_close (struct net_device *dev);
|
||||
#endif
|
||||
|
||||
#define SPPPIOCCISCO (SIOCDEVPRIVATE)
|
||||
#define SPPPIOCPPP (SIOCDEVPRIVATE+1)
|
||||
#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2)
|
||||
#define SPPPIOCSFLAGS (SIOCDEVPRIVATE+3)
|
||||
#define SPPPIOCGFLAGS (SIOCDEVPRIVATE+4)
|
||||
|
||||
#endif /* _SYNCPPP_H_ */
|
Loading…
Reference in a new issue