* Re: [PATCH] fix ACK processing after netlink_dump_start
From: Thomas Graf @ 2007-10-23 16:34 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: dcbw, jfannin, davem, netdev, kuznet
In-Reply-To: <20071023144023.GA15035@iris.sw.ru>
* Denis V. Lunev <den@openvz.org> 2007-10-23 18:40
> Revert to original netlink behavior. Do not reply with ACK if the
> netlink dump has bees successfully started.
>
> libnl has been broken by the cd40b7d3983c708aabe3d3008ec64ffce56d33b0
> The following command reproduce the problem:
> /nl-route-get 192.168.1.1
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
ACK. Thank you for taking care of this.
^ permalink raw reply
* Re: [PATCH] wan: new driver retina
From: Stephen Hemminger @ 2007-10-23 16:31 UTC (permalink / raw)
To: Matti Linnanvuori; +Cc: akpm, jgarzik, netdev
In-Reply-To: <956438.34005.qm@web52003.mail.re2.yahoo.com>
On Tue, 23 Oct 2007 02:58:29 -0700 (PDT)
Matti Linnanvuori <mattilinnanvuori@yahoo.com> wrote:
> From: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
>
> Retina G.703 and G.SHDSL driver.
>
> Signed-off-by: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
> ---
>
> Fixed bugs according to linux-netdev comments.
>
> 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-23 12:30:45.853384514 +0300
> @@ -494,4 +494,14 @@ config SBNI_MULTILINE
>
> If unsure, say N.
>
> +config RETINA
> + tristate "Retina support"
> + depends on PCI
> + help
> + Driver for Retina C5400 and E2200 network PCI cards, which
> + support G.703, G.SHDSL with Ethernet encapsulation.
> +
> + To compile this driver as a module, choose M here: 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-23 12:31:17.598640178 +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-23 12:52:17.122802714 +0300
> @@ -0,0 +1,4428 @@
> +/* 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.
> +*/
> +
> +#define DRV_NAME "retina"
> +#define DRV_VERSION "1.2.6"
> +
> +#define DBG_PRINT(xyz...) /* printk(KERN_DEBUG xyz) */
pr_debug()
> +/* uncomment this if you want to have debug files in /proc
> + * #define DEBUG_PROC_FILES */
> +
> +/* Keep 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 */
You can't use /proc for this in new drivers. Either:
1. Remove the code since it doesn't do anything useful
2. Convert it to use debugfs (see skge and sky2)
3. Convert it to use sysfs attributes.
> +/* Time in jiffies before concluding that the transmitter is hung */
> +#define TX_TIMEOUT (20*HZ)
Pretty long.
> +#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);
> +
> +/* PCI I/O space extent */
> +#define FEPCI_SIZE 0x20000
> +#define PCI_IOTYPE (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)
> +
> +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;
> + unsigned 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,},
> +};
You shouldn't need this if you use current pci device discovery
methods.
> +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,}
> +};
You might want to add PCI_VENDOR_ID_FEPCI to pci_ids.h
> +MODULE_DESCRIPTION("Frame Engine for PCI (FEPCI)");
> +MODULE_AUTHOR("Jouni Kujala");
> +MODULE_LICENSE("GPL");
> +MODULE_DEVICE_TABLE(pci, fepci_pci_tbl);
> +
> +/* Linux 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 Linux 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 */
> + unsigned bufsize;
> + unsigned unit_sz_order; /* 8=256B...14=16kB */
> + unsigned 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;
> + unsigned 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 */
Why are you using regular major/minor for a network device?
Any local variable like this has to be declared static so
as not to pollute the namespace of the whole kernel.
> +struct fepci_card_private card_privates[MAX_DEVICES];
> +unsigned long stream_pointers;
> +struct proc_dir_entry *proc_root_entry;
More name space pollution
> +void set_int_mask(int channel, u_char value, struct fepci_card_private *cp)
> +{
> + void *address;
> + unsigned shift, oldvalue;
> + DBG_PRINT("set_int_mask\n");
> + address = (cp->ioaddr) + reg_first_int_mask + (channel / 4L) * 4L;
> + shift = 8L * (channel % 4L);
> + oldvalue = readl((void *)address);
> + oldvalue &= ~(0xff << shift); /* clear bits */
> + oldvalue |= value << shift; /* set bits */
> + writel(oldvalue, (void *)address);
> +}
All these have to be declared static.
> +u_char get_int_mask(int channel, void *ioaddr)
> +{
> + void *address;
> + unsigned shift, oldvalue;
> + DBG_PRINT("get_int_mask\n");
> + address = ioaddr + reg_first_int_mask + (channel / 4L) * 4L;
> + shift = 8L * (channel % 4L);
> + oldvalue = readl((void *)address);
> + oldvalue &= (0xff << shift); /* clear other bits */
> + return (oldvalue >> shift);
> +}
> +
> +void clear_int(int channel, u_char value, void *ioaddr)
> +{
> + void *address;
> + unsigned shift, longvalue;
> + DBG_PRINT("clear_int\n");
> + address = ioaddr + reg_first_int_status + (channel / 4L) * 4L;
> + shift = 8L * (channel % 4L);
> + longvalue = value << shift;
> + writel(~longvalue, (void *)address);
> +}
> +
> +u_char get_int_status(int channel, void *ioaddr)
> +{
> + void *address;
> + unsigned shift, oldvalue;
> + DBG_PRINT("get_int_status\n");
> + address = ioaddr + reg_first_int_status + (channel / 4L) * 4L;
> + shift = 8L * (channel % 4L);
> + oldvalue = readl((void *)address);
> + oldvalue &= (0xff << shift); /* clear other bits */
> + return (oldvalue >> shift);
> +}
> +
> +void fillregisterswith_00(void *ioaddr)
> +{
> + DBG_PRINT("fillregisterswith_00\n");
> + writel(0x0, (void *)(ioaddr + reg_first_rxctrl));
> + writel(0x0, (void *)(ioaddr + reg_first_txctrl));
> + writel(0x0, (void *)(ioaddr + reg_first_int_mask));
> + writel(0x0, (void *)(ioaddr + reg_first_int_status));
> + writel(0x0, (void *)(ioaddr + first_rx_desc));
> + writel(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,
> +};
Please use C99 style initializers not old Gcc style.
> +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;
> +}
If you use owner properly on proc files, you won't need to be
dorking with module ref counts.
> +
> +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->vm_pgoff << PAGE_SHIFT;
> + unsigned long size = vma->vm_end - vma->vm_start;
> +
> + unsigned long 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 =
> + (unsigned long)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 =
> + (unsigned long)card_privates[card].
> + ch_privates[channel]->tx_buffer;
> + else
> + goto INVALID;
> + } else {
> +INVALID:
> + DBG_PRINT("%s: mmap: invalid address 0x%lx\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)
> +{
> + unsigned number = readl(&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);
> + writel(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 (unlikely(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 (unlikely(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 (unlikely(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) {
> + rx_order = 0;
> + tx_order = 0;
> + rx_pages = 1;
> + tx_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++) {
> + writel(0, &fp->rx_desc[i].desc_a);
> + writel(0, &fp->rx_desc[i].desc_b);
> + }
> + for (i = 0; i < TX_RING_SIZE; i++) {
> + writel(0, &fp->tx_desc[i].desc_a);
> + writel(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++) {
> + dma_addr_t 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);
> + if (unlikely(pci_dma_mapping_error(address)))
> + printk(KERN_WARNING
> + "%s: failed to map DMA buffer.\n", fepci_NAME);
> + else {
> + writel(address,
> + &fp->rx_desc[(fp->cur_rx + i) &
> + (RX_RING_SIZE - 1)].desc_a);
> + if (!
> + (readl
> + (&fp->
> + rx_desc[(fp->cur_rx + i) & (RX_RING_SIZE -
> + 1)].
> + desc_b) & enable_transfer))
> + writel(enable_transfer,
> + &fp->rx_desc[(fp->cur_rx + i) %
> + RX_RING_SIZE].desc_b);
> + }
> + 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);
> + writel(address,
> + &fp->
> + tx_desc[(fp->cur_tx + i) & (TX_RING_SIZE - 1)].desc_a);
> + if (unlikely(pci_dma_mapping_error(address)))
> + printk(KERN_WARNING
> + "%s: failed to map DMA buffer.\n", fepci_NAME);
> + else {
> + if (!
> + (readl
> + (&fp->
> + tx_desc[(fp->cur_tx + i) & (TX_RING_SIZE -
> + 1)].
> + desc_b) & enable_transfer))
> + writel(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 */
> + writel(Receive_enable |
> + (Rx_fifo_threshold & RX_FIFO_THRESHOLD_STREAM_MODE),
> + (void *)(ioaddr + fp->reg_rxctrl));
> + writel((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. */
> + writel(0x0, (void *)(ioaddr + fp->reg_rxctrl));
> + writel(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 {
> + dma_addr_t bus_address = readl(&fp->rx_desc[i].desc_a);
> + if (likely(!pci_dma_mapping_error(bus_address)))
> + pci_unmap_single(fp->this_card_priv->
> + pci_dev, bus_address,
> + fp->unit_sz,
> + PCI_DMA_FROMDEVICE);
> + bus_address = readl(&fp->tx_desc[i].desc_a);
> + if (likely(!pci_dma_mapping_error(bus_address)))
> + 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) {
> + rx_order = 0;
> + tx_order = 0;
> + rx_pages = 1;
> + tx_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((unsigned long)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((unsigned long)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;
> + unsigned 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 ((readl(&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))) {
> + dma_addr_t bus_address = readl(&fp->rx_desc[fp->cur_rx].
> + desc_a);
> + if (likely(!pci_dma_mapping_error(bus_address)))
> + 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) {
> + unsigned desc_b = readl(&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;
> + unsigned length = desc_b & frame_length;
> + dma_addr_t 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);
> + if (likely(!pci_dma_mapping_error(bus_address))) {
> + writel(bus_address,
> + &fp->rx_desc[temp_rx].desc_a);
> + writel(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 ((readl(&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))) {
> + dma_addr_t bus_address = readl(&fp->tx_desc[fp->cur_tx].
> + desc_a);
> + if (likely(!pci_dma_mapping_error(bus_address)))
> + 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) {
> + unsigned desc_b = readl(&fp->tx_desc[temp_tx].desc_b);
> + if ((desc_b & transfer_not_done) == 0) {
> + dma_addr_t 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);
> + writel(bus_address, &fp->tx_desc[temp_tx].desc_a);
> + if (likely(!pci_dma_mapping_error(bus_address)))
> + writel(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 intr_status ? IRQ_HANDLED : IRQ_NONE;
> +}
> +
> +/* 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 (readl((void *)(ioaddr + reg_custom)) & AM_interrupt_status) {
> + /* clear int (zero everything, but the mask bit) */
> + writel(readl((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;
> + 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;
> + unsigned j;
> + resource_size_t real_ioaddr;
> + void *ioaddr;
> + unsigned position;
> +
> + i = pci_enable_device(pdev);
> + 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));
> + writel(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+'0'; channel number -> ascii */
> + /* minor number -> ascii */
> + dev->name[4] = ((fp->minor * CHANNELS + j) % 10) + '0';
> + /* minor number -> ascii */
> + dev->name[3] = ((fp->minor * CHANNELS + j) / 10) + '0';
> +
> + 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);
> +
> + random_ether_addr(dev->dev_addr);
> + /* 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);
> + writel(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, 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. */
> + writel(Receive_enable |
> + (Rx_fifo_threshold & RX_FIFO_THRESHOLD_PACKET_MODE),
> + (void *)(ioaddr + fp->reg_rxctrl));
> +
> + writel((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 {
> + unsigned desc_b;
> + if ((fp->tx_skbuff[i] != NULL)
> + &&
> + (((desc_b =
> + readl(&fp->tx_desc[i].
> + desc_b)) & transfer_not_done) ==
> + 0)) {
> + /* has been sent */
> + pci_unmap_single(fp->
> + this_card_priv->
> + pci_dev,
> + readl(&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 (!
> + (readl(&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 (unlikely(skb == NULL)) {
> +ZERO:
> + writel(0, &fp->rx_desc[i].desc_a);
> + writel(0, &fp->rx_desc[i].desc_b);
> + continue;
> + } else {
> + dma_addr_t 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;
> + writel(bus_address, &fp->rx_desc[i].desc_a);
> + writel(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;
> + writel(0, &fp->tx_desc[i].desc_a); /* no skbuff */
> + /* no transfer enable, no int enable */
> + writel(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;
> + unsigned next;
> + unsigned tx_length = skb->len;
> + dma_addr_t bus_address;
> + struct sk_buff *old;
> +
> + fp->tx_skbuffs_in++;
> +
> + 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];
> + writel(bus_address, &descriptor->desc_a);
> + writel((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 */
> + 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;
> + unsigned 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;
> + unsigned next;
> + do {
> + unsigned desc_b;
> + if ((fp->tx_skbuff[i] != NULL)
> + &&
> + (((desc_b =
> + readl(&fp->tx_desc[i].
> + desc_b)) & transfer_not_done) ==
> + 0)) {
> + /* has been sent */
> + pci_unmap_single(fp->
> + this_card_priv->
> + pci_dev,
> + readl(&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--);
> + next = fp->cur_tx;
> + /* if next tx descriptor is free,
> + * continue taking new ones */
> + if (!(readl(&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)) {
> + unsigned desc_b;
> + struct sk_buff *skb;
> + /* transfer done */
> + bool condition = (skb = fp->rx_skbuff[i]) &&
> + ((desc_b =
> + readl(&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;
> + unsigned length = desc_b & frame_length;
> + pci_unmap_single(fp->this_card_priv->pci_dev,
> + readl(&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++;
> + writel(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++;
> + writel(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++;
> + writel(enable_transfer, &fp->rx_desc[i].desc_b);
> + } else if (octet) {
> + fp->rx_desc_octet_err++;
> + writel(enable_transfer, &fp->rx_desc[i].desc_b);
> + } else if (line) {
> + fp->rx_desc_line_err++;
> + writel(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 {
> + dma_addr_t 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];
> + writel(address, &descriptor->desc_a);
> + writel(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 */
> + writel(0x0, ioaddr + fp->reg_rxctrl);
> + writel(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,
> + readl(&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,
> + readl(&fp->tx_desc[i].
> + desc_a),
> + readl(&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 = ((unsigned)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;
> +
> + writel(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 =
> + (unsigned long)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);
> +
>
--
Stephen Hemminger <shemminger@linux-foundation.org>
^ permalink raw reply
* Re: [PATCH] PowerPC: Add BCM5248 and Marvell 88E1111 PHY support to NEW EMAC.
From: Josh Boyer @ 2007-10-23 16:17 UTC (permalink / raw)
To: Kumar Gala
Cc: Jeff Garzik, Valentine Barshak, Michael Ellerman, linuxppc-dev,
netdev
In-Reply-To: <38505C5B-4252-4AA7-B4F5-6B5267A6DBAA@kernel.crashing.org>
On Tue, 23 Oct 2007 11:13:48 -0500
Kumar Gala <galak@kernel.crashing.org> wrote:
>
> On Oct 23, 2007, at 10:20 AM, Josh Boyer wrote:
>
> > On Mon, 15 Oct 2007 14:27:23 -0400
> > Jeff Garzik <jeff@garzik.org> wrote:
> >
> >> Valentine Barshak wrote:
> >>> This patch adds BCM5248 and Marvell 88E1111 PHY support to NEW
> >>> EMAC driver.
> >>> These PHY chips are used on PowerPC 440EPx boards.
> >>> The PHY code is based on the previous work by Stefan Roese
> >>> <sr@denx.de>
> >>>
> >>> Signed-off-by: Stefan Roese <sr@denx.de>
> >>> Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
> >>> ---
>
> You guys should really look at moving emac over to the phylib so we
> don't have to duplicate drivers for the same phys all over the place :)
Yes, we should. It's on the list. Just not for 2.6.24 since it's way
too late.
josh
^ permalink raw reply
* Re: [PATCH] PowerPC: Add BCM5248 and Marvell 88E1111 PHY support to NEW EMAC.
From: Kumar Gala @ 2007-10-23 16:13 UTC (permalink / raw)
To: Josh Boyer
Cc: Jeff Garzik, Valentine Barshak, Michael Ellerman, linuxppc-dev,
netdev
In-Reply-To: <20071023102035.6d35d3fe@weaponx.rchland.ibm.com>
On Oct 23, 2007, at 10:20 AM, Josh Boyer wrote:
> On Mon, 15 Oct 2007 14:27:23 -0400
> Jeff Garzik <jeff@garzik.org> wrote:
>
>> Valentine Barshak wrote:
>>> This patch adds BCM5248 and Marvell 88E1111 PHY support to NEW
>>> EMAC driver.
>>> These PHY chips are used on PowerPC 440EPx boards.
>>> The PHY code is based on the previous work by Stefan Roese
>>> <sr@denx.de>
>>>
>>> Signed-off-by: Stefan Roese <sr@denx.de>
>>> Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
>>> ---
You guys should really look at moving emac over to the phylib so we
don't have to duplicate drivers for the same phys all over the place :)
- k
^ permalink raw reply
* Re: [PATCH RESEND] ip_gre: sendto/recvfrom NBMA address
From: Patrick McHardy @ 2007-10-23 16:10 UTC (permalink / raw)
To: Timo Teräs; +Cc: davem, netdev, kuznet
In-Reply-To: <471E19E5.5040509@iki.fi>
Timo Teräs wrote:
> When GRE tunnel is in NBMA mode, this patch allows an application to use
> a PF_PACKET socket to:
> - send a packet to specific NBMA address with sendto()
> - use recvfrom() to receive packet and check which NBMA address it
> came from
>
> This is required to implement properly NHRP over GRE tunnel.
>
> Signed-off-by: Timo Teras <timo.teras@iki.fi>
>
> ---
> Patrick McHardy wrote:
>> Your mailer mangled tabs, it won't apply like this. Try sending to
>> yourself for testing, then repost when it works properly.
>
> Tabs were ok, I think. But somehow it seems that cut'n'paste from my
> default editor loses the space from context lines. It should be good now.
Might have been a problem on my side, I just updated my mailer
and it still displays tabs broken, but the actual patch seems
fine. Sorry for the noise ...
^ permalink raw reply
* [PATCH 10/11] [IPSEC]: Move flow construction into xfrm_dst_lookup
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Move flow construction into xfrm_dst_lookup
This patch moves the flow construction from the callers of xfrm_dst_lookup
into that function. It also changes xfrm_dst_lookup so that it takes an
xfrm state as its argument instead of explicit addresses.
This removes any address-specific logic from the callers of xfrm_dst_lookup
which is needed to correctly support inter-family transforms.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 10 +---
net/ipv4/xfrm4_policy.c | 80 ++++++++++++++++++---------------------
net/ipv6/xfrm6_policy.c | 97 +++++++++++++++++-------------------------------
net/xfrm/xfrm_policy.c | 25 +++++++-----
4 files changed, 91 insertions(+), 121 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9ca4ae5..206c6f6 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -231,7 +231,8 @@ struct xfrm_policy_afinfo {
unsigned short family;
struct dst_ops *dst_ops;
void (*garbage_collect)(void);
- int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
+ struct dst_entry *(*dst_lookup)(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr);
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
int (*bundle_create)(struct xfrm_policy *policy,
@@ -1077,7 +1078,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
#ifdef CONFIG_XFRM
extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
-extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
#else
static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
{
@@ -1090,13 +1090,9 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
-
-static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family)
-{
- return -EINVAL;
-}
#endif
+extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index d903c8b..cebc847 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -8,7 +8,8 @@
*
*/
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/inetdevice.h>
#include <net/dst.h>
#include <net/xfrm.h>
@@ -17,28 +18,44 @@
static struct dst_ops xfrm4_dst_ops;
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
-static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
+static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr)
{
- return __ip_route_output_key((struct rtable**)dst, fl);
-}
-
-static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
-{
- struct rtable *rt;
- struct flowi fl_tunnel = {
+ struct flowi fl = {
.nl_u = {
.ip4_u = {
+ .tos = tos,
.daddr = daddr->a4,
},
},
};
+ struct dst_entry *dst;
+ struct rtable *rt;
+ int err;
- if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
- saddr->a4 = rt->rt_src;
- dst_release(&rt->u.dst);
- return 0;
- }
- return -EHOSTUNREACH;
+ if (saddr)
+ fl.fl4_src = saddr->a4;
+
+ err = __ip_route_output_key(&rt, &fl);
+ dst = &rt->u.dst;
+ if (err)
+ dst = ERR_PTR(err);
+ return dst;
+}
+
+static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
+{
+ struct dst_entry *dst;
+ struct rtable *rt;
+
+ dst = xfrm4_dst_lookup(0, NULL, daddr);
+ if (IS_ERR(dst))
+ return -EHOSTUNREACH;
+
+ rt = (struct rtable *)dst;
+ saddr->a4 = rt->rt_src;
+ dst_release(dst);
+ return 0;
}
static struct dst_entry *
@@ -73,15 +90,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rtable *rt0 = (struct rtable*)(*dst_p);
struct rtable *rt = rt0;
- struct flowi fl_tunnel = {
- .nl_u = {
- .ip4_u = {
- .saddr = fl->fl4_src,
- .daddr = fl->fl4_dst,
- .tos = fl->fl4_tos
- }
- }
- };
+ int tos = fl->fl4_tos;
int i;
int err;
int header_len = 0;
@@ -119,25 +128,12 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- unsigned short encap_family = xfrm[i]->props.family;
- switch (encap_family) {
- case AF_INET:
- fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
- fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
- break;
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
- case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
- ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
- break;
-#endif
- default:
- BUG_ON(1);
- }
- err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
- &fl_tunnel, encap_family);
- if (err)
+ dst1 = xfrm_dst_lookup(xfrm[i], tos);
+ err = PTR_ERR(dst1);
+ if (IS_ERR(dst1))
goto error;
+
+ rt = (struct rtable *)dst1;
} else
dst_hold(&rt->u.dst);
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index ed29bef..864258f 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -11,7 +11,8 @@
*
*/
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
#include <net/dst.h>
@@ -26,35 +27,40 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
-static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
+static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr)
{
- struct dst_entry *dst = ip6_route_output(NULL, fl);
- int err = dst->error;
- if (!err)
- *xdst = (struct xfrm_dst *) dst;
- else
+ struct flowi fl = {};
+ struct dst_entry *dst;
+ int err;
+
+ memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst));
+ if (saddr)
+ memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
+
+ dst = ip6_route_output(NULL, &fl);
+
+ err = dst->error;
+ if (dst->error) {
dst_release(dst);
- return err;
+ dst = ERR_PTR(err);
+ }
+
+ return dst;
}
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
{
- struct rt6_info *rt;
- struct flowi fl_tunnel = {
- .nl_u = {
- .ip6_u = {
- .daddr = *(struct in6_addr *)&daddr->a6,
- },
- },
- };
-
- if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
- ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
- (struct in6_addr *)&saddr->a6);
- dst_release(&rt->u.dst);
- return 0;
- }
- return -EHOSTUNREACH;
+ struct dst_entry *dst;
+
+ dst = xfrm6_dst_lookup(0, NULL, daddr);
+ if (IS_ERR(dst))
+ return -EHOSTUNREACH;
+
+ ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
+ (struct in6_addr *)&saddr->a6);
+ dst_release(dst);
+ return 0;
}
static struct dst_entry *
@@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
-{
- return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
- &x->id.daddr;
-}
-
-static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
-{
- return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
- &x->props.saddr;
-}
-
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
* all the metrics... Shortly, bundle a bundle.
*/
@@ -110,14 +104,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
struct rt6_info *rt = rt0;
- struct flowi fl_tunnel = {
- .nl_u = {
- .ip6_u = {
- .saddr = fl->fl6_src,
- .daddr = fl->fl6_dst,
- }
- }
- };
int i;
int err;
int header_len = 0;
@@ -160,25 +146,12 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- unsigned short encap_family = xfrm[i]->props.family;
- switch(encap_family) {
- case AF_INET:
- fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
- fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
- break;
- case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
-
- ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
- break;
- default:
- BUG_ON(1);
- }
-
- err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
- &fl_tunnel, encap_family);
- if (err)
+ dst1 = xfrm_dst_lookup(xfrm[i], 0);
+ err = PTR_ERR(dst1);
+ if (IS_ERR(dst1))
goto error;
+
+ rt = (struct rt6_info *)dst1;
} else
dst_hold(&rt->u.dst);
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b702bd8..6168341 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/list.h>
@@ -84,21 +85,25 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
-int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
- unsigned short family)
+struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
{
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
- int err = 0;
+ xfrm_address_t *saddr = &x->props.saddr;
+ xfrm_address_t *daddr = &x->id.daddr;
+ struct xfrm_policy_afinfo *afinfo;
+ struct dst_entry *dst;
+ if (x->type->flags & XFRM_TYPE_LOCAL_COADDR)
+ saddr = x->coaddr;
+ if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
+ daddr = x->coaddr;
+
+ afinfo = xfrm_policy_get_afinfo(x->props.family);
if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
+ return ERR_PTR(-EAFNOSUPPORT);
- if (likely(afinfo->dst_lookup != NULL))
- err = afinfo->dst_lookup(dst, fl);
- else
- err = -EINVAL;
+ dst = afinfo->dst_lookup(tos, saddr, daddr);
xfrm_policy_put_afinfo(afinfo);
- return err;
+ return dst;
}
EXPORT_SYMBOL(xfrm_dst_lookup);
^ permalink raw reply related
* [PATCH 11/11] [IPSEC]: Merge common code into xfrm_bundle_create
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Merge common code into xfrm_bundle_create
Half of the code in xfrm4_bundle_create and xfrm6_bundle_create are common.
This patch extracts that logic and puts it into xfrm_bundle_create. The
rest of it are then accessed through afinfo.
As a result this fixes the problem with inter-family transforms where we
treat every xfrm dst in the bundle as if it belongs to the top family.
This patch also fixes a long-standing error-path bug where we may free the
xfrm states twice.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 11 +-
net/ipv4/xfrm4_policy.c | 134 ++++++-----------------------------
net/ipv6/xfrm6_policy.c | 143 ++++++-------------------------------
net/xfrm/xfrm_policy.c | 183 +++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 215 insertions(+), 256 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 206c6f6..2da5ac5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -225,6 +225,7 @@ struct km_event
u32 event;
};
+struct net_device;
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -235,13 +236,11 @@ struct xfrm_policy_afinfo {
xfrm_address_t *daddr);
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
- int (*bundle_create)(struct xfrm_policy *policy,
- struct xfrm_state **xfrm,
- int nx,
- struct flowi *fl,
- struct dst_entry **dst_p);
void (*decode_session)(struct sk_buff *skb,
struct flowi *fl);
+ int (*get_tos)(struct flowi *fl);
+ int (*fill_dst)(struct xfrm_dst *xdst,
+ struct net_device *dev);
};
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
@@ -1092,7 +1091,6 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
}
#endif
-extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
@@ -1111,7 +1109,6 @@ extern int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
struct flowi *fl, int family, int strict);
-extern void xfrm_init_pmtu(struct dst_entry *dst);
#ifdef CONFIG_XFRM_MIGRATE
extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index cebc847..1d75243 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -79,122 +79,39 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm4_get_tos(struct flowi *fl)
{
- struct dst_entry *dst, *dst_prev;
- struct rtable *rt0 = (struct rtable*)(*dst_p);
- struct rtable *rt = rt0;
- int tos = fl->fl4_tos;
- int i;
- int err;
- int header_len = 0;
- int trailer_len = 0;
-
- dst = dst_prev = NULL;
- dst_hold(&rt->u.dst);
-
- for (i = 0; i < nx; i++) {
- struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
- struct xfrm_dst *xdst;
-
- if (unlikely(dst1 == NULL)) {
- err = -ENOBUFS;
- dst_release(&rt->u.dst);
- goto error;
- }
+ return fl->fl4_tos;
+}
- if (!dst)
- dst = dst1;
- else {
- dst_prev->child = dst1;
- dst1->flags |= DST_NOHASH;
- dst_clone(dst1);
- }
+static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct rtable *rt = (struct rtable *)xdst->route;
- xdst = (struct xfrm_dst *)dst1;
- xdst->route = &rt->u.dst;
- xdst->genid = xfrm[i]->genid;
+ xdst->u.rt.fl = rt->fl;
- dst1->next = dst_prev;
- dst_prev = dst1;
+ xdst->u.dst.dev = dev;
+ dev_hold(dev);
- header_len += xfrm[i]->props.header_len;
- trailer_len += xfrm[i]->props.trailer_len;
+ xdst->u.rt.idev = in_dev_get(dev);
+ if (!xdst->u.rt.idev)
+ return -ENODEV;
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- dst1 = xfrm_dst_lookup(xfrm[i], tos);
- err = PTR_ERR(dst1);
- if (IS_ERR(dst1))
- goto error;
+ xdst->u.rt.peer = rt->peer;
+ if (rt->peer)
+ atomic_inc(&rt->peer->refcnt);
- rt = (struct rtable *)dst1;
- } else
- dst_hold(&rt->u.dst);
- }
+ /* Sheit... I remember I did this right. Apparently,
+ * it was magically lost, so this code needs audit */
+ xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
+ RTCF_LOCAL);
+ xdst->u.rt.rt_type = rt->rt_type;
+ xdst->u.rt.rt_src = rt->rt_src;
+ xdst->u.rt.rt_dst = rt->rt_dst;
+ xdst->u.rt.rt_gateway = rt->rt_gateway;
+ xdst->u.rt.rt_spec_dst = rt->rt_spec_dst;
- dst_prev->child = &rt->u.dst;
- dst->path = &rt->u.dst;
-
- /* Copy neighbout for reachability confirmation */
- dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
- *dst_p = dst;
- dst = dst_prev;
-
- dst_prev = *dst_p;
- i = 0;
- err = -ENODEV;
- for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
- struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
- x->u.rt.fl = *fl;
-
- dst_prev->xfrm = xfrm[i++];
- dst_prev->dev = rt->u.dst.dev;
- if (!rt->u.dst.dev)
- goto error;
- dev_hold(rt->u.dst.dev);
-
- x->u.rt.idev = in_dev_get(rt->u.dst.dev);
- if (!x->u.rt.idev)
- goto error;
-
- dst_prev->obsolete = -1;
- dst_prev->flags |= DST_HOST;
- dst_prev->lastuse = jiffies;
- dst_prev->header_len = header_len;
- dst_prev->trailer_len = trailer_len;
- memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
- dst_prev->input = dst_discard;
- dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
- if (rt0->peer)
- atomic_inc(&rt0->peer->refcnt);
- x->u.rt.peer = rt0->peer;
- /* Sheit... I remember I did this right. Apparently,
- * it was magically lost, so this code needs audit */
- x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
- x->u.rt.rt_type = rt0->rt_type;
- x->u.rt.rt_src = rt0->rt_src;
- x->u.rt.rt_dst = rt0->rt_dst;
- x->u.rt.rt_gateway = rt0->rt_gateway;
- x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
- header_len -= x->u.dst.xfrm->props.header_len;
- trailer_len -= x->u.dst.xfrm->props.trailer_len;
- }
-
- xfrm_init_pmtu(dst);
return 0;
-
-error:
- if (dst)
- dst_free(dst);
- return err;
}
static void
@@ -330,8 +247,9 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
.dst_lookup = xfrm4_dst_lookup,
.get_saddr = xfrm4_get_saddr,
.find_bundle = __xfrm4_find_bundle,
- .bundle_create = __xfrm4_bundle_create,
.decode_session = _decode_session4,
+ .get_tos = xfrm4_get_tos,
+ .fill_dst = xfrm4_fill_dst,
};
static void __init xfrm4_policy_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 864258f..50a3841 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -93,126 +93,34 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm6_get_tos(struct flowi *fl)
{
- struct dst_entry *dst, *dst_prev;
- struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
- struct rt6_info *rt = rt0;
- int i;
- int err;
- int header_len = 0;
- int trailer_len = 0;
-
- dst = dst_prev = NULL;
- dst_hold(&rt->u.dst);
-
- for (i = 0; i < nx; i++) {
- struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
- struct xfrm_dst *xdst;
-
- if (unlikely(dst1 == NULL)) {
- err = -ENOBUFS;
- dst_release(&rt->u.dst);
- goto error;
- }
-
- if (!dst)
- dst = dst1;
- else {
- dst_prev->child = dst1;
- dst1->flags |= DST_NOHASH;
- dst_clone(dst1);
- }
-
- xdst = (struct xfrm_dst *)dst1;
- xdst->route = &rt->u.dst;
- xdst->genid = xfrm[i]->genid;
- if (rt->rt6i_node)
- xdst->route_cookie = rt->rt6i_node->fn_sernum;
-
- dst1->next = dst_prev;
- dst_prev = dst1;
-
- if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
- ((struct rt6_info *)dst)->nfheader_len +=
- xfrm[i]->props.header_len;
- header_len += xfrm[i]->props.header_len;
- trailer_len += xfrm[i]->props.trailer_len;
-
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- dst1 = xfrm_dst_lookup(xfrm[i], 0);
- err = PTR_ERR(dst1);
- if (IS_ERR(dst1))
- goto error;
-
- rt = (struct rt6_info *)dst1;
- } else
- dst_hold(&rt->u.dst);
- }
+ return 0;
+}
- dst_prev->child = &rt->u.dst;
- dst->path = &rt->u.dst;
-
- /* Copy neighbour for reachability confirmation */
- dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
- if (rt->rt6i_node)
- ((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
-
- *dst_p = dst;
- dst = dst_prev;
-
- dst_prev = *dst_p;
- i = 0;
- err = -ENODEV;
- for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
- struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
-
- dst_prev->xfrm = xfrm[i++];
- dst_prev->dev = rt->u.dst.dev;
- if (!rt->u.dst.dev)
- goto error;
- dev_hold(rt->u.dst.dev);
-
- x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
- if (!x->u.rt6.rt6i_idev)
- goto error;
-
- dst_prev->obsolete = -1;
- dst_prev->flags |= DST_HOST;
- dst_prev->lastuse = jiffies;
- dst_prev->header_len = header_len;
- dst_prev->trailer_len = trailer_len;
- memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
- dst_prev->input = dst_discard;
- dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
- /* Sheit... I remember I did this right. Apparently,
- * it was magically lost, so this code needs audit */
- x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
- x->u.rt6.rt6i_metric = rt0->rt6i_metric;
- x->u.rt6.rt6i_node = rt0->rt6i_node;
- x->u.rt6.rt6i_gateway = rt0->rt6i_gateway;
- memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));
- x->u.rt6.rt6i_dst = rt0->rt6i_dst;
- x->u.rt6.rt6i_src = rt0->rt6i_src;
- header_len -= x->u.dst.xfrm->props.header_len;
- trailer_len -= x->u.dst.xfrm->props.trailer_len;
- }
+static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct rt6_info *rt = (struct rt6_info*)xdst->route;
+
+ xdst->u.dst.dev = dev;
+ dev_hold(dev);
+
+ xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
+ if (!xdst->u.rt6.rt6i_idev)
+ return -ENODEV;
+
+ /* Sheit... I remember I did this right. Apparently,
+ * it was magically lost, so this code needs audit */
+ xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTCF_BROADCAST |
+ RTCF_MULTICAST |
+ RTCF_LOCAL);
+ xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
+ xdst->u.rt6.rt6i_node = rt->rt6i_node;
+ xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
+ xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
+ xdst->u.rt6.rt6i_src = rt->rt6i_src;
- xfrm_init_pmtu(dst);
return 0;
-
-error:
- if (dst)
- dst_free(dst);
- return err;
}
static inline void
@@ -355,8 +263,9 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
.dst_lookup = xfrm6_dst_lookup,
.get_saddr = xfrm6_get_saddr,
.find_bundle = __xfrm6_find_bundle,
- .bundle_create = __xfrm6_bundle_create,
.decode_session = _decode_session6,
+ .get_tos = xfrm6_get_tos,
+ .fill_dst = xfrm6_fill_dst,
};
static void __init xfrm6_policy_init(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 6168341..5a03612 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -24,6 +24,7 @@
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/cache.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
@@ -50,6 +51,7 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
+static void xfrm_init_pmtu(struct dst_entry *dst);
static inline int
__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
@@ -85,7 +87,8 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
-struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
+static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+ int family)
{
xfrm_address_t *saddr = &x->props.saddr;
xfrm_address_t *daddr = &x->id.daddr;
@@ -97,7 +100,7 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
daddr = x->coaddr;
- afinfo = xfrm_policy_get_afinfo(x->props.family);
+ afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return ERR_PTR(-EAFNOSUPPORT);
@@ -105,7 +108,6 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
xfrm_policy_put_afinfo(afinfo);
return dst;
}
-EXPORT_SYMBOL(xfrm_dst_lookup);
static inline unsigned long make_jiffies(long secs)
{
@@ -1235,24 +1237,164 @@ xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short fa
return x;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
+static inline int xfrm_get_tos(struct flowi *fl, int family)
+{
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+ int tos;
-static int
-xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p,
- unsigned short family)
+ if (!afinfo)
+ return -EINVAL;
+
+ tos = afinfo->get_tos(fl);
+
+ xfrm_policy_put_afinfo(afinfo);
+
+ return tos;
+}
+
+static inline struct xfrm_dst *xfrm_alloc_dst(int family)
{
- int err;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
- if (unlikely(afinfo == NULL))
+ struct xfrm_dst *xdst;
+
+ if (!afinfo)
+ return ERR_PTR(-EINVAL);
+
+ xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS);
+
+ xfrm_policy_put_afinfo(afinfo);
+
+ return xdst;
+}
+
+static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct xfrm_policy_afinfo *afinfo =
+ xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
+ int err;
+
+ if (!afinfo)
return -EINVAL;
- err = afinfo->bundle_create(policy, xfrm, nx, fl, dst_p);
+
+ err = afinfo->fill_dst(xdst, dev);
+
xfrm_policy_put_afinfo(afinfo);
+
return err;
}
+/* Allocate chain of dst_entry's, attach known xfrm's, calculate
+ * all the metrics... Shortly, bundle a bundle.
+ */
+
+static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
+ struct xfrm_state **xfrm, int nx,
+ struct flowi *fl,
+ struct dst_entry *dst)
+{
+ unsigned long now = jiffies;
+ struct net_device *dev;
+ struct dst_entry *dst_prev = NULL;
+ struct dst_entry *dst0 = NULL;
+ int i = 0;
+ int err;
+ int header_len = 0;
+ int trailer_len = 0;
+ int tos;
+ int family = policy->selector.family;
+
+ tos = xfrm_get_tos(fl, family);
+ err = tos;
+ if (tos < 0)
+ goto put_states;
+
+ dst_hold(dst);
+
+ for (; i < nx; i++) {
+ struct xfrm_dst *xdst = xfrm_alloc_dst(family);
+ struct dst_entry *dst1 = &xdst->u.dst;
+
+ err = PTR_ERR(xdst);
+ if (IS_ERR(xdst)) {
+ dst_release(dst);
+ goto put_states;
+ }
+
+ if (!dst_prev)
+ dst0 = dst1;
+ else {
+ dst_prev->child = dst_clone(dst1);
+ dst1->flags |= DST_NOHASH;
+ }
+
+ xdst->route = dst;
+ memcpy(&dst1->metrics, &dst->metrics, sizeof(dst->metrics));
+
+ if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+ family = xfrm[i]->props.family;
+ dst = xfrm_dst_lookup(xfrm[i], tos, family);
+ err = PTR_ERR(dst);
+ if (IS_ERR(dst))
+ goto put_states;
+ } else
+ dst_hold(dst);
+
+ dst1->xfrm = xfrm[i];
+ xdst->genid = xfrm[i]->genid;
+
+ dst1->obsolete = -1;
+ dst1->flags |= DST_HOST;
+ dst1->lastuse = now;
+
+ dst1->input = dst_discard;
+ dst1->output = xfrm[i]->outer_mode->afinfo->output;
+
+ dst1->next = dst_prev;
+ dst_prev = dst1;
+
+ header_len += xfrm[i]->props.header_len;
+ trailer_len += xfrm[i]->props.trailer_len;
+ }
+
+ dst_prev->child = dst;
+ dst0->path = dst;
+
+ err = -ENODEV;
+ dev = dst->dev;
+ if (!dev)
+ goto free_dst;
+
+ /* Copy neighbout for reachability confirmation */
+ dst0->neighbour = neigh_clone(dst->neighbour);
+
+ xfrm_init_pmtu(dst_prev);
+
+ for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
+ struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
+
+ err = xfrm_fill_dst(xdst, dev);
+ if (err)
+ goto free_dst;
+
+ dst_prev->header_len = header_len;
+ dst_prev->trailer_len = trailer_len;
+ header_len -= xdst->u.dst.xfrm->props.header_len;
+ trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
+ }
+
+out:
+ return dst0;
+
+put_states:
+ for (; i < nx; i++)
+ xfrm_state_put(xfrm[i]);
+free_dst:
+ if (dst0)
+ dst_free(dst0);
+ dst0 = ERR_PTR(err);
+ goto out;
+}
+
static int inline
xfrm_dst_alloc_copy(void **target, void *src, int size)
{
@@ -1452,15 +1594,10 @@ restart:
return 0;
}
- dst = dst_orig;
- err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family);
-
- if (unlikely(err)) {
- int i;
- for (i=0; i<nx; i++)
- xfrm_state_put(xfrm[i]);
+ dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
+ err = PTR_ERR(dst);
+ if (IS_ERR(dst))
goto error;
- }
for (pi = 0; pi < npols; pi++) {
read_lock_bh(&pols[pi]->lock);
@@ -1883,7 +2020,7 @@ static int xfrm_flush_bundles(void)
return 0;
}
-void xfrm_init_pmtu(struct dst_entry *dst)
+static void xfrm_init_pmtu(struct dst_entry *dst)
{
do {
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -1904,8 +2041,6 @@ void xfrm_init_pmtu(struct dst_entry *dst)
} while ((dst = dst->next));
}
-EXPORT_SYMBOL(xfrm_init_pmtu);
-
/* Check that the bundle accepts the flow and its components are
* still valid.
*/
^ permalink raw reply related
* [PATCH 9/11] [IPSEC]: Replace x->type->{local,remote}_addr with flags
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Replace x->type->{local,remote}_addr with flags
The functions local_addr and remote_addr are more than what they're needed
for. The same thing can be done easily with flags on the type object.
This patch does that and simplifies the wrapper functions in xfrm6_policy
accordingly.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 4 ++--
net/ipv6/mip6.c | 11 ++---------
net/ipv6/xfrm6_policy.c | 20 ++++++++------------
3 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 688f6f5..9ca4ae5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -280,6 +280,8 @@ struct xfrm_type
__u8 flags;
#define XFRM_TYPE_NON_FRAGMENT 1
#define XFRM_TYPE_REPLAY_PROT 2
+#define XFRM_TYPE_LOCAL_COADDR 4
+#define XFRM_TYPE_REMOTE_COADDR 8
int (*init_state)(struct xfrm_state *x);
void (*destructor)(struct xfrm_state *);
@@ -287,8 +289,6 @@ struct xfrm_type
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *);
int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
- xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *);
- xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *);
/* Estimate maximal size of result of transformation of a dgram */
u32 (*get_mtu)(struct xfrm_state *, int size);
};
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 7fd841d..edfd9cd 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -34,11 +34,6 @@
#include <net/xfrm.h>
#include <net/mip6.h>
-static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr)
-{
- return x->coaddr;
-}
-
static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
{
return (n - len + 16) & 0x7;
@@ -337,14 +332,13 @@ static struct xfrm_type mip6_destopt_type =
.description = "MIP6DESTOPT",
.owner = THIS_MODULE,
.proto = IPPROTO_DSTOPTS,
- .flags = XFRM_TYPE_NON_FRAGMENT,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
.init_state = mip6_destopt_init_state,
.destructor = mip6_destopt_destroy,
.input = mip6_destopt_input,
.output = mip6_destopt_output,
.reject = mip6_destopt_reject,
.hdr_offset = mip6_destopt_offset,
- .local_addr = mip6_xfrm_addr,
};
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
@@ -467,13 +461,12 @@ static struct xfrm_type mip6_rthdr_type =
.description = "MIP6RT",
.owner = THIS_MODULE,
.proto = IPPROTO_ROUTING,
- .flags = XFRM_TYPE_NON_FRAGMENT,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
.init_state = mip6_rthdr_init_state,
.destructor = mip6_rthdr_destroy,
.input = mip6_rthdr_input,
.output = mip6_rthdr_output,
.hdr_offset = mip6_rthdr_offset,
- .remote_addr = mip6_xfrm_addr,
};
static int __init mip6_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index f04e718..ed29bef 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -87,20 +87,16 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-static inline struct in6_addr*
-__xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr)
+static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
{
- return (x->type->remote_addr) ?
- (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) :
- (struct in6_addr*)&x->id.daddr;
+ return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
+ &x->id.daddr;
}
-static inline struct in6_addr*
-__xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
+static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
{
- return (x->type->local_addr) ?
- (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) :
- (struct in6_addr*)&x->props.saddr;
+ return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
+ &x->props.saddr;
}
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
@@ -171,9 +167,9 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
break;
case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst));
+ ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
- ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_local(xfrm[i], &fl->fl6_src));
+ ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
break;
default:
BUG_ON(1);
^ permalink raw reply related
* [PATCH 8/11] [IPSEC]: Make sure idev is consistent with dev in xfrm_dst
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Make sure idev is consistent with dev in xfrm_dst
Previously we took the device from the bottom route and idev from the top
route. This is bad because idev may well point to a different device.
This patch changes it so that we get the idev from the device directly.
It also makes it an error if either dev or idev is NULL. This is consistent
with the rest of the routing code which also treats these cases as errors.
I've removed the err initialisation in xfrm6_policy.c because it achieves
no purpose and hid a bug when an initial version of this patch neglected
to set err to -ENODEV (fortunately the IPv4 version warned about it).
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 13 +++++++++----
net/ipv6/xfrm6_policy.c | 15 ++++++++++-----
2 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index c40a71b..d903c8b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -153,14 +153,21 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = *dst_p;
i = 0;
+ err = -ENODEV;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
x->u.rt.fl = *fl;
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ if (!rt->u.dst.dev)
+ goto error;
+ dev_hold(rt->u.dst.dev);
+
+ x->u.rt.idev = in_dev_get(rt->u.dst.dev);
+ if (!x->u.rt.idev)
+ goto error;
+
dst_prev->obsolete = -1;
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
@@ -181,8 +188,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
x->u.rt.rt_dst = rt0->rt_dst;
x->u.rt.rt_gateway = rt0->rt_gateway;
x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
- x->u.rt.idev = rt0->idev;
- in_dev_hold(rt0->idev);
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index a1c6b7c..f04e718 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -123,7 +123,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
};
int i;
- int err = 0;
+ int err;
int header_len = 0;
int trailer_len = 0;
@@ -201,13 +201,20 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = *dst_p;
i = 0;
+ err = -ENODEV;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ if (!rt->u.dst.dev)
+ goto error;
+ dev_hold(rt->u.dst.dev);
+
+ x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
+ if (!x->u.rt6.rt6i_idev)
+ goto error;
+
dst_prev->obsolete = -1;
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
@@ -226,8 +233,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));
x->u.rt6.rt6i_dst = rt0->rt6i_dst;
x->u.rt6.rt6i_src = rt0->rt6i_src;
- x->u.rt6.rt6i_idev = rt0->rt6i_idev;
- in6_dev_hold(rt0->rt6i_idev);
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
^ permalink raw reply related
* [PATCH 6/11] [IPSEC]: Only set neighbour on top xfrm dst
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Only set neighbour on top xfrm dst
The neighbour field is only used by dst_confirm which only ever happens on
the top-most xfrm dst. So it's a waste to duplicate for every other xfrm
dst. This patch moves its setting out of the loop so that only the top one
gets set.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 5 +++--
net/ipv6/xfrm6_policy.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 5ee3a2f..7d250a1 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -144,6 +144,9 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
+ /* Copy neighbout for reachability confirmation */
+ dst->neighbour = neigh_clone(rt->u.dst.neighbour);
+
*dst_p = dst;
dst = dst_prev;
@@ -164,8 +167,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- /* Copy neighbout for reachability confirmation */
- dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
if (rt0->peer)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 9095dfc..15747f3 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -188,6 +188,10 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
+
+ /* Copy neighbour for reachability confirmation */
+ dst->neighbour = neigh_clone(rt->u.dst.neighbour);
+
if (rt->rt6i_node)
((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
@@ -210,8 +214,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- /* Copy neighbour for reachability confirmation */
- dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
/* Sheit... I remember I did this right. Apparently,
^ permalink raw reply related
* [PATCH 7/11] [IPSEC]: Set dst->input to dst_discard
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Set dst->input to dst_discard
The input function should never be invoked on IPsec dst objects. This is
because we don't apply IPsec on input until after we've made the routing
decision.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 3 ++-
net/ipv6/xfrm6_policy.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 7d250a1..c40a71b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -10,6 +10,7 @@
#include <linux/compiler.h>
#include <linux/inetdevice.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
@@ -167,7 +168,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- dst_prev->input = rt->u.dst.input;
+ dst_prev->input = dst_discard;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
if (rt0->peer)
atomic_inc(&rt0->peer->refcnt);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 15747f3..a1c6b7c 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -214,7 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- dst_prev->input = rt->u.dst.input;
+ dst_prev->input = dst_discard;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
^ permalink raw reply related
* [PATCH 5/11] [NET]: Remove unnecessary inclusion of dst.h
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[NET]: Remove unnecessary inclusion of dst.h
The file net/netevent.h only refers to struct dst_entry * so it doesn't
need to include dst.h. I've replaced it with a forward declaration.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/netevent.h | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/net/netevent.h b/include/net/netevent.h
index e5d2162..e82b7ba 100644
--- a/include/net/netevent.h
+++ b/include/net/netevent.h
@@ -12,7 +12,7 @@
*/
#ifdef __KERNEL__
-#include <net/dst.h>
+struct dst_entry;
struct netevent_redirect {
struct dst_entry *old;
^ permalink raw reply related
* [PATCH 4/11] [NET]: Eliminate duplicate copies of dst_discard
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[NET]: Eliminate duplicate copies of dst_discard
We have a number of copies of dst_discard scattered around the place which
all do the same thing, namely free a packet on the input or output paths.
This patch deletes all of them except dst_discard and points all the users
to it.
The only non-trivial bit is decnet where it returns an error. However,
conceptually this is identical to the blackhole functions used in IPv4
and IPv6 which do not return errors. So they should either all return
errors or all return zero. For now I've stuck with the majority and
picked zero as the return value.
It doesn't really matter in practice since few if any driver would react
differently depending on a zero return value or NET_RX_DROP.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/dst.h | 1 +
net/core/dst.c | 3 ++-
net/decnet/dn_route.c | 13 +------------
net/ipv4/route.c | 11 +++--------
net/ipv6/exthdrs.c | 13 ++-----------
net/ipv6/route.c | 21 ++++-----------------
6 files changed, 13 insertions(+), 49 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 8f88c52..4df103b 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -172,6 +172,7 @@ static inline struct dst_entry *dst_pop(struct dst_entry *dst)
return child;
}
+extern int dst_discard(struct sk_buff *skb);
extern void * dst_alloc(struct dst_ops * ops);
extern void __dst_free(struct dst_entry * dst);
extern struct dst_entry *dst_destroy(struct dst_entry * dst);
diff --git a/net/core/dst.c b/net/core/dst.c
index 16958e6..21b1d0f 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -154,11 +154,12 @@ loop:
#endif
}
-static int dst_discard(struct sk_buff *skb)
+int dst_discard(struct sk_buff *skb)
{
kfree_skb(skb);
return 0;
}
+EXPORT_SYMBOL(dst_discard);
void * dst_alloc(struct dst_ops * ops)
{
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 97eee5e..e1f6669 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -769,17 +769,6 @@ drop:
}
/*
- * Drop packet. This is used for endnodes and for
- * when we should not be forwarding packets from
- * this dest.
- */
-static int dn_blackhole(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-/*
* Used to catch bugs. This should never normally get
* called.
*/
@@ -1402,7 +1391,7 @@ make_route:
default:
case RTN_UNREACHABLE:
case RTN_BLACKHOLE:
- rt->u.dst.input = dn_blackhole;
+ rt->u.dst.input = dst_discard;
}
rt->rt_flags = flags;
if (rt->u.dst.dev)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 21b12de..d5cbcee 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -92,6 +92,7 @@
#include <linux/jhash.h>
#include <linux/rcupdate.h>
#include <linux/times.h>
+#include <net/dst.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
@@ -2362,12 +2363,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
};
-static int ipv4_blackhole_output(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk)
{
struct rtable *ort = *rp;
@@ -2379,8 +2374,8 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
atomic_set(&new->__refcnt, 1);
new->__use = 1;
- new->input = ipv4_blackhole_output;
- new->output = ipv4_blackhole_output;
+ new->input = dst_discard;
+ new->output = dst_discard;
memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
new->dev = ort->u.dst.dev;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 1e89efd..cee06b1 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -32,6 +32,7 @@
#include <linux/in6.h>
#include <linux/icmpv6.h>
+#include <net/dst.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -318,18 +319,8 @@ void __init ipv6_destopt_init(void)
printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
}
-/********************************
- NONE header. No data in packet.
- ********************************/
-
-static int ipv6_nodata_rcv(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
static struct inet6_protocol nodata_protocol = {
- .handler = ipv6_nodata_rcv,
+ .handler = dst_discard,
.flags = INET6_PROTO_NOPOLICY,
};
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 95f8e4a..7db3cdf 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -156,7 +156,6 @@ struct rt6_info ip6_null_entry = {
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
-static int ip6_pkt_blk_hole(struct sk_buff *skb);
struct rt6_info ip6_prohibit_entry = {
.u = {
@@ -185,8 +184,8 @@ struct rt6_info ip6_blk_hole_entry = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_blk_hole,
- .output = ip6_pkt_blk_hole,
+ .input = dst_discard,
+ .output = dst_discard,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
@@ -785,12 +784,6 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
EXPORT_SYMBOL(ip6_route_output);
-static int ip6_blackhole_output(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl)
{
struct rt6_info *ort = (struct rt6_info *) *dstp;
@@ -803,8 +796,8 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
atomic_set(&new->__refcnt, 1);
new->__use = 1;
- new->input = ip6_blackhole_output;
- new->output = ip6_blackhole_output;
+ new->input = dst_discard;
+ new->output = dst_discard;
memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
new->dev = ort->u.dst.dev;
@@ -1814,12 +1807,6 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
-static int ip6_pkt_blk_hole(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
#endif
/*
^ permalink raw reply related
* [PATCH 3/11] [IPV6]: Move nfheader_len into rt6_info
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPV6]: Move nfheader_len into rt6_info
The dst member nfheader_len is only used by IPv6. It's also currently
creating a rather ugly alignment hole in struct dst. Therefore this patch
moves it from there into struct rt6_info.
It also reorders the fields in rt6_info to minimize holes.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/dst.h | 1 -
include/net/ip6_fib.h | 11 ++++++++---
net/ipv4/xfrm4_policy.c | 1 -
net/ipv6/ip6_output.c | 5 +++--
net/ipv6/xfrm6_policy.c | 3 ++-
5 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index e9ff4a4..8f88c52 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -50,7 +50,6 @@ struct dst_entry
unsigned long expires;
unsigned short header_len; /* more space at head required */
- unsigned short nfheader_len; /* more non-fragment space at head required */
unsigned short trailer_len; /* space to reserve at tail */
u32 metrics[RTAX_MAX];
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 8578213..4cefcff 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -99,16 +99,21 @@ struct rt6_info
u32 rt6i_flags;
u32 rt6i_metric;
atomic_t rt6i_ref;
- struct fib6_table *rt6i_table;
- struct rt6key rt6i_dst;
- struct rt6key rt6i_src;
+ /* more non-fragment space at head required */
+ unsigned short nfheader_len;
u8 rt6i_protocol;
+ struct fib6_table *rt6i_table;
+
+ struct rt6key rt6i_dst;
+
#ifdef CONFIG_XFRM
u32 rt6i_flow_cache_genid;
#endif
+
+ struct rt6key rt6i_src;
};
static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index cc86fb1..5ee3a2f 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -161,7 +161,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
dst_prev->header_len = header_len;
- dst_prev->nfheader_len = 0;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index b1647f5..85c5eb8 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1097,7 +1097,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
- rt->u.dst.nfheader_len;
+ rt->nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
} else {
@@ -1112,7 +1112,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
- fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0);
+ fragheaderlen = sizeof(struct ipv6hdr) + rt->nfheader_len +
+ (opt ? opt->opt_nflen : 0);
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index e5170bc..9095dfc 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -157,7 +157,8 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = dst1;
if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
- dst->nfheader_len += xfrm[i]->props.header_len;
+ ((struct rt6_info *)dst)->nfheader_len +=
+ xfrm[i]->props.header_len;
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
^ permalink raw reply related
* [PATCH 1/11] [IPV6]: Only set nfheader_len for top xfrm dst
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPV6]: Only set nfheader_len for top xfrm dst
We only need to set nfheader_len in the top xfrm dst. This is because
we only ever read the nfheader_len from the top xfrm dst.
It is also easier to count nfheader_len as part of header_len which
then lets us remove the ugly wrapper functions for incrementing and
decrementing header lengths in xfrm6_policy.c.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv6/ip6_output.c | 3 ++-
net/ipv6/xfrm6_policy.c | 26 ++++----------------------
2 files changed, 6 insertions(+), 23 deletions(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 13565df..b1647f5 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1096,7 +1096,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0);
+ exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
+ rt->u.dst.nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
} else {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 82e27b8..e5170bc 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -102,24 +102,6 @@ __xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
(struct in6_addr*)&x->props.saddr;
}
-static inline void
-__xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x)
-{
- if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
- *nflen += x->props.header_len;
- else
- *len += x->props.header_len;
-}
-
-static inline void
-__xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x)
-{
- if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
- *nflen -= x->props.header_len;
- else
- *len -= x->props.header_len;
-}
-
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
* all the metrics... Shortly, bundle a bundle.
*/
@@ -142,7 +124,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
int i;
int err = 0;
int header_len = 0;
- int nfheader_len = 0;
int trailer_len = 0;
dst = dst_prev = NULL;
@@ -175,7 +156,9 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->next = dst_prev;
dst_prev = dst1;
- __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
+ if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
+ dst->nfheader_len += xfrm[i]->props.header_len;
+ header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
@@ -223,7 +206,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
dst_prev->header_len = header_len;
- dst_prev->nfheader_len = nfheader_len;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
@@ -242,7 +224,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
x->u.rt6.rt6i_src = rt0->rt6i_src;
x->u.rt6.rt6i_idev = rt0->rt6i_idev;
in6_dev_hold(rt0->rt6i_idev);
- __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm);
+ header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
^ permalink raw reply related
* [PATCH 2/11] [IPSEC]: Use dst->header_len when resizing on output
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
In-Reply-To: <20071023160217.GA32102@gondor.apana.org.au>
[IPSEC]: Use dst->header_len when resizing on output
Currently we use x->props.header_len when resizing on output. However,
if we're resizing at all we might as well go the whole hog and do it
for the whole dst.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/xfrm/xfrm_output.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index f4bfd6c..58d5a74 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -19,7 +19,8 @@
static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
{
- int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
+ struct dst_entry *dst = skb->dst;
+ int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
- skb_headroom(skb);
if (nhead > 0)
^ permalink raw reply related
* [0/11] Merge bundle creation and other misc fixes/clean-ups
From: Herbert Xu @ 2007-10-23 16:02 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
Hi Dave:
This series of patches fixes the bug where the bundle creation
code treats IPv6 routes as IPv4 or vice versa.
I think this is suitable for 2.6.25.
They do fix bugs but I don't think any of them are serious enough
for inclusion in 2.6.24.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] Consolidate sctp_ulpq_renege_xxx functions
From: Vlad Yasevich @ 2007-10-23 15:57 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, lksctp-developers, Linux Netdev List, devel
In-Reply-To: <471E1082.8010607@openvz.org>
Pavel Emelyanov wrote:
> Both are equal, except for the list to be traversed.
>
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
>
ACK. Good clean-up Pavel.
Thanks
-vlad
^ permalink raw reply
* Re: [ANNOUNCE] iproute2-2.6.23
From: Herbert Xu @ 2007-10-23 15:57 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20071023083702.2904c0a0@shemminger-laptop>
On Tue, Oct 23, 2007 at 08:37:02AM -0700, Stephen Hemminger wrote:
>
> I was just holding off for a few days to see if there were any bug fixes
> to 2.6.23 version that needed to go in first. It is first in queue for 2.6.24
> related stuff.
>
> Promise to get it in before 2.6.24-rc1
Thanks Stephen!
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH RESEND] ip_gre: sendto/recvfrom NBMA address
From: Timo Teräs @ 2007-10-23 15:57 UTC (permalink / raw)
To: Patrick McHardy; +Cc: davem, netdev, kuznet
In-Reply-To: <471E0638.9040405@trash.net>
When GRE tunnel is in NBMA mode, this patch allows an application to use
a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from
This is required to implement properly NHRP over GRE tunnel.
Signed-off-by: Timo Teras <timo.teras@iki.fi>
---
Patrick McHardy wrote:
> Your mailer mangled tabs, it won't apply like this. Try sending to
> yourself for testing, then repost when it works properly.
Tabs were ok, I think. But somehow it seems that cut'n'paste from my
default editor loses the space from context lines. It should be good now.
net/ipv4/ip_gre.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f151900..b1e3816 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1033,7 +1033,6 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-#ifdef CONFIG_NET_IPGRE_BROADCAST
/* Nice toy. Unfortunately, useless in real life :-)
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
@@ -1092,10 +1091,19 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
return -t->hlen;
}
+static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+ struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
+ memcpy(haddr, &iph->saddr, 4);
+ return 4;
+}
+
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
+ .parse = ipgre_header_parse,
};
+#ifdef CONFIG_NET_IPGRE_BROADCAST
static int ipgre_open(struct net_device *dev)
{
struct ip_tunnel *t = netdev_priv(dev);
@@ -1197,6 +1205,8 @@ static int ipgre_tunnel_init(struct net_device *dev)
dev->stop = ipgre_close;
}
#endif
+ } else {
+ dev->header_ops = &ipgre_header_ops;
}
if (!tdev && tunnel->parms.link)
^ permalink raw reply related
* [PATCH RESEND] ip_gre: sendto/recvfrom NBMA address
From: Timo Teräs @ 2007-10-23 15:08 UTC (permalink / raw)
To: Patrick McHardy; +Cc: davem, netdev, kuznet
In-Reply-To: <471E0638.9040405@trash.net>
When GRE tunnel is in NBMA mode, this patch allows an application to use
a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from
This is required to implement properly NHRP over GRE tunnel.
Signed-off-by: Timo Teras <timo.teras@iki.fi>
---
> Your mailer mangled tabs, it won't apply like this. Try sending to
> yourself for testing, then repost when it works properly.
Sorry. Tabs were ok, but the initial white space on context lines was somehow
removed. Apparently a bug in my editor where I cut/pasted from.
net/ipv4/ip_gre.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f151900..b1e3816 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1033,7 +1033,6 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-#ifdef CONFIG_NET_IPGRE_BROADCAST
/* Nice toy. Unfortunately, useless in real life :-)
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
@@ -1092,10 +1091,19 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
return -t->hlen;
}
+static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+ struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
+ memcpy(haddr, &iph->saddr, 4);
+ return 4;
+}
+
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
+ .parse = ipgre_header_parse,
};
+#ifdef CONFIG_NET_IPGRE_BROADCAST
static int ipgre_open(struct net_device *dev)
{
struct ip_tunnel *t = netdev_priv(dev);
@@ -1197,6 +1205,8 @@ static int ipgre_tunnel_init(struct net_device *dev)
dev->stop = ipgre_close;
}
#endif
+ } else {
+ dev->header_ops = &ipgre_header_ops;
}
if (!tdev && tunnel->parms.link)
^ permalink raw reply related
* Re: [ANNOUNCE] iproute2-2.6.23
From: Stephen Hemminger @ 2007-10-23 15:37 UTC (permalink / raw)
To: Herbert Xu; +Cc: netdev
In-Reply-To: <20071023061207.GA27560@gondor.apana.org.au>
On Tue, 23 Oct 2007 14:12:07 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Wed, Oct 17, 2007 at 09:10:02AM +0800, Herbert Xu wrote:
> >
> > Any chance you could include the NAT patch for the next release?
> >
> > [TC]: Add NAT action
> >
> > This patch adds the parser for the nat action which is used
> > for stateless NAT.
> >
> > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> Hi Stephen:
>
> Is there a problem with merging this patch?
I was just holding off for a few days to see if there were any bug fixes
to 2.6.23 version that needed to go in first. It is first in queue for 2.6.24
related stuff.
Promise to get it in before 2.6.24-rc1
^ permalink raw reply
* Re: [PATCH] fix ACK processing after netlink_dump_start
From: Joseph Fannin @ 2007-10-23 15:36 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: dcbw, tgraf, jfannin, davem, netdev, kuznet
In-Reply-To: <20071023144023.GA15035@iris.sw.ru>
On Tue, Oct 23, 2007 at 06:40:23PM +0400, Denis V. Lunev wrote:
> Revert to original netlink behavior. Do not reply with ACK if the
> netlink dump has bees successfully started.
>
> libnl has been broken by the cd40b7d3983c708aabe3d3008ec64ffce56d33b0
> The following command reproduce the problem:
> /nl-route-get 192.168.1.1
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
Network Manager works correctly here with this patch applied against
Linus's current -git.
(Sorry for the lack of response before -- I think I forgot to ask to
be CC'd on replies, and found the discussion of this in archives
only this morning.)
--
Joseph Fannin
jfannin@gmail.com
^ permalink raw reply
* Re: iproute2: git pull request from debian repo.
From: Andreas Henriksson @ 2007-10-23 15:27 UTC (permalink / raw)
To: Patrick McHardy; +Cc: maximilian attems, shemminger, netdev
In-Reply-To: <471E0E5A.40306@trash.net>
On Tue, Oct 23, 2007 at 05:08:10PM +0200, Patrick McHardy wrote:
> Andreas Henriksson wrote:
> >On Tue, Oct 23, 2007 at 04:38:06PM +0200, Patrick McHardy wrote:
> >>Almost - the default behaviour shouldn't change IMO. Also please
> >>send a complete patch, not one on top of your old one.
> >
> >Which "default behaviour"? ip addr flush or ip neigh flush behaviour?
> >Both of those should behave the same IMHO.
>
> In both cases your changed behaviour should be optional and it should
> default to the old behaviour. Not actually flushing completely when the
> user specified "flush" is counter-intuitive.
>
I did not change the behaviour in both cases! I'm only sending in a change
for ip addr flush to make it match how ip neigh flush already works!
Two different behaviours -> one change -> same behaviour for both.
I've mentioned this multiple times already... I don't know how to express
myself in another/better way about this.
> >Defaulting to never bail out is causing problems in a bunch of firewalling
> >frontends which has been reported multiple times to both debian and ubuntu
> >(and possibly others I don't know about), and looping forever causes the
> >bootup to never finish.
> >Thats my reason for advocating not selecting the "loop forever" as the
> >default choice.
>
> Then those frontends should add "maxrounds N" if they want to abort
> before the flush is complete.
>
So you prefer that I rather change the default for ip neigh flush, then touch
ip addr flush? Making the problematic version the default for both, and
changing every application out there who uses any of these two functions.
Sorry, I'll pass on that one and let someone else do it if it's the preferred
solution.
--
Regards,
Andreas Henriksson
^ permalink raw reply
* Re: [PATCH] PowerPC: Add BCM5248 and Marvell 88E1111 PHY support to NEW EMAC.
From: Josh Boyer @ 2007-10-23 15:20 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Valentine Barshak, Michael Ellerman, linuxppc-dev, netdev
In-Reply-To: <4713B10B.5000607@garzik.org>
On Mon, 15 Oct 2007 14:27:23 -0400
Jeff Garzik <jeff@garzik.org> wrote:
> Valentine Barshak wrote:
> > This patch adds BCM5248 and Marvell 88E1111 PHY support to NEW EMAC driver.
> > These PHY chips are used on PowerPC 440EPx boards.
> > The PHY code is based on the previous work by Stefan Roese <sr@denx.de>
> >
> > Signed-off-by: Stefan Roese <sr@denx.de>
> > Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
> > ---
> > drivers/net/ibm_newemac/phy.c | 39 +++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 39 insertions(+)
> >
> > --- linux.orig/drivers/net/ibm_newemac/phy.c 2007-06-15 21:45:18.000000000 +0400
> > +++ linux/drivers/net/ibm_newemac/phy.c 2007-06-15 20:45:15.000000000 +0400
> > @@ -306,8 +306,47 @@
> > .ops = &cis8201_phy_ops
> > };
> >
> > +static struct mii_phy_def bcm5248_phy_def = {
> > +
> > + .phy_id = 0x0143bc00,
> > + .phy_id_mask = 0x0ffffff0,
> > + .name = "BCM5248 10/100 SMII Ethernet",
> > + .ops = &generic_phy_ops
> > +};
> > +
> > +static int m88e1111_init(struct mii_phy *phy)
> > +{
> > + printk("%s: Marvell 88E1111 Ethernet\n", __FUNCTION__);
> > + phy_write(phy, 0x14, 0x0ce3);
> > + phy_write(phy, 0x18, 0x4101);
> > + phy_write(phy, 0x09, 0x0e00);
> > + phy_write(phy, 0x04, 0x01e1);
> > + phy_write(phy, 0x00, 0x9140);
> > + phy_write(phy, 0x00, 0x1140);
> > +
> > + return 0;
> > +}
> > +
> > +static struct mii_phy_ops m88e1111_phy_ops = {
> > + .init = m88e1111_init,
> > + .setup_aneg = genmii_setup_aneg,
> > + .setup_forced = genmii_setup_forced,
> > + .poll_link = genmii_poll_link,
> > + .read_link = genmii_read_link
> > +};
> > +
> > +static struct mii_phy_def m88e1111_phy_def = {
> > +
> > + .phy_id = 0x01410CC0,
> > + .phy_id_mask = 0x0ffffff0,
> > + .name = "Marvell 88E1111 Ethernet",
> > + .ops = &m88e1111_phy_ops,
> > +};
> > +
> > static struct mii_phy_def *mii_phy_table[] = {
> > &cis8201_phy_def,
> > + &bcm5248_phy_def,
> > + &m88e1111_phy_def,
> > &genmii_phy_def,
>
> Seems sane to me -- ACK -- but we have multiple people sending me
> patches for a single driver. That's normal for janitorial cleanups
> across the whole tree, but discouraged when multiple people are actively
> working on the same driver.
>
> Please coordinate, and have ONE person send me patches...
Jeff, could you please pull in this patch for 2.6.24? We'll get the
coordination down for any further patches.
thx,
josh
>
^ 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