* Re: net: alignment problem in icmp code
From: Pierre Ossman @ 2007-10-22 9:26 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20071022.020538.74751031.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 1235 bytes --]
On Mon, 22 Oct 2007 02:05:38 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:
> From: Pierre Ossman <drzeus@drzeus.cx>
> Date: Mon, 22 Oct 2007 10:42:08 +0200
>
> > This seems like a rather evil layering violation.
>
> This has a 10+ year precedence and it's why the Linux networking stack
> is so fast. If you read any other driver you would have seen the
> skb_reserve() call every one of them do to align the headers.
>
The norm seems to be to not comment this call. It's hardly obvious.
> I think I've tolerated this long enough.
>
> Are you going keep teaching me how the C language works, how GCC
> interprets it, and how evil the Linux networking is, or are you going
> to fix the bug in your driver? :-)
Settle down, "bug" fixed even before this discussion even began. I just don't like papering over problems so I want to know why this is needed and if it isn't indicative of a larger problem. If you don't want the discussions, make sure people know the gotchas.
(And I wasn't try to teach anyone. I was giving my view on things, and if you think I'm off my meds, feel free to say so. Groveling and excessively putting every statement as a question demeans us both. ;))
Rgds
Pierre
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] [IPSEC] IPV6: Fix to add tunnel mode SA correctly.
From: David Miller @ 2007-10-22 9:42 UTC (permalink / raw)
To: herbert; +Cc: nakam, netdev
In-Reply-To: <20071022083720.GA17865@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Mon, 22 Oct 2007 16:37:20 +0800
> On Mon, Oct 22, 2007 at 03:09:34PM +0900, Masahide NAKAMURA wrote:
> > Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
>
> Thanks for catching my silly bug!
Applied, thanks!
^ permalink raw reply
* Re: net: alignment problem in icmp code
From: Eric Dumazet @ 2007-10-22 9:52 UTC (permalink / raw)
To: Pierre Ossman; +Cc: David Miller, netdev
In-Reply-To: <20071022112605.11f7893e@poseidon.drzeus.cx>
Pierre Ossman a écrit :
> On Mon, 22 Oct 2007 02:05:38 -0700 (PDT)
> David Miller <davem@davemloft.net> wrote:
>
>
>> From: Pierre Ossman <drzeus@drzeus.cx>
>> Date: Mon, 22 Oct 2007 10:42:08 +0200
>>
>>
>>> This seems like a rather evil layering violation.
>>>
>> This has a 10+ year precedence and it's why the Linux networking stack
>> is so fast. If you read any other driver you would have seen the
>> skb_reserve() call every one of them do to align the headers.
>>
>>
>
> The norm seems to be to not comment this call. It's hardly obvious.
>
>
This is not obvious you are right, but documented in
include/linux/skbuff.h (lines 1150 ...)
/*
* CPUs often take a performance hit when accessing unaligned memory
* locations. The actual performance hit varies, it can be small if the
* hardware handles it or large if we have to take an exception and fix it
* in software.
*
* Since an ethernet header is 14 bytes network drivers often end up with
* the IP header at an unaligned offset. The IP header can be aligned by
* shifting the start of the packet by 2 bytes. Drivers should do this
* with:
*
* skb_reserve(NET_IP_ALIGN);
*
* The downside to this alignment of the IP header is that the DMA is now
* unaligned. On some architectures the cost of an unaligned DMA is high
* and this cost outweighs the gains made by aligning the IP header.
*
* Since this trade off varies between architectures, we allow NET_IP_ALIGN
* to be overridden.
*/
#ifndef NET_IP_ALIGN
#define NET_IP_ALIGN 2
#endif
But then, many drivers dont use NET_IP_ALIGN but a hardcoded 2
drivers/net/pcnet32.c:608: skb_reserve(rx_skbuff, 2);
drivers/net/pcnet32.c:1214: skb_reserve(newskb, 2);
drivers/net/pcnet32.c:1245: skb_reserve(skb, 2); /* 16
byte align */
drivers/net/pcnet32.c:2396: skb_reserve(rx_skbuff, 2);
drivers/net/sundance.c:989: skb_reserve(skb, 2); /* 16
byte align the IP header. */
drivers/net/sundance.c:1312: skb_reserve(skb,
2); /* 16 byte align the IP header */
drivers/net/sundance.c:1375: skb_reserve(skb, 2); /*
Align IP on 16 byte boundaries */
^ permalink raw reply
* [PATCH] wan: new driver retina
From: Matti Linnanvuori @ 2007-10-22 11:14 UTC (permalink / raw)
To: akpm, jgarzik; +Cc: netdev
From: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
Retina G.703 and G.SHDSL driver.
Signed-off-by: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
---
Fixed Kconfig and the body of the explanation.
diff -Napur
linux-2.6.23/drivers/net/wan/Kconfig
linux-2.6.24/drivers/net/wan/Kconfig
--- linux-2.6.23/drivers/net/wan/Kconfig 2007-10-09 23:31:38.000000000 +0300
+++ linux-2.6.24/drivers/net/wan/Kconfig 2007-10-22 13:54:55.383644167 +0300
@@ -494,4 +494,15 @@ config SBNI_MULTILINE
If unsure, say N.
+config RETINA
+ tristate "Retina support"
+ depends on m && PCI
+ help
+ Driver for Retina C5400 and E2200 network cards, which
+ support G.703, G.SHDSL, Ethernet encapsulation and PCI.
+
+ The driver will be compiled as a module: the
+ module will be called retina.
+
+
endif # WAN
diff -Napur linux-2.6.23/drivers/net/wan/Makefile linux-2.6.24/drivers/net/wan/Makefile
--- linux-2.6.23/drivers/net/wan/Makefile 2007-10-09 23:31:38.000000000 +0300
+++ linux-2.6.24/drivers/net/wan/Makefile 2007-10-22 12:05:57.638172823 +0300
@@ -42,6 +42,7 @@ obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
obj-$(CONFIG_PC300TOO) += pc300too.o
+obj-$(CONFIG_RETINA) += retina.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff -Napur linux-2.6.23/drivers/net/wan/retina.c linux-2.6.24/drivers/net/wan/retina.c
--- linux-2.6.23/drivers/net/wan/retina.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.24/drivers/net/wan/retina.c 2007-10-22 12:01:44.856033562 +0300
@@ -0,0 +1,4503 @@
+/* V1.2.4 */
+
+/* retina.c: */
+
+/*
+ This driver is based on:
+
+ /drivers/net/fepci.c
+ FEPCI (Frame Engine for PCI) driver for Linux operating system
+
+ Copyright (C) 2002-2003 Jouni Kujala, Flexibilis Oy.
+
+ This program 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.
+
+ 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.
+
+ All the drivers derived from or based on this code fall under the
+ GPL and must retain the copyright and license notice.
+
+ CHANGES
+ -------
+
+ v1.0.0 (JK) - May 27, 2003:
+ * Original driver.
+
+ v1.1.0 (JK) - June, 2003:
+ * final Flexibilis driver
+
+ v1.2.0: NO_ARP option back again
+
+ v1.2.1: (JT) - Aug 21, 2003:
+ * Added support for Retina C5400 card including PROC stuff.
+
+ v1.2.2: (Petri Ahonen) - Sep 19, 2003:
+ * PtP changes:
+ * Added retina_ptp_interfaces module parameter for initializing
+ * interfaces in PtP mode.
+ * for example:
+ * insmod ./retina.o retina_ptp_interfaces=dcp00,dcp01
+ * Added retina_noarp_with_ptp module parameter to set/clear
+ * NOARP flag on PtP interfaces
+ * for example:
+ * insmod ./retina.o retina_ptp_interfaces=dcp00 retina_noarp_with_ptp=0
+
+ v1.2.3: (JT) - Nov 14, 2003:
+ * Fixed PROC packet counters.
+
+ v1.2.4: (JT) - May 14, 2004:
+ * Made initializing MACs safer.
+*/
+
+#define DRV_NAME "retina"
+#define DRV_VERSION "1.2.5"
+#define DRV_RELDATE "November 14, 2003"
+
+#define DBG_PRINT(xyz...)
+/* printk(KERN_DEBUG xyz) */
+
+/* uncomment this if you want to have debug files in /proc */
+/* #define DEBUG_PROC_FILES */
+
+/* obsolete
+ see retina_noarp_with_ptp
+define FEPCI_NO_ARP */
+
+/* uncomment this if you want to have point-to-point links
+ ! Only interfaces listed in retina_ptp_interfaces will
+ be created in PtP mode
+ see retina_ptp_interfaces */
+#define FEPCI_POINT_TO_POINT
+
+/* need to update MODULE_PARM also */
+#define MAX_DEVICES 32u
+
+#define MAX_TX_UNITS 256u
+#define MAX_RX_UNITS 256u
+
+#define MAX_UNIT_SZ_ORDER 10u
+
+#define TX_RING_SIZE 8u
+#define RX_RING_SIZE 8u
+
+/* need to update MODULE_PARM also */
+#define CHANNELS 4u
+
+#define RX_FIFO_THRESHOLD_PACKET_MODE 0x4
+#define TX_FIFO_THRESHOLD_PACKET_MODE 0x4
+#define TX_DESC_THRESHOLD_PACKET_MODE 0x4
+
+#define RX_FIFO_THRESHOLD_STREAM_MODE 0x4
+#define TX_FIFO_THRESHOLD_STREAM_MODE 0x7
+#define TX_DESC_THRESHOLD_STREAM_MODE 0x1
+
+/* need to update MODULE_PARM also */
+#define MAX_INTERFACES (CHANNELS*MAX_DEVICES)
+
+const char fepci_name[] = "retina";
+const char fepci_alarm_manager_name[] = "retina alarm manager";
+const char fepci_NAME[] = "RETINA";
+const char fepci_netdev_name[] = "dcpxx";
+const char fepci_proc_entry_name[] = "driver/retina";
+
+static unsigned int find_cnt;
+
+#ifdef FEPCI_POINT_TO_POINT
+static char *retina_ptp_interfaces[MAX_INTERFACES];
+static int retina_noarp_with_ptp = 1;
+#endif /* FEPCI_POINT_TO_POINT */
+
+#define fepci_features_proc_entry_name "driver/retina/%02x:%02x.%02x/features"
+#define fepci_settings_proc_entry_name "driver/retina/%02x:%02x.%02x/settings"
+#define fepci_status_proc_entry_name "driver/retina/%02x:%02x.%02x/status"
+
+#ifdef DEBUG_PROC_FILES
+#define fepci_counters_proc_entry_name \
+"driver/retina/%02x:%02x.%02x/counters_ch%d"
+#define fepci_descriptors_proc_entry_name \
+"driver/retina/%02x:%02x.%02x/descriptors_ch%d"
+#define fepci_stream_counters_proc_entry_name \
+"driver/retina/%02x:%02x.%02x/stream_counters_ch%d"
+#define fepci_registers_proc_entry_name \
+"driver/retina/%02x:%02x.%02x/registers_ch%d"
+#endif /* DEBUG_PROC_FILES */
+
+/* Time in jiffies before concluding that the transmitter is hung */
+#define TX_TIMEOUT (20*HZ)
+
+#if !defined(__OPTIMIZE__)
+#warning You must compile this file with correct options.
+#warning See the last lines of the source file.
+#error You have to compile this driver with "-O".
+#endif
+#include "retina.h"
+
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/version.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/unaligned.h>
+#include <asm/pgtable.h>
+
+MODULE_VERSION(DRV_VERSION);
+
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
+#define inb nonexistent /* force using only 32bit access */
+#define inw nonexistent /* force using only 32bit access */
+#define inl(x) le32_to_cpu(readl(x))
+#define outb nonexistent /* force using only 32bit access */
+#define outw nonexistent /* force using only 32bit access */
+#define outl(value, address) writel(cpu_to_le32(value), address)
+
+#define VMA_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+
+enum pci_id_flags_bits {
+ /* Set PCI command register bits before calling probe */
+ PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
+ /* Read and map the single following PCI BAR */
+ PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 =
+ 2 << 4, PCI_ADDR3 = 3 << 4,
+ PCI_ADDR_64BITS = 0x100, PCI_NO_ACPI_WAKE =
+ 0x200, PCI_NO_MIN_LATENCY = 0x400,
+ PCI_UNUSED_IRQ = 0x800,
+};
+
+/* PCI I/O space extent */
+#define FEPCI_SIZE 0x20000
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
+
+struct pci_id_info {
+ const char *name;
+ struct match_info {
+ int pci, pci_mask, subsystem, subsystem_mask;
+ int revision, revision_mask; /* Only 8 bits. */
+ } id;
+ enum pci_id_flags_bits pci_flags;
+ int io_size; /* Needed for I/O region check or ioremap */
+ int drv_flags; /* Driver use, intended as capability flags */
+};
+
+static struct pci_id_info pci_id_tbl[] = {
+ {"Frame Engine for PCI (FEPCI)",
+ {0x1FC00300, 0x1FC00301, 0xffffffff},
+ PCI_IOTYPE, FEPCI_SIZE},
+ {0,},
+};
+
+static struct pci_device_id fepci_pci_tbl[] __devinitdata = {
+ {0x1FC0, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x1FC0, 0x0301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DESCRIPTION("Frame Engine for PCI (FEPCI)");
+MODULE_AUTHOR("Jouni Kujala");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, fepci_pci_tbl);
+
+/* Linux 2.4 appears to drop POINTOPOINT,BROADCAST and NOARP flags in SIOCSFLAGS
+ * This workaround allows load time per interface ptp mode configuration.
+ * Runtime ptp mode changes would either require changes to 2.4 or
+ * use of proprietary ioctls, which ifconfig knows nothing about anyway
+ */
+
+static unsigned interfaces = MAX_INTERFACES;
+#ifdef FEPCI_POINT_TO_POINT
+module_param_array(retina_ptp_interfaces, charp, &interfaces, S_IRUGO);
+module_param(retina_noarp_with_ptp, bool, S_IRUGO);
+MODULE_PARM_DESC(retina_noarp_with_ptp,
+ "0 to disable NOARP, "
+ "1 to enable NOARP on pointopoint interfaces");
+#endif
+
+struct fepci_ch_private {
+ unsigned int channel_number;
+ struct net_device *this_dev;
+
+ struct fepci_card_private *this_card_priv;
+
+ unsigned int reg_rxctrl;
+ unsigned int reg_txctrl;
+
+ struct fepci_desc *rx_desc; /* rx_ring start */
+ struct fepci_desc *tx_desc; /* tx_ring start */
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+
+ struct timer_list timer;
+ struct net_device_stats stats;
+
+ unsigned drv_flags;
+
+ unsigned int rx_buf_sz; /* MTU+slack */
+ unsigned int cur_tx; /* the next filled tx_descriptor */
+ /* in stream mode the desc which is being transmitted */
+ /* rx_descriptor where next packet transferred */
+ unsigned int cur_rx;
+ /* in stream mode the desc which is being received */
+
+/* stream mode: */
+ bool in_eth_mode;
+ bool in_stream_mode;
+ bool stream_on;
+ u32 *rx_buffer;
+ u32 *tx_buffer;
+ unsigned bufsize_order; /* 10=1kB,11=2kB,12=4kB...16=64kB */
+ u32 bufsize;
+ unsigned unit_sz_order; /* 8=256B...14=16kB */
+ u32 unit_sz;
+ unsigned units; /* 2,4,8,16,...,256 */
+ /* fake units (and pointers) are for faking larger unit sizes to
+ * the user than what is the maximum internal unit size in FEPCI */
+ unsigned fake_unit_sz_order;
+ u32 fake_unit_sz;
+ unsigned fake_units;
+ u32 *tx_unit[MAX_TX_UNITS];
+ u32 *rx_unit[MAX_RX_UNITS];
+ unsigned cur_tx_unit; /* last sent tx_unit */
+ /* rx_unit where to next packet is transferred */
+ unsigned cur_rx_unit;
+/* char device: */
+ unsigned minor; /* currently the same as card_nuber */
+/* debugging stuff for packet mode: */
+ /* rx-errors in descriptors */
+ unsigned int rx_desc_fifo_err;
+ unsigned int rx_desc_size_err;
+ unsigned int rx_desc_crc_err;
+ unsigned int rx_desc_octet_err;
+ unsigned rx_desc_line_err;
+ /* tx-errors in descriptors */
+ unsigned tx_desc_fifo_err;
+ /* rx-errors in interrupts */
+ unsigned rx_int_fifo_err;
+ unsigned rx_int_frame_dropped_err;
+ /* tx-errors in interrupts */
+ unsigned tx_int_fifo_err;
+ /* ints */
+ unsigned interrupts;
+ unsigned rx_interrupts;
+ unsigned tx_interrupts;
+ /* error combination tables */
+ /* fifo,size,crc,octet,line */
+ unsigned rx_desc_err_table[2][2][2][2][2];
+ unsigned int_err_table[2][2]; /* fifo,frame_dropped */
+ /* skbuff counters */
+ unsigned rx_skbuffs_in;
+ unsigned rx_skbuffs_out;
+ unsigned tx_skbuffs_in;
+ unsigned tx_skbuffs_out;
+/* debugging stuff for stream mode: */
+ /* rx-errors in descriptors */
+ unsigned rx_desc_fifo_err_stream;
+ unsigned rx_desc_size_err_stream;
+ unsigned rx_desc_crc_err_stream;
+ unsigned rx_desc_octet_err_stream;
+ unsigned rx_desc_line_err_stream;
+ /* tx-errors in descriptors */
+ unsigned tx_desc_fifo_err_stream;
+ /* rx-errors in interrupts */
+ unsigned rx_int_fifo_err_stream;
+ unsigned rx_int_frame_dropped_err_stream;
+ /* tx-errors in interrupts */
+ unsigned tx_int_fifo_err_stream;
+ /* ints */
+ unsigned interrupts_stream;
+ unsigned rx_interrupts_stream;
+ unsigned tx_interrupts_stream;
+ /* error combination tables */
+ /* fifo,size,crc,octet,line */
+ unsigned rx_desc_err_table_stream[2][2][2][2][2];
+ unsigned int_err_table_stream[2][2]; /* fifo,frame_dropped */
+/* other: */
+ /* tx interrupts since last timer interrupt */
+ unsigned tx_interrupts_since_last_timer;
+/* small packet counters: */
+ unsigned rx_packets_of_size_0;
+ unsigned rx_packets_of_size_1;
+ unsigned rx_packets_of_size_2;
+ unsigned rx_packets_of_size_3;
+ unsigned rx_packets_of_size_4_7;
+ unsigned rx_packets_of_size_8_15;
+ unsigned rx_packets_of_size_16_31;
+/* small packet counters for stream: */
+ unsigned rx_packets_of_size_0_stream;
+ unsigned rx_packets_of_size_1_stream;
+ unsigned rx_packets_of_size_2_stream;
+ unsigned rx_packets_of_size_3_stream;
+ unsigned rx_packets_of_size_4_7_stream;
+ unsigned rx_packets_of_size_8_15_stream;
+ unsigned rx_packets_of_size_16_31_stream;
+};
+
+struct fepci_card_private {
+ unsigned int card_number;
+ u8 *ioaddr;
+ /* Process ID of the current mailbox user
+ * (for whom it is reserved for) */
+ unsigned int ioctl_saved_pid;
+ struct pci_dev *pci_dev;
+ struct fepci_ch_private *ch_privates[CHANNELS];
+
+ wait_queue_head_t alarm_manager_wait_q;
+ struct timer_list mailbox_timer;
+
+ wait_queue_head_t stream_receive_q;
+ wait_queue_head_t stream_transmit_q;
+ wait_queue_head_t stream_both_q;
+
+ struct rw_semaphore semaphore;
+};
+
+/* Offsets to the FEPCI registers */
+enum fepci_offsets {
+ reg_custom = 0x40,
+
+ reg_first_int_mask = 0x80,
+ reg_first_int_status = 0xc0,
+
+ reg_first_rxctrl = 0x4000,
+ to_next_rxctrl = 0x80,
+
+ reg_first_txctrl = 0x6000,
+ to_next_txctrl = 0x80,
+
+ first_rx_desc = 0x10000,
+ to_next_ch_rx_desc = 0x200,
+
+ first_tx_desc = 0x18000,
+ to_next_ch_tx_desc = 0x200,
+};
+
+enum reg_custom_bits {
+ AM_interrupt_mask = 0x1,
+ AM_interrupt_status = 0x100,
+};
+
+enum reg_receive_control {
+ Rx_fifo_threshold = 0x7,
+ Receive_enable = 0x80000000,
+};
+
+enum reg_transmit_control {
+ Tx_fifo_threshold = 0x7,
+ Tx_desc_threshold = 0x700,
+ Transmit_enable = 0x80000000,
+};
+
+enum int_bits {
+ MaskFrameReceived = 0x01, MaskRxFifoError =
+ 0x02, MaskRxFrameDroppedError = 0x04,
+ MaskFrameTransmitted = 0x40, MaskTxFifoError = 0x80,
+ MaskAllInts = 0xc7,
+ IntrFrameReceived = 0x01, IntrRxFifoError =
+ 0x02, IntrRxFrameDroppedError = 0x04,
+ IntrFrameTransmitted = 0x40, IntrTxFifoError = 0x80,
+ IntrAllInts = 0xc7,
+};
+
+/* The FEPCI Rx and Tx buffer descriptors
+ * Elements are written as 32 bit for endian portability */
+
+struct fepci_desc {
+ u32 desc_a;
+ u32 desc_b;
+};
+
+enum desc_b_bits {
+ frame_length = 0xFFF,
+ fifo_error = 0x10000,
+ size_error = 0x20000,
+ crc_error = 0x40000,
+ octet_error = 0x80000,
+ line_error = 0x100000,
+ enable_transfer = 0x80000000,
+ transfer_not_done = 0x80000000,
+};
+
+/* global variables (common to whole driver, all the cards): */
+int major; /* char device major number */
+struct fepci_card_private card_privates[MAX_DEVICES];
+u32 stream_pointers;
+struct proc_dir_entry *proc_root_entry;
+
+void set_int_mask(int channel, u_char value, struct fepci_card_private *cp)
+{
+ void *address;
+ u32 shift, oldvalue;
+ DBG_PRINT("set_int_mask\n");
+ address = (cp->ioaddr) + reg_first_int_mask + (channel / 4L) * 4L;
+ shift = 8L * (channel % 4L);
+ oldvalue = inl((void *)address);
+ oldvalue &= ~(u32) (0xff << shift); /* clear bits */
+ oldvalue |= (value << shift); /* set bits */
+ outl(oldvalue, (void *)address);
+}
+
+u_char get_int_mask(int channel, void *ioaddr)
+{
+ void *address;
+ u32 shift, oldvalue;
+ DBG_PRINT("get_int_mask\n");
+ address = ioaddr + reg_first_int_mask + (channel / 4L) * 4L;
+ shift = 8L * (channel % 4L);
+ oldvalue = inl((void *)address);
+ oldvalue &= (0xff << shift); /* clear other bits */
+ return (oldvalue >> shift);
+}
+
+void clear_int(int channel, u_char value, void *ioaddr)
+{
+ void *address;
+ u32 shift, longvalue;
+ DBG_PRINT("clear_int\n");
+ address = ioaddr + reg_first_int_status + (channel / 4L) * 4L;
+ shift = 8L * (channel % 4L);
+ longvalue = value << shift;
+ outl(~longvalue, (void *)address);
+}
+
+u_char get_int_status(int channel, void *ioaddr)
+{
+ void *address;
+ u32 shift, oldvalue;
+ DBG_PRINT("get_int_status\n");
+ address = ioaddr + reg_first_int_status + (channel / 4L) * 4L;
+ shift = 8L * (channel % 4L);
+ oldvalue = inl((void *)address);
+ oldvalue &= (0xff << shift); /* clear other bits */
+ return (oldvalue >> shift);
+}
+
+void fillregisterswith_00(void *ioaddr)
+{
+ DBG_PRINT("fillregisterswith_00\n");
+ outl(0x0, (void *)(ioaddr + reg_first_rxctrl));
+ outl(0x0, (void *)(ioaddr + reg_first_txctrl));
+ outl(0x0, (void *)(ioaddr + reg_first_int_mask));
+ outl(0x0, (void *)(ioaddr + reg_first_int_status));
+ outl(0x0, (void *)(ioaddr + first_rx_desc));
+ outl(0x0, (void *)(ioaddr + first_tx_desc));
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int fepci_open(struct net_device *dev);
+static void fepci_timer(unsigned long data);
+static void fepci_tx_timeout(struct net_device *dev);
+static void fepci_init_ring(struct net_device *dev);
+static int fepci_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t fepci_interrupt(int irq, void *dev_instance);
+static int fepci_rx(struct net_device *dev);
+static int fepci_close(struct net_device *dev);
+static struct net_device_stats *fepci_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static void fepci_remove_one(struct pci_dev *pdev);
+
+/* proc filesystem functions introduced: */
+
+static int fepci_proc_init_driver(void);
+static void fepci_proc_cleanup_driver(void);
+static void fepci_proc_init_card(int card_number, void *card_data);
+static void fepci_proc_cleanup_card(int card_number);
+#ifdef DEBUG_PROC_FILES
+static void fepci_proc_init_channel(int card_number, int channel_number,
+ void *channel_data);
+static void fepci_proc_cleanup_channel(int card_number, int channel_number);
+#endif /* DEBUG_PROC_FILES */
+
+/* char device operations: */
+
+ssize_t fepci_char_read(struct file *filp, char *buf, size_t count,
+ loff_t *f_pos);
+int fepci_char_open(struct inode *inode, struct file *filp);
+int fepci_char_release(struct inode *inode, struct file *filp);
+int fepci_char_mmap(struct file *filp, struct vm_area_struct *vma);
+int fepci_char_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+struct file_operations fepci_char_fops = {
+ read:fepci_char_read,
+ ioctl:fepci_char_ioctl,
+ open:fepci_char_open,
+ release:fepci_char_release,
+ mmap:fepci_char_mmap,
+};
+
+int fepci_char_open(struct inode *inode, struct file *filp)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ DBG_PRINT("fepci_char_open\n");
+ if (unlikely(minor >= find_cnt || card_privates[minor].pci_dev == NULL))
+ return -ENXIO;
+ filp->f_op = &fepci_char_fops;
+ if (unlikely(!try_module_get(THIS_MODULE)))
+ return -EBUSY;
+ return 0;
+}
+
+int fepci_char_release(struct inode *inode, struct file *filp)
+{
+ DBG_PRINT("fepci_char_release\n");
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+void fepci_vma_open(struct vm_area_struct *vma)
+{
+ DBG_PRINT("fepci_vma_open\n");
+}
+
+void fepci_vma_close(struct vm_area_struct *vma)
+{
+ DBG_PRINT("fepci_vma_close\n");
+ module_put(THIS_MODULE);
+}
+
+static struct vm_operations_struct fepci_vm_ops = {
+ open:fepci_vma_open,
+ close:fepci_vma_close,
+};
+
+int fepci_char_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long offset = VMA_OFFSET(vma);
+ unsigned long size = vma->vm_end - vma->vm_start;
+
+ u32 virtual_address = 0;
+
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_ops = &fepci_vm_ops;
+ vma->vm_file = filp;
+
+ if (offset == STREAM_BUFFER_POINTER_AREA) {
+ virtual_address = stream_pointers;
+ if (virtual_address == 0) {
+ printk(KERN_WARNING "%s: mmap: internal error.\n",
+ fepci_name);
+ return -ENOMEM;
+ }
+ if (size > (1 << PAGE_SHIFT)) {
+ printk(KERN_WARNING
+ "%s: mmap: area size over range.\n", fepci_name);
+ return -EINVAL;
+ }
+ } else {
+ unsigned int page;
+
+ unsigned int card;
+ unsigned int channel;
+ unsigned int area; /* 0=rx, 1=tx */
+
+ card = (offset >> CARD_ADDRESS_SHIFT) & 0xf;
+ channel = (offset >> CHANNEL_ADDRESS_SHIFT) & 0xf;
+ area = (offset >> AREA_ADDRESS_SHIFT) & 0xf;
+ page = (offset & 0xffff); /* >> PAGE_SHIFT; */
+
+ if (area == 0) {
+ /* if there really is such card */
+ if (card < find_cnt && card_privates[card].pci_dev)
+ virtual_address =
+ (u32) card_privates[card].
+ ch_privates[channel]->rx_buffer;
+ else
+ goto INVALID;
+ } else if (area == 1) {
+ /* if there really is such card */
+ if (card < find_cnt && card_privates[card].pci_dev)
+ virtual_address =
+ (u32) card_privates[card].
+ ch_privates[channel]->tx_buffer;
+ else
+ goto INVALID;
+ } else {
+ INVALID:
+ DBG_PRINT("%s: mmap: invalid address 0x%x\n",
+ fepci_NAME, virtual_address);
+ return -EINVAL;
+ }
+ if (virtual_address == 0)
+ goto INVALID;
+ }
+
+ if (!try_module_get(THIS_MODULE))
+ return -EBUSY;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ {
+ unsigned pfn = PFN_DOWN(virt_to_phys((void *)virtual_address));
+ int error = io_remap_pfn_range(vma, vma->vm_start, pfn,
+ size, vma->vm_page_prot);
+ if (unlikely(error))
+ return error;
+ }
+ fepci_vma_open(vma);
+ return 0;
+}
+
+/* mmap operations end */
+
+/* char operations start */
+
+void fepci_copy_to_user(unsigned long to, void *from, unsigned long len,
+ int shrink)
+{
+ unsigned int i;
+ DBG_PRINT("fepci_copy_to_user\n");
+ if (shrink) {
+ for (i = 0; i < len; i += 2) {
+ put_user((((unsigned long *)from)[i / 2]) & 0xff,
+ (unsigned char *)(to + i));
+ put_user((((unsigned long *)from)[i / 2]) >> 8,
+ (unsigned char *)(to + i + 1));
+ }
+ } else {
+ for (i = 0; i < len; i += 4)
+ put_user(((unsigned long *)from)[i / 4],
+ (unsigned long *)(to + i));
+ }
+}
+
+void fepci_copy_from_user(void *to, unsigned long from, unsigned long len,
+ int enlarge)
+{
+ unsigned int i;
+ if (enlarge) {
+ for (i = 0; i < len; i += 2) {
+ unsigned char temp1;
+ unsigned char temp2;
+ get_user(temp1, (unsigned char *)(from + i));
+ get_user(temp2, (unsigned char *)(from + i + 1));
+ *((unsigned long *)(to + i * 2)) = temp1 + (temp2 << 8);
+ }
+ } else {
+ for (i = 0; i < len; i += 4)
+ get_user(((unsigned long *)to)[i / 4],
+ (unsigned long *)(from + i));
+ }
+}
+
+unsigned get_semafore(struct fepci_real_mailbox *mailbox)
+{
+ unsigned semafore = readb(&mailbox->Semafore_Mail_number);
+ DBG_PRINT("get_semafore = %x\n", semafore);
+ return semafore;
+}
+
+int set_semafore(struct fepci_real_mailbox *mailbox, unsigned semafore)
+{
+ u32 number = inl(&mailbox->Semafore_Mail_number);
+ DBG_PRINT("got number %u at %p.\n", number,
+ &mailbox->Semafore_Mail_number);
+ number = ((number & ~0xFF) | semafore) + (1 << 8);
+ DBG_PRINT
+ ("increases the mail number to %u at the same time at %p.\n",
+ number, &mailbox->Semafore_Mail_number);
+ outl(number, &mailbox->Semafore_Mail_number);
+ DBG_PRINT("set_semafore %p, %u returns 0.\n", mailbox, semafore);
+ return 0;
+}
+
+static void fepci_mailbox_timer(unsigned long data)
+{
+ int card_number = data;
+ unsigned int *saved_pid = &card_privates[card_number].ioctl_saved_pid;
+ void *ioaddr = card_privates[card_number].ioaddr;
+ struct fepci_real_mailbox *real_mailbox =
+ (struct fepci_real_mailbox *)(ioaddr + FEPCI_MAILBOX_OFFSETT);
+
+ set_semafore(real_mailbox, 0x0);
+ *saved_pid = 0;
+}
+
+int fepci_char_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ void *ioaddr;
+ struct fepci_real_mailbox *real_mailbox;
+ int retval = 0;
+ unsigned int *saved_pid;
+ unsigned int my_pid;
+
+ if (minor >= find_cnt || card_privates[minor].pci_dev == NULL) {
+ printk(KERN_WARNING
+ "%s: trying to access a card that does not exist.\n",
+ fepci_NAME);
+ /* if trying to access a card that does not exist */
+ return -ENXIO;
+ }
+
+ DBG_PRINT("fepci_char_ioctl minor %u.\n", minor);
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ if (!access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (!access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+
+ ioaddr = card_privates[minor].ioaddr;
+ real_mailbox =
+ (struct fepci_real_mailbox *)(ioaddr + FEPCI_MAILBOX_OFFSETT);
+ saved_pid = &card_privates[minor].ioctl_saved_pid;
+ my_pid = current->pid;
+
+ switch (cmd) {
+ case FEPCI_IOCTL_STREAM_TRANSMIT_POLL:
+ /* here: arg == channel number */
+ if (arg < 0 || arg >= CHANNELS
+ || !(card_privates[minor].ch_privates[arg]->stream_on))
+ return 0x2;
+ {
+ u32 pointer = *USER_TX_S_FAKE_POINTER(minor, arg,
+ stream_pointers);
+ wait_event_interruptible((card_privates[minor].
+ stream_transmit_q)
+ ,
+ (pointer !=
+ *USER_TX_S_FAKE_POINTER
+ (minor, arg,
+ stream_pointers)));
+ return 0x1;
+ }
+ return retval;
+ case FEPCI_IOCTL_STREAM_RECEIVE_POLL:
+ /* here: arg == channel number */
+ if (arg < 0 || arg >= CHANNELS
+ || !(card_privates[minor].ch_privates[arg]->stream_on))
+ return 0x2;
+ {
+ u32 pointer = *USER_RX_S_FAKE_POINTER(minor, arg,
+ stream_pointers);
+ wait_event_interruptible((card_privates[minor].
+ stream_receive_q)
+ ,
+ (pointer !=
+ *USER_RX_S_FAKE_POINTER
+ (minor, arg,
+ stream_pointers)));
+ retval = 0x1;
+ }
+ return retval;
+ case FEPCI_IOCTL_STREAM_BOTH_POLL:
+ /* here: arg == channel number */
+ if (arg < 0 || arg >= CHANNELS
+ || !(card_privates[minor].ch_privates[arg]->stream_on))
+ return 0x2;
+ {
+ u32 temp_tx_pointer =
+ *USER_TX_S_FAKE_POINTER(minor, arg,
+ stream_pointers);
+ u32 temp_rx_pointer =
+ *USER_RX_S_FAKE_POINTER(minor, arg,
+ stream_pointers);
+
+ wait_event_interruptible((card_privates[minor].
+ stream_both_q)
+ ,
+ (temp_tx_pointer !=
+ *USER_TX_S_FAKE_POINTER
+ (minor, arg, stream_pointers))
+ || (temp_rx_pointer !=
+ *USER_RX_S_FAKE_POINTER
+ (minor, arg,
+ stream_pointers)));
+ retval = 0x1;
+ }
+ return retval;
+ case FEPCI_IOCTL_R_SHARED_MEM:
+ DBG_PRINT(" %s: ioctl read shared mem commanded.\n",
+ fepci_NAME);
+ fepci_copy_to_user(arg, ioaddr + FEPCI_SHARED_MEM_OFFSETT,
+ _IOC_SIZE(cmd), 0);
+ break;
+ case FEPCI_IOCTL_W_SHARED_MEM:
+ DBG_PRINT(" %s: ioctl write shared mem commanded.\n",
+ fepci_NAME);
+ fepci_copy_from_user(ioaddr + FEPCI_SHARED_MEM_OFFSETT,
+ arg, _IOC_SIZE(cmd), 0);
+ break;
+ case FEPCI_IOCTL_G_IDENTIFICATION:
+ DBG_PRINT(" %s: IOCTL_G_IDENTIFICATION commanded.\n",
+ fepci_NAME);
+ fepci_copy_to_user(arg,
+ ioaddr + FEPCI_IDENTIFICATION_OFFSETT,
+ _IOC_SIZE(cmd), 1);
+ break;
+ case FEPCI_IOCTL_G_FEATURES:
+ DBG_PRINT(" %s: IOCTL_G_FEATURES commanded.\n", fepci_NAME);
+ fepci_copy_to_user(arg, ioaddr + FEPCI_FEATURES_OFFSETT,
+ _IOC_SIZE(cmd), 1);
+ break;
+ case FEPCI_IOCTL_G_SETTINGS:
+ DBG_PRINT(" %s: IOCTL_G_SETTINGS commanded.\n", fepci_NAME);
+ fepci_copy_to_user(arg, ioaddr + FEPCI_SETTINGS_OFFSETT,
+ _IOC_SIZE(cmd), 1);
+ break;
+ case FEPCI_IOCTL_G_STATUS:
+ DBG_PRINT(" %s: IOCTL_G_STATUS commanded.\n", fepci_NAME);
+ fepci_copy_to_user(arg, ioaddr + FEPCI_STATUS_OFFSETT,
+ _IOC_SIZE(cmd), 1);
+ break;
+ case FEPCI_IOCTL_B_POLL:
+ DBG_PRINT(" %s: IOCTL_B_POLL commanded.\n", fepci_NAME);
+ retval = get_semafore(real_mailbox);
+ if ((retval == 0x20 || retval == 0x21 || retval == 0x40)
+ && *saved_pid != my_pid)
+ retval = 0x7;
+ del_timer_sync(&card_privates[minor].mailbox_timer);
+ card_privates[minor].mailbox_timer.expires = jiffies + 20 * HZ;
+ card_privates[minor].mailbox_timer.data = minor;
+ card_privates[minor].mailbox_timer.function =
+ &fepci_mailbox_timer;
+ add_timer(&card_privates[minor].mailbox_timer);
+ break;
+ case FEPCI_IOCTL_B_GRAB:
+ DBG_PRINT("%s: IOCTL_B_GRAB commanded.\n", fepci_NAME);
+ if ((my_pid != *saved_pid) && (*saved_pid != 0)) {
+ retval = 0x2;
+ break;
+ }
+ DBG_PRINT("%s: IOCTL_B_GRAB getting semaphore.\n", fepci_NAME);
+ if (get_semafore(real_mailbox) == 0x0) {
+ DBG_PRINT("%s: IOCTL_B_GRAB setting semaphore.\n",
+ fepci_NAME);
+ set_semafore(real_mailbox, 0x40);
+ DBG_PRINT("%s: IOCTL_B_GRAB sleeping.\n", fepci_NAME);
+ msleep(1); /* delay at least 1 millisecond */
+ DBG_PRINT
+ ("%s: IOCTL_B_GRAB getting semaphore again.\n",
+ fepci_NAME);
+ switch (get_semafore(real_mailbox)) {
+ case 0x40:
+ retval = 0x0;
+ DBG_PRINT
+ ("%s: IOCTL_B_GRAB saving pid to %p.\n",
+ fepci_NAME, saved_pid);
+ *saved_pid = my_pid;
+ DBG_PRINT
+ ("%s: IOCTL_B_GRAB deleting timer at %p.\n",
+ fepci_NAME,
+ &card_privates[minor].mailbox_timer);
+ del_timer_sync(&card_privates[minor].
+ mailbox_timer);
+ card_privates[minor].mailbox_timer.
+ expires = jiffies + 20 * HZ;
+ card_privates[minor].mailbox_timer.data = minor;
+ card_privates[minor].mailbox_timer.
+ function = &fepci_mailbox_timer;
+ add_timer(&card_privates[minor].mailbox_timer);
+ break;
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ default:
+ retval = 0xff;
+ }
+ } else {
+ switch (get_semafore(real_mailbox)) {
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ default:
+ retval = 0xff;
+ }
+ }
+ break;
+ case FEPCI_IOCTL_B_RELEASE:
+ DBG_PRINT(" %s: IOCTL_B_RELEASE commanded.\n", fepci_NAME);
+ if (my_pid != *saved_pid) {
+ retval = 0x2;
+ break;
+ }
+ switch (get_semafore(real_mailbox)) {
+ case 0x40:
+ case 0x20:
+ retval = 0x0;
+ set_semafore(real_mailbox, 0x0);
+ *saved_pid = 0;
+ del_timer(&card_privates[minor].mailbox_timer);
+ break;
+ case 0x21:
+ retval = 0x04;
+ break;
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ default:
+ retval = 0xff;
+ }
+ break;
+ case FEPCI_IOCTL_B_S_CMAIL:
+ DBG_PRINT(" %s: IOCTL_B_S_CMAIL commanded.\n", fepci_NAME);
+ if (my_pid != *saved_pid) {
+ retval = 0x2;
+ break;
+ }
+ switch (get_semafore(real_mailbox)) {
+ case 0x40:
+ case 0x20:
+ case 0x21:
+ /* copy the mailbox */
+ fepci_copy_from_user(ioaddr +
+ FEPCI_MAILBOX_OFFSETT + 4,
+ arg + 2, _IOC_SIZE(cmd) - 2, 1);
+ /* semafore -> 10 */
+ set_semafore(real_mailbox, 0x10);
+ retval = 0x0;
+
+ del_timer_sync(&card_privates[minor].mailbox_timer);
+ card_privates[minor].mailbox_timer.expires =
+ jiffies + 20 * HZ;
+ card_privates[minor].mailbox_timer.data = minor;
+ card_privates[minor].mailbox_timer.function =
+ &fepci_mailbox_timer;
+ add_timer(&card_privates[minor].mailbox_timer);
+
+ break;
+
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ case 0x0:
+ retval = 0x3;
+ break;
+ default:
+ retval = 0xff;
+ }
+ break;
+ case FEPCI_IOCTL_B_S_QMAIL:
+ DBG_PRINT(" %s: IOCTL_B_S_QMAIL commanded.\n", fepci_NAME);
+ if (my_pid != *saved_pid) {
+ retval = 0x2;
+ break;
+ }
+ switch (get_semafore(real_mailbox)) {
+ case 0x40:
+ case 0x20:
+ case 0x21:
+ /* copy the mailbox; */
+ fepci_copy_from_user(ioaddr +
+ FEPCI_MAILBOX_OFFSETT + 4,
+ arg + 2, _IOC_SIZE(cmd) - 2, 1);
+ /* semafore -> 11 */
+ set_semafore(real_mailbox, 0x11);
+ retval = 0x0;
+
+ del_timer_sync(&card_privates[minor].mailbox_timer);
+ card_privates[minor].mailbox_timer.expires =
+ jiffies + 20 * HZ;
+ card_privates[minor].mailbox_timer.data = minor;
+ card_privates[minor].mailbox_timer.function =
+ &fepci_mailbox_timer;
+ add_timer(&card_privates[minor].mailbox_timer);
+
+ break;
+
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ case 0x0:
+ retval = 0x3;
+ break;
+ default:
+ retval = 0xff;
+ }
+ break;
+ case FEPCI_IOCTL_B_G_MAIL:
+ DBG_PRINT(" %s: IOCTL_B_G_MAIL commanded.\n", fepci_NAME);
+ if (my_pid != *saved_pid) {
+ retval = 0x2;
+ } else {
+ switch (get_semafore(real_mailbox)) {
+ case 0x10:
+ case 0x11:
+ case 0x80:
+ retval = 0x1;
+ break;
+ case 0x40:
+ case 0x20:
+ case 0x21:
+ retval = 0x0;
+ fepci_copy_to_user(arg,
+ ioaddr +
+ FEPCI_MAILBOX_OFFSETT,
+ _IOC_SIZE(cmd), 1);
+
+ del_timer_sync(&card_privates[minor].
+ mailbox_timer);
+ card_privates[minor].mailbox_timer.
+ expires = jiffies + 20 * HZ;
+ card_privates[minor].mailbox_timer.data = minor;
+ card_privates[minor].mailbox_timer.
+ function = &fepci_mailbox_timer;
+ add_timer(&card_privates[minor].mailbox_timer);
+
+ break;
+ case 0x0:
+ retval = 0x3;
+ break;
+ default:
+ retval = 0xff;
+ }
+ }
+ if (retval != 0) {
+ static unsigned char seven = 7;
+ /* copy four lowest bytes from the mailbox */
+ fepci_copy_to_user(arg,
+ ioaddr + FEPCI_MAILBOX_OFFSETT,
+ 4, 1);
+ /* lowest byte = 0x7 */
+ __put_user(arg, &seven);
+ }
+ break;
+ case FEPCI_IOCTL_ALARM_MANAGER:
+ DBG_PRINT(" %s: IOCTL_ALARM_MANAGER commanded.\n", fepci_NAME);
+ interruptible_sleep_on(&
+ (card_privates[minor].
+ alarm_manager_wait_q));
+ return retval;
+ default:
+ DBG_PRINT(" %s: Unknown ioctl command 0x%x.\n", fepci_NAME,
+ cmd);
+ return -ENOTTY;
+ }
+ return retval;
+}
+
+ssize_t fepci_char_read(struct file *filp, char *buf, size_t count,
+ loff_t *f_pos)
+{
+ DBG_PRINT("fepci_char_read\n");
+ if (count > 1)
+ count = 1;
+ if (copy_to_user(buf, "\n", count))
+ return -EFAULT;
+ return count;
+}
+
+static int fepci_register_char_device(void)
+{
+ int error =
+ register_chrdev(0 /* dynamic */ , fepci_name, &fepci_char_fops);
+ if (error < 0)
+ printk(KERN_WARNING
+ "%s: unable to register char device.\n", fepci_NAME);
+ else
+ DBG_PRINT("%s: registered char device, major:0x%x.\n",
+ fepci_NAME, error);
+ return error;
+}
+
+void fepci_unregister_char_device(void)
+{
+ unregister_chrdev(major, fepci_name);
+}
+
+/* char operations end */
+
+/* stream operations start */
+
+static irqreturn_t fepci_stream_interrupt(int irq, void *dev_instance);
+static int fepci_stream_close(struct net_device *dev);
+
+static int fepci_stream_open(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ unsigned tx_pages, rx_pages, tx_order, rx_order;
+ unsigned page_number;
+ unsigned int i;
+
+ down_write(&fp->this_card_priv->semaphore);
+ if (fp->in_eth_mode) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Interface is in Ethernet mode, "
+ "cannot open stream interface.\n", fepci_NAME);
+ BUSY:
+ return -EBUSY;
+ }
+ if (fp->in_stream_mode) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Interface is already in stream mode, "
+ "cannot open stream interface.\n", fepci_NAME);
+ goto BUSY;
+ }
+
+ if (fp->this_card_priv->pci_dev == NULL) {
+ up_write(&fp->this_card_priv->semaphore);
+ return -ENXIO;
+ }
+
+ fp->bufsize = 1 << fp->bufsize_order;
+
+ if (fp->fake_unit_sz_order < 5) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Unit size has to be at least 32 Bytes.\n",
+ fepci_NAME);
+ INVALID:
+ return (-EINVAL);
+ }
+
+ if (fp->fake_unit_sz_order >= fp->bufsize_order) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Bufsize has to be greater than unit size.\n",
+ fepci_NAME);
+ goto INVALID;
+ }
+
+ if (fp->fake_unit_sz_order >= MAX_UNIT_SZ_ORDER) {
+ fp->unit_sz_order = MAX_UNIT_SZ_ORDER;
+ } else {
+ fp->unit_sz_order = fp->fake_unit_sz_order;
+ }
+
+ fp->fake_unit_sz = 1 << fp->fake_unit_sz_order;
+ fp->unit_sz = 1 << fp->unit_sz_order;
+ fp->units = 1 << (fp->bufsize_order - fp->unit_sz_order);
+ fp->fake_units = 1 << (fp->bufsize_order - fp->fake_unit_sz_order);
+
+ /* reserve memory */
+ if (fp->bufsize_order < PAGE_SHIFT) {
+ tx_order = rx_order = 0;
+ tx_pages = rx_pages = 1;
+ } else {
+ tx_order = fp->bufsize_order - PAGE_SHIFT;
+ tx_pages = 1 << tx_order;
+ rx_order = tx_order + 1;
+ rx_pages = 1 << rx_order;
+ }
+ fp->in_stream_mode = 1;
+ fp->tx_buffer = (u32 *) __get_dma_pages(GFP_KERNEL, tx_order);
+ if (!fp->tx_buffer)
+ goto NO_MEMORY;
+ fp->rx_buffer = (u32 *) __get_dma_pages(GFP_KERNEL, rx_order);
+ if (!fp->rx_buffer) {
+ NO_MEMORY:
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: unable to allocate memory for buffers.\n",
+ fepci_NAME);
+ fepci_stream_close(dev);
+ return (-ENOMEM);
+ }
+
+ for (page_number = 0; page_number < rx_pages; page_number++)
+ /* make pages reserved to allow remappping pages
+ with io_remap_pfn_range */
+ SetPageReserved(virt_to_page
+ ((unsigned long)fp->rx_buffer +
+ (page_number << PAGE_SHIFT)));
+ for (page_number = 0; page_number < tx_pages; page_number++)
+ /* make pages reserved to allow remappping pages
+ with io_remap_pfn_range */
+ SetPageReserved(virt_to_page
+ ((unsigned long)fp->tx_buffer +
+ (page_number << PAGE_SHIFT)));
+
+ for (i = 0; i < (fp->bufsize) / 4; i++)
+ fp->tx_buffer[i] = 0xffffffff;
+
+ /* + fp->channel_number; */
+ *USER_RX_S_POINTER(fp->this_card_priv->card_number, fp->channel_number,
+ stream_pointers) = 0;
+ /* + fp->channel_number; */
+ *USER_TX_S_POINTER(fp->this_card_priv->card_number, fp->channel_number,
+ stream_pointers) = 0;
+ /* + fp->channel_number; */
+ *USER_RX_S_FAKE_POINTER(fp->this_card_priv->card_number,
+ fp->channel_number, stream_pointers) = 0;
+ /* + fp->channel_number; */
+ *USER_TX_S_FAKE_POINTER(fp->this_card_priv->card_number,
+ fp->channel_number, stream_pointers) = 0;
+
+ DBG_PRINT("%s: Bufsize is 0x%x.\n", fepci_NAME, fp->bufsize);
+ DBG_PRINT("%s: Unit_size is 0x%x.\n", fepci_NAME, fp->unit_sz);
+ DBG_PRINT("%s: Number of units is 0x%x.\n", fepci_NAME, fp->units);
+
+ DBG_PRINT("%s: Fake_unit_size is 0x%x.\n", fepci_NAME,
+ fp->fake_unit_sz);
+ DBG_PRINT("%s: Number of fake units is 0x%x.\n", fepci_NAME,
+ fp->fake_units);
+
+ /* init ring buffers */
+ for (i = 0; i < MAX_RX_UNITS; i++)
+ fp->rx_unit[i] =
+ (u32 *) ((u32) (fp->rx_buffer) + (fp->unit_sz * i));
+ for (i = 0; i < MAX_TX_UNITS; i++)
+ fp->tx_unit[i] =
+ (u32 *) ((u32) (fp->tx_buffer) + (fp->unit_sz * i));
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ outl(0, &fp->rx_desc[i].desc_a);
+ outl(0, &fp->rx_desc[i].desc_b);
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ outl(0, &fp->tx_desc[i].desc_a);
+ outl(0, &fp->tx_desc[i].desc_b);
+ }
+
+ up_write(&fp->this_card_priv->semaphore);
+ return 0;
+}
+
+static int fepci_stream_start(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ unsigned i;
+ down_write(&fp->this_card_priv->semaphore);
+
+ if (fp->in_stream_mode == 0) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Interface is not in stream mode, "
+ "streaming cannot be started.\n", fepci_NAME);
+ return (-EBUSY);
+ }
+ if (fp->stream_on) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: Streaming is already on, "
+ "streaming cannot be started.\n", fepci_NAME);
+ return (-EBUSY);
+ }
+
+ {
+ /* reserve irq */
+ int error = request_irq(dev->irq, &fepci_stream_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (error) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: unable to allocate IRQ %d, error 0x%x\n",
+ fepci_NAME, dev->irq, error);
+ return -ENOMEM;
+ }
+ }
+
+ fp->stream_on = 1;
+
+ /* sending &receiving on, start from the beginning of the buffer */
+ fp->cur_tx_unit = 0;
+ fp->cur_rx_unit = 0;
+ fp->cur_tx = 0;
+ fp->cur_rx = 0;
+
+ /* all the descriptors ready to go: */
+ for (i = 0; i < min(RX_RING_SIZE, TX_RING_SIZE); i++) {
+ u32 bus_address = pci_map_single(fp->this_card_priv->pci_dev,
+ fp->
+ rx_unit[(fp->cur_rx_unit +
+ i) % fp->units],
+ fp->unit_sz,
+ PCI_DMA_FROMDEVICE);
+ outl(bus_address,
+ &fp->
+ rx_desc[(fp->cur_rx + i) & (RX_RING_SIZE - 1)].desc_a);
+ if (unlikely(pci_dma_mapping_error(bus_address)))
+ printk(KERN_WARNING
+ "%s: failed to map DMA buffer.\n", fepci_NAME);
+ else {
+ if (!
+ (inl
+ (&fp->
+ rx_desc[(fp->cur_rx + i) & (RX_RING_SIZE -
+ 1)].
+ desc_b) & enable_transfer))
+ outl(enable_transfer,
+ &fp->rx_desc[(fp->cur_rx + i) %
+ RX_RING_SIZE].desc_b);
+ }
+ bus_address =
+ pci_map_single(fp->this_card_priv->pci_dev,
+ fp->tx_unit[(fp->cur_tx_unit + i) %
+ fp->units], fp->unit_sz,
+ PCI_DMA_TODEVICE);
+ outl(bus_address,
+ &fp->
+ tx_desc[(fp->cur_tx + i) & (TX_RING_SIZE - 1)].desc_a);
+ if (unlikely(pci_dma_mapping_error(bus_address)))
+ printk(KERN_WARNING
+ "%s: failed to map DMA buffer.\n", fepci_NAME);
+ else {
+ if (!
+ (inl
+ (&fp->
+ tx_desc[(fp->cur_tx + i) & (TX_RING_SIZE -
+ 1)].
+ desc_b) & enable_transfer))
+ outl(enable_transfer |
+ (fp->unit_sz & frame_length),
+ &fp->
+ tx_desc[(fp->cur_tx +
+ i) & (TX_RING_SIZE - 1)].desc_b);
+ }
+ }
+
+ /* irq on */
+ set_int_mask(fp->channel_number,
+ MaskFrameReceived | MaskFrameTransmitted |
+ MaskRxFifoError | MaskRxFrameDroppedError |
+ MaskTxFifoError, fp->this_card_priv);
+ {
+ void *ioaddr = (void *)dev->base_addr;
+ /* Start Rx and Tx channels */
+ outl(Receive_enable |
+ (Rx_fifo_threshold & RX_FIFO_THRESHOLD_STREAM_MODE),
+ (void *)(ioaddr + fp->reg_rxctrl));
+ outl((Transmit_enable |
+ (Tx_desc_threshold &
+ (TX_DESC_THRESHOLD_STREAM_MODE << 8)) |
+ (Tx_fifo_threshold & TX_FIFO_THRESHOLD_STREAM_MODE)),
+ (void *)(ioaddr + fp->reg_txctrl));
+ }
+ up_write(&fp->this_card_priv->semaphore);
+
+ return 0;
+}
+
+static int fepci_stream_stop(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ void *ioaddr = (void *)dev->base_addr;
+ down_write(&fp->this_card_priv->semaphore);
+ if (fp->in_stream_mode == 0) {
+ up_write(&fp->this_card_priv->semaphore);
+ return (1);
+ }
+ fp->stream_on = 0;
+ /* Stop Rx and Tx channels. */
+ outl(0x0, (void *)(ioaddr + fp->reg_rxctrl));
+ outl(0x0, (void *)(ioaddr + fp->reg_txctrl));
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ set_int_mask(fp->channel_number, 0x0, fp->this_card_priv);
+
+ /* unregister irq */
+ free_irq(dev->irq, dev);
+
+ {
+ unsigned i = min(RX_RING_SIZE, TX_RING_SIZE) - 1;
+ do {
+ u32 bus_address;
+ if (likely
+ (!pci_dma_mapping_error
+ (bus_address = inl(&fp->rx_desc[i].desc_a))))
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev, bus_address,
+ fp->unit_sz,
+ PCI_DMA_FROMDEVICE);
+ if (likely
+ (!pci_dma_mapping_error
+ (bus_address = inl(&fp->tx_desc[i].desc_a))))
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev, bus_address,
+ fp->unit_sz, PCI_DMA_TODEVICE);
+ }
+ while (i--);
+ }
+
+ up_write(&fp->this_card_priv->semaphore);
+ return 0;
+}
+
+static int fepci_stream_close(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ unsigned rx_pages, tx_pages, rx_order, tx_order;
+
+ if (fepci_stream_stop(dev))
+ return -ENODEV;
+ down_write(&fp->this_card_priv->semaphore);
+ if (!(fp->in_stream_mode)) {
+ up_write(&fp->this_card_priv->semaphore);
+ return -ENODEV;
+ }
+ /* release memory */
+ if (fp->bufsize_order < PAGE_SHIFT) {
+ tx_order = rx_order = 0;
+ tx_pages = rx_pages = 1;
+ } else {
+ rx_order = (int)((fp->bufsize_order) - PAGE_SHIFT + 1);
+ rx_pages = 1 << rx_order;
+ tx_order = (int)((fp->bufsize_order) - PAGE_SHIFT);
+ tx_pages = 1 << tx_order;
+ }
+ if (fp->rx_buffer) {
+ unsigned page_number;
+ for (page_number = 0; page_number < rx_pages; page_number++)
+ /* turn pages back to non-reserved */
+ ClearPageReserved(virt_to_page
+ ((unsigned long)fp->rx_buffer +
+ (page_number << PAGE_SHIFT)));
+ free_pages((u32) fp->rx_buffer, rx_order);
+ fp->rx_buffer = NULL;
+ }
+ if (fp->tx_buffer) {
+ unsigned page_number;
+ for (page_number = 0; page_number < tx_pages; page_number++)
+ /* turn pages back to non-reserved */
+ ClearPageReserved(virt_to_page
+ ((unsigned long)fp->tx_buffer +
+ (page_number << PAGE_SHIFT)));
+ free_pages((u32) fp->tx_buffer, tx_order);
+ fp->tx_buffer = NULL;
+ }
+
+ fp->in_stream_mode = 0;
+ up_write(&fp->this_card_priv->semaphore);
+ return 0;
+}
+
+static irqreturn_t fepci_stream_interrupt(int irq, void *dev_instance)
+{
+ struct net_device *dev = dev_instance;
+ struct fepci_ch_private *fp = dev->priv;
+ void *ioaddr = (void *)dev->base_addr;
+ u32 intr_status = get_int_status(fp->channel_number, ioaddr);
+ bool fifo, dropped;
+ unsigned int temp_rx;
+ unsigned int temp_rx_unit;
+ unsigned int temp_tx;
+ unsigned int temp_tx_unit;
+
+ clear_int(fp->channel_number, intr_status, ioaddr);
+
+ /* debugging */
+ fp->interrupts_stream++;
+ fifo = (intr_status & IntrRxFifoError) != 0;
+ dropped = (intr_status & IntrRxFrameDroppedError) != 0;
+ fp->int_err_table_stream[fifo][dropped]++;
+ if (intr_status & IntrFrameReceived)
+ fp->rx_interrupts_stream++;
+ if (intr_status & IntrFrameTransmitted)
+ fp->tx_interrupts_stream++;
+ if (fifo)
+ fp->rx_int_fifo_err_stream++;
+ if (dropped)
+ fp->rx_int_frame_dropped_err_stream++;
+ if (intr_status & IntrTxFifoError)
+ fp->tx_int_fifo_err_stream++;
+ /* first update cur_rx, and do stuff if it has moved
+ (+ packets have been received) */
+ {
+ temp_rx = fp->cur_rx;
+ /* has been received */
+ while ((inl(&fp->rx_desc[fp->cur_rx].desc_b) &
+ transfer_not_done) == 0
+ /* stop if made one round */
+ && temp_rx != ((fp->cur_rx + 1) & (RX_RING_SIZE - 1))) {
+ u32 bus_address;
+ if (likely(!pci_dma_mapping_error(bus_address =
+ inl(&fp->
+ rx_desc[fp->
+ cur_rx].
+ desc_a))))
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev, bus_address,
+ fp->unit_sz,
+ PCI_DMA_FROMDEVICE);
+ fp->cur_rx = (fp->cur_rx + 1) & (RX_RING_SIZE - 1);
+ fp->cur_rx_unit = (fp->cur_rx_unit + 1);
+ fp->cur_rx_unit *= fp->cur_rx_unit < fp->units;
+
+ *USER_RX_S_POINTER(fp->this_card_priv->
+ card_number,
+ fp->channel_number,
+ stream_pointers) = fp->cur_rx_unit;
+ *USER_RX_S_FAKE_POINTER(fp->this_card_priv->
+ card_number,
+ fp->channel_number,
+ stream_pointers) =
+ fp->cur_rx_unit * fp->unit_sz / fp->fake_unit_sz;
+ wake_up_interruptible(&
+ (fp->this_card_priv->
+ stream_receive_q));
+ wake_up_interruptible(&
+ (fp->this_card_priv->
+ stream_both_q));
+ }
+ }
+ /* from the first uninitialized descriptor to cur_rx */
+ temp_rx = (fp->cur_rx + 1) & (RX_RING_SIZE - 1);
+ temp_rx_unit = (fp->cur_rx_unit + 1);
+ temp_rx_unit *= temp_rx_unit < fp->units;
+
+ while (temp_rx != fp->cur_rx) {
+ u32 desc_b = inl(&fp->rx_desc[temp_rx].desc_b);
+ if ((desc_b & transfer_not_done) == 0) {
+ bool fifo = (desc_b & fifo_error) != 0;
+ bool size = (desc_b & size_error) != 0;
+ bool crc = (desc_b & crc_error) != 0;
+ bool octet = (desc_b & octet_error) != 0;
+ bool line = (desc_b & line_error) != 0;
+ u32 length = desc_b & frame_length;
+ u32 bus_address;
+ /* update debug counters */
+ fp->rx_desc_err_table_stream[fifo]
+ [size]
+ [crc]
+ [octet]
+ [line]++;
+ if (length == 0) {
+ fp->rx_packets_of_size_0_stream++;
+ } else if (length == 1) {
+ fp->rx_packets_of_size_1_stream++;
+ } else if (length == 2) {
+ fp->rx_packets_of_size_2_stream++;
+ } else if (length == 3) {
+ fp->rx_packets_of_size_3_stream++;
+ } else if (length < 8) {
+ fp->rx_packets_of_size_4_7_stream++;
+ } else if (length < 16) {
+ fp->rx_packets_of_size_8_15_stream++;
+ } else if (length < 32) {
+ fp->rx_packets_of_size_16_31_stream++;
+ }
+ if (fifo) {
+ fp->rx_desc_fifo_err_stream++;
+ } else if (size) {
+ fp->rx_desc_size_err_stream++;
+ } else if (crc) {
+ fp->rx_desc_crc_err_stream++;
+ } else if (octet) {
+ fp->rx_desc_octet_err_stream++;
+ } else if (line) {
+ fp->rx_desc_line_err_stream++;
+ }
+ /* initialize the descriptor for transfer */
+ bus_address =
+ pci_map_single(fp->this_card_priv->pci_dev,
+ fp->rx_unit[temp_rx_unit],
+ fp->unit_sz, PCI_DMA_FROMDEVICE);
+ outl(bus_address, &fp->rx_desc[temp_rx].desc_a);
+ if (likely(!pci_dma_mapping_error(bus_address)))
+ outl(enable_transfer,
+ &fp->rx_desc[temp_rx].desc_b);
+ else
+ printk(KERN_WARNING
+ "%s: failed to map DMA for reception.\n",
+ fepci_NAME);
+ }
+ temp_rx = (temp_rx + 1) & (RX_RING_SIZE - 1);
+ temp_rx_unit = (temp_rx_unit + 1);
+ temp_rx_unit *= temp_rx_unit < fp->units;
+ }
+
+ /* first update cur_tx, and do stuff if it has moved
+ (+ packets have been transmitted) */
+ {
+ temp_tx = fp->cur_tx;
+ /* has been transmitted */
+ while ((inl(&fp->tx_desc[fp->cur_tx].desc_b) &
+ transfer_not_done) == 0
+ /* stop if made one round */
+ && temp_tx != ((fp->cur_tx + 1) & (TX_RING_SIZE - 1))) {
+ u32 bus_address;
+ if (likely(!pci_dma_mapping_error(bus_address =
+ inl(&fp->
+ tx_desc[fp->
+ cur_tx].
+ desc_a))))
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev, bus_address,
+ fp->unit_sz, PCI_DMA_TODEVICE);
+ fp->cur_tx = (fp->cur_tx + 1) & (TX_RING_SIZE - 1);
+ fp->cur_tx_unit = (fp->cur_tx_unit + 1);
+ fp->cur_tx_unit *= fp->cur_tx_unit < fp->units;
+
+ *USER_TX_S_POINTER(fp->this_card_priv->
+ card_number,
+ fp->channel_number,
+ stream_pointers) = fp->cur_tx_unit;
+ *USER_TX_S_FAKE_POINTER(fp->this_card_priv->
+ card_number,
+ fp->channel_number,
+ stream_pointers) =
+ fp->cur_tx_unit * fp->unit_sz / fp->fake_unit_sz;
+ wake_up_interruptible(&
+ (fp->this_card_priv->
+ stream_transmit_q));
+ wake_up_interruptible(&
+ (fp->this_card_priv->
+ stream_both_q));
+ }
+ }
+ /* from the first uninitialized descriptor to cur_tx */
+ temp_tx = (fp->cur_tx + 1) & (TX_RING_SIZE - 1);
+ temp_tx_unit = (fp->cur_tx_unit + 1);
+ temp_tx_unit *= temp_tx_unit < fp->units;
+
+ while (temp_tx != fp->cur_tx) {
+ u32 desc_b = inl(&fp->tx_desc[temp_tx].desc_b);
+ if ((desc_b & transfer_not_done) == 0) {
+ u32 bus_address;
+ /* update debug counters */
+ if (desc_b & fifo_error)
+ fp->tx_desc_fifo_err_stream++;
+ /* initialize the desctiptor for transfer */
+ bus_address =
+ pci_map_single(fp->this_card_priv->pci_dev,
+ fp->tx_unit[temp_tx_unit],
+ fp->unit_sz, PCI_DMA_TODEVICE);
+ outl(bus_address, &fp->tx_desc[temp_tx].desc_a);
+ if (likely(!pci_dma_mapping_error(bus_address)))
+ outl(enable_transfer |
+ (fp->unit_sz & frame_length),
+ &fp->tx_desc[temp_tx].desc_b);
+ else
+ printk(KERN_WARNING
+ "%s: failed to map tranmission DMA.\n",
+ fepci_NAME);
+ }
+ temp_tx = (temp_tx + 1) & (TX_RING_SIZE - 1);
+ temp_tx_unit = (temp_tx_unit + 1);
+ temp_tx_unit *= temp_tx_unit < fp->units;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* stream operations end */
+
+int fepci_rebuild_header(struct sk_buff *skb)
+{
+ DBG_PRINT("fepci_rebuild_header\n");
+ return 0;
+}
+
+static inline u16 get_common_reg_word(void *ioaddr, unsigned long offsett)
+{
+ u16 word;
+ DBG_PRINT("get_common_reg_word ioaddr %p, offsett %lu\n", ioaddr,
+ offsett);
+ __clear_bit(0, &offsett);
+ DBG_PRINT("get_common_reg_word %p\n",
+ ioaddr + FEPCI_IDENTIFICATION_OFFSETT + (offsett << 1));
+ word = le16_to_cpu(readw
+ (ioaddr + FEPCI_IDENTIFICATION_OFFSETT +
+ (offsett << 1)));
+ DBG_PRINT("get_common_reg_word %p: %hu\n",
+ ioaddr + FEPCI_IDENTIFICATION_OFFSETT + (offsett << 1), word);
+ return word;
+}
+
+static irqreturn_t alarm_manager_interrupt(int irq, void *pointer)
+{
+ struct fepci_card_private *card_private = pointer;
+ void *ioaddr = card_private->ioaddr;
+ /* check int status */
+ if (inl((void *)(ioaddr + reg_custom)) & AM_interrupt_status) {
+ /* clear int (zero everything, but the mask bit) */
+ outl(inl((void *)(ioaddr + reg_custom)) &
+ AM_interrupt_mask, (void *)(ioaddr + reg_custom));
+ /* wake queue */
+ wake_up(&(card_private->alarm_manager_wait_q));
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef FEPCI_POINT_TO_POINT
+static int is_ptp_interface(struct net_device *dev)
+{
+ char **p_ptp_if_name = retina_ptp_interfaces;
+ unsigned int i = interfaces;
+ while (i > 0 && *p_ptp_if_name != NULL) {
+ if (!strncmp(dev->name, *p_ptp_if_name, sizeof(dev->name))) {
+ return 1;
+ } else {
+ }
+ p_ptp_if_name++;
+ i--;
+ }
+ return 0;
+}
+#endif /* FEPCI_POINT_TO_POINT */
+
+static int __devinit fepci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev = NULL;
+ struct fepci_ch_private *fp = NULL;
+ int chip_idx = ent->driver_data;
+ int drv_flags = pci_id_tbl[chip_idx].drv_flags;
+ int i = pci_enable_device(pdev);
+ u32 j;
+ resource_size_t real_ioaddr;
+ void *ioaddr;
+ unsigned position;
+
+ if (i) {
+ printk(KERN_WARNING "%s: pci_enable_device returned %x.\n",
+ fepci_NAME, i);
+ return i;
+ }
+
+ pci_set_master(pdev);
+
+ i = pci_request_regions(pdev, (char *)fepci_name);
+ if (i) {
+ printk(KERN_WARNING
+ "%s: pci_request_regions returned %x.\n", fepci_NAME, i);
+ pci_disable_device(pdev);
+ return i;
+ }
+
+ /* make sure above region is MMIO */
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ printk(KERN_WARNING "%s: region not MMIO region\n", fepci_NAME);
+ goto err_1;
+ }
+
+ j = pci_resource_len(pdev, 0);
+ if (j < FEPCI_SIZE) {
+ printk(KERN_WARNING
+ "%s: resource length %u less than required %u.\n",
+ fepci_NAME, j, FEPCI_SIZE);
+ goto err_1;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "%s: no suitable DMA available.\n",
+ fepci_NAME);
+ goto err_1;
+ }
+
+ real_ioaddr = pci_resource_start(pdev, 0);
+ DBG_PRINT("pci_resource_start %lu.\n", real_ioaddr);
+ ioaddr = ioremap_nocache(real_ioaddr, FEPCI_SIZE);
+ DBG_PRINT("ioremap_nocache = %p.\n", ioaddr);
+ if (!ioaddr) {
+ printk(KERN_WARNING "%s: remapping failed.\n", fepci_NAME);
+ goto err_1_5;
+ }
+ position = 0;
+ for (; position < MAX_DEVICES; position++) {
+ down_write(&card_privates[position].semaphore);
+ if (card_privates[position].pci_dev == NULL) {
+ card_privates[position].pci_dev = pdev;
+ if (position == find_cnt)
+ find_cnt++;
+ goto FOUND;
+ }
+ up_write(&card_privates[position].semaphore);
+ }
+ printk(KERN_WARNING
+ "%s: no space to inialize device #%u.\n",
+ fepci_NAME, MAX_DEVICES + 1);
+ goto err_2;
+ FOUND:
+ card_privates[position].card_number = position;
+ card_privates[position].ioaddr = ioaddr;
+ card_privates[position].pci_dev = pdev;
+ DBG_PRINT("fillregisterswith_00 %p.\n", ioaddr);
+ fillregisterswith_00(ioaddr);
+
+ fepci_proc_init_card(position, (void *)&(card_privates[position]));
+
+ init_waitqueue_head(&(card_privates[position].alarm_manager_wait_q));
+ init_waitqueue_head(&(card_privates[position].stream_transmit_q));
+ init_waitqueue_head(&(card_privates[position].stream_receive_q));
+ init_waitqueue_head(&(card_privates[position].stream_both_q));
+
+ init_timer(&card_privates[position].mailbox_timer);
+
+ DBG_PRINT("request_irq %d, %s.\n", pdev->irq, fepci_alarm_manager_name);
+ i = request_irq(pdev->irq, &alarm_manager_interrupt,
+ IRQF_SHARED,
+ fepci_alarm_manager_name, &card_privates[position]);
+ if (i) {
+ up_write(&card_privates[position].semaphore);
+ printk(KERN_WARNING
+ "%s: unable to allocate IRQ %d alarm manager: 0x%x\n",
+ fepci_NAME, pdev->irq, i);
+ goto err_2;
+ }
+ DBG_PRINT("alarm manager int on %p.\n", (void *)(ioaddr + reg_custom));
+ outl(AM_interrupt_mask, (void *)(ioaddr + reg_custom));
+ /* alarm manager int on */
+
+ for (j = 0; j < CHANNELS; j++) {
+ DBG_PRINT("alloc_etherdev %u.\n", j);
+ dev = alloc_etherdev(sizeof(struct fepci_ch_private));
+ if (!dev) {
+ printk(KERN_WARNING
+ "%s: cannot allocate ethernet device\n",
+ fepci_NAME);
+ continue;
+ }
+
+ fp = dev->priv;
+ fp->minor = position; /* * CHANNELS + j; */
+ /* name := xxx01..xxxnn */
+ memcpy(dev->name, fepci_netdev_name, 6);
+ /* dev->name[3]= j+0x30; channel number -> ascii */
+ /* minor number -> ascii */
+ dev->name[4] = ((fp->minor * CHANNELS + j) % 10) + 0x30;
+ /* minor number -> ascii */
+ dev->name[3] = ((fp->minor * CHANNELS + j) / 10) + 0x30;
+
+ SET_MODULE_OWNER(dev);
+ DBG_PRINT("clear_int %u, %x, %p.\n", j, IntrAllInts, ioaddr);
+ clear_int(j, IntrAllInts, ioaddr);
+ DBG_PRINT("ether_setup %p.\n", dev);
+ ether_setup(dev);
+
+ /* HW_ADDR: 00:rnd:rnd:rnd:rnd:05 */
+ dev->dev_addr[0] = 0;
+ get_random_bytes(&(dev->dev_addr[1]), 4);
+ dev->dev_addr[5] = 5;
+ /* HW_ADDR is got using the mailbox: */
+ {
+ struct fepci_real_mailbox *real_mailbox =
+ (struct fepci_real_mailbox *)
+ (ioaddr + FEPCI_MAILBOX_OFFSETT);
+ unsigned long waituntil;
+
+ set_semafore(real_mailbox, 0x40);
+ outl(0x1 /*size */ +
+ (0x8 << 8) /* get mac command */ ,
+ &real_mailbox->Size_Command);
+ set_semafore(real_mailbox, 0x11);
+
+ waituntil = jiffies + HZ;
+ while (time_before(jiffies, waituntil) &&
+ get_semafore(real_mailbox) != 0x20) {
+ DBG_PRINT("jiffies %lu < waituntil %lu.\n",
+ jiffies, waituntil);
+ msleep(0);
+ }
+
+ /* 14.5.2004 JT: Made this safer. */
+ if (get_semafore(real_mailbox) == 0x20) {
+ dev->dev_addr[5] =
+ readb(&real_mailbox->Data[0 + 3 * j]);
+ dev->dev_addr[4] =
+ readb(((u8 *) & real_mailbox->
+ Data[0 + 3 * j]) + 1);
+ dev->dev_addr[3] =
+ readb(&real_mailbox->Data[1 + 3 * j]);
+ dev->dev_addr[2] =
+ readb(((u8 *) & real_mailbox->
+ Data[1 + 3 * j]) + 1);
+ dev->dev_addr[1] =
+ readb(&real_mailbox->Data[2 + 3 * j]);
+ dev->dev_addr[0] =
+ readb(((u8 *) & real_mailbox->
+ Data[2 + 3 * j]) + 1);
+ }
+
+ set_semafore(real_mailbox, 0x0);
+ }
+ dev->addr_len = 6;
+
+ dev->base_addr = (unsigned long)ioaddr;
+ dev->irq = pdev->irq;
+ DBG_PRINT("alarm pci_set_drvdata %p, %p.\n", pdev, dev);
+ if (j == 0)
+ pci_set_drvdata(pdev, dev);
+
+ fp->drv_flags = drv_flags;
+
+ fp->rx_desc =
+ (struct fepci_desc *)(dev->base_addr + first_rx_desc +
+ j * to_next_ch_rx_desc);
+ fp->tx_desc =
+ (struct fepci_desc *)(dev->base_addr + first_tx_desc +
+ j * to_next_ch_tx_desc);
+
+ fp->channel_number = j; /*channel in this device */
+ fp->this_dev = dev;
+
+ fp->this_card_priv = &card_privates[position];
+ fp->this_card_priv->ch_privates[j] = fp;
+
+ fp->cur_tx = 0;
+
+ fp->in_stream_mode = 0;
+ fp->in_eth_mode = 0;
+
+ fp->reg_rxctrl = reg_first_rxctrl + j * to_next_rxctrl;
+ fp->reg_txctrl = reg_first_txctrl + j * to_next_txctrl;
+
+ /* The FEPCI specific entries in the device structure */
+ dev->open = &fepci_open;
+ dev->hard_start_xmit = &fepci_start_xmit;
+ dev->stop = &fepci_close;
+ dev->get_stats = &fepci_get_stats;
+ dev->set_multicast_list = &set_rx_mode;
+ dev->do_ioctl = &netdev_ioctl;
+ dev->tx_timeout = fepci_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+#ifdef FEPCI_POINT_TO_POINT
+ if (is_ptp_interface(dev)) {
+ dev->flags |= (IFF_POINTOPOINT);
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+ if (retina_noarp_with_ptp) {
+ dev->rebuild_header = fepci_rebuild_header;
+ dev->flags |= (IFF_NOARP);
+ }
+ }
+#endif
+ DBG_PRINT("register_netdev %p.\n", dev);
+ i = register_netdev(dev);
+ if (i) {
+ printk(KERN_WARNING
+ "%s: register_netdev failed 0x%x.\n",
+ fepci_NAME, i);
+ continue;
+ }
+
+ printk("%s: %s type %x at %p, ",
+ dev->name, pci_id_tbl[chip_idx].name,
+ 0x0 /* inl(ioaddr + ChipRev) */ , ioaddr);
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
+#ifdef DEBUG_PROC_FILES
+ fepci_proc_init_channel(position, j, fp);
+#endif /* DEBUG_PROC_FILES */
+ }
+ up_write(&card_privates[position].semaphore);
+ DBG_PRINT("fepci_init_one %u.\n", position);
+ return 0;
+
+ err_2:
+ iounmap(ioaddr);
+ err_1_5:
+ pci_set_drvdata(pdev, NULL);
+ err_1:
+ pci_disable_device(pdev);
+ pci_release_regions(pdev);
+ return -ENODEV;
+}
+
+static int fepci_open(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+
+ down_write(&fp->this_card_priv->semaphore);
+
+ if (fp->this_card_priv->pci_dev == NULL) {
+ up_write(&fp->this_card_priv->semaphore);
+ fepci_close(dev);
+ return -ENXIO;
+ }
+
+ while (fp->in_stream_mode) {
+ up_write(&fp->this_card_priv->semaphore);
+ fepci_stream_close(dev);
+ down_write(&fp->this_card_priv->semaphore);
+ }
+
+ {
+ int i = request_irq(dev->irq, &fepci_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (i) {
+ up_write(&fp->this_card_priv->semaphore);
+ printk(KERN_WARNING
+ "%s: unable to allocate IRQ %d, error 0x%x",
+ fepci_NAME, dev->irq, i);
+ return i;
+ }
+ }
+
+ fp->in_eth_mode = 1;
+
+ fepci_init_ring(dev);
+ set_rx_mode(dev);
+
+ fp->cur_rx = 0;
+ fp->cur_tx = 0;
+
+ netif_carrier_off(dev);
+
+ /* Enable interrupts by setting the interrupt mask. */
+
+ set_int_mask(fp->channel_number,
+ MaskFrameReceived | MaskFrameTransmitted |
+ MaskRxFifoError | MaskRxFrameDroppedError |
+ MaskTxFifoError, fp->this_card_priv);
+
+ {
+ void *ioaddr = (void *)dev->base_addr;
+
+ /* Start Rx and Tx channels. */
+ outl(Receive_enable |
+ (Rx_fifo_threshold & RX_FIFO_THRESHOLD_PACKET_MODE),
+ (void *)(ioaddr + fp->reg_rxctrl));
+
+ outl((Transmit_enable |
+ (Tx_desc_threshold &
+ (TX_DESC_THRESHOLD_PACKET_MODE << 8)) |
+ (Tx_fifo_threshold & TX_FIFO_THRESHOLD_PACKET_MODE)),
+ (void *)(ioaddr + fp->reg_txctrl));
+ }
+
+ netif_start_queue(dev);
+
+ /* Set timer */
+ init_timer(&fp->timer);
+ fp->timer.expires = jiffies + HZ;
+ fp->timer.data = (unsigned long)dev;
+ fp->timer.function = &fepci_timer; /* timer handler */
+ add_timer(&fp->timer);
+
+ up_write(&fp->this_card_priv->semaphore);
+
+ return 0;
+}
+
+static void fepci_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct fepci_ch_private *fp = dev->priv;
+
+ /* just to make it absolutely sure the sending starts again
+ * if the system jams: free already sent skbuffs */
+
+ if (netif_tx_trylock(dev)) {
+ if (!(fp->tx_interrupts_since_last_timer)) {
+ unsigned i = TX_RING_SIZE - 1;
+ do {
+ u32 desc_b;
+ if ((fp->tx_skbuff[i] != NULL)
+ &&
+ (((desc_b =
+ inl(&fp->tx_desc[i].
+ desc_b)) & transfer_not_done) ==
+ 0)) {
+ /* has been sent */
+ pci_unmap_single(fp->
+ this_card_priv->
+ pci_dev,
+ inl(&fp->
+ tx_desc[i].
+ desc_a),
+ desc_b &
+ frame_length,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(fp->tx_skbuff[i]);
+ fp->tx_skbuffs_out++;
+
+ fp->tx_skbuff[i] = NULL;
+
+ if (desc_b & fifo_error) {
+ fp->stats.tx_fifo_errors++;
+ fp->tx_desc_fifo_err++;
+ } else
+ fp->stats.tx_packets++;
+ }
+ }
+ while (i--);
+ }
+ /* if the next descriptor is free, continue taking new ones */
+ if (!(inl(&fp->tx_desc[fp->cur_tx].desc_b) & transfer_not_done))
+ netif_wake_queue(dev);
+ netif_tx_unlock(dev);
+ }
+
+ fp->tx_interrupts_since_last_timer = 0;
+
+ if ((get_common_reg_word(fp->this_card_priv->ioaddr, 0x72) >> fp->
+ channel_number) & 1) {
+ netif_carrier_off(dev);
+ } else {
+ netif_carrier_on(dev);
+ }
+
+ if (fp->in_eth_mode)
+ mod_timer(&fp->timer, jiffies + 5 * HZ);
+}
+
+static void fepci_tx_timeout(struct net_device *dev)
+{
+ DBG_PRINT("%s: transmit timed out!\n", dev->name);
+}
+
+/* Initialize the rx and tx rings */
+static void fepci_init_ring(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ unsigned i;
+
+ fp->rx_buf_sz = 2000;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb =
+ __dev_alloc_skb(fp->rx_buf_sz, GFP_KERNEL);
+
+ if (skb == NULL) {
+ ZERO:
+ outl(0, &fp->rx_desc[i].desc_a);
+ outl(0, &fp->rx_desc[i].desc_b);
+ continue;
+ } else {
+ u32 bus_address;
+ bus_address =
+ pci_map_single(fp->this_card_priv->pci_dev,
+ skb->data, fp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ if (likely(!pci_dma_mapping_error(bus_address))) {
+ fp->rx_skbuffs_in++;
+ /* Mark as being used by this device */
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ fp->rx_skbuff[i] = skb;
+ outl(bus_address, &fp->rx_desc[i].desc_a);
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else {
+ dev_kfree_skb(skb);
+ goto ZERO;
+ }
+ }
+ }
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ fp->tx_skbuff[i] = NULL;
+ outl(0, &fp->tx_desc[i].desc_a); /* no skbuff */
+ /* no transfer enable, no int enable */
+ outl(0, &fp->tx_desc[i].desc_b);
+ }
+
+ return;
+}
+
+static int fepci_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ const unsigned cur_tx = fp->cur_tx;
+
+ fp->tx_skbuffs_in++;
+
+ {
+ u32 tx_length = skb->len;
+ u32 bus_address;
+ struct sk_buff *old;
+ if (unlikely(tx_length < ETH_ZLEN)) {
+ struct sk_buff *bigger =
+ skb_copy_expand(skb, 0, ETH_ZLEN - tx_length,
+ GFP_ATOMIC);
+ if (unlikely(!bigger))
+ return NET_XMIT_CN;
+ tx_length = ETH_ZLEN;
+ old = skb;
+ skb = bigger;
+ } else
+ old = NULL;
+ bus_address =
+ pci_map_single(fp->this_card_priv->pci_dev, skb->data,
+ tx_length, PCI_DMA_TODEVICE);
+ if (likely(!pci_dma_mapping_error(bus_address))) {
+ struct fepci_desc *descriptor;
+ if (old)
+ dev_kfree_skb(old);
+ descriptor = &fp->tx_desc[cur_tx];
+ outl(bus_address, &descriptor->desc_a);
+ outl((tx_length & frame_length) | enable_transfer,
+ &descriptor->desc_b);
+ } else {
+ if (old)
+ dev_kfree_skb(skb);
+ return NET_XMIT_CN;
+ }
+ fp->stats.tx_bytes += tx_length;
+ }
+
+ fp->tx_skbuff[cur_tx] = skb;
+
+ {
+ /* Calculate the next Tx descriptor entry */
+ unsigned next = (cur_tx + 1) & (TX_RING_SIZE - 1);
+ fp->cur_tx = next;
+ /* if the next descriptor is busy,
+ * discontinue taking new ones */
+ if (fp->tx_skbuff[next] != NULL)
+ netif_stop_queue(dev);
+ }
+ dev->trans_start = jiffies;
+
+ return NET_XMIT_SUCCESS;
+}
+
+static irqreturn_t fepci_interrupt(int irq, void *dev_instance)
+{
+ struct net_device *dev = dev_instance;
+ void *ioaddr = (void *)dev->base_addr;
+ struct fepci_ch_private *fp = dev->priv;
+ u32 intr_status = get_int_status(fp->channel_number, ioaddr);
+ bool RxFifoError;
+ bool RxFrameDroppedError;
+
+ clear_int(fp->channel_number, intr_status, ioaddr);
+
+ RxFifoError = (intr_status & IntrRxFifoError) != 0;
+ RxFrameDroppedError = (intr_status & IntrRxFrameDroppedError) != 0;
+ /* first update interrupt error table */
+ fp->int_err_table[RxFifoError][RxFrameDroppedError]++;
+
+ fp->interrupts++;
+
+ if (intr_status & IntrFrameReceived) {
+ fepci_rx(dev);
+ fp->rx_interrupts++;
+ }
+ if (intr_status & IntrFrameTransmitted) {
+ fp->tx_interrupts_since_last_timer++;
+ if (netif_tx_trylock(dev)) {
+ unsigned i = TX_RING_SIZE - 1;
+ do {
+ u32 desc_b;
+ if ((fp->tx_skbuff[i] != NULL)
+ &&
+ (((desc_b =
+ inl(&fp->tx_desc[i].
+ desc_b)) & transfer_not_done) ==
+ 0)) {
+ /* has been sent */
+ pci_unmap_single(fp->
+ this_card_priv->
+ pci_dev,
+ inl(&fp->
+ tx_desc[i].
+ desc_a),
+ desc_b &
+ frame_length,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(fp->tx_skbuff[i]);
+ fp->tx_skbuffs_out++;
+ fp->tx_skbuff[i] = NULL;
+ if (desc_b & fifo_error) {
+ fp->stats.tx_fifo_errors++;
+ fp->tx_desc_fifo_err++;
+ } else {
+ fp->stats.tx_packets++;
+ }
+ }
+ }
+ while (i--);
+ {
+ unsigned next = fp->cur_tx;
+ /* if next tx descriptor is free,
+ * continue taking new ones */
+ if (!(inl(&fp->tx_desc[next].desc_b) &
+ transfer_not_done))
+ netif_wake_queue(dev);
+ }
+ netif_tx_unlock(dev);
+ }
+ fp->tx_interrupts++;
+ }
+ if (RxFifoError) {
+ fp->rx_int_fifo_err++;
+ fepci_rx(dev);
+ }
+ if (RxFrameDroppedError) {
+ fp->rx_int_frame_dropped_err++;
+ fepci_rx(dev);
+ }
+ if (intr_status & IntrTxFifoError)
+ fp->tx_int_fifo_err++;
+ return intr_status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int fepci_rx(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+
+ unsigned int i, old_cur_rx = fp->cur_rx;
+ for (i = old_cur_rx;
+ i != ((old_cur_rx + RX_RING_SIZE - 1) & (RX_RING_SIZE - 1));
+ i = (i + 1) & (RX_RING_SIZE - 1)) {
+ u32 desc_b;
+ struct sk_buff *skb;
+ /* transfer done */
+ bool condition = (skb = fp->rx_skbuff[i]) &&
+ ((desc_b =
+ inl(&fp->rx_desc[i].desc_b)) & transfer_not_done) == 0;
+ if (condition) {
+ bool fifo = (desc_b & fifo_error) != 0;
+ bool size = (desc_b & size_error) != 0;
+ bool crc = (desc_b & crc_error) != 0;
+ bool octet = (desc_b & octet_error) != 0;
+ bool line = (desc_b & line_error) != 0;
+ u32 length = desc_b & frame_length;
+ pci_unmap_single(fp->this_card_priv->pci_dev,
+ inl(&fp->rx_desc[i].desc_a),
+ fp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ fp->cur_rx = (i + 1) & (RX_RING_SIZE - 1);
+ /* first update error table */
+ fp->rx_desc_err_table[fifo]
+ [size]
+ [crc]
+ [octet]
+ [line]++;
+ /* small packet counters */
+ if (length == 0)
+ fp->rx_packets_of_size_0++;
+ else if (length == 1)
+ fp->rx_packets_of_size_1++;
+ else if (length == 2)
+ fp->rx_packets_of_size_2++;
+ else if (length == 3)
+ fp->rx_packets_of_size_3++;
+ else if (length < 8)
+ fp->rx_packets_of_size_4_7++;
+ else if (length < 16)
+ fp->rx_packets_of_size_8_15++;
+ else if (length < 32)
+ fp->rx_packets_of_size_16_31++;
+
+ if (fifo) {
+ fp->stats.rx_errors++;
+ fp->stats.rx_frame_errors++;
+ fp->rx_desc_fifo_err++;
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else if (size) {
+ fp->stats.rx_errors++;
+ fp->stats.rx_over_errors++;
+ fp->rx_desc_size_err++;
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else if (crc) {
+ fp->stats.rx_errors++;
+ fp->stats.rx_crc_errors++;
+ fp->rx_desc_crc_err++;
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else if (octet) {
+ fp->rx_desc_octet_err++;
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else if (line) {
+ fp->rx_desc_line_err++;
+ outl(enable_transfer, &fp->rx_desc[i].desc_b);
+ } else {
+ skb_put(skb, length - 4);
+
+ skb->protocol = eth_type_trans(skb, dev);
+#ifdef FEPCI_POINT_TO_POINT
+ if (dev->flags & IFF_POINTOPOINT) {
+ /* everything received is for us. */
+
+ if (dev->flags & IFF_NOARP) {
+ /* NOARP applied ->
+ * destination MAC addresses
+ * are bogus */
+ if (skb->
+ pkt_type ==
+ PACKET_OTHERHOST)
+ skb->
+ pkt_type =
+ PACKET_HOST;
+ } else {
+ /* NOARP not applied ->
+ * destination MAC addresses are
+ * broadcast */
+ if (skb->
+ pkt_type ==
+ PACKET_BROADCAST)
+ skb->
+ pkt_type =
+ PACKET_HOST;
+
+ } /* IFF_NOARP */
+ } /* IFF_POINTOPOINT */
+#endif
+ skb_reset_mac_header(skb);
+ netif_rx(skb);
+ fp->rx_skbuffs_out++;
+ /* statistics -4==crc */
+ fp->stats.rx_bytes += length - 4;
+ fp->stats.rx_packets++;
+
+ fp->rx_skbuff[i] = NULL;
+ dev->last_rx = jiffies;
+ }
+ }
+ /* reserve a new one */
+ if (fp->rx_skbuff[i] == NULL) {
+ struct sk_buff *skb = dev_alloc_skb(fp->rx_buf_sz);
+
+ if (skb == NULL)
+ continue; /* Better luck next round. */
+ else {
+ u32 address =
+ pci_map_single(fp->this_card_priv->pci_dev,
+ skb->data,
+ fp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ if (likely(!pci_dma_mapping_error(address))) {
+ struct fepci_desc *descriptor;
+ fp->rx_skbuffs_in++;
+ fp->rx_skbuff[i] = skb;
+ /* Mark as being used by this device. */
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ descriptor = &fp->rx_desc[i];
+ outl(address, &descriptor->desc_a);
+ outl(enable_transfer,
+ &descriptor->desc_b);
+ } else {
+ dev_kfree_skb(skb);
+ printk(KERN_WARNING
+ "%s: failed to map DMA.\n",
+ dev->name);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int fepci_close(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ unsigned i;
+ void *ioaddr = (void *)dev->base_addr;
+
+ down_write(&fp->this_card_priv->semaphore);
+
+ netif_stop_queue(dev);
+
+ /* Disable interrupts by clearing the interrupt mask */
+ set_int_mask(fp->channel_number, 0x0, fp->this_card_priv);
+
+ /* Stop the Tx and Rx processes */
+ outl(0x0, ioaddr + fp->reg_rxctrl);
+ outl(0x0, ioaddr + fp->reg_txctrl);
+ fp->in_eth_mode = 0;
+
+ del_timer_sync(&fp->timer);
+
+ free_irq(dev->irq, dev);
+
+ /* Free all the rx skbuffs */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (fp->rx_skbuff[i] != NULL) {
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev,
+ inl(&fp->rx_desc[i].
+ desc_a),
+ fp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(fp->rx_skbuff[i]);
+ fp->rx_skbuffs_out++;
+ fp->rx_skbuff[i] = NULL;
+ }
+ }
+ /* and tx */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (fp->tx_skbuff[i] != NULL) {
+ pci_unmap_single(fp->this_card_priv->
+ pci_dev,
+ inl(&fp->tx_desc[i].
+ desc_a),
+ inl(&fp->tx_desc[i].
+ desc_b) & frame_length,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(fp->tx_skbuff[i]);
+ fp->tx_skbuffs_out++;
+ fp->tx_skbuff[i] = NULL;
+ }
+ }
+ up_write(&fp->this_card_priv->semaphore);
+ return 0;
+}
+
+static struct net_device_stats *fepci_get_stats(struct net_device *dev)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ return &fp->stats;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+ DBG_PRINT("set_rx_mode\n");
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct fepci_ch_private *fp = dev->priv;
+ char data = ((u32) rq->ifr_data) & 0xff;
+ int ret = 0;
+
+ DBG_PRINT("%s: netdev_ioctl called (command_nmbr:0x%x).\n",
+ dev->name, cmd);
+
+ switch (cmd) {
+ case FEPCI_NETDEV_IOCTL_STREAM_BUFSIZE:
+ DBG_PRINT
+ (" ioctl stream bufsize commanded. (bufsize:0x%x)\n", data);
+ down_write(&fp->this_card_priv->semaphore);
+ if (fp->in_stream_mode) {
+ up_write(&fp->this_card_priv->semaphore);
+ return -EBUSY;
+ }
+ fp->bufsize_order = data;
+ up_write(&fp->this_card_priv->semaphore);
+ break;
+ case FEPCI_NETDEV_IOCTL_STREAM_UNITSIZE:
+ DBG_PRINT
+ (" ioctl stream unitsize commanded. (unitsize:0x%x)\n",
+ data);
+ down_write(&fp->this_card_priv->semaphore);
+ if (fp->in_stream_mode) {
+ up_write(&fp->this_card_priv->semaphore);
+ return -EBUSY;
+ }
+ fp->fake_unit_sz_order = data;
+ up_write(&fp->this_card_priv->semaphore);
+ break;
+ case FEPCI_NETDEV_IOCTL_STREAM_OPEN:
+ DBG_PRINT(" ioctl stream open commanded.\n");
+ ret = fepci_stream_open(dev);
+ break;
+ case FEPCI_NETDEV_IOCTL_STREAM_START:
+ DBG_PRINT(" ioctl stream start commanded.\n");
+ ret = fepci_stream_start(dev);
+ break;
+ case FEPCI_NETDEV_IOCTL_STREAM_CLOSE:
+ DBG_PRINT(" ioctl stream close commanded.\n");
+ ret = fepci_stream_close(dev);
+ break;
+ default:
+ DBG_PRINT(" unknown ioctl command 0x%x.\n", cmd);
+ return -ENOTTY;
+ }
+ return ret;
+}
+
+static void fepci_remove_one(struct pci_dev *pdev)
+{
+ /* from first dev, same in all */
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct fepci_ch_private *fp = dev->priv;
+ struct fepci_card_private *cardp = fp->this_card_priv;
+ unsigned int i;
+
+ outl(0, (void *)(cardp->ioaddr + reg_custom));
+ /* alarm manager int off */
+
+ for (i = 0; i < CHANNELS; i++) {
+ dev = cardp->ch_privates[i]->this_dev;
+ fp = dev->priv;
+#ifdef DEBUG_PROC_FILES
+ fepci_proc_cleanup_channel(cardp->card_number,
+ fp->channel_number);
+#endif /* DEBUG_PROC_FILES */
+ unregister_netdev(dev);
+ fepci_stream_close(dev);
+ free_netdev(dev);
+ }
+
+ pdev = cardp->pci_dev;
+ free_irq(pdev->irq, (void *)cardp);
+
+ down_write(&cardp->semaphore);
+
+ fepci_proc_cleanup_card(cardp->card_number);
+
+ pci_set_drvdata(pdev, NULL);
+
+ if (cardp->card_number + 1 == find_cnt)
+ find_cnt--;
+ cardp->pci_dev = NULL;
+
+ iounmap(cardp->ioaddr);
+
+ up_write(&cardp->semaphore);
+
+ pci_disable_device(pdev);
+ pci_release_regions(pdev);
+}
+
+static struct pci_driver fepci_driver = {
+ name:DRV_NAME,
+ id_table:fepci_pci_tbl,
+ probe:fepci_init_one,
+ remove:fepci_remove_one,
+};
+
+static int __init fepci_init(void)
+{
+ unsigned card = MAX_DEVICES - 1;
+ do
+ init_rwsem(&card_privates[card].semaphore);
+ while (card--);
+ major = fepci_register_char_device();
+ if (major < 0)
+ return major;
+ stream_pointers = (u32) get_zeroed_page(GFP_KERNEL | __GFP_DMA);
+ DBG_PRINT(" %x.\n", stream_pointers);
+ if (stream_pointers == 0) {
+ fepci_unregister_char_device();
+ return -ENOMEM;
+ }
+ DBG_PRINT("SetPageReserved %u.\n", stream_pointers);
+ SetPageReserved(virt_to_page(stream_pointers));
+ DBG_PRINT("fepci_proc_init_driver.\n");
+ fepci_proc_init_driver();
+ DBG_PRINT("pci_register_driver %p.\n", &fepci_driver);
+ {
+ int ret = pci_register_driver(&fepci_driver);
+ if (ret) {
+ fepci_unregister_char_device();
+ ClearPageReserved(virt_to_page(stream_pointers));
+ free_page(stream_pointers);
+ DBG_PRINT
+ ("pci_register_driver %p failed with %d.\n",
+ &fepci_driver, ret);
+ fepci_proc_cleanup_driver();
+ return ret;
+ }
+ DBG_PRINT("fepci_init %d.\n", ret);
+ return ret;
+ }
+}
+
+static void __exit fepci_cleanup(void)
+{
+ DBG_PRINT("fepci_cleanup\n");
+ pci_unregister_driver(&fepci_driver);
+ fepci_proc_cleanup_driver();
+ fepci_unregister_char_device();
+ ClearPageReserved(virt_to_page(stream_pointers));
+ free_page(stream_pointers);
+}
+
+module_init(fepci_init);
+module_exit(fepci_cleanup);
+
+/* proc-filesystem specific stuff: */
+
+#ifdef DEBUG_PROC_FILES
+
+static char string_true[] = "<true> ";
+static char string_false[] = " - ";
+
+/* convert boolean value to more clarifying string format */
+static char *b(int b)
+{
+ if (b)
+ return string_true;
+ return string_false;
+}
+
+static int fepci_proc_read_descriptors(char *buf, char **start,
+ off_t offset, int len, int *eof,
+ void *data)
+{
+ int pos = 0;
+
+ int d; /* descriptor */
+
+ struct fepci_ch_private *fp;
+ struct fepci_card_private *cardp;
+ fp = (struct fepci_ch_private *)data;
+ cardp = (struct fepci_card_private *)fp->this_card_priv;
+
+ pos +=
+ sprintf(buf + pos,
+ "Rx descriptors of channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos += sprintf(buf + pos, "\n");
+
+ for (d = 0; d < RX_RING_SIZE; d++) {
+ pos += sprintf(buf + pos, " rx descriptor number %u : \n", d);
+ pos +=
+ sprintf(buf + pos, " desc_a value : 0x%8x \n",
+ inl(&fp->rx_desc[d].desc_a));
+ pos +=
+ sprintf(buf + pos, " desc_b value : 0x%8x \n",
+ inl(&fp->rx_desc[d].desc_b));
+ }
+
+ pos += sprintf(buf + pos, "\n");
+ pos +=
+ sprintf(buf + pos,
+ "Tx descriptors of channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos += sprintf(buf + pos, "\n");
+
+ for (d = 0; d < TX_RING_SIZE; d++) {
+ pos += sprintf(buf + pos, " tx descriptor number %u : \n", d);
+ pos +=
+ sprintf(buf + pos, " desc_a value : 0x%8x \n",
+ inl(&fp->tx_desc[d].desc_a));
+ pos +=
+ sprintf(buf + pos, " desc_b value : 0x%8x \n",
+ inl(&fp->tx_desc[d].desc_b));
+ }
+
+ pos += sprintf(buf + pos, "\n");
+ pos += sprintf(buf + pos, "last line\n");
+
+ *eof = 1;
+ return pos;
+}
+
+static int fepci_proc_read_stream_counters(char *buf, char **start,
+ off_t offset, int len, int *eof,
+ void *data)
+{
+ int pos = 0;
+
+ int fifo;
+ int size;
+ int crc;
+ int octet;
+ int line;
+ int frame_dropped;
+
+ struct fepci_ch_private *fp;
+ struct fepci_card_private *cardp;
+
+ fp = (struct fepci_ch_private *)data;
+ cardp = (struct fepci_card_private *)fp->this_card_priv;
+
+ pos +=
+ sprintf(buf + pos,
+ "Stream status for channel %u of card %u : \n",
+ fp->channel_number, cardp->card_number);
+ if (fp->in_stream_mode) {
+ pos += sprintf(buf + pos, " Channel is in stream mode \n");
+ if (fp->stream_on) {
+ pos += sprintf(buf + pos, " Stream is on (started) \n");
+ } else {
+ pos +=
+ sprintf(buf + pos,
+ " Stream is off (not started)\n");
+ }
+ } else {
+ pos += sprintf(buf + pos, " Channel is NOT in stream mode \n");
+ }
+ pos += sprintf(buf + pos, "\n");
+
+ pos +=
+ sprintf(buf + pos,
+ "Error counters for channel %u of card %u "
+ "(in stream mode) : \n",
+ fp->channel_number, cardp->card_number);
+
+ pos +=
+ sprintf(buf + pos, " rx_desc_fifo_err_stream : %10u \n",
+ fp->rx_desc_fifo_err_stream);
+
+ pos +=
+ sprintf(buf + pos, " rx_desc_size_err_stream : %10u \n",
+ fp->rx_desc_size_err_stream);
+ pos +=
+ sprintf(buf + pos, " rx_desc_crc_err_stream : %11u \n",
+ fp->rx_desc_crc_err_stream);
+ pos +=
+ sprintf(buf + pos, " rx_desc_octet_err_stream : %9u \n",
+ fp->rx_desc_octet_err_stream);
+ pos +=
+ sprintf(buf + pos, " rx_desc_line_err_stream : %10u \n",
+ fp->rx_desc_line_err_stream);
+ pos +=
+ sprintf(buf + pos, " tx_desc_fifo_err_stream : %10u \n",
+ fp->tx_desc_fifo_err_stream);
+ pos +=
+ sprintf(buf + pos, " rx_int_fifo_err_stream : %11u \n",
+ fp->rx_int_fifo_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ " rx_int_frame_dropped_err_stream : %2u \n",
+ fp->rx_int_frame_dropped_err_stream);
+ pos +=
+ sprintf(buf + pos, " tx_int_fifo_err_stream : %11u \n",
+ fp->tx_int_fifo_err_stream);
+
+ pos += sprintf(buf + pos, "\n");
+ pos +=
+ sprintf(buf + pos,
+ "Other counters for channel %u of card %u "
+ "(in stream mode) : \n",
+ fp->channel_number, cardp->card_number);
+ pos +=
+ sprintf(buf + pos, " interrupts : %10u \n",
+ fp->interrupts_stream);
+ pos +=
+ sprintf(buf + pos, " rx_interrupts : %10u \n",
+ fp->rx_interrupts_stream);
+ pos +=
+ sprintf(buf + pos, " tx_interrupts : %10u \n",
+ fp->tx_interrupts_stream);
+ pos += sprintf(buf + pos, "\n");
+
+ pos +=
+ sprintf(buf + pos,
+ "Error counter tables for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos += sprintf(buf + pos, " rx_desc_error_table_stream:\n");
+ pos +=
+ sprintf(buf + pos,
+ " [fifo] [size] [crc] [octet] [line] : [count]\n");
+
+ for (fifo = 0; fifo < 2; fifo++)
+ for (size = 0; size < 2; size++)
+ for (crc = 0; crc < 2; crc++)
+ for (octet = 0; octet < 2; octet++)
+ for (line = 0; line < 2; line++)
+ pos +=
+ sprintf(buf + pos,
+ " %s %s %s %s %s "
+ ": %7u \n",
+ b(fifo),
+ b(size),
+ b(crc),
+ b(octet),
+ b(line),
+ fp->
+ rx_desc_err_table_stream
+ [fifo][size]
+ [crc][octet]
+ [line]);
+
+ pos += sprintf(buf + pos, "\n");
+ pos += sprintf(buf + pos, " int_error_table:\n");
+ pos += sprintf(buf + pos, " [rx_fifo] [frame_dropped] : [count]\n");
+ for (fifo = 0; fifo < 2; fifo++)
+ for (frame_dropped = 0; frame_dropped < 2; frame_dropped++)
+ pos +=
+ sprintf(buf + pos,
+ " %s %s : %7u\n", b(fifo),
+ b(frame_dropped),
+ fp->int_err_table_stream[fifo]
+ [frame_dropped]);
+
+ pos += sprintf(buf + pos, "\n");
+
+ pos +=
+ sprintf(buf + pos,
+ "Small packet counters for channel %u of card %u "
+ "(stream mode): \n",
+ fp->channel_number, cardp->card_number);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 0 : %10u \n",
+ fp->rx_packets_of_size_0_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 1 : %10u \n",
+ fp->rx_packets_of_size_1_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 2 : %10u \n",
+ fp->rx_packets_of_size_2_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 3 : %10u \n",
+ fp->rx_packets_of_size_3_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 4..7 : %10u \n",
+ fp->rx_packets_of_size_4_7_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 8..15 : %10u \n",
+ fp->rx_packets_of_size_8_15_stream);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 16..31 : %10u \n",
+ fp->rx_packets_of_size_16_31_stream);
+
+ pos += sprintf(buf + pos, "\n");
+ pos += sprintf(buf + pos, "last line\n");
+
+ *eof = 1;
+ return pos;
+}
+
+static int fepci_proc_read_counters(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int pos = 0;
+
+ int fifo;
+ int size;
+ int crc;
+ int octet;
+ int line;
+ int frame_dropped;
+
+ struct fepci_ch_private *fp;
+ struct fepci_card_private *cardp;
+
+ fp = (struct fepci_ch_private *)data;
+ cardp = (struct fepci_card_private *)fp->this_card_priv;
+
+ pos +=
+ sprintf(buf + pos,
+ "Error counters for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+
+ pos +=
+ sprintf(buf + pos, " rx_desc_fifo_err : %10u \n",
+ fp->rx_desc_fifo_err);
+ pos +=
+ sprintf(buf + pos, " rx_desc_size_err : %10u \n",
+ fp->rx_desc_size_err);
+ pos +=
+ sprintf(buf + pos, " rx_desc_crc_err : %11u \n",
+ fp->rx_desc_crc_err);
+ pos +=
+ sprintf(buf + pos, " rx_desc_octet_err : %9u \n",
+ fp->rx_desc_octet_err);
+ pos +=
+ sprintf(buf + pos, " rx_desc_line_err : %10u \n",
+ fp->rx_desc_line_err);
+ pos +=
+ sprintf(buf + pos, " tx_desc_fifo_err : %10u \n",
+ fp->tx_desc_fifo_err);
+ pos +=
+ sprintf(buf + pos, " rx_int_fifo_err : %11u \n",
+ fp->rx_int_fifo_err);
+ pos +=
+ sprintf(buf + pos, " rx_int_frame_dropped_err : %2u \n",
+ fp->rx_int_frame_dropped_err);
+ pos +=
+ sprintf(buf + pos, " tx_int_fifo_err : %11u \n",
+ fp->tx_int_fifo_err);
+
+ pos += sprintf(buf + pos, "\n");
+ pos +=
+ sprintf(buf + pos,
+ "Other counters for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos += sprintf(buf + pos, " interrupts : %10u \n", fp->interrupts);
+ pos +=
+ sprintf(buf + pos, " rx_interrupts : %10u \n", fp->rx_interrupts);
+ pos +=
+ sprintf(buf + pos, " tx_interrupts : %10u \n", fp->tx_interrupts);
+ pos += sprintf(buf + pos, "\n");
+
+ pos +=
+ sprintf(buf + pos, " rx_skbuffs_in : %10u \n", fp->rx_skbuffs_in);
+ pos +=
+ sprintf(buf + pos, " rx_skbuffs_out : %9u \n", fp->rx_skbuffs_out);
+ pos +=
+ sprintf(buf + pos, " difference : %13i \n",
+ fp->rx_skbuffs_in - fp->rx_skbuffs_out);
+ pos +=
+ sprintf(buf + pos, " tx_skbuffs_in : %10u \n", fp->tx_skbuffs_in);
+ pos +=
+ sprintf(buf + pos, " tx_skbuffs_out : %9u \n", fp->tx_skbuffs_out);
+ pos +=
+ sprintf(buf + pos, " difference : %13i \n",
+ fp->tx_skbuffs_in - fp->tx_skbuffs_out);
+
+ pos += sprintf(buf + pos, "\n");
+ pos +=
+ sprintf(buf + pos,
+ "Error counter tables for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos += sprintf(buf + pos, " rx_desc_error_table:\n");
+ pos +=
+ sprintf(buf + pos,
+ " [fifo] [size] [crc] [octet] [line] : [count]\n");
+
+ for (fifo = 0; fifo < 2; fifo++)
+ for (size = 0; size < 2; size++)
+ for (crc = 0; crc < 2; crc++)
+ for (octet = 0; octet < 2; octet++)
+ for (line = 0; line < 2; line++)
+ pos +=
+ sprintf(buf + pos,
+ " %s %s %s %s %s "
+ ": %7u \n",
+ b(fifo),
+ b(size),
+ b(crc),
+ b(octet),
+ b(line),
+ fp->
+ rx_desc_err_table
+ [fifo][size]
+ [crc][octet]
+ [line]);
+
+ pos += sprintf(buf + pos, "\n");
+ pos += sprintf(buf + pos, " int_error_table:\n");
+ pos += sprintf(buf + pos, " [rx_fifo] [frame_dropped] : [count]\n");
+ for (fifo = 0; fifo < 2; fifo++)
+ for (frame_dropped = 0; frame_dropped < 2; frame_dropped++)
+ pos +=
+ sprintf(buf + pos,
+ " %s %s : %7u\n", b(fifo),
+ b(frame_dropped),
+ fp->int_err_table[fifo][frame_dropped]);
+
+ pos += sprintf(buf + pos, "\n");
+
+ pos +=
+ sprintf(buf + pos,
+ "Small packet counters for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 0 : %10u \n",
+ fp->rx_packets_of_size_0);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 1 : %10u \n",
+ fp->rx_packets_of_size_1);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 2 : %10u \n",
+ fp->rx_packets_of_size_2);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 3 : %10u \n",
+ fp->rx_packets_of_size_3);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 4..7 : %10u \n",
+ fp->rx_packets_of_size_4_7);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 8..15 : %10u \n",
+ fp->rx_packets_of_size_8_15);
+ pos +=
+ sprintf(buf + pos, " rx_packets of size 16..31 : %10u \n",
+ fp->rx_packets_of_size_16_31);
+
+ pos += sprintf(buf + pos, "\n");
+ pos += sprintf(buf + pos, "last line\n");
+
+ *eof = 1;
+ return pos;
+}
+
+static int fepci_proc_read_registers(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int pos = 0;
+
+ struct fepci_ch_private *fp;
+ struct fepci_card_private *cardp;
+ void *ioaddr;
+
+ fp = (struct fepci_ch_private *)data;
+ cardp = (struct fepci_card_private *)fp->this_card_priv;
+ ioaddr = cardp->ioaddr;
+
+ pos +=
+ sprintf(buf + pos, "Registers for channel %u of card %u: \n",
+ fp->channel_number, cardp->card_number);
+
+ pos +=
+ sprintf(buf + pos, " interrupt status : 0x%8x \n",
+ get_int_status(fp->channel_number, ioaddr));
+ pos +=
+ sprintf(buf + pos, " interrupt mask : 0x%8x \n",
+ get_int_mask(fp->channel_number, ioaddr));
+ pos +=
+ sprintf(buf + pos, " rxctrl : 0x%8x \n",
+ inl(ioaddr + fp->reg_rxctrl));
+ pos +=
+ sprintf(buf + pos, " txctrl : 0x%8x \n",
+ inl(ioaddr + fp->reg_txctrl));
+
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "last line\n");
+
+ *eof = 1;
+ return pos;
+}
+
+#endif /* DEBUG_PROC_FILES */
+
+int get_line_data_rate_value(unsigned char line_rate)
+{
+ switch (line_rate) {
+ case 0x00:
+ return 0;
+ case 0x01:
+ return 1;
+ case 0x05:
+ return 8;
+ case 0x06:
+ return 10;
+ case 0x14:
+ return 256;
+ case 0x15:
+ return 300;
+ case 0x20:
+ return 1;
+ case 0x28:
+ return 8;
+ case 0x29:
+ return 10;
+ case 0x30:
+ return 32;
+ case 0x34:
+ return 56;
+ case 0x36:
+ return 64;
+ case 0x60:
+ return 1;
+ case 0xa0:
+ return 1;
+ default:
+ return -1;
+ }
+}
+
+char get_line_data_rate_unit(unsigned char line_rate)
+{
+ switch (line_rate) {
+ case 0x00:
+ return 0;
+ case 0x01:
+ return 0;
+ case 0x05:
+ return 0;
+ case 0x06:
+ return 0;
+ case 0x14:
+ return 0;
+ case 0x15:
+ return 0;
+ case 0x20:
+ return 'k';
+ case 0x28:
+ return 'k';
+ case 0x29:
+ return 'k';
+ case 0x30:
+ return 'k';
+ case 0x34:
+ return 'k';
+ case 0x36:
+ return 'k';
+ case 0x60:
+ return 'M';
+ case 0xa0:
+ return 'G';
+ default:
+ return 0;
+ }
+}
+
+int print_line_type(unsigned char type, char *buf, int pos)
+{
+ DBG_PRINT("print_line_type %c\n", type);
+ switch (type) {
+ case 0:
+ pos += sprintf(buf + pos, "NONE");
+ break;
+ case 1:
+ pos += sprintf(buf + pos, "DCombus management bus");
+ break;
+ case 2:
+ pos += sprintf(buf + pos, "V.24");
+ break;
+ case 3:
+ pos += sprintf(buf + pos, "X.21");
+ break;
+ case 4:
+ pos += sprintf(buf + pos, "V.35");
+ break;
+ case 5:
+ pos += sprintf(buf + pos, "V.11");
+ break;
+ case 6:
+ pos += sprintf(buf + pos, "IDSL (ISDN Basic Rate");
+ break;
+ case 7:
+ pos += sprintf(buf + pos, "E1 nonframed/framed");
+ break;
+ case 8:
+ pos += sprintf(buf + pos, "E2 nonframed/framed");
+ break;
+ case 9:
+ pos += sprintf(buf + pos, "E3 nonframed/framed");
+ break;
+ case 10:
+ pos += sprintf(buf + pos, "T1 nonframed/framed");
+ break;
+ case 11:
+ pos += sprintf(buf + pos, "T2 nonframed/framed");
+ break;
+ case 12:
+ pos += sprintf(buf + pos, "T3 nonframed/framed");
+ break;
+ case 13:
+ pos += sprintf(buf + pos, "HDSL");
+ break;
+ case 14:
+ pos += sprintf(buf + pos, "ADSL");
+ break;
+ case 15:
+ pos += sprintf(buf + pos, "SDSL");
+ break;
+ case 16:
+ pos += sprintf(buf + pos, "HDSL2");
+ break;
+ case 17:
+ pos += sprintf(buf + pos, "VDSL");
+ break;
+ case 18:
+ pos += sprintf(buf + pos, "G.shdsl");
+ break;
+ case 19:
+ pos += sprintf(buf + pos, "SDH");
+ break;
+ case 255:
+ pos +=
+ sprintf(buf + pos, "COMBINATION, get list using mailbox");
+ break;
+ default:
+ pos += sprintf(buf + pos, "reserved");
+ }
+ return pos;
+}
+
+int print_card_type(unsigned char type, char *buf, int pos)
+{
+ DBG_PRINT("print_card_type\n");
+ switch (type) {
+ case 0x00:
+ pos += sprintf(buf + pos, "illegal ");
+ break;
+ case 0x01:
+ case 0x02:
+ pos += sprintf(buf + pos, "Retina ");
+ break;
+ default:
+ pos += sprintf(buf + pos, "reserved ");
+ }
+
+ return pos;
+}
+
+int print_card_model(unsigned char model, char *buf, int pos)
+{
+ DBG_PRINT("print_card_model\n");
+ switch (model) {
+ case 0x00:
+ pos += sprintf(buf + pos, "illegal ");
+ break;
+ case 0x01:
+ pos += sprintf(buf + pos, "E2200 ");
+ break;
+ case 0x02:
+ pos += sprintf(buf + pos, "C5400 ");
+ break;
+ default:
+ pos += sprintf(buf + pos, "reserved ");
+ }
+
+ return pos;
+}
+
+static inline u8 get_common_reg(void *ioaddr, unsigned long offsett)
+{
+ unsigned long byte = __test_and_clear_bit(0, &offsett);
+ u8 reg;
+ DBG_PRINT("get_common_reg %p, old %p\n",
+ ioaddr + FEPCI_IDENTIFICATION_OFFSETT + (offsett << 1) +
+ byte,
+ &((u32 *) (ioaddr +
+ FEPCI_IDENTIFICATION_OFFSETT))[offsett / 2]);
+ reg =
+ readb(ioaddr + FEPCI_IDENTIFICATION_OFFSETT + (offsett << 1) +
+ byte);
+ DBG_PRINT("get_common_reg %p: %u\n",
+ ioaddr + FEPCI_IDENTIFICATION_OFFSETT + (offsett << 1) +
+ byte, reg);
+ return reg;
+}
+
+static int fepci_proc_read_features(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int pos = 0;
+ int tab = 0;
+ struct fepci_card_private *cardp;
+ void *ioaddr;
+
+ cardp = (struct fepci_card_private *)data;
+
+ down_read(&cardp->semaphore);
+
+ if (unlikely(cardp->pci_dev == NULL))
+ goto EOF;
+
+ ioaddr = cardp->ioaddr;
+
+ switch (offset) {
+ case 0:
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "card type: ");
+ pos = print_card_type(get_common_reg(ioaddr, 0x00), buf, pos);
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "model: ");
+ pos = print_card_model(get_common_reg(ioaddr, 0x00), buf, pos);
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "serial number: ");
+ pos +=
+ sprintf(buf + pos, "%2.2x", get_common_reg(ioaddr, 0x07));
+ pos +=
+ sprintf(buf + pos, "%2.2x", get_common_reg(ioaddr, 0x06));
+ pos +=
+ sprintf(buf + pos, "%2.2x", get_common_reg(ioaddr, 0x05));
+ pos +=
+ sprintf(buf + pos, "%2.2x\n", get_common_reg(ioaddr, 0x04));
+
+ pos += sprintf(buf + pos, "version: ");
+ pos +=
+ sprintf(buf + pos, "%2.2x.", get_common_reg(ioaddr, 0x08));
+ pos +=
+ sprintf(buf + pos, "%2.2x.", get_common_reg(ioaddr, 0x09));
+ pos +=
+ sprintf(buf + pos, "%2.2x.", get_common_reg(ioaddr, 0x0a));
+ pos +=
+ sprintf(buf + pos, "%2.2x\n", get_common_reg(ioaddr, 0x0b));
+
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "max. pipe count: ");
+ pos += sprintf(buf + pos, "%d\n", get_common_reg(ioaddr, 0x03));
+
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+ case 1:
+ pos += sprintf(buf + pos, "line count: ");
+ pos += sprintf(buf + pos, "%d\n", get_common_reg(ioaddr, 0x02));
+
+ pos += sprintf(buf + pos, "line type: ");
+ pos = print_line_type(get_common_reg(ioaddr, 0x0c), buf, pos);
+
+ /* JT: Secondary interface is also printed also,
+ * if there is one. */
+ if (get_common_reg(ioaddr, 0x10) > 0) {
+ pos += sprintf(buf + pos, " / ");
+ pos =
+ print_line_type(get_common_reg(ioaddr, 0x10),
+ buf, pos);
+ }
+
+ pos += sprintf(buf + pos, "\n");
+
+ /* JT: Line modes are printed only if
+ * the card has NO secondary interface. */
+ if (get_common_reg(ioaddr, 0x10) == 0) {
+ pos += sprintf(buf + pos, "line modes: ");
+ tab = 0;
+ if (get_common_reg(ioaddr, 0x21) & 0x80) {
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "framed mode supported\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x40) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "unframed mode supported\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x20) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "line code setting available\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x10) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "line attenuation available\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x08) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "line quality available\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x04) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "timing setting available\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x02) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos += sprintf(buf + pos, "reserved\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) & 0x01) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos +=
+ sprintf(buf + pos,
+ "line shutdown setting "
+ "available\n");
+ }
+ if (get_common_reg(ioaddr, 0x21) == 0) {
+ if (tab)
+ pos +=
+ sprintf(buf + pos,
+ " ");
+ else
+ tab = 1;
+ pos += sprintf(buf + pos, "n/a\n");
+ }
+ }
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+ case 2:
+ pos += sprintf(buf + pos, "line rate: ");
+ if (get_common_reg(ioaddr, 0x28) ==
+ get_common_reg(ioaddr, 0x2a)) {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26)) < 0)
+ pos += sprintf(buf + pos, "Invalid value");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))) {
+ pos += sprintf(buf + pos, "fixed ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))
+ * get_common_reg_word(ioaddr,
+ 0x28));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos, "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, "
+ "get value or list using mailbox");
+ } else {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26)) < 0)
+ pos += sprintf(buf + pos, "Invalid value");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))) {
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))
+ * get_common_reg_word(ioaddr,
+ 0x28));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos, "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps - ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))
+ * get_common_reg_word(ioaddr,
+ 0x2a));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos, "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, "
+ "get value or list using mailbox");
+ }
+
+ /* JT: Line rate of a secondary interface is printed,
+ * if there is one. */
+ if (get_common_reg(ioaddr, 0x10) > 0) {
+ pos += sprintf(buf + pos, " / ");
+
+ if (get_common_reg(ioaddr, 0x34) ==
+ get_common_reg(ioaddr, 0x36)) {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26)) < 0)
+ pos +=
+ sprintf(buf + pos, "Invalid value");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))) {
+ pos += sprintf(buf + pos, "fixed ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x26)) *
+ get_common_reg_word
+ (ioaddr, 0x34));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, "
+ "get value or "
+ "list using mailbox");
+ } else {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26)) < 0)
+ pos +=
+ sprintf(buf + pos, "Invalid value");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))) {
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x26)) *
+ get_common_reg_word
+ (ioaddr, 0x34));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps - ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x26)) *
+ get_common_reg_word
+ (ioaddr, 0x36));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, "
+ "get value or list "
+ "using mailbox");
+ }
+ }
+
+ pos += sprintf(buf + pos, "\n");
+
+ /* JT: Primary line special info is printed only
+ * if the card has NO secondary interface. */
+ if (get_common_reg(ioaddr, 0x10) == 0) {
+ pos += sprintf(buf + pos, "rate sel. methods: ");
+ if (get_common_reg(ioaddr, 0x28) ==
+ get_common_reg(ioaddr, 0x2a))
+ pos += sprintf(buf + pos, "n/a\n");
+ else if ((get_common_reg(ioaddr, 0x22) & 4)
+ && (get_common_reg(ioaddr, 0x23) & 4))
+ pos += sprintf(buf + pos, "adjust\n");
+ else if (((!get_common_reg(ioaddr, 0x22)) & 4)
+ && (get_common_reg(ioaddr, 0x23) & 4))
+ pos += sprintf(buf + pos, "adjust(framed)\n");
+ else if ((get_common_reg(ioaddr, 0x22) & 4)
+ && ((!get_common_reg(ioaddr, 0x23)) & 4))
+ pos += sprintf(buf + pos, "adjust(unframed)\n");
+ else
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "\n");
+
+ pos += sprintf(buf + pos, "unframed data rate: ");
+ if (get_common_reg(ioaddr, 0x30) ==
+ get_common_reg(ioaddr, 0x32)) {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27)) < 0)
+ pos +=
+ sprintf(buf + pos,
+ "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27))) {
+ pos += sprintf(buf + pos, "fixed ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x30));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, "
+ "get value or list using "
+ "mailbox\n");
+ } else {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27)) < 0)
+ pos +=
+ sprintf(buf + pos,
+ "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27))) {
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x30));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps - ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x32));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, get value "
+ "or list using mailbox\n");
+ }
+ }
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+
+ case 3:
+ /* JT: Line modes are printed only
+ * if the card has NO secondary interface. */
+ if (get_common_reg(ioaddr, 0x10) == 0) {
+ pos += sprintf(buf + pos, "rate sel. methods: ");
+ if (get_common_reg(ioaddr, 0x30) ==
+ get_common_reg(ioaddr, 0x32))
+ pos += sprintf(buf + pos, "n/a\n");
+ else {
+ if (get_common_reg(ioaddr, 0x23) & 1)
+ pos +=
+ sprintf(buf + pos,
+ "timeslot map\n");
+ if (get_common_reg(ioaddr, 0x23) & 2)
+ pos += sprintf(buf + pos, "adjust\n");
+ }
+
+ pos += sprintf(buf + pos, "framed data rate: ");
+ if (get_common_reg(ioaddr, 0x2c) ==
+ get_common_reg(ioaddr, 0x2e)) {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27)) < 0)
+ pos +=
+ sprintf(buf + pos,
+ "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27))) {
+ pos += sprintf(buf + pos, "fixed ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x2c));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, get value "
+ "or list using mailbox\n");
+ } else {
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27)) < 0)
+ pos +=
+ sprintf(buf + pos,
+ "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x27))) {
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x2c));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps - ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x27)) *
+ get_common_reg_word
+ (ioaddr, 0x2e));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x27)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x27)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, get value "
+ "or list using mailbox\n");
+ }
+
+ pos += sprintf(buf + pos, "rate sel. methods: ");
+ if (get_common_reg_word(ioaddr, 0x2c) ==
+ get_common_reg_word(ioaddr, 0x2e))
+ pos += sprintf(buf + pos, "n/a\n");
+ else {
+ if (get_common_reg(ioaddr, 0x22) & 1)
+ pos +=
+ sprintf(buf + pos,
+ "timeslot map\n");
+ if (get_common_reg(ioaddr, 0x22) & 2)
+ pos += sprintf(buf + pos, "adjust\n");
+ }
+ }
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+ default:
+ EOF:
+ up_read(&cardp->semaphore);
+ *start = (char *)0;
+ *eof = 1;
+ return 0;
+ }
+}
+
+static int fepci_proc_read_settings(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int pos = 0;
+ int i, j;
+
+ struct fepci_card_private *cardp;
+ void *ioaddr;
+
+ cardp = (struct fepci_card_private *)data;
+
+ down_read(&cardp->semaphore);
+
+ if (unlikely(cardp->pci_dev == NULL))
+ goto EOF;
+
+ ioaddr = cardp->ioaddr;
+
+ switch (offset) {
+ case 0:
+ j = get_common_reg(ioaddr, 0x02);
+
+ for (i = 0; i < j; i++) {
+ if ((get_common_reg_word(ioaddr, 0x44) >> i) & 1) {
+ pos += sprintf(buf + pos, "\nline %2d\n", i);
+ pos += sprintf(buf + pos, "-------\n");
+ pos +=
+ sprintf(buf + pos, "mode: ");
+ if ((get_common_reg_word(ioaddr, 0x46) >>
+ i) & 1)
+ pos += sprintf(buf + pos, "framed\n");
+ else
+ pos += sprintf(buf + pos, "unframed\n");
+
+ pos +=
+ sprintf(buf + pos, "scrambler: ");
+ if ((get_common_reg_word(ioaddr, 0x48) >>
+ i) & 1)
+ pos += sprintf(buf + pos, "enabled\n");
+ else if ((get_common_reg_word(ioaddr, 0x46)
+ >> i) & 1)
+ pos += sprintf(buf + pos, "n/a\n");
+ else
+ pos += sprintf(buf + pos, "disabled\n");
+
+ pos +=
+ sprintf(buf + pos, "line crc: ");
+ if ((get_common_reg_word(ioaddr, 0x46) >>
+ i) & 1) {
+ if ((get_common_reg_word
+ (ioaddr, 0x4a) >> i) & 1)
+ pos +=
+ sprintf(buf + pos,
+ "enabled\n");
+ else if (get_common_reg
+ (ioaddr, 0x22) & 0x20)
+ pos +=
+ sprintf(buf + pos,
+ "disabled\n");
+ else
+ pos +=
+ sprintf(buf + pos, "n/a\n");
+ } else {
+ if ((get_common_reg_word
+ (ioaddr, 0x4a) >> i) & 1)
+ pos +=
+ sprintf(buf + pos,
+ "enabled\n");
+ else if (get_common_reg
+ (ioaddr, 0x23) & 0x20)
+ pos +=
+ sprintf(buf + pos,
+ "disabled\n");
+ else
+ pos +=
+ sprintf(buf + pos, "n/a\n");
+ }
+ }
+ }
+
+ /* If there are no enabled lines, "No enabled lines!" printed.
+ * The settings file would remain empty otherwise. */
+ if ((get_common_reg_word(ioaddr, 0x44)) == 0)
+ pos += sprintf(buf + pos, "No enabled lines!\n");
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+ case 1:
+ j = get_common_reg(ioaddr, 0x03);
+
+ if ((get_common_reg_word(ioaddr, 0x44)) != 0) {
+ for (i = 0; i < j; i++) {
+ pos += sprintf(buf + pos, "\npipe %2d\n", i);
+ pos += sprintf(buf + pos, "-------\n");
+
+ pos +=
+ sprintf(buf + pos, "access mode: ");
+ if ((get_common_reg_word(ioaddr, 0x4e) >>
+ i) & 1)
+ pos += sprintf(buf + pos, "packet\n");
+ else
+ pos += sprintf(buf + pos, "stream\n");
+
+ pos +=
+ sprintf(buf + pos, "data rate: ");
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x42)) < 0)
+ pos +=
+ sprintf(buf + pos,
+ "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x42))) {
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x42)) *
+ get_common_reg_word
+ (ioaddr, 0x50 + 2 * i));
+ if (get_line_data_rate_unit
+ Àg#\x03+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x42)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, get value "
+ "or list using mailbox\n");
+ }
+ }
+ up_read(&cardp->semaphore);
+ *start = (char *)1;
+ *eof = 1;
+ return min(pos, len);
+ default:
+ EOF:
+ up_read(&cardp->semaphore);
+ *start = (char *)0;
+ *eof = 1;
+ return 0;
+ }
+}
+
+void proc_cpy(char *buf_from, char *buf_to, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ *(buf_to + i) = *(buf_from + i);
+}
+
+static int fepci_proc_read_status(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ unsigned int pos = 0;
+ unsigned int i, j;
+
+ struct fepci_card_private *cardp;
+
+ void *ioaddr;
+
+ struct fepci_ch_private *fp;
+
+ cardp = (struct fepci_card_private *)data;
+
+ down_read(&cardp->semaphore);
+
+ if (unlikely(cardp->pci_dev == NULL))
+ goto EOF;
+
+ ioaddr = cardp->ioaddr;
+
+ if ((offset & 0xff000) == 0) {
+ j = get_common_reg(ioaddr, 0x02);
+ for (i = 0; i < j; i++) {
+ pos += sprintf(buf + pos, "\nline %2d\n", i);
+ pos += sprintf(buf + pos, "-------\n");
+ pos += sprintf(buf + pos, "status: ");
+ if ((get_common_reg_word(ioaddr, 0x72) >> i) & 1) {
+ pos += sprintf(buf + pos, "DOWN\n");
+ netif_carrier_off(cardp->ch_privates[i]->
+ this_dev);
+ } else {
+ netif_carrier_on(cardp->ch_privates[i]->
+ this_dev);
+ if ((get_common_reg_word(ioaddr, 0x74) >>
+ i) & 1)
+ pos += sprintf(buf + pos, "UP/Alarm\n");
+ else
+ pos += sprintf(buf + pos, "UP\n");
+ }
+ pos += sprintf(buf + pos, "primary clock: ");
+ if ((get_common_reg_word(ioaddr, 0x76) >> i) & 1)
+ pos += sprintf(buf + pos, "OK\n");
+ else
+ pos += sprintf(buf + pos, "FAIL\n");
+ }
+ up_read(&cardp->semaphore);
+ if (pos - (0xfff & offset) > (unsigned)len)
+ *start = (char *)len;
+ else
+ *start = (char *)(0x1000 - (offset & 0xfff));
+ proc_cpy(buf + (offset & 0xfff), buf, len);
+ return min((int)(pos - (0xfff & offset)), len);
+ }
+
+ j = get_common_reg(ioaddr, 0x03);
+ if ((j <= 0) || (j > 16))
+ j = 16;
+ if ((((((unsigned)offset) & 0xff000) >> 12) > 0) &&
+ (((((unsigned)offset) & 0xff000) >> 12) <= j)) {
+ i = ((int)((offset & 0xff000) >> 12)) - 1;
+ if (i < CHANNELS) {
+ pos += sprintf(buf + pos, "\npipe %2d\n", i);
+ pos += sprintf(buf + pos, "-------\n");
+ pos += sprintf(buf + pos, "status: ");
+
+ if (!((get_common_reg_word(ioaddr, 0x78) >> i) & 1))
+ pos += sprintf(buf + pos, "DOWN\n");
+ else if ((get_common_reg_word(ioaddr, 0x7a) >> i) & 1)
+ pos += sprintf(buf + pos, "UP/Degraded\n");
+ else
+ pos += sprintf(buf + pos, "UP\n");
+ if ((get_common_reg_word(ioaddr, 0x4e) >> i) & 1) {
+ pos +=
+ sprintf(buf + pos, "packet counters:\n\n");
+ pos +=
+ sprintf(buf + pos, "rx count: %lu \n",
+ cardp->ch_privates[i]->stats.
+ rx_packets);
+ pos +=
+ sprintf(buf + pos, "rx data: %lu \n",
+ cardp->ch_privates[i]->stats.
+ rx_bytes);
+ pos +=
+ sprintf(buf + pos, "rx errors:%lu \n",
+ cardp->ch_privates[i]->stats.
+ rx_errors);
+ pos +=
+ sprintf(buf + pos, "tx count: %lu \n",
+ cardp->ch_privates[i]->stats.
+ tx_packets);
+ pos +=
+ sprintf(buf + pos, "tx data: %lu \n",
+ cardp->ch_privates[i]->stats.
+ tx_bytes);
+ pos +=
+ sprintf(buf + pos, "tx errors:%lu \n",
+ cardp->ch_privates[i]->stats.
+ tx_errors);
+ } else {
+ pos +=
+ sprintf(buf + pos, "stream counters:\n\n");
+ fp = cardp->ch_privates[i];
+ pos += sprintf(buf + pos,
+ "rx_desc_fifo_err_stream : %10u"
+ " \n",
+ fp->rx_desc_fifo_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "rx_desc_size_err_stream : %10u"
+ " \n",
+ fp->rx_desc_size_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "rx_desc_octet_err_stream : %9u"
+ " \n",
+ fp->rx_desc_octet_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "rx_desc_line_err_stream : %10u"
+ " \n",
+ fp->rx_desc_line_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "tx_desc_fifo_err_stream : %10u"
+ " \n",
+ fp->tx_desc_fifo_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "rx_int_fifo_err_stream : %11u \n",
+ fp->rx_int_fifo_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "rx_int_frame_dropped_err_stream :"
+ " %2u \n",
+ fp->
+ rx_int_frame_dropped_err_stream);
+ pos +=
+ sprintf(buf + pos,
+ "tx_int_fifo_err_stream : %11u \n",
+ fp->tx_int_fifo_err_stream);
+ }
+ if (pos - (0xfff & offset) > (unsigned)len)
+ *start = (char *)len;
+ else
+ *start = (char *)(0x1000 - (offset & 0xfff));
+ proc_cpy(buf + (offset & 0xfff), buf, len);
+ }
+ up_read(&cardp->semaphore);
+ return min((int)(pos - (0xfff & offset)), len);
+ } else {
+ EOF:
+ up_read(&cardp->semaphore);
+ *start = (char *)0;
+ *eof = 1;
+ return 0;
+ }
+}
+
+static int fepci_proc_read_devices(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ void *ioaddr;
+ unsigned int pos = 0;
+ unsigned int i;
+
+ pos +=
+ sprintf(buf + pos,
+ "bus:card.function cardtype model lines, max rate\n");
+ for (i = 0; i < find_cnt; i++) {
+ down_read(&card_privates[i].semaphore);
+ if (likely(card_privates[i].pci_dev)) { /* the card exists */
+ pos +=
+ sprintf(buf + pos,
+ "%02x:%s ",
+ card_privates[i].pci_dev->bus->
+ number,
+ card_privates[i].pci_dev->procent->name);
+ ioaddr = card_privates[i].ioaddr;
+ pos =
+ print_card_type(get_common_reg
+ (ioaddr, 0x00), buf, pos);
+ pos =
+ print_card_model(get_common_reg
+ (ioaddr, 0x00), buf, pos);
+ pos +=
+ sprintf(buf + pos, "%d",
+ get_common_reg(ioaddr, 0x02));
+ pos += sprintf(buf + pos, " x ");
+ pos =
+ print_line_type(get_common_reg
+ (ioaddr, 0x0c), buf, pos);
+ if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26)) < 0)
+ pos += sprintf(buf + pos, "Invalid value\n");
+ else if (get_line_data_rate_value
+ (get_common_reg(ioaddr, 0x26))) {
+ pos += sprintf(buf + pos, ", total ");
+ pos +=
+ sprintf(buf + pos, "%d ",
+ get_line_data_rate_value
+ (get_common_reg
+ (ioaddr,
+ 0x26)) *
+ get_common_reg_word
+ (ioaddr,
+ 0x2a) *
+ get_common_reg(ioaddr, 0x02));
+ if (get_line_data_rate_unit
+ (get_common_reg(ioaddr, 0x26)))
+ pos +=
+ sprintf(buf + pos,
+ "%c",
+ get_line_data_rate_unit
+ (get_common_reg
+ (ioaddr, 0x26)));
+ pos += sprintf(buf + pos, "bps\n");
+ } else
+ pos +=
+ sprintf(buf + pos,
+ "No multiplier, get value or list "
+ "using mailbox\n");
+
+ }
+ up_read(&card_privates[i].semaphore);
+ }
+ DBG_PRINT("fepci_proc_read_devices pos %u < %lu?\n", pos, PAGE_SIZE);
+ *eof = 1;
+ return pos;
+}
+
+static int fepci_proc_read_id_list(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ unsigned int pos = 0;
+ unsigned int i;
+
+ pos += sprintf(buf + pos, "bus:card.function major minor interfaces\n");
+ for (i = 0; i < find_cnt; i++) {
+ down_read(&card_privates[i].semaphore);
+ if (likely(card_privates[i].pci_dev)) /* the card exists */
+ pos +=
+ sprintf(buf + pos,
+ "%02x:%s %03i %03i %s..%s\n",
+ card_privates[i].pci_dev->bus->
+ number,
+ card_privates[i].pci_dev->
+ procent->name, major,
+ card_privates[i].
+ ch_privates[0]->minor,
+ card_privates[i].
+ ch_privates[0]->this_dev->name,
+ card_privates[i].
+ ch_privates[CHANNELS - 1]->this_dev->name);
+ up_read(&card_privates[i].semaphore);
+ }
+
+ pos += sprintf(buf + pos, "\n");
+ DBG_PRINT("fepci_proc_read_id_list pos %u < %lu?\n", pos, PAGE_SIZE);
+ *eof = 1;
+ return pos;
+}
+
+const static char DEVICES[] = "devices";
+const static char ID_LIST[] = "id_list";
+
+static int fepci_proc_init_driver(void)
+{
+ DBG_PRINT("fepci_proc_init_driver\n");
+ proc_root_entry = create_proc_entry(fepci_proc_entry_name, S_IFDIR, 0);
+ if (!proc_root_entry)
+ printk(KERN_WARNING
+ "%s: creating proc root dir entry failed.\n",
+ fepci_NAME);
+
+ create_proc_read_entry(DEVICES, 0, proc_root_entry,
+ fepci_proc_read_devices, NULL);
+ create_proc_read_entry(ID_LIST, 0, proc_root_entry,
+ fepci_proc_read_id_list, NULL);
+
+ return 0;
+}
+
+static void fepci_proc_cleanup_driver(void)
+{
+ char name[sizeof(fepci_proc_entry_name) + sizeof(DEVICES)];
+ strcpy(name, fepci_proc_entry_name);
+ name[sizeof(fepci_proc_entry_name) - 1] = '/';
+ strcpy(name + sizeof(fepci_proc_entry_name), DEVICES);
+ remove_proc_entry(name, 0);
+ strcpy(name + sizeof(fepci_proc_entry_name), ID_LIST);
+ remove_proc_entry(name, 0);
+ remove_proc_entry(fepci_proc_entry_name, 0);
+}
+
+static void fepci_proc_init_card(int card_number, void *card_data)
+{
+ char buf[50];
+ struct proc_dir_entry *ent;
+ sprintf(buf, "%02x:%02x.%02x",
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+
+ ent = create_proc_entry(buf, S_IFDIR, proc_root_entry);
+ if (!ent)
+ printk("%s: creating proc dir entry failed.\n", fepci_NAME);
+
+ sprintf(buf, fepci_features_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_features,
+ card_data);
+
+ sprintf(buf, fepci_settings_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_settings,
+ card_data);
+
+ sprintf(buf, fepci_status_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_status, card_data);
+}
+
+static void fepci_proc_cleanup_card(int card_number)
+{
+ char buf[50];
+
+ sprintf(buf, fepci_features_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+ remove_proc_entry(buf, 0);
+ sprintf(buf, fepci_settings_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+ remove_proc_entry(buf, 0);
+ sprintf(buf, fepci_status_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+ remove_proc_entry(buf, 0);
+
+ sprintf(buf, "%02x:%02x.%02x",
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn));
+
+ remove_proc_entry(buf, proc_root_entry);
+}
+
+#ifdef DEBUG_PROC_FILES
+static void fepci_proc_init_channel(int card_number, int channel_number,
+ void *channel_data)
+{
+ DBG_PRINT("fepci_proc_init_channel\n");
+ char buf[50];
+
+ sprintf(buf, fepci_counters_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_counters,
+ channel_data);
+
+ sprintf(buf, fepci_descriptors_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_descriptors,
+ channel_data);
+
+ sprintf(buf, fepci_stream_counters_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+
+ create_proc_read_entry(buf, 0, NULL,
+ fepci_proc_read_stream_counters, channel_data);
+
+ sprintf(buf, fepci_registers_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+ create_proc_read_entry(buf, 0, NULL, fepci_proc_read_registers,
+ channel_data);
+}
+
+static void fepci_proc_cleanup_channel(int card_number, int channel_number)
+{
+ char buf[50];
+ sprintf(buf, fepci_counters_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+ remove_proc_entry(buf, 0);
+
+ sprintf(buf, fepci_descriptors_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+ remove_proc_entry(buf, 0);
+
+ sprintf(buf, fepci_stream_counters_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+ remove_proc_entry(buf, 0);
+
+ sprintf(buf, fepci_registers_proc_entry_name,
+ card_privates[card_number].pci_dev->bus->number,
+ PCI_SLOT(card_privates[card_number].pci_dev->devfn),
+ PCI_FUNC(card_privates[card_number].pci_dev->devfn),
+ channel_number);
+ remove_proc_entry(buf, 0);
+}
+#endif /* DEBUG_PROC_FILES */
diff -Napur linux-2.6.23/drivers/net/wan/retina.h linux-2.6.24/drivers/net/wan/retina.h
--- linux-2.6.23/drivers/net/wan/retina.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.24/drivers/net/wan/retina.h 2007-10-22 12:01:44.856033562 +0300
@@ -0,0 +1,164 @@
+/* V1.0.0 */
+
+/*
+ Copyright (C) 2002-2003 Jouni Kujala, Flexibilis Oy.
+
+ This program 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.
+
+ 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.
+
+ All the drivers derived from or based on this code fall under the
+ GPL and must retain the copyright and license notice.
+*/
+
+#ifndef RETINA_H
+#define RETINA_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* net device related stuff: */
+#define FEPCI_NETDEV_IOCTL_STREAM_BUFSIZE 0x89F1
+#define FEPCI_NETDEV_IOCTL_STREAM_UNITSIZE 0x89F2
+#define FEPCI_NETDEV_IOCTL_STREAM_OPEN 0x89F3
+#define FEPCI_NETDEV_IOCTL_STREAM_START 0x89F4
+#define FEPCI_NETDEV_IOCTL_STREAM_CLOSE 0x89F6
+
+/* char device related stuff: */
+
+#define FEPCI_SHARED_MEM_OFFSETT 0x8000
+#define FEPCI_IDENTIFICATION_OFFSETT (FEPCI_SHARED_MEM_OFFSETT+0x0)
+#define FEPCI_FEATURES_OFFSETT (FEPCI_SHARED_MEM_OFFSETT+0x40)
+#define FEPCI_SETTINGS_OFFSETT (FEPCI_SHARED_MEM_OFFSETT+0x80)
+#define FEPCI_STATUS_OFFSETT (FEPCI_SHARED_MEM_OFFSETT+0xE0)
+#define FEPCI_MAILBOX_OFFSETT (FEPCI_SHARED_MEM_OFFSETT+0x100)
+
+/* structures for ioctl calls: */
+struct fepci_ioctl_identification {
+ unsigned char data[0x20];
+};
+struct fepci_real_identification {
+ unsigned long int data[0x10];
+};
+
+struct fepci_ioctl_features {
+ unsigned char data[0x20];
+};
+struct fepci_real_features {
+ unsigned long int data[0x10];
+};
+
+struct fepci_ioctl_settings {
+ unsigned char data[0x30];
+};
+struct fepci_real_settings {
+ unsigned long int data[0x15];
+};
+
+struct fepci_ioctl_status {
+ unsigned char data[0x10];
+};
+struct fepci_real_status {
+ unsigned long int data[0x5];
+};
+
+struct fepci_ioctl_shared_mem {
+ unsigned long int data[0x80];
+};
+
+#define FEPCI_IOCTL_MAGIC 0xAA
+
+#define FEPCI_IOCTL_R_SHARED_MEM _IOR(FEPCI_IOCTL_MAGIC, 1, \
+struct fepci_ioctl_shared_mem)
+#define FEPCI_IOCTL_W_SHARED_MEM _IOW(FEPCI_IOCTL_MAGIC, 2, \
+struct fepci_ioctl_shared_mem)
+
+#define FEPCI_IOCTL_G_IDENTIFICATION _IOR(FEPCI_IOCTL_MAGIC, 0x81, \
+struct fepci_ioctl_identification)
+#define FEPCI_IOCTL_G_FEATURES _IOR(FEPCI_IOCTL_MAGIC, 0x82, \
+struct fepci_ioctl_features)
+#define FEPCI_IOCTL_G_SETTINGS _IOR(FEPCI_IOCTL_MAGIC, 0x83, \
+struct fepci_ioctl_settings)
+#define FEPCI_IOCTL_G_STATUS _IOR(FEPCI_IOCTL_MAGIC, 0x84, \
+struct fepci_ioctl_status)
+
+/* mailbox: */
+
+struct fepci_ioctl_mailbox {
+ unsigned char Semafore;
+ unsigned char Mail_number;
+ unsigned char Size;
+ unsigned char Command;
+ unsigned char Data[112];
+};
+
+struct fepci_real_mailbox {
+ __u32 Semafore_Mail_number;
+ __u32 Size_Command;
+ __u32 Data[112 / 2];
+};
+
+#define FEPCI_IOCTL_B_POLL _IO(FEPCI_IOCTL_MAGIC, 0x85)
+#define FEPCI_IOCTL_B_GRAB _IO(FEPCI_IOCTL_MAGIC, 0x86)
+#define FEPCI_IOCTL_B_RELEASE _IO(FEPCI_IOCTL_MAGIC, 0x87)
+#define FEPCI_IOCTL_B_S_CMAIL _IOW(FEPCI_IOCTL_MAGIC, 0x88, \
+struct fepci_ioctl_mailbox)
+#define FEPCI_IOCTL_B_S_QMAIL _IOW(FEPCI_IOCTL_MAGIC, 0x89, \
+struct fepci_ioctl_mailbox)
+#define FEPCI_IOCTL_B_G_MAIL _IOR(FEPCI_IOCTL_MAGIC, 0x90, \
+struct fepci_ioctl_mailbox)
+
+#define FEPCI_IOCTL_ALARM_MANAGER _IO(FEPCI_IOCTL_MAGIC, 0x91)
+#define FEPCI_IOCTL_STREAM_TRANSMIT_POLL _IO(FEPCI_IOCTL_MAGIC, 0x92)
+#define FEPCI_IOCTL_STREAM_RECEIVE_POLL _IO(FEPCI_IOCTL_MAGIC, 0x93)
+#define FEPCI_IOCTL_STREAM_BOTH_POLL _IO(FEPCI_IOCTL_MAGIC, 0x94)
+
+/* stream related stuff: */
+
+/* stream buffer address space:
+ * address: 0x 7 6 5 4 3 2 1 0
+ * ^ ^ ^
+ * | | |
+ * card | area(rx/tx,0==rx,1==tx)
+ * channel */
+
+#define CARD_ADDRESS_SHIFT 24u
+#define CHANNEL_ADDRESS_SHIFT 20u
+#define AREA_ADDRESS_SHIFT 16u
+
+#define STREAM_BUFFER_POINTER_AREA 0x7fff0000 /* one page reserved */
+
+/* stream buffer pointers (at pointer area):
+ * address: 0x 7 6 5 4 3 2 1 0
+ * ^ ^ ^
+ * | | |
+ * card | area(rx/tx,0==rx,4==tx)
+ * channel */
+
+#define CARD_POINTER_SHIFT 8u
+#define CHANNEL_POINTER_SHIFT 4u
+#define AREA_POINTER_SHIFT 2u
+
+/* fake pointers are for faking larger unit sizes to the user than
+ * what is the maximum internal unit size in FEPCI */
+#define USER_RX_S_FAKE_POINTER(__card, __channel, __offset) \
+((u32 *)(((__card << CARD_POINTER_SHIFT) | \
+(__channel << CHANNEL_POINTER_SHIFT) | 0x0) + __offset))
+#define USER_TX_S_FAKE_POINTER(__card, __channel, __offset) \
+((u32 *)(((__card << CARD_POINTER_SHIFT) | \
+(__channel << CHANNEL_POINTER_SHIFT) | 0x4) + __offset))
+
+#define USER_RX_S_POINTER(__card, __channel, __offset) \
+((u32 *)(((__card << CARD_POINTER_SHIFT) | \
+(__channel << CHANNEL_POINTER_SHIFT) | 0x8) + __offset))
+#define USER_TX_S_POINTER(__card, __channel, __offset) \
+((u32 *)(((__card << CARD_POINTER_SHIFT) | \
+(__channel << CHANNEL_POINTER_SHIFT) | 0xC) + __offset))
+
+#endif
diff -Napur linux-2.6.23/MAINTAINERS linux-2.6.24/MAINTAINERS
--- linux-2.6.23/MAINTAINERS 2007-10-09 23:31:38.000000000 +0300
+++ linux-2.6.24/MAINTAINERS 2007-10-22 11:50:13.190983316 +0300
@@ -3149,6 +3149,11 @@ L: reiserfs-devel@vger.kernel.org
W: http://www.namesys.com
S: Supported
+RETINA DRIVER
+P: Matti Linnanvuori
+M: mattilinnanvuori@yahoo.com
+S: Supported
+
ROCKETPORT DRIVER
P: Comtrol Corp.
W: http://www.comtrol.com
__________________________________ Ihr erstes Baby? Holen Sie sich Tipps von anderen Eltern. www.yahoo.de/clever
^ permalink raw reply
* [PATCH 1/2] NFS: change the ip_map cache code to handle IPv6 addresses
From: Aurélien Charbon @ 2007-10-22 11:27 UTC (permalink / raw)
To: Mailing list NFSv4; +Cc: netdev ML
[-- Attachment #1: Type: text/plain, Size: 14675 bytes --]
Here is a patch for the ip_map caching code part in nfs server.
I have updated the code to use Brian
Haley's ipv6_addr_v4mapped function, and corrected pointed out mistakes.
So the first patch in attachment must be applied on a vanilla kernel
before.
In case of bad formatting due to my mailer, you can also find the patch
in attachment.
Tests: tested with only IPv4 network and basic nfs ops (mount, file
creation and modification)
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
diff -p -u -r -N linux-2.6.23-haley/fs/nfsd/export.c
linux-2.6.23-ipmap/fs/nfsd/export.c
--- linux-2.6.23-haley/fs/nfsd/export.c 2007-10-22 09:43:17.000000000
+0200
+++ linux-2.6.23-ipmap/fs/nfsd/export.c 2007-10-22 13:04:50.000000000
+0200
@@ -35,6 +35,7 @@
#include <linux/lockd/bind.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ ipv6_addr_set(&addr6, 0, 0, htonl(0x0000FFFF),
ncp->cl_addrlist[i].s_addr);
+ auth_unix_add_addr(&addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -p -u -r -N linux-2.6.23-haley/fs/nfsd/nfsctl.c
linux-2.6.23-ipmap/fs/nfsd/nfsctl.c
--- linux-2.6.23-haley/fs/nfsd/nfsctl.c 2007-10-22 09:43:17.000000000
+0200
+++ linux-2.6.23-ipmap/fs/nfsd/nfsctl.c 2007-10-22 10:32:51.000000000
+0200
@@ -37,6 +37,7 @@
#include <linux/nfsd/syscall.h>
#include <asm/uaccess.h>
+#include <net/ipv6.h>
/*
* We have a single directory with 9 nodes in it.
@@ -222,6 +223,7 @@ static ssize_t write_getfs(struct file *
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
@@ -236,7 +238,11 @@ static ssize_t write_getfs(struct file *
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -257,6 +263,7 @@ static ssize_t write_getfd(struct file *
int err = 0;
struct knfsd_fh fh;
char *res;
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
@@ -271,7 +278,11 @@ static ssize_t write_getfd(struct file *
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -p -u -r -N linux-2.6.23-haley/include/linux/sunrpc/svcauth.h
linux-2.6.23-ipmap/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-haley/include/linux/sunrpc/svcauth.h 2007-10-22
09:43:04.000000000 +0200
+++ linux-2.6.23-ipmap/include/linux/sunrpc/svcauth.h 2007-10-22
10:10:37.000000000 +0200
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_auth
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain
*dom);
+extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain
*dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct
auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -p -u -r -N linux-2.6.23-haley/include/net/ipv6.h
linux-2.6.23-ipmap/include/net/ipv6.h
--- linux-2.6.23-haley/include/net/ipv6.h 2007-10-22
09:42:58.000000000 +0200
+++ linux-2.6.23-ipmap/include/net/ipv6.h 2007-10-22
10:10:59.000000000 +0200
@@ -21,6 +21,7 @@
#include <net/ndisc.h>
#include <net/flow.h>
#include <net/snmp.h>
+#include <linux/in.h>
#define SIN6_LEN_RFC2133 24
@@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6,
field); \
else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
+#define IS_ADDR_MAPPED(a) \
+ (((uint32_t *) (a))[0] == 0 \
+ && ((uint32_t *) (a))[1] == 0 \
+ && (((uint32_t *) (a))[2] == 0 \
+ || ((uint32_t *) (a))[2] == htonl(0xffff)))
+
struct ip6_ra_chain
{
struct ip6_ra_chain *next;
@@ -380,7 +387,7 @@ static inline int ipv6_addr_any(const st
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 &&
- a->s6_addr32[2] == htonl(0x0000ffff));
+ a->s6_addr32[2] == htonl(0x0000ffff));
}
/*
diff -p -u -r -N linux-2.6.23-haley/net/sunrpc/svcauth_unix.c
linux-2.6.23-ipmap/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-haley/net/sunrpc/svcauth_unix.c 2007-10-22
09:43:05.000000000 +0200
+++ linux-2.6.23-ipmap/net/sunrpc/svcauth_unix.c 2007-10-22
10:12:03.000000000 +0200
@@ -11,7 +11,8 @@
#include <linux/hash.h>
#include <linux/string.h>
#include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +113,19 @@ static inline int hash_ip(__be32 ip)
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^
+ hash_ip(ip.s6_addr32[1]) ^
+ hash_ip(ip.s6_addr32[2]) ^
+ hash_ip(ip.s6_addr32[3]));
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ ipv6_addr_copy(&(new->m_addr), &(item->m_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -149,22 +157,24 @@ static void ip_map_request(struct cache_
struct cache_head *h,
char **bpp, int *blen)
{
- char text_addr[20];
+ char text_addr[40];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
-
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ if (ipv6_addr_v4mapped(&(im->m_addr))) {
+ snprintf(text_addr, 20, NIPQUAD_FMT,
+ ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
+ } else {
+ snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+ }
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom,
time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,9 +207,26 @@ static int ip_map_parse(struct cache_det
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, NIP6_FMT "%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+ addr.s6_addr16[0] = htons(b1);
+ addr.s6_addr16[1] = htons(b2);
+ addr.s6_addr16[2] = htons(b3);
+ addr.s6_addr16[3] = htons(b4);
+ addr.s6_addr16[4] = htons(b5);
+ addr.s6_addr16[5] = htons(b6);
+ addr.s6_addr16[6] = htons(b7);
+ addr.s6_addr16[7] = htons(b8);
+ } else
return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
return -EINVAL;
@@ -215,10 +242,7 @@ static int ip_map_parse(struct cache_det
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
- ipmp = ip_map_lookup(class,addr);
+ ipmp = ip_map_lookup(class, &addr);
if (ipmp) {
err = ip_map_update(ipmp,
container_of(dom, struct unix_domain, h),
@@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,20 +271,24 @@ static int ip_map_show(struct seq_file *
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ ipv6_addr_copy(&addr, &im->m_addr);
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
- im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
- dom
- );
+ if (ipv6_addr_v4mapped(&addr)) {
+ seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
+ dom);
+ } else {
+ seq_printf(m, "%s" NIP6_FMT "%s\n",
+ im->m_class, NIP6(addr), dom);
+ }
return 0;
}
@@ -280,16 +308,16 @@ struct cache_detail ip_map_cache = {
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ ipv6_addr_copy(&ip.m_addr, addr);
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(*addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +346,14 @@ static int ip_map_update(struct ip_map *
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +380,7 @@ int auth_unix_forget_old(struct auth_dom
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,9 +669,24 @@ static int unix_gid_find(uid_t uid, stru
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct ip_map *ipm;
+ switch (rqstp->rq_addr.ss_family) {
+ case AF_INET:
+ sin = svc_addr_in(rqstp);
+ sin6 = &sin6_storage;
+ ipv6_addr_set(&sin6->sin6_addr, 0, 0,
+ htonl(0x0000FFFF), sin->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ sin6 = svc_addr_in6(rqstp);
+ break;
+ default:
+ BUG();
+ }
+
rqstp->rq_client = NULL;
if (rqstp->rq_proc == 0)
return SVC_OK;
@@ -651,7 +694,7 @@ svcauth_unix_set_client(struct svc_rqst
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ &(sin6->sin6_addr));
if (ipm == NULL)
return SVC_DENIED;
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
[-- Attachment #2: linux-2.6.23-ipmap.diff --]
[-- Type: text/x-patch, Size: 12728 bytes --]
diff -p -u -r -N linux-2.6.23-haley/fs/nfsd/export.c linux-2.6.23-ipmap/fs/nfsd/export.c
--- linux-2.6.23-haley/fs/nfsd/export.c 2007-10-22 09:43:17.000000000 +0200
+++ linux-2.6.23-ipmap/fs/nfsd/export.c 2007-10-22 13:04:50.000000000 +0200
@@ -35,6 +35,7 @@
#include <linux/lockd/bind.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -1559,6 +1560,7 @@ exp_addclient(struct nfsctl_client *ncp)
{
struct auth_domain *dom;
int i, err;
+ struct in6_addr addr6;
/* First, consistency check. */
err = -EINVAL;
@@ -1577,9 +1579,11 @@ exp_addclient(struct nfsctl_client *ncp)
goto out_unlock;
/* Insert client into hashtable. */
- for (i = 0; i < ncp->cl_naddr; i++)
- auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+ for (i = 0; i < ncp->cl_naddr; i++) {
+ /* Mapping address */
+ ipv6_addr_set(&addr6, 0, 0, htonl(0x0000FFFF), ncp->cl_addrlist[i].s_addr);
+ auth_unix_add_addr(&addr6, dom);
+ }
auth_unix_forget_old(dom);
auth_domain_put(dom);
diff -p -u -r -N linux-2.6.23-haley/fs/nfsd/nfsctl.c linux-2.6.23-ipmap/fs/nfsd/nfsctl.c
--- linux-2.6.23-haley/fs/nfsd/nfsctl.c 2007-10-22 09:43:17.000000000 +0200
+++ linux-2.6.23-ipmap/fs/nfsd/nfsctl.c 2007-10-22 10:32:51.000000000 +0200
@@ -37,6 +37,7 @@
#include <linux/nfsd/syscall.h>
#include <asm/uaccess.h>
+#include <net/ipv6.h>
/*
* We have a single directory with 9 nodes in it.
@@ -222,6 +223,7 @@ static ssize_t write_getfs(struct file *
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
@@ -236,7 +238,11 @@ static ssize_t write_getfs(struct file *
res = (struct knfsd_fh*)buf;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -257,6 +263,7 @@ static ssize_t write_getfd(struct file *
int err = 0;
struct knfsd_fh fh;
char *res;
+ struct in6_addr in6;
if (size < sizeof(*data))
return -EINVAL;
@@ -271,7 +278,11 @@ static ssize_t write_getfd(struct file *
res = buf;
sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
- if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+
+ if (!(clp = auth_unix_lookup(in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff -p -u -r -N linux-2.6.23-haley/include/linux/sunrpc/svcauth.h linux-2.6.23-ipmap/include/linux/sunrpc/svcauth.h
--- linux-2.6.23-haley/include/linux/sunrpc/svcauth.h 2007-10-22 09:43:04.000000000 +0200
+++ linux-2.6.23-ipmap/include/linux/sunrpc/svcauth.h 2007-10-22 10:10:37.000000000 +0200
@@ -120,10 +120,10 @@ extern void svc_auth_unregister(rpc_auth
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
diff -p -u -r -N linux-2.6.23-haley/include/net/ipv6.h linux-2.6.23-ipmap/include/net/ipv6.h
--- linux-2.6.23-haley/include/net/ipv6.h 2007-10-22 09:42:58.000000000 +0200
+++ linux-2.6.23-ipmap/include/net/ipv6.h 2007-10-22 10:10:59.000000000 +0200
@@ -21,6 +21,7 @@
#include <net/ndisc.h>
#include <net/flow.h>
#include <net/snmp.h>
+#include <linux/in.h>
#define SIN6_LEN_RFC2133 24
@@ -167,6 +168,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplit
if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \
else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0)
+#define IS_ADDR_MAPPED(a) \
+ (((uint32_t *) (a))[0] == 0 \
+ && ((uint32_t *) (a))[1] == 0 \
+ && (((uint32_t *) (a))[2] == 0 \
+ || ((uint32_t *) (a))[2] == htonl(0xffff)))
+
struct ip6_ra_chain
{
struct ip6_ra_chain *next;
@@ -380,7 +387,7 @@ static inline int ipv6_addr_any(const st
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 &&
- a->s6_addr32[2] == htonl(0x0000ffff));
+ a->s6_addr32[2] == htonl(0x0000ffff));
}
/*
diff -p -u -r -N linux-2.6.23-haley/net/sunrpc/svcauth_unix.c linux-2.6.23-ipmap/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-haley/net/sunrpc/svcauth_unix.c 2007-10-22 09:43:05.000000000 +0200
+++ linux-2.6.23-ipmap/net/sunrpc/svcauth_unix.c 2007-10-22 10:12:03.000000000 +0200
@@ -11,7 +11,8 @@
#include <linux/hash.h>
#include <linux/string.h>
#include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
- struct in_addr m_addr;
+ struct in6_addr m_addr;
struct unix_domain *m_client;
int m_add_change;
};
@@ -112,12 +113,19 @@ static inline int hash_ip(__be32 ip)
return (hash ^ (hash>>8)) & 0xff;
}
#endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+ return (hash_ip(ip.s6_addr32[0]) ^
+ hash_ip(ip.s6_addr32[1]) ^
+ hash_ip(ip.s6_addr32[2]) ^
+ hash_ip(ip.s6_addr32[3]));
+}
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
{
struct ip_map *orig = container_of(corig, struct ip_map, h);
struct ip_map *new = container_of(cnew, struct ip_map, h);
return strcmp(orig->m_class, new->m_class) == 0
- && orig->m_addr.s_addr == new->m_addr.s_addr;
+ && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
}
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
{
@@ -125,7 +133,7 @@ static void ip_map_init(struct cache_hea
struct ip_map *item = container_of(citem, struct ip_map, h);
strcpy(new->m_class, item->m_class);
- new->m_addr.s_addr = item->m_addr.s_addr;
+ ipv6_addr_copy(&(new->m_addr), &(item->m_addr));
}
static void update(struct cache_head *cnew, struct cache_head *citem)
{
@@ -149,22 +157,24 @@ static void ip_map_request(struct cache_
struct cache_head *h,
char **bpp, int *blen)
{
- char text_addr[20];
+ char text_addr[40];
struct ip_map *im = container_of(h, struct ip_map, h);
- __be32 addr = im->m_addr.s_addr;
-
- snprintf(text_addr, 20, "%u.%u.%u.%u",
- ntohl(addr) >> 24 & 0xff,
- ntohl(addr) >> 16 & 0xff,
- ntohl(addr) >> 8 & 0xff,
- ntohl(addr) >> 0 & 0xff);
+ if (ipv6_addr_v4mapped(&(im->m_addr))) {
+ snprintf(text_addr, 20, NIPQUAD_FMT,
+ ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
+ } else {
+ snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+ }
qword_add(bpp, blen, im->m_class);
qword_add(bpp, blen, text_addr);
(*bpp)[-1] = '\n';
}
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +185,10 @@ static int ip_map_parse(struct cache_det
* for scratch: */
char *buf = mesg;
int len;
- int b1,b2,b3,b4;
+ int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8];
- struct in_addr addr;
+ struct in6_addr addr;
int err;
struct ip_map *ipmp;
@@ -197,9 +207,26 @@ static int ip_map_parse(struct cache_det
len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL;
- if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+ } else if (sscanf(buf, NIP6_FMT "%c",
+ &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+ addr.s6_addr16[0] = htons(b1);
+ addr.s6_addr16[1] = htons(b2);
+ addr.s6_addr16[2] = htons(b3);
+ addr.s6_addr16[3] = htons(b4);
+ addr.s6_addr16[4] = htons(b5);
+ addr.s6_addr16[5] = htons(b6);
+ addr.s6_addr16[6] = htons(b7);
+ addr.s6_addr16[7] = htons(b8);
+ } else
return -EINVAL;
+
expiry = get_expiry(&mesg);
if (expiry ==0)
return -EINVAL;
@@ -215,10 +242,7 @@ static int ip_map_parse(struct cache_det
} else
dom = NULL;
- addr.s_addr =
- htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
- ipmp = ip_map_lookup(class,addr);
+ ipmp = ip_map_lookup(class, &addr);
if (ipmp) {
err = ip_map_update(ipmp,
container_of(dom, struct unix_domain, h),
@@ -238,7 +262,7 @@ static int ip_map_show(struct seq_file *
struct cache_head *h)
{
struct ip_map *im;
- struct in_addr addr;
+ struct in6_addr addr;
char *dom = "-no-domain-";
if (h == NULL) {
@@ -247,20 +271,24 @@ static int ip_map_show(struct seq_file *
}
im = container_of(h, struct ip_map, h);
/* class addr domain */
- addr = im->m_addr;
+ ipv6_addr_copy(&addr, &im->m_addr);
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
dom = im->m_client->h.name;
- seq_printf(m, "%s %d.%d.%d.%d %s\n",
- im->m_class,
- ntohl(addr.s_addr) >> 24 & 0xff,
- ntohl(addr.s_addr) >> 16 & 0xff,
- ntohl(addr.s_addr) >> 8 & 0xff,
- ntohl(addr.s_addr) >> 0 & 0xff,
- dom
- );
+ if (ipv6_addr_v4mapped(&addr)) {
+ seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ im->m_class,
+ ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
+ ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
+ dom);
+ } else {
+ seq_printf(m, "%s" NIP6_FMT "%s\n",
+ im->m_class, NIP6(addr), dom);
+ }
return 0;
}
@@ -280,16 +308,16 @@ struct cache_detail ip_map_cache = {
.alloc = ip_map_alloc,
};
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
- ip.m_addr = addr;
+ ipv6_addr_copy(&ip.m_addr, addr);
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
hash_str(class, IP_HASHBITS) ^
- hash_ip(addr.s_addr));
+ hash_ip6(*addr));
if (ch)
return container_of(ch, struct ip_map, h);
@@ -318,14 +346,14 @@ static int ip_map_update(struct ip_map *
ch = sunrpc_cache_update(&ip_map_cache,
&ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
- hash_ip(ipm->m_addr.s_addr));
+ hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
cache_put(ch, &ip_map_cache);
return 0;
}
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -352,7 +380,7 @@ int auth_unix_forget_old(struct auth_dom
return 0;
}
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
@@ -641,9 +669,24 @@ static int unix_gid_find(uid_t uid, stru
int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
- struct sockaddr_in *sin = svc_addr_in(rqstp);
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct ip_map *ipm;
+ switch (rqstp->rq_addr.ss_family) {
+ case AF_INET:
+ sin = svc_addr_in(rqstp);
+ sin6 = &sin6_storage;
+ ipv6_addr_set(&sin6->sin6_addr, 0, 0,
+ htonl(0x0000FFFF), sin->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ sin6 = svc_addr_in6(rqstp);
+ break;
+ default:
+ BUG();
+ }
+
rqstp->rq_client = NULL;
if (rqstp->rq_proc == 0)
return SVC_OK;
@@ -651,7 +694,7 @@ svcauth_unix_set_client(struct svc_rqst
ipm = ip_map_cached_get(rqstp);
if (ipm == NULL)
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- sin->sin_addr);
+ &(sin6->sin6_addr));
if (ipm == NULL)
return SVC_DENIED;
[-- Attachment #3: linux-2.6.23-haley.diff --]
[-- Type: text/x-patch, Size: 3700 bytes --]
diff -p -u -r -N linux-2.6.23/include/net/ipv6.h linux-2.6.23-haley/include/net/ipv6.h
--- linux-2.6.23/include/net/ipv6.h 2007-10-22 10:45:55.000000000 +0200
+++ linux-2.6.23-haley/include/net/ipv6.h 2007-10-22 09:42:58.000000000 +0200
@@ -377,6 +377,12 @@ static inline int ipv6_addr_any(const st
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
}
+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
+{
+ return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 &&
+ a->s6_addr32[2] == htonl(0x0000ffff));
+}
+
/*
* find the first different bit between two addresses
* length of address must be a multiple of 32bits
diff -p -u -r -N linux-2.6.23/net/ipv6/ipv6_sockglue.c linux-2.6.23-haley/net/ipv6/ipv6_sockglue.c
--- linux-2.6.23/net/ipv6/ipv6_sockglue.c 2007-10-22 10:46:02.000000000 +0200
+++ linux-2.6.23-haley/net/ipv6/ipv6_sockglue.c 2007-10-22 09:43:05.000000000 +0200
@@ -249,7 +249,7 @@ static int do_ipv6_setsockopt(struct soc
}
if (ipv6_only_sock(sk) ||
- !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
+ !ipv6_addr_v4mapped(&np->daddr)) {
retv = -EADDRNOTAVAIL;
break;
}
diff -p -u -r -N linux-2.6.23/net/ipv6/tcp_ipv6.c linux-2.6.23-haley/net/ipv6/tcp_ipv6.c
--- linux-2.6.23/net/ipv6/tcp_ipv6.c 2007-10-22 10:46:02.000000000 +0200
+++ linux-2.6.23-haley/net/ipv6/tcp_ipv6.c 2007-10-22 09:43:05.000000000 +0200
@@ -697,7 +697,7 @@ static int tcp_v6_parse_md5_keys (struct
if (!cmd.tcpm_keylen) {
if (!tcp_sk(sk)->md5sig_info)
return -ENOENT;
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
+ if (ipv6_addr_v4mapped(&sin6->sin6_addr))
return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
}
@@ -720,7 +720,7 @@ static int tcp_v6_parse_md5_keys (struct
newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
if (!newkey)
return -ENOMEM;
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) {
+ if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
newkey, cmd.tcpm_keylen);
}
diff -p -u -r -N linux-2.6.23/net/ipv6/udp.c linux-2.6.23-haley/net/ipv6/udp.c
--- linux-2.6.23/net/ipv6/udp.c 2007-10-22 10:46:02.000000000 +0200
+++ linux-2.6.23-haley/net/ipv6/udp.c 2007-10-22 09:43:05.000000000 +0200
@@ -612,7 +612,7 @@ int udpv6_sendmsg(struct kiocb *iocb, st
daddr = NULL;
if (daddr) {
- if (ipv6_addr_type(daddr) == IPV6_ADDR_MAPPED) {
+ if (ipv6_addr_v4mapped(daddr)) {
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = sin6 ? sin6->sin6_port : inet->dport;
diff -p -u -r -N linux-2.6.23/net/sctp/ipv6.c linux-2.6.23-haley/net/sctp/ipv6.c
--- linux-2.6.23/net/sctp/ipv6.c 2007-10-22 10:46:03.000000000 +0200
+++ linux-2.6.23-haley/net/sctp/ipv6.c 2007-10-22 09:43:06.000000000 +0200
@@ -493,7 +493,7 @@ static int sctp_v6_cmp_addr(const union
if (addr1->sa.sa_family != addr2->sa.sa_family) {
if (addr1->sa.sa_family == AF_INET &&
addr2->sa.sa_family == AF_INET6 &&
- IPV6_ADDR_MAPPED == ipv6_addr_type(&addr2->v6.sin6_addr)) {
+ ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) {
if (addr2->v6.sin6_port == addr1->v4.sin_port &&
addr2->v6.sin6_addr.s6_addr32[3] ==
addr1->v4.sin_addr.s_addr)
@@ -501,7 +501,7 @@ static int sctp_v6_cmp_addr(const union
}
if (addr2->sa.sa_family == AF_INET &&
addr1->sa.sa_family == AF_INET6 &&
- IPV6_ADDR_MAPPED == ipv6_addr_type(&addr1->v6.sin6_addr)) {
+ ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) {
if (addr1->v6.sin6_port == addr2->v4.sin_port &&
addr1->v6.sin6_addr.s6_addr32[3] ==
addr2->v4.sin_addr.s_addr)
^ permalink raw reply
* [PATCH 2/2] NFS: handle IPv6 addresses in nfs ctl
From: Aurélien Charbon @ 2007-10-22 11:27 UTC (permalink / raw)
To: Mailing list NFSv4; +Cc: netdev ML
[-- Attachment #1: Type: text/plain, Size: 4050 bytes --]
Here is a second missing part of the IPv6 support in NFS server code
concerning knfd syscall interface.
It updates write_getfd and write_getfd to accept IPv6 addresses.
I've updated it according to Brian's comments, and removed some unused code.
Applies on a kernel including ip_map cache modifications
Tests: tested with only IPv4 network and basic nfs ops (mount, file
creation and modification)
Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---
diff -p -u -r -N linux-2.6.23-ipmap/fs/nfsd/nfsctl.c
linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c
--- linux-2.6.23-ipmap/fs/nfsd/nfsctl.c 2007-10-22 10:32:51.000000000
+0200
+++ linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c 2007-10-22
11:06:13.000000000 +0200
@@ -219,7 +219,7 @@ static ssize_t write_unexport(struct fil
static ssize_t write_getfs(struct file *file, char *buf, size_t size)
{
struct nfsctl_fsparm *data;
- struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
@@ -229,9 +229,20 @@ static ssize_t write_getfs(struct file *
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
err = -EPROTONOSUPPORT;
- if (data->gd_addr.sa_family != AF_INET)
+ switch (data->gd_addr.sa_family) {
+ case AF_INET6:
+ sin6 = &sin6_storage;
+ sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+ ipv6_addr_copy(&in6, &(sin6->sin6_addr));
+ break;
+ case AF_INET:
+ /* Map v4 address into v6 structure */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+ break;
+ default:
goto out;
- sin = (struct sockaddr_in *)&data->gd_addr;
+ }
+
if (data->gd_maxlen > NFS3_FHSIZE)
data->gd_maxlen = NFS3_FHSIZE;
@@ -239,10 +250,7 @@ static ssize_t write_getfs(struct file *
exp_readlock();
- /* IPv6 address mapping */
- ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
-
- if (!(clp = auth_unix_lookup(in6)))
+ if (!(clp = auth_unix_lookup(&in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -258,7 +266,7 @@ static ssize_t write_getfs(struct file *
static ssize_t write_getfd(struct file *file, char *buf, size_t size)
{
struct nfsctl_fdparm *data;
- struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -269,20 +277,30 @@ static ssize_t write_getfd(struct file *
return -EINVAL;
data = (struct nfsctl_fdparm*)buf;
err = -EPROTONOSUPPORT;
- if (data->gd_addr.sa_family != AF_INET)
+ if (data->gd_addr.sa_family != AF_INET && data->gd_addr.sa_family
!= AF_INET6)
goto out;
err = -EINVAL;
if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
goto out;
res = buf;
- sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
-
- /* IPv6 address mapping */
- ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
- if (!(clp = auth_unix_lookup(in6)))
+ switch (data->gd_addr.sa_family) {
+ case AF_INET:
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), ((struct
sockaddr_in *)&data->gd_addr)->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ sin6 = &sin6_storage;
+ sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+ ipv6_addr_copy(&in6, &(sin6->sin6_addr));
+ break;
+ default:
+ BUG();
+ }
+
+ if (!(clp = auth_unix_lookup(&in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
--
********************************
Aurelien Charbon
Linux NFSv4 team
Bull SAS
Echirolles - France
http://nfsv4.bullopensource.org/
********************************
[-- Attachment #2: linux-2.6.23-nfsctl.diff --]
[-- Type: text/x-patch, Size: 3073 bytes --]
diff -p -u -r -N linux-2.6.23-ipmap/fs/nfsd/nfsctl.c linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c
--- linux-2.6.23-ipmap/fs/nfsd/nfsctl.c 2007-10-22 10:32:51.000000000 +0200
+++ linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c 2007-10-22 11:06:13.000000000 +0200
@@ -219,7 +219,7 @@ static ssize_t write_unexport(struct fil
static ssize_t write_getfs(struct file *file, char *buf, size_t size)
{
struct nfsctl_fsparm *data;
- struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh *res;
@@ -229,9 +229,20 @@ static ssize_t write_getfs(struct file *
return -EINVAL;
data = (struct nfsctl_fsparm*)buf;
err = -EPROTONOSUPPORT;
- if (data->gd_addr.sa_family != AF_INET)
+ switch (data->gd_addr.sa_family) {
+ case AF_INET6:
+ sin6 = &sin6_storage;
+ sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+ ipv6_addr_copy(&in6, &(sin6->sin6_addr));
+ break;
+ case AF_INET:
+ /* Map v4 address into v6 structure */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
+ break;
+ default:
goto out;
- sin = (struct sockaddr_in *)&data->gd_addr;
+ }
+
if (data->gd_maxlen > NFS3_FHSIZE)
data->gd_maxlen = NFS3_FHSIZE;
@@ -239,10 +250,7 @@ static ssize_t write_getfs(struct file *
exp_readlock();
- /* IPv6 address mapping */
- ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
-
- if (!(clp = auth_unix_lookup(in6)))
+ if (!(clp = auth_unix_lookup(&in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -258,7 +266,7 @@ static ssize_t write_getfs(struct file *
static ssize_t write_getfd(struct file *file, char *buf, size_t size)
{
struct nfsctl_fdparm *data;
- struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6, sin6_storage;
struct auth_domain *clp;
int err = 0;
struct knfsd_fh fh;
@@ -269,20 +277,30 @@ static ssize_t write_getfd(struct file *
return -EINVAL;
data = (struct nfsctl_fdparm*)buf;
err = -EPROTONOSUPPORT;
- if (data->gd_addr.sa_family != AF_INET)
+ if (data->gd_addr.sa_family != AF_INET && data->gd_addr.sa_family != AF_INET6)
goto out;
err = -EINVAL;
if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
goto out;
res = buf;
- sin = (struct sockaddr_in *)&data->gd_addr;
exp_readlock();
-
- /* IPv6 address mapping */
- ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), (((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr));
- if (!(clp = auth_unix_lookup(in6)))
+ switch (data->gd_addr.sa_family) {
+ case AF_INET:
+ /* IPv6 address mapping */
+ ipv6_addr_set(&in6, 0, 0, htonl(0x0000FFFF), ((struct sockaddr_in *)&data->gd_addr)->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ sin6 = &sin6_storage;
+ sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+ ipv6_addr_copy(&in6, &(sin6->sin6_addr));
+ break;
+ default:
+ BUG();
+ }
+
+ if (!(clp = auth_unix_lookup(&in6)))
err = -EPERM;
else {
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
NFSv4 mailing list
NFSv4@linux-nfs.org
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4
^ permalink raw reply
* Re: [RFC][PATCH 0/3][XFRM]: Support packet processing error statistics.
From: jamal @ 2007-10-22 12:28 UTC (permalink / raw)
To: Masahide NAKAMURA; +Cc: Herbert Xu, David Miller, netdev
In-Reply-To: <11930334662094-git-send-email-nakam@linux-ipv6.org>
On Mon, 2007-22-10 at 15:11 +0900, Masahide NAKAMURA wrote:
> This patch introduces statistics about transformation error (or almost error)
> factor at packet processing for developer.
> It is not a SNMP/MIB specification from IPsec/MIPv6 but a counter
> designed from current transformation source code.
>
> Comment please.
very nice - these stats make IPSEC a lot more usable (I will go look and
see if theres anything that i have used for debug before that you dont
have and send you mail). Two comments:
1) Since these are not MIB stats, it sounds like a good idea not to use
_MIB_ extender in the naming. Maybe something like _NOTMIB_ ;-> or
totaly leave it out. One other approach is to push these to be a MIB at
IETF since they are sensible to have.
2) Why /proc? Are you going to make these available also via netlink?
cheers,
jamal
^ permalink raw reply
* [PATCH 0/5] Diet struct net_device a bit
From: Pavel Emelyanov @ 2007-10-22 12:31 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
There are some pointers, that are used in protocols/drivers/etc
in this struct. E.g. br_port, macvlan_port, ec_ptr, etc. Some of
them can be simply compile out with ifdefs, some require a bit
closer look.
Here's the summary:
Compiled out in this set with appropriate ifdef:
* br_port
* macvlan_port
* dn_ptr
* ec_ptr
* ax25_ptr
Require a closer look:
* atalk_ptr is shared with irda with "should we get our own
field?" comment;
* ip_ptr and
* ip6_ptr are used in headers and gcc complains when trying
to compile net/socket.c that these fields are unreclared;
* ieee80211_ptr is used in many wireless drivers. Need time
to check for the config dependencies.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
^ permalink raw reply
* [PATCH 1/5] Cut off br_port fied from net_device
From: Pavel Emelyanov @ 2007-10-22 12:33 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
In-Reply-To: <471C9830.5070407@openvz.org>
And add the forward declaration for br_handle_frame_hook in
include/linux/if_bridge.h
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 58e43e5..a718586 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -104,6 +104,8 @@ struct __fdb_entry
#include <linux/netdevice.h>
+struct net_bridge_port;
+
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
struct sk_buff *skb);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4a3f54e..469e04f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -699,8 +699,10 @@ struct net_device
/* Network namespace this network device is inside */
struct net *nd_net;
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
/* bridge stuff */
struct net_bridge_port *br_port;
+#endif
/* macvlan */
struct macvlan_port *macvlan_port;
--
1.5.3.4
^ permalink raw reply related
* [PATCH 2/5] Cut off macvlan_port from net_device
From: Pavel Emelyanov @ 2007-10-22 12:34 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
In-Reply-To: <471C9830.5070407@openvz.org>
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 469e04f..c41a5c4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -703,8 +703,10 @@ struct net_device
/* bridge stuff */
struct net_bridge_port *br_port;
#endif
+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
/* macvlan */
struct macvlan_port *macvlan_port;
+#endif
/* class/net/name entry */
struct device dev;
--
1.5.3.4
^ permalink raw reply related
* [PATCH 3/5] Cut off ax25_ptr from net_device
From: Pavel Emelyanov @ 2007-10-22 12:35 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
In-Reply-To: <471C9830.5070407@openvz.org>
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c41a5c4..504f843 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -580,7 +580,9 @@ struct net_device
void *dn_ptr; /* DECnet specific data */
void *ip6_ptr; /* IPv6 specific data */
void *ec_ptr; /* Econet specific data */
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
void *ax25_ptr; /* AX.25 specific data */
+#endif
struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
assign before registering */
--
1.5.3.4
^ permalink raw reply related
* [PATCH 4/5] Cut off ec_ptr from net_device
From: Pavel Emelyanov @ 2007-10-22 12:36 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
In-Reply-To: <471C9830.5070407@openvz.org>
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 504f843..472d9cc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -579,7 +579,9 @@ struct net_device
void *ip_ptr; /* IPv4 specific data */
void *dn_ptr; /* DECnet specific data */
void *ip6_ptr; /* IPv6 specific data */
+#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
void *ec_ptr; /* Econet specific data */
+#endif
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
void *ax25_ptr; /* AX.25 specific data */
#endif
--
1.5.3.4
^ permalink raw reply related
* [PATCH 5/5] Cut off dn_ptr from net_device
From: Pavel Emelyanov @ 2007-10-22 12:37 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, devel
In-Reply-To: <471C9830.5070407@openvz.org>
And remove a BUG_TRAP from netdev_run_todo as well.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 472d9cc..e94c636 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -577,7 +577,9 @@ struct net_device
void *atalk_ptr; /* AppleTalk link */
void *ip_ptr; /* IPv4 specific data */
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
void *dn_ptr; /* DECnet specific data */
+#endif
void *ip6_ptr; /* IPv6 specific data */
#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
void *ec_ptr; /* Econet specific data */
diff --git a/net/core/dev.c b/net/core/dev.c
index 8726589..3ac35fe 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3781,7 +3781,9 @@ void netdev_run_todo(void)
BUG_ON(atomic_read(&dev->refcnt));
BUG_TRAP(!dev->ip_ptr);
BUG_TRAP(!dev->ip6_ptr);
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
BUG_TRAP(!dev->dn_ptr);
+#endif
if (dev->destructor)
dev->destructor(dev);
--
1.5.3.4
^ permalink raw reply related
* Re: [Devel] [PATCH 1/5] Cut off br_port fied from net_device
From: Alexey Dobriyan @ 2007-10-22 12:49 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List, devel
In-Reply-To: <471C989D.9030207@openvz.org>
On Mon, Oct 22, 2007 at 04:33:33PM +0400, Pavel Emelyanov wrote:
> And add the forward declaration for br_handle_frame_hook in
> include/linux/if_bridge.h
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -699,8 +699,10 @@ struct net_device
> /* Network namespace this network device is inside */
> struct net *nd_net;
>
> +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
> /* bridge stuff */
> struct net_bridge_port *br_port;
> +#endif
Such ifdefs are troublesome, because one can compile kernel with
CONFIG_BRIDGE=n and later decide he needs BRIDGE=m and go boom.
IPv6 -- the biggest violator of this rule should not be taken as
example. :^)
^ permalink raw reply
* Re: [Devel] [PATCH 1/5] Cut off br_port fied from net_device
From: Pavel Emelyanov @ 2007-10-22 13:02 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: David Miller, Linux Netdev List, devel
In-Reply-To: <20071022124915.GD6271@localhost.sw.ru>
Alexey Dobriyan wrote:
> On Mon, Oct 22, 2007 at 04:33:33PM +0400, Pavel Emelyanov wrote:
>> And add the forward declaration for br_handle_frame_hook in
>> include/linux/if_bridge.h
>
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -699,8 +699,10 @@ struct net_device
>> /* Network namespace this network device is inside */
>> struct net *nd_net;
>>
>> +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
>> /* bridge stuff */
>> struct net_bridge_port *br_port;
>> +#endif
>
> Such ifdefs are troublesome, because one can compile kernel with
> CONFIG_BRIDGE=n and later decide he needs BRIDGE=m and go boom.
You will have to recompile the whole kernel when this config
is on. Look at netif_receive_skb() ;)
> IPv6 -- the biggest violator of this rule should not be taken as
> example. :^)
>
>
^ permalink raw reply
* RE: [PATCH] [POWERPC] ucc_geth: Eliminate compile warnings
From: Medve Emilian-EMMEDVE1 @ 2007-10-22 13:47 UTC (permalink / raw)
To: David Miller; +Cc: jgarzik, Li Yang-r58472, netdev, linuxppc-dev
In-Reply-To: <20071019.164143.75786621.davem@davemloft.net>
Hello David,
> No piece of code in the kernel should live in a vacuum.
>
> In order to improve overall code quality, every piece of
> driver code should avoid assuming things about pointer
> sizes and things of this nature.
I'm afraid we might be talking about orthogonal issues here. I actively
agree that all code (not only kernel) should be written up to the
coding/quality standards you mention above, but I see a difference
between fixing a warning and making a driver portable (to 64-bit
PowerPCs, to other platforms, etc.). If there is a kernel todo list
somewhere lets add to it the task to make the ucc_geth more portable.
> Then the driver can get enabled into the build on every
> platform, and therefore nobody will break the build of
> this driver again since it will get hit by "allmodconfig"
> et al. builds even on platforms other than the one it is
> meant for.
>
> This hack fix is not acceptable, really.
Are you suggesting we leave those warnings there until somebody decides
to fix all the portability issues of this driver? My patch is a small
and insignificant improvement and not the revolution you're asking for,
but is an small improvement today (I dislike warnings) vs. an improbable
big one in the future.
Leo, as author and maintainer of this driver, what's your take on this?
Cheers,
Emil.
^ permalink raw reply
* RE: e100 problems in .23rc8 ?
From: David Mack @ 2007-10-22 14:05 UTC (permalink / raw)
To: Dave Jones, Kok, Auke; +Cc: Herbert Xu, netdev, esandeen
In-Reply-To: <20071022010440.GA11165@redhat.com>
Then I got very, very lucky, since I have successfully rebooted
2.6.23.1-23.fc8 four times (zero panics) and this is the first time a
2.6.23 kernel has not panicked on me in months.
This does not fill me with confidence in the theory that the panics I've
been seeing are due to a race condition.
Dave
> -----Original Message-----
> From: Dave Jones [mailto:davej@redhat.com]
> Sent: Sunday, October 21, 2007 6:05 PM
> To: Kok, Auke
> Cc: David Mack; Herbert Xu; netdev@vger.kernel.org;
> esandeen@redhat.com
> Subject: Re: e100 problems in .23rc8 ?
>
> On Thu, Oct 18, 2007 at 10:59:59AM -0700, Kok, Auke wrote:
> > David Mack wrote:
> > > It appears that the needed e100 fix made it into the Fedora
> > > 2.6.23.1-23.fc8 kernel. Boots reliably now.
> > >
> > > Huge thanks and great work, guys.
> >
> > DaveJ, I didn't push anything upstream. Can you verify
> this now works?
>
> There was no e100 changes in the kernel above, so David just
> got lucky. (The race doesn't always occur, so it sometimes appears
> something got fixed.).
>
> I included the patch below in the latest build, but I've not had
> chance to try it on an e100 box yet..
>
> Dave
>
> --- linux-2.6.23.noarch/drivers/net/e100.c~ 2007-10-18
> 16:10:40.000000000 -0400
> +++ linux-2.6.23.noarch/drivers/net/e100.c 2007-10-18
> 16:16:02.000000000 -0400
> @@ -2682,6 +2682,8 @@ static int __devinit e100_probe(struct p
> if (err)
> DPRINTK(PROBE, ERR, "Error clearing wake event\n");
>
> + netif_poll_disable(netdev);
> +
> strcpy(netdev->name, "eth%d");
> if((err = register_netdev(netdev))) {
> DPRINTK(PROBE, ERR, "Cannot register net
> device, aborting.\n");
>
> --
> http://www.codemonkey.org.uk
>
^ permalink raw reply
* appletalk bugs
From: Gabriel C @ 2007-10-22 14:19 UTC (permalink / raw)
To: Linux Kernel Mailing List; +Cc: netdev, Eric W. Biederman
Hi,
modprobing appletalk on current git gives a warning in dmesg :
[38506.600269] sysctl table check failed: /net/appletalk .3.7 procname does not match binary path procname
on rmmod appletalk I get an Oops :
[38541.525258] BUG: unable to handle kernel NULL pointer dereference at virtual address 0000000c
[38541.525266] printing eip: c011d4f0 *pde = 00000000
[38541.525274] Oops: 0000 [#1] PREEMPT SMP
[38541.525282] Modules linked in: appletalk psnap llc pc87360 hwmon_vid eeprom adm1021 sr_mod shpchp pci_hotplug iTCO_wdt iTCO_vendor_support intel_agp i82860_edac i2c_i801 edac_core cdrom agpgart 3c59x mii ext4dev jbd2 crc16 loop lp parport_pc parport evdev
[38541.525312]
[38541.525316] Pid: 28887, comm: rmmod Not tainted (2.6.23-gcfa76f02 #341)
[38541.525321] EIP: 0060:[<c011d4f0>] EFLAGS: 00010202 CPU: 0
[38541.525334] EIP is at unregister_sysctl_table+0x11/0x70
[38541.525339] EAX: 00000001 EBX: e8ef2180 ECX: 00000002 EDX: 00000000
[38541.525343] ESI: 00000000 EDI: 00000880 EBP: cc094000 ESP: cc095f38
[38541.525347] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[38541.525352] Process rmmod (pid: 28887, ti=cc094000 task=e0da0560 task.ti=cc094000)
[38541.525355] Stack: 00000001 00000296 cebf5020 fffffff5 00000880 e8ef2180 00000000 e8eed5b1
[38541.525367] c01353b2 6c707061 6c617465 b7ee006b e0da0560 c01101fd 00000000 c2bf3a50
[38541.525378] c0148684 ffffffff b7fd5000 c31a2004 b7fd4000 b7fd5000 00000004 00095fb8
[38541.525389] Call Trace:
[38541.525395] [<e8eed5b1>] atalk_exit+0x5/0x4b [appletalk]
[38541.525410] [<c01353b2>] sys_delete_module+0x187/0x1b5
[38541.525420] [<c01101fd>] do_page_fault+0x18b/0x51a
[38541.525426] [<c0148684>] do_munmap+0x19b/0x1b4
[38541.525437] [<c01026fa>] sysenter_past_esp+0x5f/0x85
[38541.525448] =======================
[38541.525450] Code: ff ff ff f7 d8 eb 06 c7 03 00 00 00 00 e8 65 df ff ff 89 07 31 c0 5b 5e 5f c3 56 53 83 ec 14 89 c6 b8 b8 1c 3c c0 e8 c6 42 1f 00 <83> 7e 0c 00 74 2e c7 04 24 00 00 00 00 8d 44 24 04 e8 66 a2 00
[38541.525502] EIP: [<c011d4f0>] unregister_sysctl_table+0x11/0x70 SS:ESP 0068:cc095f38
[38541.525513] note: rmmod[28887] exited with preempt_count 1
Regards,
Gabriel C
^ permalink raw reply
* [patch 2/2] s390 MAINTAINERS
From: Ursula Braun @ 2007-10-22 14:16 UTC (permalink / raw)
To: jgarzik, netdev, linux-s390
Cc: frank.blaschka, mschwid2, heicars2, apw, kamalesh, kaber,
shemminger
In-Reply-To: <20071022141613.957690000@linux.vnet.ibm.com>
[-- Attachment #1: maintainer.patch --]
[-- Type: text/plain, Size: 703 bytes --]
From: Ursula Braun <braunu@de.ibm.com>
adding Frank Blaschka to s390 networking maintainers
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
---
MAINTAINERS | 2 ++
1 file changed, 2 insertions(+)
Index: linux-2.6-uschi/MAINTAINERS
===================================================================
--- linux-2.6-uschi.orig/MAINTAINERS
+++ linux-2.6-uschi/MAINTAINERS
@@ -3246,6 +3246,8 @@ S: Supported
S390 NETWORK DRIVERS
P: Ursula Braun
M: ubraun@linux.vnet.ibm.com
+P: Frank Blaschka
+M: blaschka@linux.vnet.ibm.com
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
--
^ permalink raw reply
* [patch 0/2] remove header_ops bug in qeth driver (part 2)
From: Ursula Braun @ 2007-10-22 14:16 UTC (permalink / raw)
To: jgarzik, netdev, linux-s390
Cc: frank.blaschka, mschwid2, heicars2, apw, kamalesh, kaber,
shemminger
--
Jeff,
another patch in include/linux/netdevice.h is necessary
to solve the qeth bug of 2.6.23-git
And an update of the MAINTAINERS file is appended.
Regards, Ursula Braun
^ permalink raw reply
* [patch 1/2] : remove header_ops bug in qeth driver
From: Ursula Braun @ 2007-10-22 14:16 UTC (permalink / raw)
To: jgarzik, netdev, linux-s390
Cc: frank.blaschka, mschwid2, heicars2, apw, kamalesh, kaber,
shemminger
In-Reply-To: <20071022141613.957690000@linux.vnet.ibm.com>
[-- Attachment #1: qeth.patch --]
[-- Type: text/plain, Size: 945 bytes --]
From: Ursula Braun <braunu@de.ibm.com>
Remove qeth bug caused by commit:
[NET]: Move hardware header operations out of netdevice.
This is the second part of the qeth header_ops patch, since
first patch sent 10/19 has been insufficient.
Nevertheless first patch is still valid and should be kept.
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
---
include/linux/netdevice.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6-uschi/include/linux/netdevice.h
===================================================================
--- linux-2.6-uschi.orig/include/linux/netdevice.h
+++ linux-2.6-uschi/include/linux/netdevice.h
@@ -834,7 +834,7 @@ static inline int dev_hard_header(struct
const void *daddr, const void *saddr,
unsigned len)
{
- if (!dev->header_ops)
+ if (!dev->header_ops || !dev->header_ops->create)
return 0;
return dev->header_ops->create(skb, dev, type, daddr, saddr, len);
--
^ permalink raw reply
* Re: e100 problems in .23rc8 ?
From: Chuck Ebbert @ 2007-10-22 14:44 UTC (permalink / raw)
To: Kok, Auke; +Cc: Dave Jones, David Mack, Herbert Xu, netdev, esandeen
In-Reply-To: <47179F1F.3030202@intel.com>
On 10/18/2007 01:59 PM, Kok, Auke wrote:
> David Mack wrote:
>> It appears that the needed e100 fix made it into the Fedora
>> 2.6.23.1-23.fc8 kernel. Boots reliably now.
>>
>> Huge thanks and great work, guys.
>
>
> DaveJ, I didn't push anything upstream. Can you verify this now works?
>
One of our users just posted this:
We observed the same panic on a Dell Dimension 5150 (E510), although not
limited to warm boots. We noticed that the following trace is possible:
- when starting the interface, e100_up() gets called
- it calls e100_hw_init(), which disables e100 IRQ generation
(e100_disable_irq())
- it registers the interrupt handler
- the interrupt handler (e100_intr()) gets called - this happens because the
IRQ line is shared with another device (in this case, the SATA controller)
- the interrupt handler examines the stat_ack register of the interface: even
though interrupts are disabled, an event is indicated and the interrupt handler
proceeds
- the interrupt handler calls netif_rx_schedule_prep(), which sets the
__LINK_STATE_RX_SCHED bit, and __netif_rx_schedule(), which adds the interface
to the poll list
- when the interrupt handler returns, e100_up() calls netif_poll_enable(), thus
clearing the __LINK_STATE_RX_SCHED bit
- now the NET RX softirq (net_rx_action) calls e100_poll(), which in turn calls
netif_rx_complete()
- netif_rx_complete() checks whether the __LINK_STATE_RX_SCHED bit is set and
triggers the panic
To avoid this situation, where the interrupt handler executes although e100
interrupts are disabled, we suggest the attached patch. It lets the interrupt
handler check the interrupt mask bit before proceeding with the interrupt
handling.
Authors: Christof Efkemann <chref@tzi.de>, Kai Thomsen <kthomsen@tzi.de>
Description:
Avoid interrupt handler execution if e100 interrupts are disabled.
Checks the interrupt mask bit before proceeding with the interrupt handling.
--- drivers/net/e100.c.old 2007-10-20 18:32:40.000000000 +0200
+++ drivers/net/e100.c 2007-10-20 18:36:02.000000000 +0200
@@ -1960,11 +1960,13 @@
struct net_device *netdev = dev_id;
struct nic *nic = netdev_priv(netdev);
u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
+ u8 cmd_hi = ioread8(&nic->csr->scb.cmd_hi);
DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
if(stat_ack == stat_ack_not_ours || /* Not our interrupt */
- stat_ack == stat_ack_not_present) /* Hardware is ejected */
+ stat_ack == stat_ack_not_present || /* Hardware is ejected */
+ cmd_hi & irq_mask_all) /* Interrupts masked */
return IRQ_NONE;
/* Ack interrupt(s) */
^ permalink raw reply
* Re: [PATCH 1/6] Convert bonding timers to workqueues
From: Mike Snitzer @ 2007-10-22 14:55 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Jay Vosburgh, netdev, andy
In-Reply-To: <20038.1192475339@death>
On 10/15/07, Jay Vosburgh <fubar@us.ibm.com> wrote:
> Jeff Garzik <jgarzik@pobox.com> wrote:
>
> >Jay Vosburgh wrote:
> >> Convert bonding timers to workqueues. This converts the various
> >> monitor functions to run in periodic work queues instead of timers. This
> >> patch introduces the framework and convers the calls, but does not resolve
> >> various locking issues, and does not stand alone.
> >>
> >> Signed-off-by: Andy Gospodarek <andy@greyhouse.net>
> >> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
> >
> >"does not stand alone" == it is not bisectable? That's a problem.
>
> The patch will compile fine (this is true for any point in the
> series), but it's possible for bonding to deadlock or misbehave when
> doing certain operations. Those problems are addressed in the later
> patches.
>
> I didn't want to just vomit out one big mega-patch that has the
> whole set of changes, because that's harder to understand, and the later
> patches generally address discrete issues.
>
> Does that make you more or less nervous about its bisectability?
> I can repost the whole thing as a big blob if that's what you'd prefer.
>
> >Anyway, we have more fun fish to fry: after applying the IPoIB bonding
> >patchset, this no longer applies...
>
> Yah, I'll rebase it (once I know your blob vs. not-blob
> preference). I wasn't sure how long the IPoIB mystery bug hunt was
> going to take.
Jeff,
Given that Jay rebased and posted updated bonding locking patches on
Oct 17 will you be pushing them for inclusion in 2.6.24-rc1? or
2.6.24-rcX? I don't see them queued in your netdev-2.6 tree. These
bonding locking issues have been a problem for some time and it would
be very good to get them fixed upstream sooner rather than later.
thanks,
Mike
^ permalink raw reply
* Re: e100 problems in .23rc8 ?
From: Eric Sandeen @ 2007-10-22 14:59 UTC (permalink / raw)
To: David Mack; +Cc: Dave Jones, Kok, Auke, Herbert Xu, netdev, esandeen
In-Reply-To: <7DCDA0F058071B49AED9D3D7886C41BE0A43B10E@muon.jnpr.net>
David Mack wrote:
> Then I got very, very lucky, since I have successfully rebooted
> 2.6.23.1-23.fc8 four times (zero panics) and this is the first time a
> 2.6.23 kernel has not panicked on me in months.
>
> This does not fill me with confidence in the theory that the panics I've
> been seeing are due to a race condition.
I'll agree with the testing results, at least. I booted successfully
*60* times with 2.6.23.1-23.fc8, booting the stock F8test3 kernel would
oops every 5 or 6 boots.
It may well be a race, but if so something is apparently opening/closing
the window on us! :)
-Eric
^ permalink raw reply
* Re: [PATCH] wan: new driver retina
From: Randy Dunlap @ 2007-10-22 15:02 UTC (permalink / raw)
To: Matti Linnanvuori; +Cc: akpm, jgarzik, netdev
In-Reply-To: <720714.25776.qm@web52011.mail.re2.yahoo.com>
On Mon, 22 Oct 2007 04:14:57 -0700 (PDT) Matti Linnanvuori wrote:
> From: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
>
> Retina G.703 and G.SHDSL driver.
>
> Signed-off-by: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
> ---
Hi,
Just a few basic questions... I'm not reviewing any of the code parts.
> Fixed Kconfig and the body of the explanation.
>
> diff -Napur
> linux-2.6.23/drivers/net/wan/Kconfig
> linux-2.6.24/drivers/net/wan/Kconfig
> --- linux-2.6.23/drivers/net/wan/Kconfig 2007-10-09 23:31:38.000000000 +0300
> +++ linux-2.6.24/drivers/net/wan/Kconfig 2007-10-22 13:54:55.383644167 +0300
> @@ -494,4 +494,15 @@ config SBNI_MULTILINE
>
> If unsure, say N.
>
> +config RETINA
> + tristate "Retina support"
> + depends on m && PCI
> + help
> + Driver for Retina C5400 and E2200 network cards, which
> + support G.703, G.SHDSL, Ethernet encapsulation and PCI.
> +
> + The driver will be compiled as a module: the
> + module will be called retina.
Why is the driver restricted/limited to module only?
> +
> endif # WAN
> diff -Napur linux-2.6.23/drivers/net/wan/retina.c linux-2.6.24/drivers/net/wan/retina.c
> --- linux-2.6.23/drivers/net/wan/retina.c 1970-01-01 02:00:00.000000000 +0200
> +++ linux-2.6.24/drivers/net/wan/retina.c 2007-10-22 12:01:44.856033562 +0300
> @@ -0,0 +1,4503 @@
> +/* V1.2.4 */
> +
> +/* retina.c: */
> +
> +
> +#define DRV_NAME "retina"
> +#define DRV_VERSION "1.2.5"
> +#define DRV_RELDATE "November 14, 2003"
huh?
> +#if !defined(__OPTIMIZE__)
> +#warning You must compile this file with correct options.
> +#warning See the last lines of the source file.
> +#error You have to compile this driver with "-O".
> +#endif
What defines __OPTIMIZE__ in the kernel build environment?
> diff -Napur linux-2.6.23/drivers/net/wan/retina.h linux-2.6.24/drivers/net/wan/retina.h
> --- linux-2.6.23/drivers/net/wan/retina.h 1970-01-01 02:00:00.000000000 +0200
> +++ linux-2.6.24/drivers/net/wan/retina.h 2007-10-22 12:01:44.856033562 +0300
> @@ -0,0 +1,164 @@
> diff -Napur linux-2.6.23/MAINTAINERS linux-2.6.24/MAINTAINERS
> --- linux-2.6.23/MAINTAINERS 2007-10-09 23:31:38.000000000 +0300
> +++ linux-2.6.24/MAINTAINERS 2007-10-22 11:50:13.190983316 +0300
> @@ -3149,6 +3149,11 @@ L: reiserfs-devel@vger.kernel.org
> W: http://www.namesys.com
> S: Supported
>
> +RETINA DRIVER
> +P: Matti Linnanvuori
> +M: mattilinnanvuori@yahoo.com
and what mailing list?
> +S: Supported
> +
> ROCKETPORT DRIVER
> P: Comtrol Corp.
> W: http://www.comtrol.com
---
~Randy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox