Matti Linnanvuori wrote:
From: Matti Linnanvuori <[EMAIL PROTECTED]>

Adding Retina G.703 and G.SHDSL driver.

Signed-off-by: Matti Linnanvuori <[EMAIL PROTECTED]>

Overall comment:  very nice and clean, well done.



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-25 09:23:19.933170522 
+0300
@@ -494,4 +494,15 @@ 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 or
+         character device stream.
+
+         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-25 13:10:05.004606703 
+0300
@@ -0,0 +1,3708 @@
+/* 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.8"
+
+/* 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)
+
+static const char fepci_name[] = "retina";
+static const char fepci_alarm_manager_name[] = "retina alarm manager";
+static const char fepci_NAME[] = "RETINA";
+static const char fepci_netdev_name[] = "dcpxx";
+static 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"
+
+/* Time in jiffies before concluding that the transmitter is hung */
+#define TX_TIMEOUT  (5 * HZ)
+
+#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

consider making an enum like your other constants


+#define PCI_IOTYPE (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)

delete, never used


+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},

some prefer

        { PCI_VDEVICE(VENDOR_NAME, 0x0300) },
        { PCI_VDEVICE(VENDOR_NAME, 0x0301) },
        { }     /* terminate list */

but it's up to you.


+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 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 stream mode: */
+       /* rx-errors in descriptors */
+       unsigned rx_desc_fifo_err_stream;
+       unsigned rx_desc_size_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;
+/* other: */
+       /* tx interrupts since last timer interrupt */
+       unsigned tx_interrupts_since_last_timer;

if these are purely informational statistics, recommend a separate structure that is in turn embedded within struct fepci_ch_private


+};
+
+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,

I recommend making these enums more readable by tabbing the values into alignment:

        fifo_error              = 0x10000,
        transfer_not_done       = 0x80000000,
        etc.


+/* global variables (common to whole driver, all the cards): */
+static int major;                      /* char device major number */
+static struct fepci_card_private card_privates[MAX_DEVICES];
+static unsigned long stream_pointers;
+static struct proc_dir_entry *proc_root_entry;

generally new procfs nodes are discouraged, in favor of sysfs attributes


+static void set_int_mask(int channel, u_char value,
+                        struct fepci_card_private *cp)
+{
+       void *address;
+       unsigned shift, oldvalue;
+       pr_debug("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 addresses passed to writel() and readl() should be marked with 'void __iomem *'

then run sparse to validate (Documentation/sparse.txt)


+static void clear_int(unsigned channel, unsigned value, void *ioaddr)
+{
+       void *address;
+       unsigned shift, longvalue;
+       pr_debug("clear_int\n");
+       address = ioaddr + reg_first_int_status + (channel / 4) * 4;
+       shift = 8 * (channel % 4);
+       longvalue = value << shift;
+       writel(~longvalue, (void *)address);

1) delete cast

2) void __iomem *address

+static u_char get_int_status(int channel, void *ioaddr)
+{
+       void *address;
+       unsigned shift, oldvalue;
+       pr_debug("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);
+}
+
+static void fillregisterswith_00(void *ioaddr)
+{
+       pr_debug("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));

ditto

+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);
+
+/* char device operations: */
+
+static ssize_t fepci_char_read(struct file *filp, char *buf, size_t count,
+                       loff_t *f_pos);
+static int fepci_char_open(struct inode *inode, struct file *filp);
+static int fepci_char_release(struct inode *inode, struct file *filp);
+static int fepci_char_mmap(struct file *filp, struct vm_area_struct *vma);
+static 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
+};
+
+static int fepci_char_open(struct inode *inode, struct file *filp)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       pr_debug("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;
+}
+
+static int fepci_char_release(struct inode *inode, struct file *filp)
+{
+       pr_debug("fepci_char_release\n");
+       module_put(THIS_MODULE);
+       return 0;
+}
+
+static void fepci_vma_open(struct vm_area_struct *vma)
+{
+       pr_debug("fepci_vma_open\n");
+}
+
+static void fepci_vma_close(struct vm_area_struct *vma)
+{
+       pr_debug("fepci_vma_close\n");
+       module_put(THIS_MODULE);
+}
+
+static struct vm_operations_struct fepci_vm_ops = {
+       .open   = fepci_vma_open,
+       .close  = fepci_vma_close
+};
+
+static 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:
+                       pr_debug("%s: mmap: invalid address 0x%lx\n",
+                                 fepci_NAME, virtual_address);
+                       return -EINVAL;
+               }
+               if (unlikely(virtual_address == 0))
+                       goto INVALID;
+       }
+
+       if (unlikely(!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 */
+
+static void fepci_copy_to_user(unsigned long to, void *from, unsigned long len,
+                       int shrink)
+{
+       unsigned int i;
+       pr_debug("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));
+       }
+}
+
+static 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));
+       }
+}

please kindly explain this char device in detail (URL to documentation?)...

a WAN driver providing mmap(2) is quite unusual. what is the interface description? what security restrictions exist?

Stopped reviewing here.  That should give you a bit to do :)

        Jeff


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to