]> git.neil.brown.name Git - history.git/commitdiff
Import 2.4.0-test5pre6 2.4.0-test5pre6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:37:09 +0000 (15:37 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:37:09 +0000 (15:37 -0500)
68 files changed:
arch/alpha/lib/csum_partial_copy.c
arch/i386/kernel/setup.c
drivers/atm/iphase.c
drivers/cdrom/mcd.c
drivers/ide/ide.c
drivers/net/gmac.c
drivers/net/gmac.h
drivers/net/rcpci45.c
drivers/pcmcia/ds.c
drivers/pcmcia/pci_socket.c
drivers/pcmcia/yenta.c
drivers/scsi/scsi_ioctl.c
drivers/sound/msnd.c
drivers/usb/usb.c
drivers/video/S3triofb.c
drivers/video/acornfb.c
drivers/video/aty128fb.c
drivers/video/chipsfb.c
drivers/video/clgenfb.c
drivers/video/controlfb.c
drivers/video/cyber2000fb.c
drivers/video/cyberfb.c
drivers/video/dn_cfb4.c
drivers/video/dn_cfb8.c
drivers/video/dnfb.c
drivers/video/fbgen.c
drivers/video/fbmem.c
drivers/video/fm2fb.c
drivers/video/g364fb.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/hpfb.c
drivers/video/igafb.c
drivers/video/macfb.c
drivers/video/offb.c
drivers/video/platinumfb.c
drivers/video/q40fb.c
drivers/video/retz3fb.c
drivers/video/sa1100fb.c
drivers/video/sbusfb.c
drivers/video/sgivwfb.c
drivers/video/sisfb.c
drivers/video/skeletonfb.c
drivers/video/sun3fb.c
drivers/video/tgafb.c
drivers/video/valkyriefb.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/virgefb.c
fs/coda/pioctl.c
fs/dquot.c
fs/ext2/inode.c
fs/fat/cache.c
fs/jffs/inode-v23.c
fs/minix/inode.c
fs/namei.c
fs/smbfs/ChangeLog
fs/smbfs/proc.c
fs/sysv/inode.c
fs/udf/inode.c
fs/ufs/inode.c
include/asm-i386/e820.h
include/asm-sh/sh_bios.h
include/linux/fb.h
include/linux/i2c.h
init/main.c
mm/memory.c

index 7130813301d08ad78d87068ad2417e46b65d838d..5638a1a0c5821f6f748c8be009a1c42551818ab9 100644 (file)
@@ -173,11 +173,11 @@ csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst,
 {
        unsigned long carry = 0;
        unsigned long word;
+       unsigned long second_dest;
        int err = 0;
 
        mskql(partial_dest, doff, partial_dest);
        while (len >= 0) {
-               unsigned long second_dest;
                err |= __get_user(word, src);
                len -= 8;
                insql(word, doff, second_dest);
@@ -189,35 +189,30 @@ csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst,
                carry = checksum < word;
                dst++;
        }
-       len += doff;
-       checksum += carry;
-       if (len >= 0) {
-               unsigned long second_dest;
+       len += 8;
+       if (len) {
+               checksum += carry;
                err |= __get_user(word, src);
-               mskql(word, len-doff, word);
+               mskql(word, len, word);
+               len -= 8;
                checksum += word;
                insql(word, doff, second_dest);
-               stq_u(partial_dest | second_dest, dst);
+               len += doff;
                carry = checksum < word;
-               if (len) {
-                       ldq_u(second_dest, dst+1);
+               partial_dest |= second_dest;
+               if (len >= 0) {
+                       stq_u(partial_dest, dst);
+                       if (!len) goto out;
+                       dst++;
                        insqh(word, doff, partial_dest);
-                       mskqh(second_dest, len, second_dest);
-                       stq_u(partial_dest | second_dest, dst+1);
                }
-               checksum += carry;
-       } else if (len & 7) {
-               unsigned long second_dest;
-               err |= __get_user(word, src);
-               ldq_u(second_dest, dst);
-               mskql(word, len-doff, word);
-               checksum += word;
-               mskqh(second_dest, len, second_dest);
-               carry = checksum < word;
-               insql(word, doff, word);
-               stq_u(partial_dest | word | second_dest, dst);
-               checksum += carry;
+               doff = len;
        }
+       ldq_u(second_dest, dst);
+       mskqh(second_dest, doff, second_dest);
+       stq_u(partial_dest | second_dest, dst);
+out:
+       checksum += carry;
        if (err) *errp = err;
        return checksum;
 }
@@ -283,7 +278,7 @@ csum_partial_cfu_unaligned(const unsigned long * src, unsigned long * dst,
                        stq_u(partial_dest | second_dest, dst+1);
                }
                checksum += carry;
-       } else if (len & 7) {
+       } else {
                unsigned long second, word;
                unsigned long second_dest;
 
index dc61a920bf56c32c102675c35f144867b1f6a58f..24ea5e641c66f640ecfe1b4fcfa00b91dea152dd 100644 (file)
@@ -142,7 +142,7 @@ extern unsigned long cpu_hz;
 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
 #define E820_MAP_NR (*(char*) (PARAM+E820NR))
-#define E820_MAP    ((unsigned long *) (PARAM+E820MAP))
+#define E820_MAP    ((struct e820entry *) (PARAM+E820MAP))
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
@@ -423,6 +423,57 @@ static void __init print_e820_map(void)
        }
 }
 
+/*
+ * Copy the BIOS e820 map into a safe place.
+ *
+ * Sanity-check it while we're at it..
+ *
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory.  If we aren't, we'll fake a memory map.
+ *
+ * We check to see that the memory map contains at least 2 elements
+ * before we'll use it, because the detection code in setup.S may
+ * not be perfect and most every PC known to man has two memory
+ * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
+ * thinkpad 560x, for example, does not cooperate with the memory
+ * detection code.)
+ */
+static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+{
+       /* Only one memory region (or negative)? Ignore it */
+       if (nr_map < 2)
+               return -1;
+
+       do {
+               unsigned long long start = biosmap->addr;
+               unsigned long long size = biosmap->size;
+               unsigned long long end = start + size;
+               long type = biosmap->type;
+
+               /* Overflow in 64 bits? Ignore the memory map. */
+               if (start > end)
+                       return -1;
+
+               /*
+                * Some BIOSes claim RAM in the 640k - 1M region.
+                * Not right. Fix it up.
+                */
+               if (type == E820_RAM) {
+                       if (start < 0x100000 && end > 0xA0000) {
+                               if (start < 0xA0000)
+                                       add_memory_region(start, 0xA0000-start, type);
+                               if (end < 0x100000)
+                                       continue;
+                               start = 0x100000;
+                               size = end - start;
+                       }
+               }
+               add_memory_region(start, size, type);
+       } while (biosmap++,--nr_map);
+       return 0;
+}
+
 /*
  * Do NOT EVER look at the BIOS memory size location.
  * It does not work on many machines.
@@ -432,33 +483,17 @@ static void __init print_e820_map(void)
 void __init setup_memory_region(void)
 {
        /*
-        * If we're lucky and live on a modern system, the setup code
-        * will have given us a memory map that we can use to properly
-        * set up memory.  If we aren't, we'll fake a memory map.
+        * Try to copy the BIOS-supplied E820-map.
         *
-        * We check to see that the memory map contains at least 2 elements
-        * before we'll use it, because the detection code in setup.S may
-        * not be perfect and most every PC known to man has two memory
-        * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
-        * thinkpad 560x, for example, does not cooperate with the memory
-        * detection code.)
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
         */
-       if (E820_MAP_NR > 1) {
-               /* got a memory map; copy it into a safe place.
-                */
-               e820.nr_map = E820_MAP_NR;
-               if (e820.nr_map > E820MAX)
-                       e820.nr_map = E820MAX;
-               memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]);
-       }
-       else {
-               /* otherwise fake a memory map; one section from 0k->640k,
-                * the next section from 1mb->appropriate_mem_k
-                */
+       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
                unsigned long mem_size;
 
                mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K;
 
+               e820.nr_map = 0;
                add_memory_region(0, LOWMEMSIZE(), E820_RAM);
                add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
        }
index 053efbd304b9d5a6d18bb5347b708179b783811b..fb224a89114e169387343d6da4fbd4d167c18370 100644 (file)
@@ -1828,7 +1828,7 @@ static int open_tx(struct atm_vcc *vcc)
                vc->acr = cellrate_to_float(iadev->LineRate);  
                 if (vcc->qos.txtp.pcr > 0) 
                    vc->acr = cellrate_to_float(vcc->qos.txtp.pcr);  
-                IF_UBR(printk("UBR: txtp.pcr = 0x%d f_rate = 0x%x\n", 
+                IF_UBR(printk("UBR: txtp.pcr = 0x%x f_rate = 0x%x\n", 
                                              vcc->qos.txtp.max_pcr,vc->acr);)
        }  
        else if (vcc->qos.txtp.traffic_class == ATM_ABR)  
index 12c85365da581dadb501a7014e2b12c148e238bb..c445462747264f68c96461914678bc9af27c3759 100644 (file)
@@ -1218,7 +1218,7 @@ int __init mcd_init(void)
        outb(MCMD_GET_VERSION,MCDPORT(0));
        for(count=0;count<3;count++)
                if(getValue(result+count)) {
-                       printk("mitsumi get version failed at 0x%d\n",
+                       printk("mitsumi get version failed at 0x%x\n",
                               mcd_port);
                         cleanup(1);
                         return -EIO;
index 88b3f8e4aece59298a4116cc04610ca458957757..6fe3f9d3647f7347d5253c0ca20b0a34da91151c 100644 (file)
@@ -2561,7 +2561,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        byte args[4], *argbuf = args;
                        byte xfer_rate = 0;
                        int argsize = 4;
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+                       if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
                        if (NULL == (void *) arg)
                                return ide_do_drive_cmd(drive, &rq, ide_wait);
                        if (copy_from_user(args, (void *)arg, 4))
@@ -2599,7 +2599,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                {
                        byte args[7], *argbuf = args;
                        int argsize = 7;
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+                       if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
                        if (copy_from_user(args, (void *)arg, 7))
                                return -EFAULT;
                        err = ide_wait_cmd_task(drive, argbuf);
index b1a431499f944c38364f588881c65c16119f56bb..4717a652c63575f67e95c77df39792e91692b60d 100644 (file)
  * Network device driver for the GMAC ethernet controller on
  * Apple G4 Powermacs.
  *
- * Copyright (C) 2000 Paul Mackerras.
+ * Copyright (C) 2000 Paul Mackerras & Ben. Herrenschmidt
+ * 
+ * portions based on sunhme.c by David S. Miller
+ * 
  */
 
 #include <linux/module.h>
+
+#include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/feature.h>
+
 #include "gmac.h"
 
 #define DEBUG_PHY
 
-#define NTX            32              /* must be power of 2 */
-#define NRX            32              /* must be power of 2 */
-#define RX_BUFLEN      (ETH_FRAME_LEN + 8)
-
-struct gmac_dma_desc {
-       unsigned int    cmd;
-       unsigned int    status;
-       unsigned int    address;        /* phys addr, low 32 bits */
-       unsigned int    hi_addr;
-};
-
-/* Bits in cmd */
-#define RX_OWN 0x80000000              /* 1 = owned by chip */
-#define TX_SOP 0x80000000
-#define TX_EOP 0x40000000
-
-struct gmac {
-       volatile unsigned int *regs;    /* hardware registers, virtual addr */
-       volatile unsigned int *sysregs;
-       unsigned long   desc_page;      /* page for DMA descriptors */
-       volatile struct gmac_dma_desc *rxring;
-       struct sk_buff  *rx_buff[NRX];
-       int             next_rx;
-       volatile struct gmac_dma_desc *txring;
-       struct sk_buff  *tx_buff[NTX];
-       int             next_tx;
-       int             tx_gone;
-       unsigned char   tx_full;
-       int             phy_addr;
-       int             full_duplex;
-       struct net_device_stats stats;
-       struct net_device *next_gmac;
-};
-
-#define GM_OUT(r, v)   out_le32(gm->regs + (r)/4, (v))
-#define GM_IN(r)       in_le32(gm->regs + (r)/4)
-#define GM_BIS(r, v)   GM_OUT((r), GM_IN(r) | (v))
-#define GM_BIC(r, v)   GM_OUT((r), GM_IN(r) & ~(v))
-
-#define PHY_B5400      0x6040
-#define PHY_B5201      0x6212
-
-static unsigned char dummy_buf[RX_BUFLEN+2];
+/* Driver version 1.1, kernel 2.4.x */
+#define GMAC_VERSION   "v1.1k4"
+
+static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN];
 static struct net_device *gmacs = NULL;
 
 /* Prototypes */
 static int mii_read(struct gmac *gm, int phy, int r);
 static int mii_write(struct gmac *gm, int phy, int r, int v);
-static void powerup_transceiver(struct gmac *gm);
-static int gmac_reset(struct net_device *dev);
+static void mii_poll_start(struct gmac *gm);
+static void mii_poll_stop(struct gmac *gm);
+static void mii_interrupt(struct gmac *gm);
+static int mii_lookup_and_reset(struct gmac *gm);
+static void mii_setup_phy(struct gmac *gm);
+
+static void gmac_set_power(struct gmac *gm, int power_up);
+static int gmac_powerup_and_reset(struct net_device *dev);
+static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex);
 static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
-static void gmac_init_rings(struct gmac *gm);
+static void gmac_init_rings(struct gmac *gm, int from_irq);
 static void gmac_start_dma(struct gmac *gm);
+static void gmac_stop_dma(struct gmac *gm);
+static void gmac_set_multicast(struct net_device *dev);
 static int gmac_open(struct net_device *dev);
 static int gmac_close(struct net_device *dev);
+static void gmac_tx_timeout(struct net_device *dev);
 static int gmac_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static int gmac_tx_cleanup(struct gmac *gm);
+static void gmac_tx_cleanup(struct net_device *dev, int force_cleanup);
 static void gmac_receive(struct net_device *dev);
 static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats *gmac_stats(struct net_device *dev);
 static int gmac_probe(void);
 static void gmac_probe1(struct device_node *gmac);
 
-/* Stuff for talking to the physical-layer chip */
+extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+                  unsigned char *devfn_ptr);
+
+/*
+ * Read via the mii interface from a PHY register
+ */
 static int
 mii_read(struct gmac *gm, int phy, int r)
 {
        int timeout;
 
-       GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18));
+       GM_OUT(GM_MIF_FRAME_CTL_DATA,
+               (0x01 << GM_MIF_FRAME_START_SHIFT) |
+               (0x02 << GM_MIF_FRAME_OPCODE_SHIFT) |
+               GM_MIF_FRAME_TURNAROUND_HI |
+               (phy << GM_MIF_FRAME_PHY_ADDR_SHIFT) |
+               (r << GM_MIF_FRAME_REG_ADDR_SHIFT));
+               
        for (timeout = 1000; timeout > 0; --timeout) {
                udelay(20);
-               if (GM_IN(MIFFRAME) & 0x10000)
-                       return GM_IN(MIFFRAME) & 0xffff;
+               if (GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_TURNAROUND_LO)
+                       return GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_DATA_MASK;
        }
        return -1;
 }
 
+/*
+ * Write on the mii interface to a PHY register
+ */
 static int
 mii_write(struct gmac *gm, int phy, int r, int v)
 {
        int timeout;
 
-       GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff));
+       GM_OUT(GM_MIF_FRAME_CTL_DATA,
+               (0x01 << GM_MIF_FRAME_START_SHIFT) |
+               (0x01 << GM_MIF_FRAME_OPCODE_SHIFT) |
+               GM_MIF_FRAME_TURNAROUND_HI |
+               (phy << GM_MIF_FRAME_PHY_ADDR_SHIFT) |
+               (r << GM_MIF_FRAME_REG_ADDR_SHIFT) |
+               (v & GM_MIF_FRAME_DATA_MASK));
+
        for (timeout = 1000; timeout > 0; --timeout) {
                udelay(20);
-               if (GM_IN(MIFFRAME) & 0x10000)
+               if (GM_IN(GM_MIF_FRAME_CTL_DATA) & GM_MIF_FRAME_TURNAROUND_LO)
                        return 0;
        }
        return -1;
 }
 
+/*
+ * Start MIF autopolling of the PHY status register
+ */
 static void 
 mii_poll_start(struct gmac *gm)
 {
        unsigned int tmp;
        
        /* Start the MIF polling on the external transceiver. */
-       tmp = GM_IN(MIFCONFIG);
-       tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK);
-       tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT);
-       tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT);
-       tmp |= GMAC_MIF_CFGPE;
-       GM_OUT(MIFCONFIG, tmp);
+       tmp = GM_IN(GM_MIF_CFG);
+       tmp &= ~(GM_MIF_CFGPR_MASK | GM_MIF_CFGPD_MASK);
+       tmp |= ((gm->phy_addr & 0x1f) << GM_MIF_CFGPD_SHIFT);
+       tmp |= (MII_SR << GM_MIF_CFGPR_SHIFT);
+       tmp |= GM_MIF_CFGPE;
+       GM_OUT(GM_MIF_CFG, tmp);
 
        /* Let the bits set. */
-       udelay(GMAC_MIF_POLL_DELAY);
+       udelay(GM_MIF_POLL_DELAY);
 
-       GM_OUT(MIFINTMASK, 0xffc0);
+       GM_OUT(GM_MIF_IRQ_MASK, 0xffc0);
 }
 
+/*
+ * Stop MIF autopolling of the PHY status register
+ */
 static void 
 mii_poll_stop(struct gmac *gm)
 {
-       GM_OUT(MIFINTMASK, 0xffff);
-       GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE);
-       udelay(GMAC_MIF_POLL_DELAY);
+       GM_OUT(GM_MIF_IRQ_MASK, 0xffff);
+       GM_BIC(GM_MIF_CFG, GM_MIF_CFGPE);
+       udelay(GM_MIF_POLL_DELAY);
 }
 
+/*
+ * Called when the MIF detect a change of the PHY status
+ * 
+ * handles monitoring the link and updating GMAC with the correct
+ * duplex mode.
+ * 
+ * Note: Are we missing status changes ? In this case, we'll have to
+ * a timer and control the autoneg. process more closely. Also, we may
+ * want to stop rx and tx side when the link is down.
+ */
 static void
 mii_interrupt(struct gmac *gm)
 {
-       unsigned long   flags;
        int             phy_status;
+       int             lpar_ability;
        
-       save_flags(flags);
-       cli();
-
        mii_poll_stop(gm);
 
        /* May the status change before polling is re-enabled ? */
        mii_poll_start(gm);
        
        /* We read the Auxilliary Status Summary register */
-       phy_status = mii_read(gm, gm->phy_addr, 0x19);
+       phy_status = mii_read(gm, gm->phy_addr, MII_SR);
+       if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) {
+               int             full_duplex;
+               int             link_100;
 #ifdef DEBUG_PHY
-       printk("mii_interrupt, phy_status: %x\n", phy_status);
+               printk("Link state change, phy_status: 0x%04x\n", phy_status);
 #endif
-       /* Auto-neg. complete ? */
-       if (phy_status & 0x8000) {
-               int full_duplex = 0;
-               switch((phy_status >> 8) & 0x7) {
-                       case 2:
-                       case 5:
-                               full_duplex = 1;
-                               break;
-               }
-               if (full_duplex != gm->full_duplex) {
-                       GM_BIC(TXMAC_CONFIG, 1);
-                       udelay(200);
-                       if (full_duplex) {
-                               printk("full duplex active\n");
-                               GM_OUT(TXMAC_CONFIG, 6);
-                               GM_OUT(XIF_CONFIG, 1);
-                       } else {
-                               printk("half duplex active\n");
-                               GM_OUT(TXMAC_CONFIG, 0);
-                               GM_OUT(XIF_CONFIG, 5);
-                       }
-                       GM_BIS(TXMAC_CONFIG, 1);
+               gm->phy_status = phy_status;
+
+               lpar_ability = mii_read(gm, gm->phy_addr, MII_ANLPA);
+               if (lpar_ability & MII_ANLPA_PAUS)
+                       GM_BIS(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
+               else
+                       GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
+
+               /* Link ? For now we handle only the 5201 PHY */
+               if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
+                   if (gm->phy_type == PHY_B5201) {
+                       int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
+#ifdef DEBUG_PHY
+                       printk("    Link up ! BCM5201 aux_stat: 0x%04x\n", aux_stat);
+#endif
+                       full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
+                       link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
+                   } else {
+                       full_duplex = 1;
+                       link_100 = 1;
+                   }
+#ifdef DEBUG_PHY
+                   printk("    full_duplex: %d, speed: %s\n", full_duplex,
+                       link_100 ? "100" : "10");
+#endif
+                   if (full_duplex != gm->full_duplex) {
                        gm->full_duplex = full_duplex;
+                       gmac_set_duplex_mode(gm, gm->full_duplex);
+                       gmac_start_dma(gm);
+                   }
+               } else if (!(phy_status & MII_SR_LKS)) {
+#ifdef DEBUG_PHY
+                   printk("    Link down !\n");
+#endif
                }
        }
+}
+
+/*
+ * Lookup for a PHY on the mii interface and reset it
+ */
+static int
+mii_lookup_and_reset(struct gmac *gm)
+{
+       int     i, timeout;
+       int     mii_status, mii_control;
 
-       restore_flags(flags);
+       /* Find the PHY */
+       gm->phy_addr = -1;
+       gm->phy_type = PHY_UNKNOWN;
+       
+       for(i=31; i>0; --i) {
+               mii_control = mii_read(gm, i, MII_CR);
+               mii_status = mii_read(gm, i, MII_SR);
+               if (mii_control != -1  && mii_status != -1 &&
+                       (mii_control != 0xffff || mii_status != 0xffff))
+                       break;
+       }
+       gm->phy_addr = i;
+       if (gm->phy_addr < 0)
+               return 0;
+
+       /* Reset it */
+       mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST);
+       mdelay(10);
+       for (timeout = 100; timeout > 0; --timeout) {
+               mii_control = mii_read(gm, gm->phy_addr, MII_CR);
+               if (mii_control == -1) {
+                       printk(KERN_ERR "%s PHY died after reset !\n",
+                               gm->dev->name);
+                       goto fail;
+               }
+               if ((mii_control & MII_CR_RST) == 0)
+                       break;
+               mdelay(10);
+       }
+       if (mii_control & MII_CR_RST) {
+               printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+               goto fail;
+       }
+       mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
+
+       /* Read the PHY ID */
+       gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
+               mii_read(gm, gm->phy_addr, MII_ID1);
+#ifdef DEBUG_PHY
+       printk("%s PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
+#endif
+       if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
+               gm->phy_type = PHY_B5400;
+               printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n",
+                       gm->dev->name);
+       } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
+               gm->phy_type = PHY_B5201;
+       } else {
+               printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n",
+                       gm->dev->name, gm->phy_id);
+       }
+
+       return 1;
+       
+fail:
+       gm->phy_addr = -1;
+       return 0;
 }
 
+/* 
+ * Setup the PHY autonegociation parameters
+ * 
+ * Code to force the PHY duplex mode and speed should be
+ * added here
+ */
 static void
-powerup_transceiver(struct gmac *gm)
+mii_setup_phy(struct gmac *gm)
 {
-       int phytype = mii_read(gm, 0, 3);
-#ifdef DEBUG_PHY
-       int i;
-#endif 
-       switch (phytype) {
-       case PHY_B5400:
-               mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800);
-               mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8);
-               break;
-       case PHY_B5201:
-               mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8);
-               break;
-       default:
-               printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype);
-       }
-       /* Check this */
-       gm->phy_addr = 0;
-       gm->full_duplex = 0;
+       int data;
+       
+       /* Stop auto-negociation */
+       data = mii_read(gm, gm->phy_addr, MII_CR);
+       mii_write(gm, gm->phy_addr, MII_CR, data & ~MII_CR_ASSE);
+
+       /* Set advertisement to 10/100 and Half/Full duplex
+        * (full capabilities) */
+       data = mii_read(gm, gm->phy_addr, MII_ANA);
+       data |= MII_ANA_TXAM | MII_ANA_FDAM | MII_ANA_10M;
+       mii_write(gm, gm->phy_addr, MII_ANA, data);
+       
+       /* Restart auto-negociation */
+       data = mii_read(gm, gm->phy_addr, MII_CR);
+       data |= MII_CR_ASSE;
+       mii_write(gm, gm->phy_addr, MII_CR, data);
+       data |= MII_CR_RAN;
+       mii_write(gm, gm->phy_addr, MII_CR, data);
+}
 
-#ifdef DEBUG_PHY
-       printk("PHY regs:\n");
-       for (i=0; i<0x20; i++) {
-               printk("%04x ", mii_read(gm, 0, i)); 
-               if ((i % 4) == 3)
-                       printk("\n");
+/* 
+ * Turn On/Off the gmac cell inside Uni-N
+ * 
+ * ToDo: Add code to support powering down of the PHY.
+ */
+static void
+gmac_set_power(struct gmac *gm, int power_up)
+{
+       if (power_up) {
+               feature_set_gmac_power(gm->of_node, 1);
+               if (gm->pci_devfn != 0xff) {
+                       u16 cmd;
+                       
+                       /*
+                        * Make sure PCI is correctly configured
+                        *
+                        * We use old pci_bios versions of the function since, by
+                        * default, gmac is not powered up, and so will be absent
+                        * from the kernel initial PCI lookup. 
+                        * 
+                        * Should be replaced by 2.4 new PCI mecanisms and really
+                        * regiser the device.
+                        */
+                       pcibios_read_config_word(gm->pci_bus, gm->pci_devfn,
+                               PCI_COMMAND, &cmd);
+                       cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+                       pcibios_write_config_word(gm->pci_bus, gm->pci_devfn,
+                               PCI_COMMAND, cmd);
+                       pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,
+                               PCI_LATENCY_TIMER, 16);
+                       pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,
+                               PCI_CACHE_LINE_SIZE, 8);
+               }
+       } else {
+               /* FIXME: Add PHY power down */
+               gm->phy_type = 0;
+               feature_set_gmac_power(gm->of_node, 0);
        }
-#endif
 }
 
+/*
+ * Makes sure the GMAC cell is powered up, and reset it
+ */
 static int
-gmac_reset(struct net_device *dev)
+gmac_powerup_and_reset(struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
        int timeout;
-
+       
        /* turn on GB clock */
-       out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2);
-       udelay(10);
-       GM_OUT(SW_RESET, 3);
+       gmac_set_power(gm, 1);
+       /* Perform a software reset */
+       GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);
        for (timeout = 100; timeout > 0; --timeout) {
                mdelay(10);
-               if ((GM_IN(SW_RESET) & 3) == 0)
+               if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) {
+                       /* Mask out all chips interrupts */
+                       GM_OUT(GM_IRQ_MASK, 0xffffffff);
                        return 0;
+               }
        }
-       printk(KERN_ERR "GMAC: reset failed!\n");
+       printk(KERN_ERR "%s reset failed!\n", dev->name);
+       gmac_set_power(gm, 0);
        return -1;
 }
 
+/*
+ * Set the MAC duplex mode.
+ * 
+ * Side effect: stops Tx MAC
+ */
+static void
+gmac_set_duplex_mode(struct gmac *gm, int full_duplex)
+{
+       /* Stop Tx MAC */
+       GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+       while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)
+               ;
+       
+       if (full_duplex) {
+               GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER
+                       | GM_MAC_TX_CONF_IGNORE_COLL);
+               GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);
+       } else {
+               GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER
+                       | GM_MAC_TX_CONF_IGNORE_COLL);
+               GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);
+       }
+}
+
+/*
+ * Initialize a bunch of registers to put the chip into a known
+ * and hopefully happy state
+ */
 static void
 gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
 {
-       int i;
+       int i, fifo_size;
+
+       /* Set random seed to low bits of MAC address */
+       GM_OUT(GM_MAC_RANDOM_SEED, mac_addr[5] | (mac_addr[4] << 8));
+       
+       /* Configure the data path mode to MII/GII */
+       GM_OUT(GM_PCS_DATAPATH_MODE, GM_PCS_DATAPATH_MII);
+       
+       /* Configure XIF to MII mode. Full duplex led is set
+        * by Apple, so...
+        */
+       GM_OUT(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_TX_MII_OUT_EN
+               | GM_MAC_XIF_CONF_FULL_DPLX_LED);
 
-       GM_OUT(RANSEED, 937);
-       GM_OUT(DATAPATHMODE, 4);
-       mii_write(gm, 0, 0, 0x1000);
-       GM_OUT(TXDMA_CONFIG, 0xffc00);
-       GM_OUT(RXDMA_CONFIG, 0);
-       GM_OUT(MACPAUSE, 0x1bf0);
-       GM_OUT(IPG0, 0);
-       GM_OUT(IPG1, 8);
-       GM_OUT(IPG2, 4);
-       GM_OUT(MINFRAMESIZE, 64);
-       GM_OUT(MAXFRAMESIZE, 2000);
-       GM_OUT(PASIZE, 7);
-       GM_OUT(JAMSIZE, 4);
-       GM_OUT(ATTEMPT_LIMIT, 16);
-       GM_OUT(SLOTTIME, 64);
-       GM_OUT(MACCNTL_TYPE, 0x8808);
-       GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]);
-       GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]);
-       GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]);
-       GM_OUT(MAC_ADDR_3, 0);
-       GM_OUT(MAC_ADDR_4, 0);
-       GM_OUT(MAC_ADDR_5, 0);
-       GM_OUT(MAC_ADDR_6, 0x0180);
-       GM_OUT(MAC_ADDR_7, 0xc200);
-       GM_OUT(MAC_ADDR_8, 0x0001);
-       GM_OUT(MAC_ADDR_FILTER_0, 0);
-       GM_OUT(MAC_ADDR_FILTER_1, 0);
-       GM_OUT(MAC_ADDR_FILTER_2, 0);
-       GM_OUT(MAC_ADDR_FILTER_MASK21, 0);
-       GM_OUT(MAC_ADDR_FILTER_MASK0, 0);
+       /* Mask out all MAC interrupts */
+       GM_OUT(GM_MAC_TX_MASK, 0xffff);
+       GM_OUT(GM_MAC_RX_MASK, 0xffff);
+       GM_OUT(GM_MAC_CTRLSTAT_MASK, 0xff);
+       
+       /* Setup bits of MAC */
+       GM_OUT(GM_MAC_SND_PAUSE, GM_MAC_SND_PAUSE_DEFAULT);
+       GM_OUT(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_RCV_PAUSE_EN);
+       
+       /* Configure GEM DMA */
+       GM_OUT(GM_GCONF, GM_GCONF_BURST_SZ |
+               (31 << GM_GCONF_TXDMA_LIMIT_SHIFT) |
+               (31 << GM_GCONF_RXDMA_LIMIT_SHIFT));
+       GM_OUT(GM_TX_CONF,
+               (GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) |
+               NTX_CONF);
+
+       /* 34 byte offset for checksum computation.  This works because ip_input() will clear out
+        * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
+        * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
+       */
+       GM_OUT(GM_RX_CONF,
+               (RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) |
+               (0x22 << GM_RX_CONF_CHK_START_SHIFT) |
+               (GM_RX_CONF_DMA_THR_DEFAULT << GM_RX_CONF_DMA_THR_SHIFT) |
+               NRX_CONF);
+
+       /* Configure other bits of MAC */
+       GM_OUT(GM_MAC_INTR_PKT_GAP0, GM_MAC_INTR_PKT_GAP0_DEFAULT);
+       GM_OUT(GM_MAC_INTR_PKT_GAP1, GM_MAC_INTR_PKT_GAP1_DEFAULT);
+       GM_OUT(GM_MAC_INTR_PKT_GAP2, GM_MAC_INTR_PKT_GAP2_DEFAULT);
+       GM_OUT(GM_MAC_MIN_FRAME_SIZE, GM_MAC_MIN_FRAME_SIZE_DEFAULT);
+       GM_OUT(GM_MAC_MAX_FRAME_SIZE, GM_MAC_MAX_FRAME_SIZE_DEFAULT);
+       GM_OUT(GM_MAC_PREAMBLE_LEN, GM_MAC_PREAMBLE_LEN_DEFAULT);
+       GM_OUT(GM_MAC_JAM_SIZE, GM_MAC_JAM_SIZE_DEFAULT);
+       GM_OUT(GM_MAC_ATTEMPT_LIMIT, GM_MAC_ATTEMPT_LIMIT_DEFAULT);
+       GM_OUT(GM_MAC_SLOT_TIME, GM_MAC_SLOT_TIME_DEFAULT);
+       GM_OUT(GM_MAC_CONTROL_TYPE, GM_MAC_CONTROL_TYPE_DEFAULT);
+       
+       /* Setup MAC addresses, clear filters, clear hash table */
+       GM_OUT(GM_MAC_ADDR_NORMAL0, (mac_addr[4] << 8) + mac_addr[5]);
+       GM_OUT(GM_MAC_ADDR_NORMAL1, (mac_addr[2] << 8) + mac_addr[3]);
+       GM_OUT(GM_MAC_ADDR_NORMAL2, (mac_addr[0] << 8) + mac_addr[1]);
+       GM_OUT(GM_MAC_ADDR_ALT0, 0);
+       GM_OUT(GM_MAC_ADDR_ALT1, 0);
+       GM_OUT(GM_MAC_ADDR_ALT2, 0);
+       GM_OUT(GM_MAC_ADDR_CTRL0, 0x0001);
+       GM_OUT(GM_MAC_ADDR_CTRL1, 0xc200);
+       GM_OUT(GM_MAC_ADDR_CTRL2, 0x0180);
+       GM_OUT(GM_MAC_ADDR_FILTER0, 0);
+       GM_OUT(GM_MAC_ADDR_FILTER1, 0);
+       GM_OUT(GM_MAC_ADDR_FILTER2, 0);
+       GM_OUT(GM_MAC_ADDR_FILTER_MASK1_2, 0);
+       GM_OUT(GM_MAC_ADDR_FILTER_MASK0, 0);
        for (i = 0; i < 27; ++i)
-               GM_OUT(MAC_HASHTABLE + i, 0);
-       GM_OUT(MACCNTL_CONFIG, 0);
+               GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + i, 0);
+       
+       /* Clear stat counters */
+       GM_OUT(GM_MAC_COLLISION_CTR, 0);
+       GM_OUT(GM_MAC_FIRST_COLLISION_CTR, 0);
+       GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);
+       GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);
+       GM_OUT(GM_MAC_DEFER_TIMER_COUNTER, 0);
+       GM_OUT(GM_MAC_PEAK_ATTEMPTS, 0);
+       GM_OUT(GM_MAC_RX_FRAME_CTR, 0);
+       GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);
+       GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);
+       GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);
+       GM_OUT(GM_MAC_RX_CODE_VIOLATION_CTR, 0);
+       
        /* default to half duplex */
-       GM_OUT(TXMAC_CONFIG, 0);
-       GM_OUT(XIF_CONFIG, 5);
+       GM_OUT(GM_MAC_TX_CONFIG, 0);
+       GM_OUT(GM_MAC_RX_CONFIG, 0);
+       gmac_set_duplex_mode(gm, gm->full_duplex);
+       
+       /* Setup pause thresholds */
+       fifo_size = GM_IN(GM_RX_FIFO_SIZE);
+       GM_OUT(GM_RX_PTH,
+               ((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 2 / GM_RX_PTH_UNITS))
+                       << GM_RX_PTH_OFF_SHIFT) |
+               ((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 3 / GM_RX_PTH_UNITS))
+                       << GM_RX_PTH_ON_SHIFT));
+               
+       /* Setup interrupt blanking */
+       if (GM_IN(GM_BIF_CFG) & GM_BIF_CFG_M66EN)
+               GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)
+                       | (8 << GM_RX_BLANK_INTR_TIME_SHIFT));
+       else
+               GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)
+                       | (4 << GM_RX_BLANK_INTR_TIME_SHIFT));  
 }
 
+/*
+ * Fill the Rx and Tx rings with good initial values, alloc
+ * fresh Rx skb's.
+ */
 static void
-gmac_init_rings(struct gmac *gm)
+gmac_init_rings(struct gmac *gm, int from_irq)
 {
        int i;
        struct sk_buff *skb;
        unsigned char *data;
        struct gmac_dma_desc *ring;
+       int gfp_flags = GFP_KERNEL;
+
+       if (from_irq || in_interrupt())
+               gfp_flags = GFP_ATOMIC;
 
        /* init rx ring */
        ring = (struct gmac_dma_desc *) gm->rxring;
        memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
        for (i = 0; i < NRX; ++i, ++ring) {
                data = dummy_buf;
-               gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+               gm->rx_buff[i] = skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
                if (skb != 0) {
-                       /*skb_reserve(skb, 2);*/
-                       data = skb->data;
+                       skb->dev = gm->dev;
+                       skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);
+                       skb_reserve(skb, RX_OFFSET);
+                       data = skb->data - RX_OFFSET;
                }
-               st_le32(&ring->address, virt_to_bus(data));
-               st_le32(&ring->cmd, RX_OWN);
+               st_le32(&ring->lo_addr, virt_to_bus(data));
+               st_le32(&ring->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));
        }
 
        /* init tx ring */
        ring = (struct gmac_dma_desc *) gm->txring;
-       memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+       memset(ring, 0, NTX * sizeof(struct gmac_dma_desc));
+
+       gm->next_rx = 0;
+       gm->next_tx = 0;
+       gm->tx_gone = 0;
 
        /* set pointers in chip */
        mb();
-       GM_OUT(RXDMA_BASE_HIGH, 0);
-       GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring));
-       GM_OUT(TXDMA_BASE_HIGH, 0);
-       GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring));
+       GM_OUT(GM_RX_DESC_HI, 0);
+       GM_OUT(GM_RX_DESC_LO, virt_to_bus(gm->rxring));
+       GM_OUT(GM_TX_DESC_HI, 0);
+       GM_OUT(GM_TX_DESC_LO, virt_to_bus(gm->txring));
 }
 
+/*
+ * Start the Tx and Rx DMA engines and enable interrupts
+ * 
+ * Note: The various mdelay(20); come from Darwin implentation. Some
+ * tests (doc ?) are needed to replace those with something more intrusive.
+ */
 static void
 gmac_start_dma(struct gmac *gm)
 {
-       GM_BIS(RXDMA_CONFIG, 1);
-       GM_BIS(RXMAC_CONFIG, 1);
-       GM_OUT(RXDMA_KICK, NRX);
-       GM_BIS(TXDMA_CONFIG, 1);
-       GM_BIS(TXMAC_CONFIG, 1);
+       /* Enable Tx and Rx */
+       GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN);
+       mdelay(20);
+       GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN);
+       mdelay(20);
+       GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
+       mdelay(20);
+       GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+       mdelay(20);
+       /* Kick the receiver and enable interrupts */
+       GM_OUT(GM_RX_KICK, NRX);
+       GM_BIC(GM_IRQ_MASK,     GM_IRQ_TX_INT_ME |
+                               GM_IRQ_TX_ALL |
+                               GM_IRQ_RX_DONE |
+                               GM_IRQ_RX_TAG_ERR |
+                               GM_IRQ_MAC_RX |
+                               GM_IRQ_MIF |
+                               GM_IRQ_BUS_ERROR);
 }
 
-static int gmac_open(struct net_device *dev)
+/*
+ * Stop the Tx and Rx DMA engines after disabling interrupts
+ * 
+ * Note: The various mdelay(20); come from Darwin implentation. Some
+ * tests (doc ?) are needed to replace those with something more intrusive.
+ */
+static void
+gmac_stop_dma(struct gmac *gm)
+{
+       /* disable interrupts */
+       GM_OUT(GM_IRQ_MASK, 0xffffffff);
+       /* Enable Tx and Rx */
+       GM_BIC(GM_TX_CONF, GM_TX_CONF_DMA_EN);
+       mdelay(20);
+       GM_BIC(GM_RX_CONF, GM_RX_CONF_DMA_EN);
+       mdelay(20);
+       GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
+       mdelay(20);
+       GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+       mdelay(20);
+}
+
+/*
+ * Configure promisc mode and setup multicast hash table
+ * filter
+ */
+#define CRC_POLY       0xedb88320
+static void
+gmac_set_multicast(struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
+       struct dev_mc_list *dmi = dev->mc_list;
+       int i,j,k,b;
+       unsigned long crc;
+       int multicast_hash = 0;
+       int multicast_all = 0;
+       int promisc = 0;
+       
 
-       if (gmac_reset(dev))
-               return -EIO;
+       /* Lock out others. */
+       netif_stop_queue(dev);
+
+
+       if (dev->flags & IFF_PROMISC)
+               promisc = 1;
+       else if ((dev->flags & IFF_ALLMULTI) /* || (dev->mc_count > XXX) */) {
+               multicast_all = 1;
+       } else {
+               u16 hash_table[16];
+
+               for(i = 0; i < 16; i++)
+                       hash_table[i] = 0;
+
+               for (i = 0; i < dev->mc_count; i++) {
+                       crc = ~0;
+                       for (j = 0; j < 6; ++j) {
+                           b = dmi->dmi_addr[j];
+                           for (k = 0; k < 8; ++k) {
+                               if ((crc ^ b) & 1)
+                                   crc = (crc >> 1) ^ CRC_POLY;
+                               else
+                                   crc >>= 1;
+                               b >>= 1;
+                           }
+                       }
+                       j = crc >> 24;  /* bit number in multicast_filter */
+                       hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
+                       dmi = dmi->next;
+               }
+
+               for (i = 0; i < 16; i++)
+                       GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + (i*4), hash_table[i]);
+               GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+               multicast_hash = 1;
+       }
+
+       if (promisc)
+               GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);
+       else
+               GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);
+
+       if (multicast_hash)
+               GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+       else
+               GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);
+
+       if (multicast_all)
+               GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);
+       else
+               GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);
+       
+       /* Let us get going again. */
+       netif_wake_queue(dev);
+}
+
+/*
+ * Open the interface
+ */
+static int
+gmac_open(struct net_device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
 
        MOD_INC_USE_COUNT;
 
-       powerup_transceiver(gm);
+       /* Power up and reset chip */
+       if (gmac_powerup_and_reset(dev)) {
+               MOD_DEC_USE_COUNT;
+               return -EIO;
+       }
+
+       /* Get our interrupt */
+       if (request_irq(dev->irq, gmac_interrupt, 0, dev->name, dev)) {
+               printk(KERN_ERR "%s can't get irq %d\n", dev->name, dev->irq);
+               MOD_DEC_USE_COUNT;
+               return -EAGAIN;
+       }
+
+       gm->full_duplex = 0;
+       gm->phy_status = 0;
+       
+       /* Find a PHY */
+       if (!mii_lookup_and_reset(gm))
+               printk(KERN_WARNING "%s WARNING ! Can't find PHY\n", dev->name);
+
+       /* Configure the PHY */
+       mii_setup_phy(gm);
+       
+       /* Initialize the descriptor rings */
+       gmac_init_rings(gm, 0);
+
+       /* Initialize the MAC */
        gmac_mac_init(gm, dev->dev_addr);
-       gmac_init_rings(gm);
-       gmac_start_dma(gm);
+       
+       /* Initialize the multicast tables & promisc mode if any */
+       gmac_set_multicast(dev);
+       
+       /*
+        * Check out PHY status and start auto-poll
+        * 
+        * Note: do this before enabling interrutps
+        */
        mii_interrupt(gm);
 
-       GM_OUT(INTR_DISABLE, 0xfffdffe8);
+       /* Start the chip */
+       gmac_start_dma(gm);
+
+       gm->opened = 1;
 
        return 0;
 }
 
-static int gmac_close(struct net_device *dev)
+/* 
+ * Close the interface
+ */
+static int
+gmac_close(struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
        int i;
 
+       gm->opened = 0;
+
+       /* Stop chip and interrupts */
+       gmac_stop_dma(gm);
+
+       /* Stop polling PHY */
        mii_poll_stop(gm);
+
+       /* Free interrupt */
+       free_irq(dev->irq, dev);
        
-       GM_BIC(RXDMA_CONFIG, 1);
-       GM_BIC(RXMAC_CONFIG, 1);
-       GM_BIC(TXDMA_CONFIG, 1);
-       GM_BIC(TXMAC_CONFIG, 1);
-       GM_OUT(INTR_DISABLE, ~0U);
+       /* Shut down chip */
+       gmac_set_power(gm, 0);
+
+       /* Empty rings of any remaining gremlins */
        for (i = 0; i < NRX; ++i) {
                if (gm->rx_buff[i] != 0) {
                        dev_kfree_skb(gm->rx_buff[i]);
@@ -374,153 +786,370 @@ static int gmac_close(struct net_device *dev)
        return 0;
 }
 
-static int gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
+/*
+ * Handle a transmit timeout
+ */
+static void
+gmac_tx_timeout(struct net_device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+       int i, timeout;
+       
+       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+
+       spin_lock_irq(&gm->lock);
+
+       /* Stop chip */
+       gmac_stop_dma(gm);
+       /* Empty Tx ring of any remaining gremlins */
+       gmac_tx_cleanup(dev, 1);
+       /* Empty Rx ring of any remaining gremlins */
+       for (i = 0; i < NRX; ++i) {
+               if (gm->rx_buff[i] != 0) {
+                       dev_kfree_skb_irq(gm->rx_buff[i]);
+                       gm->rx_buff[i] = 0;
+               }
+       }
+       /* Perform a software reset */
+       GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);
+       for (timeout = 100; timeout > 0; --timeout) {
+               mdelay(10);
+               if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) {
+                       /* Mask out all chips interrupts */
+                       GM_OUT(GM_IRQ_MASK, 0xffffffff);
+                       break;
+               }
+       }
+       if (!timeout)
+               printk(KERN_ERR "%s reset chip failed !\n", dev->name);
+       /* Create fresh rings */
+       gmac_init_rings(gm, 1);
+       /* re-initialize the MAC */
+       gmac_mac_init(gm, dev->dev_addr);       
+       /* re-initialize the multicast tables & promisc mode if any */
+       gmac_set_multicast(dev);
+       /* Restart PHY auto-poll */
+       mii_interrupt(gm);
+       /* Restart chip */
+       gmac_start_dma(gm);
+       
+       spin_unlock_irq(&gm->lock);
+
+       netif_wake_queue(dev);
+}
+
+/*
+ * Add a packet to the transmit ring
+ */
+static int
+gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
        volatile struct gmac_dma_desc *dp;
-       unsigned long flags;
        int i;
 
-       save_flags(flags); cli();
+       spin_lock_irq(&gm->lock);
+
        i = gm->next_tx;
        if (gm->tx_buff[i] != 0) {
-               /* buffer is full, can't send this packet at the moment */
+               /* 
+                * Buffer is full, can't send this packet at the moment
+                * 
+                * Can this ever happen in 2.4 ?
+                */
                netif_stop_queue(dev);
-               gm->tx_full = 1;
-               restore_flags(flags);
+               spin_unlock_irq(&gm->lock);
                return 1;
        }
        gm->next_tx = (i + 1) & (NTX - 1);
        gm->tx_buff[i] = skb;
-       restore_flags(flags);
-
+       
        dp = &gm->txring[i];
-       dp->status = 0;
+       /* FIXME: Interrupt on all packet for now, change this to every N packet,
+        * with N to be adjusted
+        */
+       dp->flags = TX_FL_INTERRUPT;
        dp->hi_addr = 0;
-       st_le32(&dp->address, virt_to_bus(skb->data));
+       st_le32(&dp->lo_addr, virt_to_bus(skb->data));
        mb();
-       st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len);
+       st_le32(&dp->size, TX_SZ_SOP | TX_SZ_EOP | skb->len);
        mb();
 
-       GM_OUT(TXDMA_KICK, gm->next_tx);
+       GM_OUT(GM_TX_KICK, gm->next_tx);
+
+       if (gm->tx_buff[gm->next_tx] != 0)
+               netif_stop_queue(dev);
+
+       spin_unlock_irq(&gm->lock);
+
+       dev->trans_start = jiffies;
 
        return 0;
 }
 
-static int gmac_tx_cleanup(struct gmac *gm)
+/*
+ * Handle servicing of the transmit ring by deallocating used
+ * Tx packets and restoring flow control when necessary
+ */
+static void
+gmac_tx_cleanup(struct net_device *dev, int force_cleanup)
 {
-       int i = gm->tx_gone;
+       struct gmac *gm = (struct gmac *) dev->priv;
        volatile struct gmac_dma_desc *dp;
        struct sk_buff *skb;
-       int ret = 0;
-       int gone = GM_IN(TXDMA_COMPLETE);
+       int gone, i;
 
-       while (i != gone) {
+       i = gm->tx_gone;
+       gone = GM_IN(GM_TX_COMP);
+       
+       while (force_cleanup || i != gone) {
                skb = gm->tx_buff[i];
                if (skb == NULL)
                        break;
                dp = &gm->txring[i];
-               gm->stats.tx_bytes += skb->len;
-               ++gm->stats.tx_packets;
+               if (force_cleanup)
+                       ++gm->stats.tx_errors;
+               else {
+                       ++gm->stats.tx_packets;
+                       gm->stats.tx_bytes += skb->len;
+               }
                gm->tx_buff[i] = NULL;
                dev_kfree_skb_irq(skb);
                if (++i >= NTX)
                        i = 0;
        }
-       if (i != gm->tx_gone) {
-               ret = gm->tx_full;
-               gm->tx_gone = i;
-               gm->tx_full = 0;
-       }
-       return ret;
+       gm->tx_gone = i;
+
+       if (!force_cleanup && netif_queue_stopped(dev) &&
+           (gm->tx_buff[gm->next_tx] == 0))
+               netif_wake_queue(dev);
+
+       spin_unlock(&gm->lock);
 }
 
-static void gmac_receive(struct net_device *dev)
+/*
+ * Handle servicing of receive ring
+ */
+static void
+gmac_receive(struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
        int i = gm->next_rx;
        volatile struct gmac_dma_desc *dp;
-       struct sk_buff *skb;
-       int len;
+       struct sk_buff *skb, *new_skb;
+       int len, flags, drop, last;
        unsigned char *data;
+       u16 csum;
 
+       last = -1;
        for (;;) {
                dp = &gm->rxring[i];
-               if (ld_le32(&dp->cmd) & RX_OWN)
+               /* Buffer not yet filled, no more Rx buffers to handle */
+               if (ld_le32(&dp->size) & RX_SZ_OWN)
                        break;
-               len = (ld_le32(&dp->cmd) >> 16) & 0x7fff;
+               /* Get packet length, flags, etc... */
+               len = (ld_le32(&dp->size) >> 16) & 0x7fff;
+               flags = ld_le32(&dp->flags);
                skb = gm->rx_buff[i];
-               if (skb == 0) {
-                       ++gm->stats.rx_dropped;
-               } else if (ld_le32(&dp->status) & 0x40000000) {
+               drop = 0;
+               new_skb = NULL;
+               csum = ld_le32(&dp->size) & RX_SZ_CKSUM_MASK;
+               
+               /* Handle errors */
+               if ((len < ETH_ZLEN)||(flags & RX_FL_CRC_ERROR)||(!skb)) {
                        ++gm->stats.rx_errors;
-                       dev_kfree_skb_irq(skb);
+                       if (len < ETH_ZLEN)
+                               ++gm->stats.rx_length_errors;
+                       if (flags & RX_FL_CRC_ERROR)
+                               ++gm->stats.rx_crc_errors;
+                       if (!skb) {
+                               ++gm->stats.rx_dropped;
+                               skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+                               if (skb) {
+                                       gm->rx_buff[i] = skb;
+                                       skb->dev = dev;
+                                       skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);
+                                       skb_reserve(skb, RX_OFFSET);
+                               }
+                       }
+                       drop = 1;
                } else {
-                       skb_put(skb, len);
-                       skb->dev = dev;
+                       /* Large packet, alloc a new skb for the ring */
+                       if (len > RX_COPY_THRESHOLD) {
+                           new_skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+                           if(!new_skb) {
+                               printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",
+                                       dev->name);
+                               drop = 1;
+                               ++gm->stats.rx_dropped;
+                               goto finish;
+                           }
+
+                           gm->rx_buff[i] = new_skb;
+                           new_skb->dev = dev;
+                           skb_put(new_skb, ETH_FRAME_LEN + RX_OFFSET);
+                           skb_reserve(new_skb, RX_OFFSET);
+                           skb_trim(skb, len);
+                       } else {
+                           /* Small packet, copy it to a new small skb */
+                           struct sk_buff *copy_skb = dev_alloc_skb(len + RX_OFFSET);
+
+                           if(!copy_skb) {
+                               printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",
+                                       dev->name);
+                               drop = 1;
+                               ++gm->stats.rx_dropped;
+                               goto finish;
+                           }
+
+                           copy_skb->dev = dev;
+                           skb_reserve(copy_skb, RX_OFFSET);
+                           skb_put(copy_skb, len);
+                           memcpy(copy_skb->data, skb->data, len);
+
+                           new_skb = skb;
+                           skb = copy_skb;
+                       }
+               }
+       finish:
+               /* Need to drop packet ? */
+               if (drop) {
+                       new_skb = skb;
+                       skb = NULL;
+               }
+               
+               /* Put back ring entry */
+               data = new_skb ? (new_skb->data - RX_OFFSET) : dummy_buf;
+               dp->hi_addr = 0;
+               st_le32(&dp->lo_addr, virt_to_bus(data));
+               mb();
+               st_le32(&dp->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));
+               
+               /* Got Rx packet ? */
+               if (skb) {
+                       /* Yes, baby, keep that hot ;) */
+                       if(!(csum ^ 0xffff))
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       else
+                               skb->ip_summed = CHECKSUM_NONE;
+                       skb->ip_summed = CHECKSUM_NONE;
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);
                        gm->stats.rx_bytes += skb->len;
                        ++gm->stats.rx_packets;
                }
-               data = dummy_buf;
-               gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
-               if (skb != 0) {
-                       /*skb_reserve(skb, 2);*/
-                       data = skb->data;
-               }
-               st_le32(&dp->address, virt_to_bus(data));
-               dp->hi_addr = 0;
-               mb();
-               st_le32(&dp->cmd, RX_OWN);
+               
+               last = i;
                if (++i >= NRX)
                        i = 0;
        }
        gm->next_rx = i;
+       if (last >= 0) {
+               mb();
+               GM_OUT(GM_RX_KICK, last & 0xfffffffc);
+       }
 }
 
-static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+/*
+ * Service chip interrupts
+ */
+static void
+gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct gmac *gm = (struct gmac *) dev->priv;
        unsigned int status;
 
-       status = GM_IN(INTR_STATUS);
-       GM_OUT(INTR_ACK, status);
+       status = GM_IN(GM_IRQ_STATUS);
+       if (status & (GM_IRQ_BUS_ERROR | GM_IRQ_MIF))
+               GM_OUT(GM_IRQ_ACK, status & (GM_IRQ_BUS_ERROR | GM_IRQ_MIF));
        
-       if (status & GMAC_IRQ_MIF)
+       if (status & (GM_IRQ_RX_TAG_ERR | GM_IRQ_BUS_ERROR)) {
+               printk(KERN_ERR "%s: IRQ Error status: 0x%08x\n",
+                       dev->name, status);
+       }
+       
+       if (status & GM_IRQ_MIF) {
+               spin_lock(&gm->lock);
                mii_interrupt(gm);
-       gmac_receive(dev);
-       if (gmac_tx_cleanup(gm))
-               netif_wake_queue(dev);
+               spin_unlock(&gm->lock);
+       }
+       
+       if (status & GM_IRQ_RX_DONE) {
+               spin_lock(&gm->lock);
+               gmac_receive(dev);
+               spin_unlock(&gm->lock);
+       }
+               
+       if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) {
+               spin_lock(&gm->lock);
+               gmac_tx_cleanup(dev, 0);
+               spin_unlock(&gm->lock);
+       }
 }
 
-static struct net_device_stats *gmac_stats(struct net_device *dev)
+/*
+ * Retreive some error stats from chip and return them
+ * to above layer
+ */
+static struct net_device_stats *
+gmac_stats(struct net_device *dev)
 {
        struct gmac *gm = (struct gmac *) dev->priv;
+       struct net_device_stats *stats = &gm->stats;
+
+       if (gm && gm->opened) {
+               stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR);
+               GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);
+
+               stats->rx_frame_errors += GM_IN(GM_MAC_RX_ALIGN_ERR_CTR);
+               GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);
 
-       return &gm->stats;
+               stats->rx_length_errors += GM_IN(GM_MAC_RX_LEN_ERR_CTR);
+               GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);
+
+               stats->tx_aborted_errors += GM_IN(GM_MAC_EXCS_COLLISION_CTR);
+
+               stats->collisions +=
+                       (GM_IN(GM_MAC_EXCS_COLLISION_CTR) +
+                        GM_IN(GM_MAC_LATE_COLLISION_CTR));
+               GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);
+               GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);
+       }
+
+       return stats;
 }
 
-static int __init gmac_probe(void)
+static int __init
+gmac_probe(void)
 {
        struct device_node *gmac;
 
+       /* We bump use count during probe since get_free_page can sleep
+        * which can be a race condition if module is unloaded at this
+        * point.
+        */
+       MOD_INC_USE_COUNT;
+       
        /*
-        * We could (and maybe should) do this using PCI scanning
-        * for vendor/net_device ID 0x106b/0x21.
+        * We don't use PCI scanning on pmac since the GMAC cell is disabled
+        * by default, and thus absent from kernel original PCI probing.
         */
        for (gmac = find_compatible_devices("network", "gmac"); gmac != 0;
             gmac = gmac->next)
                gmac_probe1(gmac);
 
+
+       MOD_DEC_USE_COUNT;
+
        return 0;
 }
 
-static void gmac_probe1(struct device_node *gmac)
+static void
+gmac_probe1(struct device_node *gmac)
 {
        struct gmac *gm;
-       unsigned long descpage;
+       unsigned long tx_descpage, rx_descpage;
        unsigned char *addr;
        struct net_device *dev;
        int i;
@@ -538,9 +1167,15 @@ static void gmac_probe1(struct device_node *gmac)
                return;
        }
 
-       descpage = get_free_page(GFP_KERNEL);
-       if (descpage == 0) {
-               printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+       tx_descpage = get_free_page(GFP_KERNEL);
+       if (tx_descpage == 0) {
+               printk(KERN_ERR "GMAC: can't get a page for tx descriptors\n");
+               return;
+       }
+       rx_descpage = get_free_page(GFP_KERNEL);
+       if (rx_descpage == 0) {
+               printk(KERN_ERR "GMAC: can't get a page for rx descriptors\n");
+               free_page(tx_descpage);
                return;
        }
 
@@ -551,32 +1186,39 @@ static void gmac_probe1(struct device_node *gmac)
        dev->base_addr = gmac->addrs[0].address;
        gm->regs = (volatile unsigned int *)
                ioremap(gmac->addrs[0].address, 0x10000);
-       gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
        dev->irq = gmac->intrs[0].line;
+       gm->dev = dev;
+
+       if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) {
+               gm->pci_bus = gm->pci_devfn = 0xff;
+               printk(KERN_ERR "Can't locate GMAC PCI entry\n");
+       }
 
        printk(KERN_INFO "%s: GMAC at", dev->name);
        for (i = 0; i < 6; ++i) {
                dev->dev_addr[i] = addr[i];
                printk("%c%.2x", (i? ':': ' '), addr[i]);
        }
-       printk("\n");
+       printk(", driver " GMAC_VERSION "\n");
 
-       gm->desc_page = descpage;
-       gm->rxring = (volatile struct gmac_dma_desc *) descpage;
-       gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
+       gm->tx_desc_page = tx_descpage;
+       gm->rx_desc_page = rx_descpage;
+       gm->rxring = (volatile struct gmac_dma_desc *) rx_descpage;
+       gm->txring = (volatile struct gmac_dma_desc *) tx_descpage;
 
        gm->phy_addr = 0;
-       
+       gm->opened = 0;
+
        dev->open = gmac_open;
        dev->stop = gmac_close;
        dev->hard_start_xmit = gmac_xmit_start;
        dev->get_stats = gmac_stats;
+       dev->set_multicast_list = &gmac_set_multicast;
+       dev->tx_timeout = &gmac_tx_timeout;
+       dev->watchdog_timeo = 5*HZ;
 
        ether_setup(dev);
-
-       if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev))
-               printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
-
+       
        gm->next_gmac = gmacs;
        gmacs = dev;
 }
@@ -591,10 +1233,10 @@ static void __exit gmac_cleanup_module(void)
 
        while ((dev = gmacs) != NULL) {
                gm = (struct gmac *) dev->priv;
-               gmacs = gm->next_gmac;
-               free_irq(dev->irq, dev);
-               free_page(gm->desc_page);
                unregister_netdev(dev);
+               free_page(gm->tx_desc_page);
+               free_page(gm->rx_desc_page);
+               gmacs = gm->next_gmac;
                kfree(dev);
        }
 }
index 2e50f6072e8abf4671d0811664c4a60505bb4f5d..40bc95bfa936be2b122415deeefd29ea5422c542 100644 (file)
  * Apple G4 powermac.
  */
 
-/* Register offsets */
-#define        INTR_STATUS             0x000c
-#define INTR_DISABLE           0x0010
-#define INTR_ACK               0x0014
-#define SW_RESET               0x1010
-#define TXDMA_KICK             0x2000
-#define TXDMA_CONFIG           0x2004
-#define TXDMA_BASE_LOW         0x2008
-#define TXDMA_BASE_HIGH                0x200c
-#define TXDMA_STATE_MACH       0x2028
-#define TXDMA_COMPLETE         0x2100
-#define RXDMA_CONFIG           0x4000
-#define RXDMA_BASE_LOW         0x4004
-#define RXDMA_BASE_HIGH                0x4008
-#define RXDMA_KICK             0x4100
-#define MACPAUSE               0x6008
-#define TXMAC_STATUS           0x6010
-#define TXMAC_CONFIG           0x6030
-#define RXMAC_CONFIG           0x6034
-#define MACCNTL_CONFIG         0x6038
-#define XIF_CONFIG             0x603c
-#define IPG0                   0x6040
-#define IPG1                   0x6044
-#define IPG2                   0x6048
-#define SLOTTIME               0x604c
-#define MINFRAMESIZE           0x6050
-#define MAXFRAMESIZE           0x6054
-#define PASIZE                 0x6058
-#define JAMSIZE                        0x605c
-#define ATTEMPT_LIMIT          0x6060
-#define MACCNTL_TYPE           0x6064
-#define MAC_ADDR_0             0x6080
-#define MAC_ADDR_1             0x6084
-#define MAC_ADDR_2             0x6088
-#define MAC_ADDR_3             0x608c
-#define MAC_ADDR_4             0x6090
-#define MAC_ADDR_5             0x6094
-#define MAC_ADDR_6             0x6098
-#define MAC_ADDR_7             0x609c
-#define MAC_ADDR_8             0x60a0
-#define MAC_ADDR_FILTER_0      0x60a4
-#define MAC_ADDR_FILTER_1      0x60a8
-#define MAC_ADDR_FILTER_2      0x60ac
-#define MAC_ADDR_FILTER_MASK21 0x60b0
-#define MAC_ADDR_FILTER_MASK0  0x60b4
-#define MAC_HASHTABLE          0x60c0
-#define RANSEED                        0x6130
-#define MIFFRAME               0x620c
-#define MIFCONFIG              0x6210
-#define MIFINTMASK             0x6214
-#define MIFSTATUS              0x6218
-#define DATAPATHMODE           0x9050
+
+/* 
+ * GMAC register definitions
+ * 
+ * Note: We encode the register size the same way Apple does. I didn't copy
+ *       Apple's source as-is to avoid licence issues however. That's really
+ *       painful to re-define all those registers ...
+ *       The constants themselves were partially found in OF code, in Sun
+ *       GEM driver and in Apple's Darwin GMAC driver
+ */
+
+#define REG_SZ_8                       0x00000000
+#define REG_SZ_16                      0x40000000
+#define REG_SZ_32                      0x80000000
+#define REG_MASK                       0x0FFFFFFF
+
+       /*
+        * Global registers
+        */
+
+/* -- 0x0004   RW      Global configuration
+ * d: 0x00000042
+ */
+#define GM_GCONF                       (0x0004 | REG_SZ_16)
+#define GM_GCONF_BURST_SZ              0x0001          /* 1: 64 bytes/burst, 0: infinite */
+#define GM_GCONF_TXDMA_LIMIT_MASK      0x003e          /* 5-1: No of 64 bytes transfers */
+#define GM_GCONF_TXDMA_LIMIT_SHIFT     1
+#define GM_GCONF_RXDMA_LIMIT_MASK      0x07c0          /* 10-6: No of 64 bytes transfers */
+#define GM_GCONF_RXDMA_LIMIT_SHIFT     6
 
 /* -- 0x000C   R-C     Global Interrupt status. 
  * d: 0x00000000       bits 0-6 cleared on read (C)
  */
-#define GMAC_IRQ_TX_INT_ME     0x00000001      /* C Frame with INT_ME bit set in fifo */
-#define GMAC_IRQ_TX_ALL                0x00000002      /* C TX descriptor ring empty */
-#define GMAC_IRQ_TX_DONE       0x00000004      /* C moved from host to TX fifo */
-#define GMAC_IRQ_RX_DONE       0x00000010      /* C moved from RX fifo to host */
-#define GMAC_IRQ_RX_NO_BUF     0x00000020      /* C No RX buffer available */
-#define GMAC_IRQ_RX_TAG_ERR    0x00000040      /* C RX tag error */
+#define GM_IRQ_STATUS                  (0x000c | REG_SZ_32)
+#define GM_IRQ_TX_INT_ME               0x00000001      /* C Frame with INT_ME bit set in fifo */
+#define GM_IRQ_TX_ALL                  0x00000002      /* C TX descriptor ring empty */
+#define GM_IRQ_TX_DONE                 0x00000004      /* C moved from host to TX fifo */
+#define GM_IRQ_RX_DONE                 0x00000010      /* C moved from RX fifo to host */
+#define GM_IRQ_RX_NO_BUF               0x00000020      /* C No RX buffer available */
+#define GM_IRQ_RX_TAG_ERR              0x00000040      /* C RX tag error */
+#define GM_IRQ_PCS                     0x00002000      /* PCS interrupt ? */
+#define GM_IRQ_MAC_TX                  0x00004000      /* MAC tx register set */
+#define GM_IRQ_MAC_RX                  0x00008000      /* MAC rx register set  */
+#define GM_IRQ_MAC_CTRL                        0x00010000      /* MAC control register set  */
+#define GM_IRQ_MIF                     0x00020000      /* MIF status register set */
+#define GM_IRQ_BUS_ERROR               0x00040000      /* Bus error status register set */
+#define GM_IRQ_TX_COMP                 0xfff80000      /* TX completion mask */
+       
+/* -- 0x0010   RW      Interrupt mask. 
+ * d: 0xFFFFFFFF
+ */
+#define GM_IRQ_MASK                    (0x0010 | REG_SZ_32)
 
-#define GMAC_IRQ_PCS           0x00002000      /* PCS interrupt ? */
-#define GMAC_IRQ_MAC_TX                0x00004000      /* MAC tx register set */
-#define GMAC_IRQ_MAC_RX                0x00008000      /* MAC rx register set  */
-#define GMAC_IRQ_MAC_CTRL      0x00010000      /* MAC control register set  */
-#define GMAC_IRQ_MIF           0x00020000      /* MIF status register set */
-#define GMAC_IRQ_BUS_ERROR     0x00040000      /* Bus error status register set */
+/* -- 0x0014   WO      Interrupt ack.
+ *                     Ack. "high" interrupts
+ */
+#define GM_IRQ_ACK                     (0x0014 | REG_SZ_32)
 
-#define GMAC_IRQ_TX_COMP       0xfff80000      /* TX completion mask */
+/* -- 0x001C   WO      Alias of status register (no auto-clear of "low" interrupts)
+ */
+#define GM_IRQ_ALT_STAT                        (0x001C | REG_SZ_32)
 
-/* -- 0x6210   RW      MIF config reg
+/* -- 0x1000   R-C     PCI Error status register
+ */
+#define GM_PCI_ERR_STAT                        (0x1000 | REG_SZ_8)
+#define GM_PCI_ERR_BAD_ACK             0x01            /* Bad Ack64 */
+#define GM_PCI_ERR_TIMEOUT             0x02            /* Transaction timeout */
+#define GM_PCI_ERR_OTHER               0x04            /* Any other PCI error */
+       
+/* -- 0x1004   RW      PCI Error mask register
+ * d: 0xFFFFFFFF
+ */
+#define GM_PCI_ERR_MASK                        (0x1004 | REG_SZ_8)
+
+/* -- 0x1008   RW      BIF Configuration
+ * d: 0x00000000
+ */
+#define GM_BIF_CFG                     (0x1008 | REG_SZ_8)
+#define        GM_BIF_CFG_SLOWCLK              0x01            /* for parity error timing */
+#define        GM_BIF_CFG_HOST_64              0x02            /* 64-bit host */
+#define        GM_BIF_CFG_B64D_DIS             0x04            /* no 64-bit wide data cycle */
+#define        GM_BIF_CFG_M66EN                0x08            /* Read-only: sense if configured for 66MHz */
+       
+/* -- 0x100C   RW      BIF Diagnostic ???
+ */
+#define GM_BIF_DIAG                    (0x100C | REG_SZ_32)
+#define GM_BIF_DIAG_BURST_STATE                0x007F0000
+#define GM_BIF_DIAG_STATE_MACH         0xFF000000
+
+/* -- 0x1010   RW      Software reset
+ *                     Lower two bits reset TX and RX, both reset whole gmac. They come back
+ *                     to 0 when reset is complete.
+ *                     bit 2 force RSTOUT# pin when set (PHY reset)
+ */
+#define GM_RESET                       (0x1010 | REG_SZ_8)
+#define        GM_RESET_TX                     0x01
+#define        GM_RESET_RX                     0x02
+#define        GM_RESET_RSTOUT                 0x04            /* PHY reset */
+
+
+       /*
+        * Tx DMA Registers
+        */
+
+/* -- 0x2000   RW      Tx Kick
+ * d: 0x00000000       Written by the host with the last tx descriptor number +1 to send
+ */
+#define GM_TX_KICK                     (0x2000 | REG_SZ_16)
+
+/* -- 0x2004   RW      Tx configuration
+ * d: 0x118010         Controls operation of Tx DMA channel
+ */
+
+#define GM_TX_CONF                     (0x2004 | REG_SZ_32)
+#define        GM_TX_CONF_DMA_EN               0x00000001      /* Tx DMA enable */
+#define        GM_TX_CONF_RING_SZ_MASK         0x0000001e      /* Tx desc ring size */
+#define GM_TX_CONF_RING_SZ_SHIFT       1               /* Tx desc ring size shift */
+#define GM_TX_CONF_FIFO_PIO            0x00000020      /* Tx fifo PIO select ??? */
+#define        GM_TX_CONF_FIFO_THR_MASK        0x001ffc00      /* Tx fifo threshold */
+#define GM_TX_CONF_FIFO_THR_SHIFT      10              /* Tx fifo threshold shift */
+#define GM_TX_CONF_FIFO_THR_DEFAULT    0x7ff           /* Tx fifo threshold default */
+#define        GM_TX_CONF_PACED_MODE           0x00100000      /* 1: tx_all irq after last descriptor */
+                                                       /* 0: tx_all irq when tx fifo empty */
+#define        GM_TX_RING_SZ_32                (0 << 1)
+#define        GM_TX_RING_SZ_64                (1 << 1)
+#define        GM_TX_RING_SZ_128               (2 << 1)
+#define        GM_TX_RING_SZ_256               (3 << 1)
+#define        GM_TX_RING_SZ_512               (4 << 1)
+#define        GM_TX_RING_SZ_1024              (5 << 1)
+#define        GM_TX_RING_SZ_2048              (6 << 1)
+#define        GM_TX_RING_SZ_4086              (7 << 1)
+#define        GM_TX_RING_SZ_8192              (8 << 1)
+
+/* -- 0x2008   RW      Tx descriptor ring base low
+ * -- 0x200C   RW      Tx descriptor ring base high
+ *
+ * Base of tx ring, must be 2k aligned
+ */
+#define GM_TX_DESC_LO                  (0x2008 | REG_SZ_32)
+#define GM_TX_DESC_HI                  (0x200C | REG_SZ_32)
+/* -- 0x2100   RW      Tx Completion
+ * d: 0x00000000       Written by the gmac with the last tx descriptor number +1 sent
+ */
+#define GM_TX_COMP                     (0x2100 | REG_SZ_16)
+
+
+       /*
+        * Rx DMA registers
+        */
+
+
+/* -- 0x4000   RW      Rx configuration
+ * d: 0x1000010                Controls operation of Rx DMA channel
+ */
+
+#define GM_RX_CONF                     (0x4000 | REG_SZ_32)
+#define        GM_RX_CONF_DMA_EN               0x00000001      /* Rx DMA enable */
+#define        GM_RX_CONF_RING_SZ_MASK         0x0000001e      /* Rx desc ring size */
+#define GM_RX_CONF_RING_SZ_SHIFT       1
+#define        GM_RX_CONF_BATCH_DIS            0x00000020      /* Rx batch disable */
+#define        GM_RX_CONF_FBYTE_OFF_MASK       0x00001c00      /* First byte offset (10-12) */
+#define GM_RX_CONF_FBYTE_OFF_SHIFT     10
+#define        GM_RX_CONF_CHK_START_MASK       0x000FE000      /* Checksum start offset */
+#define GM_RX_CONF_CHK_START_SHIFT     13
+#define        GM_RX_CONF_DMA_THR_MASK         0x07000000      /* Rx DMA threshold */
+#define GM_RX_CONF_DMA_THR_SHIFT       24              /* Rx DMA threshold shift */
+#define GM_RX_CONF_DMA_THR_DEFAULT     1               /* Rx DMA threshold default */
+
+#define        GM_RX_RING_SZ_32                (0 << 1)
+#define        GM_RX_RING_SZ_64                (1 << 1)
+#define        GM_RX_RING_SZ_128               (2 << 1)
+#define        GM_RX_RING_SZ_256               (3 << 1)
+#define        GM_RX_RING_SZ_512               (4 << 1)
+#define        GM_RX_RING_SZ_1024              (5 << 1)
+#define        GM_RX_RING_SZ_2048              (6 << 1)
+#define        GM_RX_RING_SZ_4086              (7 << 1)
+#define        GM_RX_RING_SZ_8192              (8 << 1)
+
+/* -- 0x4004   RW      Rx descriptor ring base low
+ * -- 0x4008   RW      Rx descriptor ring base high
+ *
+ * Base of rx ring
+ */
+#define GM_RX_DESC_LO                  (0x4004 | REG_SZ_32)
+#define GM_RX_DESC_HI                  (0x4008 | REG_SZ_32)
+
+/* -- 0x4020   RW      Rx pause threshold
+ * d: 0x000000f8       
+ *
+ * Two PAUSE thresholds are used to define when PAUSE flow control frames are
+ * emitted by GEM. The granularity of these thresholds is in 64 byte increments.
+ * XOFF PAUSE frames use the pause_time value pre-programmed in the
+ * Send PAUSE MAC Register.
+ * XON PAUSE frames use a pause_time of 0.
+ */
+#define GM_RX_PTH                      (0x4020 | REG_SZ_32)
+                       /*
+                        * 0-8: XOFF PAUSE emitted when RX FIFO
+                        * occupancy rises above this value (times 64 bytes)
+                        */
+#define        GM_RX_PTH_OFF_MASK              0x000001ff
+#define GM_RX_PTH_OFF_SHIFT            0
+                       /*
+                        * 12-20: XON PAUSE emitted when RX FIFO
+                        * occupancy falls below this value (times 64 bytes)
+                        */
+#define        GM_RX_PTH_ON_MASK               0x001ff000
+#define        GM_RX_PTH_ON_SHIFT              12
+
+#define GM_RX_PTH_UNITS                        64
+
+/* -- 0x4100   RW      Rx Kick
+ * d: 0x00000000       The last valid RX descriptor is the one right before the value of the
+ *                      register. Initially set to 0 on reset. RX descriptors must be posted
+ *                      in multiples of 4. The first descriptor should be cache-line aligned
+ *                      for best performance.
+ */
+#define GM_RX_KICK                     (0x4100 | REG_SZ_16)
+
+/* -- 0x4104   RW      Rx Completion
+ * d: 0x00000000       All descriptors upto but excluding the register value are ready to be
+ *                      processed by the host.
+ */
+#define GM_RX_COMP                     (0x4104 | REG_SZ_16)
+/* -- 0x4108   RW      Rx Blanking
+ * d: 0x00000000       Written by the gmac with the last tx descriptor number +1 sent
+ *
+ * Defines the values used for receive interrupt blanking.
+ * For INTR_TIME field, every count is 2048 PCI clock time. For 66 Mhz, each
+ * count is about 15 ns.
+ */
+#define GM_RX_BLANK                    (0x4108 | REG_SZ_32)
+                       /*
+                        * 0-8:no.of pkts to be recvd since the last RX_DONE
+                        * interrupt, before a new interrupt
+                        */
+#define        GM_RX_BLANK_INTR_PACKETS_MASK   0x000001ff
+#define        GM_RX_BLANK_INTR_PACKETS_SHIFT  0
+                       /*
+                        * 12-19 : no. of clocks to be counted since the last
+                        * RX_DONE interrupt, before a new interrupt
+                        */
+#define        GM_RX_BLANK_INTR_TIME_MASK      0x000ff000
+#define        GM_RX_BLANK_INTR_TIME_SHIFT     12
+
+#define GM_RX_BLANK_UNITS              2048
+
+/* -- 0x4120   RO      Rx fifo size
+ *
+ * This 11-bit RO register indicates the size, in 64-byte multiples, of the
+ * RX FIFO. Software should use it to properly configure the PAUSE thresholds.
+ * The value read is 0x140, indicating a 20kbyte RX FIFO.
+ * -------------------------------------------------------------------------
+ */
+#define GM_RX_FIFO_SIZE                        (0x4120 | REG_SZ_16)
+#define GM_RZ_FIFO_SIZE_UNITS          64
+
+
+       /*
+        * MAC regisers
+        */
+
+/* -- 0x6000           MAC Tx reset control
+ */
+#define GM_MAC_TX_RESET                        (0x6000 | REG_SZ_8)
+#define GM_MAC_TX_RESET_NOW            0x01
+
+/* -- 0x6004           MAC Rx reset control
+ */
+#define GM_MAC_RX_RESET                        (0x6004 | REG_SZ_8)
+#define GM_MAC_RX_RESET_NOW            0x01
+
+/* -- 0x6008           Send Pause command register
  */
+#define GM_MAC_SND_PAUSE               (0x6008 | REG_SZ_32)
+#define GM_MAC_SND_PAUSE_TIME_MASK     0x0000ffff
+#define GM_MAC_SND_PAUSE_TIME_SHIFT    0
+#define GM_MAC_SND_PAUSE_NOW           0x00010000
+#define GM_MAC_SND_PAUSE_DEFAULT       0x00001bf0
 
-#define        GMAC_MIF_CFGPS                  0x00000001      /* PHY Select */
-#define        GMAC_MIF_CFGPE                  0x00000002      /* Poll Enable */
-#define        GMAC_MIF_CFGBB                  0x00000004      /* Bit Bang Enable */
-#define        GMAC_MIF_CFGPR_MASK             0x000000f8      /* Poll Register address */
-#define        GMAC_MIF_CFGPR_SHIFT            3
-#define        GMAC_MIF_CFGM0                  0x00000100      /* MDIO_0 Data / MDIO_0 attached */
-#define        GMAC_MIF_CFGM1                  0x00000200      /* MDIO_1 Data / MDIO_1 attached */
-#define        GMAC_MIF_CFGPD_MASK             0x00007c00      /* Poll Device PHY address */
-#define        GMAC_MIF_CFGPD_SHIFT            10
+/* -- 0x6010           MAC transmit status
+ */
+#define GM_MAC_TX_STATUS               (0x6010 | REG_SZ_16)
+#define GM_MAC_TX_STAT_SENT            0x0001
+#define GM_MAC_TX_STAT_UNDERRUN                0x0002
+#define GM_MAC_TX_STAT_MAX_PKT_ERR     0x0004
+#define GM_MAC_TX_STAT_NORM_COLL_OVF   0x0008
+#define GM_MAC_TX_STAT_EXCS_COLL_OVF   0x0010
+#define GM_MAC_TX_STAT_LATE_COLL_OVF   0x0020
+#define GM_MAC_TX_STAT_FIRS_COLL_OVF   0x0040
+#define GM_MAC_TX_STAT_DEFER_TIMER_OVF 0x0080
+#define GM_MAC_TX_STAT_PEAK_ATTMP_OVF  0x0100
+
+/* -- 0x6014           MAC receive status
+ */
+#define GM_MAC_RX_STATUS               (0x6014 | REG_SZ_16)
+#define GM_MAC_RX_STAT_RECEIVED                0x0001
+#define GM_MAC_RX_STAT_FIFO_OVF                0x0002
+#define GM_MAC_RX_STAT_FRAME_CTR_OVF   0x0004
+#define GM_MAC_RX_STAT_ALIGN_ERR_OVF   0x0008
+#define GM_MAC_RX_STAT_CRC_ERR_OVF     0x0010
+#define GM_MAC_RX_STAT_LEN_ERR_OVF     0x0020
+#define GM_MAC_RX_STAT_CODE_ERR_OVF    0x0040
+
+/* -- 0x6018           MAC control & status
+ */
+#define GM_MAC_CTRLSTAT                        (0x6018 | REG_SZ_32)
+#define GM_MAC_CTRLSTAT_PAUSE_RCVD     0x00000001
+#define GM_MAC_CTRLSTAT_PAUSE_STATE    0x00000002
+#define GM_MAC_CTRLSTAT_PAUSE_NOT      0x00000004
+#define GM_MAC_CTRLSTAT_PAUSE_TIM_MASK 0xffff0000
+#define GM_MAC_CTRLSTAT_PAUSE_TIM_SHIFT        16
+
+/* -- 0x6020           MAC Tx mask
+ *                     Same bits as MAC Tx status
+ */
+#define GM_MAC_TX_MASK                 (0x6020 | REG_SZ_16)
+
+/* -- 0x6024           MAC Rx mask
+ *                     Same bits as MAC Rx status
+ */
+#define GM_MAC_RX_MASK                 (0x6024 | REG_SZ_16)
+
+/* -- 0x6028           MAC Control/Status mask
+ *                     Same bits as MAC control/status low order byte
+ */
+#define GM_MAC_CTRLSTAT_MASK           (0x6024 | REG_SZ_8)
+
+/* -- 0x6030           MAC Tx configuration
+ */
+#define GM_MAC_TX_CONFIG               (0x6030 | REG_SZ_16)
+#define GM_MAC_TX_CONF_ENABLE          0x0001
+#define GM_MAC_TX_CONF_IGNORE_CARRIER  0x0002
+#define GM_MAC_TX_CONF_IGNORE_COLL     0x0004
+#define GM_MAC_TX_CONF_ENABLE_IPG0     0x0008
+#define GM_MAC_TX_CONF_DONT_GIVEUP     0x0010
+#define GM_MAC_TX_CONF_DONT_GIVEUP_NLMT        0x0020
+#define GM_MAC_TX_CONF_NO_BACKOFF      0x0040
+#define GM_MAC_TX_CONF_SLOWDOWN                0x0080
+#define GM_MAC_TX_CONF_NO_FCS          0x0100
+#define GM_MAC_TX_CONF_CARRIER_EXT     0x0200
+
+/* -- 0x6034           MAC Rx configuration
+ */
+#define GM_MAC_RX_CONFIG               (0x6034 | REG_SZ_16)
+#define GM_MAC_RX_CONF_ENABLE          0x0001
+#define GM_MAC_RX_CONF_STRIP_PAD       0x0002
+#define GM_MAC_RX_CONF_STIP_FCS                0x0004
+#define GM_MAC_RX_CONF_RX_ALL          0x0008
+#define GM_MAC_RX_CONF_RX_ALL_MULTI    0x0010
+#define GM_MAC_RX_CONF_HASH_ENABLE     0x0020
+#define GM_MAC_RX_CONF_ADDR_FLTR_ENABLE        0x0040
+#define GM_MAC_RX_CONF_PASS_ERROR_FRAM 0x0080
+#define GM_MAC_RX_CONF_CARRIER_EXT     0x0100
+
+/* -- 0x6038           MAC control configuration
+ */
+#define GM_MAC_CTRL_CONFIG             (0x6038 | REG_SZ_8)
+#define GM_MAC_CTRL_CONF_SND_PAUSE_EN  0x01
+#define GM_MAC_CTRL_CONF_RCV_PAUSE_EN  0x02
+#define GM_MAC_CTRL_CONF_PASS_CTRL_FRAM        0x04
+
+/* -- 0x603c           MAC XIF configuration */
+#define GM_MAC_XIF_CONFIG              (0x603c | REG_SZ_8)
+#define GM_MAC_XIF_CONF_TX_MII_OUT_EN  0x01
+#define GM_MAC_XIF_CONF_MII_INT_LOOP   0x02
+#define GM_MAC_XIF_CONF_DISABLE_ECHO   0x04
+#define GM_MAC_XIF_CONF_GMII_MODE      0x08
+#define GM_MAC_XIF_CONF_MII_BUFFER_EN  0x10
+#define GM_MAC_XIF_CONF_LINK_LED       0x20
+#define GM_MAC_XIF_CONF_FULL_DPLX_LED  0x40
+
+/* -- 0x6040           MAC inter-packet GAP 0
+ */
+#define GM_MAC_INTR_PKT_GAP0           (0x6040 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP0_DEFAULT   0x00
+
+/* -- 0x6044           MAC inter-packet GAP 1
+ */
+#define GM_MAC_INTR_PKT_GAP1           (0x6044 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP1_DEFAULT   0x08
+
+/* -- 0x6048           MAC inter-packet GAP 2
+ */
+#define GM_MAC_INTR_PKT_GAP2           (0x6048 | REG_SZ_8)
+#define GM_MAC_INTR_PKT_GAP2_DEFAULT   0x04
+
+/* -- 604c             MAC slot time
+ */
+#define GM_MAC_SLOT_TIME               (0x604C | REG_SZ_16)
+#define GM_MAC_SLOT_TIME_DEFAULT       0x0040
+
+/* -- 6050             MAC minimum frame size
+ */
+#define GM_MAC_MIN_FRAME_SIZE          (0x6050 | REG_SZ_16)
+#define GM_MAC_MIN_FRAME_SIZE_DEFAULT  0x0040
+
+/* -- 6054             MAC maximum frame size
+ */
+#define GM_MAC_MAX_FRAME_SIZE          (0x6054 | REG_SZ_16)
+#define GM_MAC_MAX_FRAME_SIZE_DEFAULT  0x05ee
+#define GM_MAC_MAX_FRAME_SIZE_ALIGN    0x5f0
+
+/* -- 6058             MAC preamble length
+ */
+#define GM_MAC_PREAMBLE_LEN            (0x6058 | REG_SZ_16)
+#define GM_MAC_PREAMBLE_LEN_DEFAULT    0x0007
+
+/* -- 605c             MAC jam size
+ */
+#define GM_MAC_JAM_SIZE                        (0x605c | REG_SZ_8)
+#define GM_MAC_JAM_SIZE_DEFAULT                0x04
 
-#define        GMAC_MIF_POLL_DELAY             200
+/* -- 6060             MAC attempt limit
+ */
+#define GM_MAC_ATTEMPT_LIMIT           (0x6060 | REG_SZ_8)
+#define GM_MAC_ATTEMPT_LIMIT_DEFAULT   0x10
+
+/* -- 6064             MAC control type
+ */
+#define GM_MAC_CONTROL_TYPE            (0x6064 | REG_SZ_16)
+#define GM_MAC_CONTROL_TYPE_DEFAULT    0x8808
 
-#define        GMAC_INTERNAL_PHYAD             1               /* PHY address for int. transceiver */
-#define        GMAC_EXTERNAL_PHYAD             0               /* PHY address for ext. transceiver */
+/* -- 6080             MAC address 15..0
+ * -- 6084             MAC address 16..31
+ * -- 6088             MAC address 32..47
+ */
+#define GM_MAC_ADDR_NORMAL0            (0x6080 | REG_SZ_16)
+#define GM_MAC_ADDR_NORMAL1            (0x6084 | REG_SZ_16)
+#define GM_MAC_ADDR_NORMAL2            (0x6088 | REG_SZ_16)
 
+/* -- 608c             MAC alternate address 15..0
+ * -- 6090             MAC alternate address 16..31
+ * -- 6094             MAC alternate address 32..47
+ */
+#define GM_MAC_ADDR_ALT0               (0x608c | REG_SZ_16)
+#define GM_MAC_ADDR_ALT1               (0x6090 | REG_SZ_16)
+#define GM_MAC_ADDR_ALT2               (0x6094 | REG_SZ_16)
+
+/* -- 6098             MAC control address 15..0
+ * -- 609c             MAC control address 16..31
+ * -- 60a0             MAC control address 32..47
+ */
+#define GM_MAC_ADDR_CTRL0              (0x6098 | REG_SZ_16)
+#define GM_MAC_ADDR_CTRL1              (0x609c | REG_SZ_16)
+#define GM_MAC_ADDR_CTRL2              (0x60a0 | REG_SZ_16)
+
+/* -- 60a4             MAC address filter (0_0)
+ * -- 60a8             MAC address filter (0_1)
+ * -- 60ac             MAC address filter (0_2)
+ */
+#define GM_MAC_ADDR_FILTER0            (0x60a4 | REG_SZ_16)
+#define GM_MAC_ADDR_FILTER1            (0x60a8 | REG_SZ_16)
+#define GM_MAC_ADDR_FILTER2            (0x60ac | REG_SZ_16)
+
+/* -- 60b0             MAC address filter mask 1,2
+ */
+#define GM_MAC_ADDR_FILTER_MASK1_2     (0x60b0 | REG_SZ_8)
+
+/* -- 60b4             MAC address filter mask 0
+ */
+#define GM_MAC_ADDR_FILTER_MASK0       (0x60b4 | REG_SZ_16)
+
+/* -- [60c0 .. 60fc]   MAC hash table
+ */
+#define GM_MAC_ADDR_FILTER_HASH0       (0x60c0 | REG_SZ_16)
+
+/* -- 6100             MAC normal collision counter
+ */
+#define GM_MAC_COLLISION_CTR           (0x6100 | REG_SZ_16)
+
+/* -- 6104             MAC 1st successful collision counter
+ */
+#define GM_MAC_FIRST_COLLISION_CTR     (0x6104 | REG_SZ_16)
+
+/* -- 6108             MAC excess collision counter
+ */
+#define GM_MAC_EXCS_COLLISION_CTR      (0x6108 | REG_SZ_16)
+
+/* -- 610c             MAC late collision counter
+ */
+#define GM_MAC_LATE_COLLISION_CTR      (0x610c | REG_SZ_16)
+
+/* -- 6110             MAC defer timer counter
+ */
+#define GM_MAC_DEFER_TIMER_COUNTER     (0x6110 | REG_SZ_16)
+
+/* -- 6114             MAC peak attempts
+ */
+#define GM_MAC_PEAK_ATTEMPTS           (0x6114 | REG_SZ_16)
+
+/* -- 6118             MAC Rx frame counter
+ */
+#define GM_MAC_RX_FRAME_CTR            (0x6118 | REG_SZ_16)
+
+/* -- 611c             MAC Rx length error counter
+ */
+#define GM_MAC_RX_LEN_ERR_CTR          (0x611c | REG_SZ_16)
+
+/* -- 6120             MAC Rx alignment error counter
+ */
+#define GM_MAC_RX_ALIGN_ERR_CTR                (0x6120 | REG_SZ_16)
+
+/* -- 6124             MAC Rx CRC error counter
+ */
+#define GM_MAC_RX_CRC_ERR_CTR          (0x6124 | REG_SZ_16)
+
+/* -- 6128             MAC Rx code violation error counter
+ */
+#define GM_MAC_RX_CODE_VIOLATION_CTR   (0x6128 | REG_SZ_16)
+
+/* -- 6130             MAC random number seed
+ */
+#define GM_MAC_RANDOM_SEED             (0x6130 | REG_SZ_16)
+
+/* -- 6134             MAC state machine
+ */
+#define GM_MAC_STATE_MACHINE           (0x6134 | REG_SZ_8)
+
+
+       /*
+        * MIF registers
+        */
+
+
+/* -- 0x6200   RW      MIF bit bang clock
+ */
+#define GM_MIF_BB_CLOCK                        (0x6200 | REG_SZ_8)
+
+/* -- 0x6204   RW      MIF bit bang data
+ */
+#define GM_MIF_BB_DATA                 (0x6204 | REG_SZ_8)
+
+/* -- 0x6208   RW      MIF bit bang output enable
+ */
+#define GM_MIF_BB_OUT_ENABLE           (0x6208 | REG_SZ_8)
+
+/* -- 0x620c   RW      MIF frame control & data
+ */
+#define GM_MIF_FRAME_CTL_DATA          (0x620c | REG_SZ_32)
+#define GM_MIF_FRAME_START_MASK                0xc0000000
+#define GM_MIF_FRAME_START_SHIFT       30
+#define GM_MIF_FRAME_OPCODE_MASK       0x30000000
+#define GM_MIF_FRAME_OPCODE_SHIFT      28
+#define GM_MIF_FRAME_PHY_ADDR_MASK     0x0f800000
+#define GM_MIF_FRAME_PHY_ADDR_SHIFT    23
+#define GM_MIF_FRAME_REG_ADDR_MASK     0x007c0000
+#define GM_MIF_FRAME_REG_ADDR_SHIFT    18
+#define GM_MIF_FRAME_TURNAROUND_HI     0x00020000
+#define GM_MIF_FRAME_TURNAROUND_LO     0x00010000
+#define GM_MIF_FRAME_DATA_MASK         0x0000ffff
+#define GM_MIF_FRAME_DATA_SHIFT                0
+
+/* -- 0x6210   RW      MIF config reg
+ */
+#define GM_MIF_CFG                     (0x6210 | REG_SZ_16)
+#define        GM_MIF_CFGPS                    0x00000001      /* PHY Select */
+#define        GM_MIF_CFGPE                    0x00000002      /* Poll Enable */
+#define        GM_MIF_CFGBB                    0x00000004      /* Bit Bang Enable */
+#define        GM_MIF_CFGPR_MASK               0x000000f8      /* Poll Register address */
+#define        GM_MIF_CFGPR_SHIFT              3
+#define        GM_MIF_CFGM0                    0x00000100      /* MDIO_0 Data / MDIO_0 attached */
+#define        GM_MIF_CFGM1                    0x00000200      /* MDIO_1 Data / MDIO_1 attached */
+#define        GM_MIF_CFGPD_MASK               0x00007c00      /* Poll Device PHY address */
+#define        GM_MIF_CFGPD_SHIFT              10
+
+#define        GM_MIF_POLL_DELAY               200
+
+#define        GM_INTERNAL_PHYAD               1               /* PHY address for int. transceiver */
+#define        GM_EXTERNAL_PHYAD               0               /* PHY address for ext. transceiver */
 
 /* -- 0x6214   RW      MIF interrupt mask reg
  *                     same as basic/status Register
  */
+#define GM_MIF_IRQ_MASK                        (0x6214 | REG_SZ_16)
 
-/* -- 0x6214   RW      MIF basic/status reg
+/* -- 0x6218   RW      MIF basic/status reg
  *                     The Basic portion of this register indicates the last
  *                     value of the register read indicated in the POLL REG field
  *                     of the Configuration Register.
  *                     terms of the bit(s) that need to be masked for generating
  *                     interrupt on the MIF Interrupt Bit of the Global Status Rgister.
  */
+#define GM_MIF_STATUS                  (0x6218 | REG_SZ_32)
+
+#define        GM_MIF_STATUS_MASK              0x0000ffff      /* 0-15 : Status */
+#define        GM_MIF_BASIC_MASK               0xffff0000      /* 16-31 : Basic register */
+
+       /*
+        * PCS link registers
+        */
+
+/* -- 0x9000   RW      PCS mii control reg
+ */
+#define GM_PCS_CONTROL                 (0x9000 | REG_SZ_16)
+
+/* -- 0x9004   RW      PCS mii status reg
+ */
+#define GM_PCS_STATUS                  (0x9004 | REG_SZ_16)
+
+/* -- 0x9008   RW      PCS mii advertisement
+ */
+#define GM_PCS_ADVERTISEMENT           (0x9008 | REG_SZ_16)
+
+/* -- 0x900c   RW      PCS mii LP ability
+ */
+#define GM_PCS_ABILITY                 (0x900c | REG_SZ_16)
+
+/* -- 0x9010   RW      PCS config
+ */
+#define GM_PCS_CONFIG                  (0x9010 | REG_SZ_8)
+
+/* -- 0x9014   RW      PCS state machine
+ */
+#define GM_PCS_STATE_MACHINE           (0x9014 | REG_SZ_32)
+
+/* -- 0x9018   RW      PCS interrupt status
+ */
+#define GM_PCS_IRQ_STATUS              (0x9018 | REG_SZ_8)
+
+/* -- 0x9050   RW      PCS datapath mode
+ */
+#define GM_PCS_DATAPATH_MODE           (0x9050 | REG_SZ_8)
+#define GM_PCS_DATAPATH_INTERNAL       0x01    /* Internal serial link */
+#define GM_PCS_DATAPATH_SERDES         0x02    /* 10-bit Serdes interface */
+#define GM_PCS_DATAPATH_MII            0x04    /* Select mii/gmii mode */
+#define GM_PCS_DATAPATH_GMII_OUT       0x08    /* serial mode only, copy data to gmii */
+
+/* -- 0x9054   RW      PCS serdes control
+ */
+#define GM_PCS_SERDES_CTRL             (0x9054 | REG_SZ_8)
+
+/* -- 0x9058   RW      PCS serdes output select
+ */
+#define GM_PCS_SERDES_SELECT           (0x9058 | REG_SZ_8)
+
+/* -- 0x905c   RW      PCS serdes state
+ */
+#define GM_PCS_SERDES_STATE            (0x905c | REG_SZ_8)
+
+
+       /*
+        * PHY registers
+        */
+
+/*
+ * Standard PHY registers (from de4x5.h)
+ */
+#define MII_CR       0x00          /* MII Management Control Register */
+#define MII_SR       0x01          /* MII Management Status Register */
+#define MII_ID0      0x02          /* PHY Identifier Register 0 */
+#define MII_ID1      0x03          /* PHY Identifier Register 1 */
+#define MII_ANA      0x04          /* Auto Negotiation Advertisement */
+#define MII_ANLPA    0x05          /* Auto Negotiation Link Partner Ability */
+#define MII_ANE      0x06          /* Auto Negotiation Expansion */
+#define MII_ANP      0x07          /* Auto Negotiation Next Page TX */
+
+/*
+** MII Management Control Register
+*/
+#define MII_CR_RST  0x8000         /* RESET the PHY chip */
+#define MII_CR_LPBK 0x4000         /* Loopback enable */
+#define MII_CR_SPD  0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_10   0x0000         /* Set 10Mb/s */
+#define MII_CR_100  0x2000         /* Set 100Mb/s */
+#define MII_CR_ASSE 0x1000         /* Auto Speed Select Enable */
+#define MII_CR_PD   0x0800         /* Power Down */
+#define MII_CR_ISOL 0x0400         /* Isolate Mode */
+#define MII_CR_RAN  0x0200         /* Restart Auto Negotiation */
+#define MII_CR_FDM  0x0100         /* Full Duplex Mode */
+#define MII_CR_CTE  0x0080         /* Collision Test Enable */
+
+/*
+** MII Management Status Register
+*/
+#define MII_SR_T4C  0x8000         /* 100BASE-T4 capable */
+#define MII_SR_TXFD 0x4000         /* 100BASE-TX Full Duplex capable */
+#define MII_SR_TXHD 0x2000         /* 100BASE-TX Half Duplex capable */
+#define MII_SR_TFD  0x1000         /* 10BASE-T Full Duplex capable */
+#define MII_SR_THD  0x0800         /* 10BASE-T Half Duplex capable */
+#define MII_SR_ASSC 0x0020         /* Auto Speed Selection Complete*/
+#define MII_SR_RFD  0x0010         /* Remote Fault Detected */
+#define MII_SR_ANC  0x0008         /* Auto Negotiation capable */
+#define MII_SR_LKS  0x0004         /* Link Status */
+#define MII_SR_JABD 0x0002         /* Jabber Detect */
+#define MII_SR_XC   0x0001         /* Extended Capabilities */
+
+/*
+** MII Management Auto Negotiation Advertisement Register
+*/
+#define MII_ANA_TAF  0x03e0        /* Technology Ability Field */
+#define MII_ANA_T4AM 0x0200        /* T4 Technology Ability Mask */
+#define MII_ANA_TXAM 0x0180        /* TX Technology Ability Mask */
+#define MII_ANA_FDAM 0x0140        /* Full Duplex Technology Ability Mask */
+#define MII_ANA_HDAM 0x02a0        /* Half Duplex Technology Ability Mask */
+#define MII_ANA_100M 0x0380        /* 100Mb Technology Ability Mask */
+#define MII_ANA_10M  0x0060        /* 10Mb Technology Ability Mask */
+#define MII_ANA_CSMA 0x0001        /* CSMA-CD Capable */
+
+/*
+** MII Management Auto Negotiation Remote End Register
+*/
+#define MII_ANLPA_NP   0x8000      /* Next Page (Enable) */
+#define MII_ANLPA_ACK  0x4000      /* Remote Acknowledge */
+#define MII_ANLPA_RF   0x2000      /* Remote Fault */
+#define MII_ANLPA_TAF  0x03e0      /* Technology Ability Field */
+#define MII_ANLPA_T4AM 0x0200      /* T4 Technology Ability Mask */
+#define MII_ANLPA_TXAM 0x0180      /* TX Technology Ability Mask */
+#define MII_ANLPA_FDAM 0x0140      /* Full Duplex Technology Ability Mask */
+#define MII_ANLPA_HDAM 0x02a0      /* Half Duplex Technology Ability Mask */
+#define MII_ANLPA_100M 0x0380      /* 100Mb Technology Ability Mask */
+#define MII_ANLPA_10M  0x0060      /* 10Mb Technology Ability Mask */
+#define MII_ANLPA_CSMA 0x0001      /* CSMA-CD Capable */
+#define MII_ANLPA_PAUS 0x0400 
+
+/*
+ * Model-specific PHY registers
+ *
+ * Note: Only the BCM5201 is described here for now. I'll add the 5400 once
+ *       I see a machine using it in real world.
+ */
+
+/* Supported PHYs (phy_type field ) */
+#define PHY_B5400      5400
+#define PHY_B5201      5201
+#define PHY_UNKNOWN    0
+
+/* Identification (for multi-PHY) */
+#define MII_BCM5201_OUI                         0x001018
+#define MII_BCM5201_MODEL                       0x21
+#define MII_BCM5201_REV                         0x01
+#define MII_BCM5201_ID                          ((MII_BCM5201_OUI << 10) | (MII_BCM5201_MODEL << 4))
+#define MII_BCM5201_MASK                        0xfffffff0
+#define MII_BCM5400_OUI                         0x000818
+#define MII_BCM5400_MODEL                       0x04
+#define MII_BCM5400_REV                         0x01
+#define MII_BCM5400_ID                          ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4))
+#define MII_BCM5400_MASK                        0xfffffff0
+
+/* BCM5201 AUX STATUS register */
+#define MII_BCM5201_AUXCTLSTATUS               0x18
+#define MII_BCM5201_AUXCTLSTATUS_DUPLEX                0x0001
+#define MII_BCM5201_AUXCTLSTATUS_SPEED         0x0002
+
+/* MII BCM5201 MULTIPHY interrupt register */
+#define MII_BCM5201_INTERRUPT                  0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE                0x4000
+
+#define MII_BCM5201_AUXMODE2                   0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER          0x0008
+
+#define MII_BCM5201_MULTIPHY                    0x1E
+
+/* MII BCM5201 MULTIPHY register bits */
+#define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+
+
+
+       /*
+        * DMA descriptors
+        */
+
+
+/* 
+ * Descriptor counts and buffer sizes
+ */
+#define NTX                    64              /* must be power of 2 */
+#define NTX_CONF               GM_TX_RING_SZ_64
+#define NRX                    64              /* must be power of 2 */
+#define NRX_CONF               GM_RX_RING_SZ_64
+#define RX_COPY_THRESHOLD      256
+#define GMAC_BUFFER_ALIGN      32              /* Align on a cache line */
+#define RX_BUF_ALLOC_SIZE      (ETH_FRAME_LEN + GMAC_BUFFER_ALIGN + 2)
+#define RX_OFFSET              2
+
+/*
+ * Definitions of Rx and Tx descriptors
+ */
+
+struct gmac_dma_desc {
+       unsigned int    size;           /* data size and OWN bit */
+       unsigned int    flags;          /* flags */
+       unsigned int    lo_addr;        /* phys addr, low 32 bits */
+       unsigned int    hi_addr;
+};
+
+/*
+ * Rx bits
+ */
+/* Bits in size */
+#define RX_SZ_OWN              0x80000000      /* 1 = owned by chip */
+#define RX_SZ_MASK             0x7FFF0000
+#define RX_SZ_SHIFT            16
+#define RX_SZ_CKSUM_MASK       0x0000FFFF
+
+/* Bits in flags */
+#define RX_FL_CRC_ERROR                0x40000000
+#define RX_FL_ALT_ADDR         0x20000000      /* Packet rcv. from alt MAC address */
+
+/* 
+ * Tx bits
+ */
+
+/* Bits in size */
+#define TX_SZ_MASK             0x00007FFF
+#define TX_SZ_CRC_MASK         0x00FF8000
+#define TX_SZ_CRC_STUFF                0x1F000000
+#define TX_SZ_CRC_ENABLE       0x20000000
+#define TX_SZ_EOP              0x40000000
+#define TX_SZ_SOP              0x80000000
+/* Bits in flags */
+#define TX_FL_INTERRUPT                0x00000001
+#define TX_FL_NO_CRC           0x00000002
+
+       /*
+        * Other stuffs
+        */
+        
+struct gmac {
+       volatile unsigned int           *regs;  /* hardware registers, virtual addr */
+       struct net_device               *dev;
+       struct device_node              *of_node;
+       unsigned long                   tx_desc_page;   /* page for DMA descriptors */
+       unsigned long                   rx_desc_page;   /* page for DMA descriptors */
+       volatile struct                 gmac_dma_desc *rxring;
+       struct sk_buff                  *rx_buff[NRX];
+       int                             next_rx;
+       volatile struct gmac_dma_desc   *txring;
+       struct sk_buff                  *tx_buff[NTX];
+       int                             next_tx;
+       int                             tx_gone;
+       int                             phy_addr;
+       unsigned int                    phy_id;
+       int                             phy_type;
+       int                             phy_status;     /* Cached PHY status */
+       int                             full_duplex;    /* Current set to full duplex */
+       struct net_device_stats         stats;
+       u8                              pci_bus;
+       u8                              pci_devfn;
+       spinlock_t                      lock;
+       int                             opened;
+       struct net_device               *next_gmac;
+};
+
+
+/* Register access macros. We hope the preprocessor will be smart enough
+ * to optimize them into one single access instruction
+ */
+#define GM_OUT(reg, v)         (((reg) & REG_SZ_32) ? out_le32(gm->regs + \
+                                       (((reg) & REG_MASK)>>2), (v))  \
+                               : (((reg) & REG_SZ_16) ? out_le16((volatile u16 *) \
+                                       (gm->regs + (((reg) & REG_MASK)>>2)), (v))  \
+                               : out_8((volatile u8 *)(gm->regs + \
+                                       (((reg) & REG_MASK)>>2)), (v))))
+#define GM_IN(reg)             (((reg) & REG_SZ_32) ? in_le32(gm->regs + \
+                                       (((reg) & REG_MASK)>>2))  \
+                               : (((reg) & REG_SZ_16) ? in_le16((volatile u16 *) \
+                                       (gm->regs + (((reg) & REG_MASK)>>2)))  \
+                               : in_8((volatile u8 *)(gm->regs + \
+                                       (((reg) & REG_MASK)>>2)))))
+#define GM_BIS(r, v)           GM_OUT((r), GM_IN(r) | (v))
+#define GM_BIC(r, v)           GM_OUT((r), GM_IN(r) & ~(v))
+
+/* Wrapper to alloc_skb to test various alignements */
+#define GMAC_ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + GMAC_BUFFER_ALIGN - 1) & \
+        ~(GMAC_BUFFER_ALIGN - 1)) - (unsigned long)(addr))
+        
+static inline struct sk_buff *
+gmac_alloc_skb(unsigned int length, int gfp_flags)
+{
+       struct sk_buff *skb;
+
+       skb = alloc_skb(length + GMAC_BUFFER_ALIGN, gfp_flags);
+       if(skb) {
+               int offset = GMAC_ALIGNED_RX_SKB_ADDR(skb->data);
 
-#define        GMAC_MIF_STATUS                 0x0000ffff      /* 0-15 : Status */
-#define        GMAC_MIF_BASIC                  0xffff0000      /* 16-31 : Basic register */
+               if(offset)
+                       skb_reserve(skb, offset);
+       }
+       return skb;
+}
 
index 7a020278feec655d62d7f9a99537147f1ed4cd38..e4e2d11609a0efa422b72f831a5d899318148700 100644 (file)
@@ -1139,19 +1139,19 @@ static int RCioctl(struct net_device *dev, struct ifreq *rq, int cmd)
             printk("RC SETSPEED\n");
             RCUD_SETSPEED = &RCuser.RCUS_SETSPEED;
             RCSetLinkSpeed(pDpa->id, (U16) RCUD_SETSPEED->LinkSpeedCode);
-            printk("RC New speed = 0x%d\n", RCUD_SETSPEED->LinkSpeedCode);
+            printk("RC New speed = 0x%x\n", RCUD_SETSPEED->LinkSpeedCode);
             break;
         case RCUC_SETPROM:
             printk("RC SETPROM\n");
             RCUD_SETPROM = &RCuser.RCUS_SETPROM;
             RCSetPromiscuousMode(pDpa->id,(U16)RCUD_SETPROM->PromMode);
-            printk("RC New prom mode = 0x%d\n", RCUD_SETPROM->PromMode);
+            printk("RC New prom mode = 0x%x\n", RCUD_SETPROM->PromMode);
             break;
         case RCUC_SETBROADCAST:
             printk("RC SETBROADCAST\n");
             RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST;
             RCSetBroadcastMode(pDpa->id,(U16)RCUD_SETBROADCAST->BroadcastMode);
-            printk("RC New broadcast mode = 0x%d\n", RCUD_SETBROADCAST->BroadcastMode);
+            printk("RC New broadcast mode = 0x%x\n", RCUD_SETBROADCAST->BroadcastMode);
             break;
         default:
             printk("RC command default\n");
index f536e42cb7121fbcec21c6143322d0524d3149c8..a2a963215d4a33e449666dcc95506b8a671c024c 100644 (file)
@@ -878,7 +878,14 @@ int __init init_pcmcia_ds(void)
     int i, ret;
     
     DEBUG(0, "%s\n", version);
-    
+    /*
+     * Ugly. But we want to wait for the socket threads to have started up.
+     * We really should let the drivers themselves drive some of this..
+     */
+    current->state = TASK_INTERRUPTIBLE;
+    schedule_timeout(HZ/10);
+
     pcmcia_get_card_services_info(&serv);
     if (serv.Revision != CS_RELEASE_CODE) {
        printk(KERN_NOTICE "ds: Card Services release does not match!\n");
index ce2fd652b3ded5fc8488978e3215d7c7acbfa9c0..7f21f827e6e52f50c4f51b61b5504914be6670ee 100644 (file)
@@ -181,6 +181,13 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
        return socket->op->open(socket);
 }
 
+void cardbus_register(pci_socket_t *socket)
+{
+       int nr = socket - pci_socket_array;
+
+       socket->pcmcia_socket = pcmcia_register_socket(nr, &pci_socket_operations, 1);
+}
+
 static int __devinit
 cardbus_probe (struct pci_dev *dev, const struct pci_device_id *id)
 {
@@ -189,10 +196,6 @@ cardbus_probe (struct pci_dev *dev, const struct pci_device_id *id)
        for (s = 0; s < MAX_SOCKETS; s++) {
                if (pci_socket_array [s].dev == 0) {
                        add_pci_socket (s, dev, &yenta_operations);
-                       pci_socket_array [s].pcmcia_socket =
-                               pcmcia_register_socket (s,
-                                       &pci_socket_operations,
-                                       1);
                        return 0;
                }
        }
index 25d3ed11f24aa6fd2860594265f41ff35f79d4d8..0556c7906d7c8236b73201e7bbeb990fff5c3d3a 100644 (file)
@@ -470,35 +470,15 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 /*
- * Watch a socket every second (and possibly in a
- * more timely manner if the state change interrupt
- * works..)
+ * Only probe "regular" interrupts, don't
+ * touch dangerous spots like the mouse irq,
+ * because there are mice that apparently
+ * get really confused if they get fondled
+ * too intimately.
+ *
+ * Default to 11, 10, 9, 7, 6, 5, 4, 3.
  */
-static int yenta_socket_thread(void * data)
-{
-       pci_socket_t * socket = (pci_socket_t *) data;
-       DECLARE_WAITQUEUE(wait, current);
-
-       daemonize();
-       strcpy(current->comm, "CardBus Watcher");
-
-       do {
-               unsigned int events = socket->events | yenta_events(socket);
-
-               if (events) {
-                       socket->events = 0;
-                       if (socket->handler)
-                               socket->handler(socket->info, events);
-               }
-
-               current->state = TASK_INTERRUPTIBLE;
-               add_wait_queue(&socket->wait, &wait);
-               if (!socket->events)
-                       schedule_timeout(HZ);
-               remove_wait_queue(&socket->wait, &wait);
-       } while (!signal_pending(current));
-       return 0;
-}
+static u32 isa_interrupts = 0x0ef8;
 
 static unsigned int yenta_probe_irq(pci_socket_t *socket, u32 isa_irq_mask)
 {
@@ -540,6 +520,61 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket, u32 isa_irq_mask)
        return mask;
 }
 
+/*
+ * Set static data that doesn't need re-initializing..
+ */
+static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask)
+{
+       socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
+       socket->cap.map_size = 0x1000;
+       socket->cap.pci_irq = socket->cb_irq;
+       socket->cap.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
+       socket->cap.cb_dev = socket->dev;
+       socket->cap.bus = NULL;
+
+       printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
+}
+
+extern void cardbus_register(pci_socket_t *socket);
+
+/*
+ * Watch a socket every second (and possibly in a
+ * more timely manner if the state change interrupt
+ * works..)
+ */
+static int yenta_socket_thread(void * data)
+{
+       pci_socket_t * socket = (pci_socket_t *) data;
+       DECLARE_WAITQUEUE(wait, current);
+
+       daemonize();
+       strcpy(current->comm, "CardBus Watcher");
+
+       /* Figure out what the dang thing can do for the PCMCIA layer... */
+       yenta_get_socket_capabilities(socket, isa_interrupts);
+       printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+
+       /* Register it with the pcmcia layer.. */
+       cardbus_register(socket);
+
+       do {
+               unsigned int events = socket->events | yenta_events(socket);
+
+               if (events) {
+                       socket->events = 0;
+                       if (socket->handler)
+                               socket->handler(socket->info, events);
+               }
+
+               current->state = TASK_INTERRUPTIBLE;
+               add_wait_queue(&socket->wait, &wait);
+               if (!socket->events)
+                       schedule_timeout(HZ);
+               remove_wait_queue(&socket->wait, &wait);
+       } while (!signal_pending(current));
+       return 0;
+}
+
 static void yenta_clear_maps(pci_socket_t *socket)
 {
        int i;
@@ -558,8 +593,10 @@ static void yenta_clear_maps(pci_socket_t *socket)
        }
 }
 
-/* Called at resume and initialization events */
-static int yenta_init(pci_socket_t *socket)
+/*
+ * Initialize the standard cardbus registers
+ */
+static int yenta_config_init(pci_socket_t *socket)
 {
        u16 bridge;
        struct pci_dev *dev = socket->dev;
@@ -600,7 +637,12 @@ static int yenta_init(pci_socket_t *socket)
 
        /* Redo card voltage interrogation */
        cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
+}
 
+/* Called at resume and initialization events */
+static int yenta_init(pci_socket_t *socket)
+{
+       yenta_config_init(socket);
        yenta_clear_maps(socket);
        return 0;
 }
@@ -624,21 +666,6 @@ static int yenta_suspend(pci_socket_t *socket)
        return 0;
 }
 
-/*
- * Set static data that doesn't need re-initializing..
- */
-static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask)
-{
-       socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
-       socket->cap.map_size = 0x1000;
-       socket->cap.pci_irq = socket->cb_irq;
-       socket->cap.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
-       socket->cap.cb_dev = socket->dev;
-       socket->cap.bus = NULL;
-
-       printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
-}
-
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
        struct pci_bus *bus;
@@ -741,17 +768,6 @@ static struct cardbus_override_struct {
 
 #define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))
 
-/*
- * Only probe "regular" interrupts, don't
- * touch dangerous spots like the mouse irq,
- * because there are mice that apparently
- * get really confused if they get fondled
- * too intimately.
- *
- * Default to 11, 10, 9, 7, 6, 5, 4, 3.
- */
-static u32 isa_interrupts = 0x0ef8;
-
 /*
  * Initialize a cardbus controller. Make sure we have a usable
  * interrupt, and that we can map the cardbus area. Fill in the
@@ -780,6 +796,8 @@ static int yenta_open(pci_socket_t *socket)
        if (!socket->base)
                return -1;
 
+       yenta_config_init(socket);
+
        /* Disable all events */
        cb_writel(socket, CB_SOCKET_MASK, 0x0);
 
@@ -802,11 +820,7 @@ static int yenta_open(pci_socket_t *socket)
                }
        }
 
-       /* Figure out what the dang thing can do for the PCMCIA layer... */
-       yenta_get_socket_capabilities(socket, isa_interrupts);
-
        kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-       printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
        return 0;
 }
 
index a211980a5a6fec113b64311e2f5b2004f26667eb..6f6020290a621993794e718ba282077a46b4cc25 100644 (file)
@@ -410,7 +410,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
        case SCSI_IOCTL_PROBE_HOST:
                return ioctl_probe(dev->host, arg);
        case SCSI_IOCTL_SEND_COMMAND:
-               if (!capable(CAP_SYS_ADMIN))
+               if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                        return -EACCES;
                return scsi_ioctl_send_command((Scsi_Device *) dev,
                                             (Scsi_Ioctl_Command *) arg);
index d0b4f9d6c4d36bce823fbaff918513e7f99ee759..43b42d0a5ee282be912fbfb3962538a553e671a1 100644 (file)
@@ -181,7 +181,7 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
                        if (copy_from_user(f->data + f->tail, buf, nwritten))
                                return -EFAULT;
                } else
-                       memcpy(f->data + f->tail, buf, nwritten);
+                       isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten);
 
                count += nwritten;
                buf += nwritten;
@@ -219,7 +219,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
                        if (copy_to_user(buf, f->data + f->head, nread))
                                return -EFAULT;
                } else
-                       memcpy(buf, f->data + f->head, nread);
+                       isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread);
 
                count += nread;
                buf += nread;
index 25026b17435d896642dd3df888128b03dfd1a825..0154d7f4885573776cbc775081e151ee02ff581e 100644 (file)
@@ -607,6 +607,11 @@ static void call_policy (char *verb, struct usb_device *dev)
                dbg ("In_interrupt");
                return;
        }
+       if (!current->fs->root) {
+               /* statically linked USB is initted rather early */
+               dbg ("call_policy %s, num %d -- no FS yet", verb, dev->devnum);
+               return;
+       }
        if (dev->devnum < 0) {
                dbg ("device already deleted ??");
                return;
@@ -691,7 +696,7 @@ static void call_policy (char *verb, struct usb_device *dev)
 
        /* NOTE: user mode daemons can call the agents too */
 
-       dbg ("kusbd: %s %s", argv [0], argv [1]);
+       dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
        value = call_usermodehelper (argv [0], argv, envp);
        kfree (buf);
        kfree (envp);
@@ -732,8 +737,10 @@ static void usb_find_drivers(struct usb_device *dev)
                dbg("unhandled interfaces on device");
 
        if (!claimed) {
-               warn("USB device %d is not claimed by any active driver.",
-                       dev->devnum);
+               warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.",
+                       dev->devnum,
+                       dev->descriptor.idVendor,
+                       dev->descriptor.idProduct);
 #ifdef DEBUG
                usb_show_device(dev);
 #endif
index dacf0e317fd57faa6c8ac4f063d439ab91250589..333fd6576ef76b88879590a3610715f104b3fd2c 100644 (file)
@@ -89,8 +89,6 @@ static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                           struct fb_info *info);
 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
                              struct fb_info *info);
-static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                       u_long arg, int con, struct fb_info *info);
 
 
     /*
@@ -146,7 +144,6 @@ static struct fb_ops s3trio_ops = {
        fb_get_cmap:    s3trio_get_cmap,
        fb_set_cmap:    s3trio_set_cmap,
        fb_pan_display: s3trio_pan_display,
-       fb_ioctl:       s3trio_ioctl,
 };
 
     /*
@@ -264,12 +261,6 @@ static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                       u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
 int __init s3triofb_init(void)
 {
 #ifdef __powerpc__
index 5412fef40f20c67e3b5f9e1176239a18bdd23346..f504cddaf6a4a32bf4cf0cda47db3a8610a9e13c 100644 (file)
@@ -1111,13 +1111,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-static int
-acornfb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
-             unsigned long arg, int con, struct fb_info *info)
-{
-       return -ENOIOCTLCMD;
-}
-
 static struct fb_ops acornfb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     acornfb_get_fix,
@@ -1126,7 +1119,6 @@ static struct fb_ops acornfb_ops = {
        fb_get_cmap:    acornfb_get_cmap,
        fb_set_cmap:    acornfb_set_cmap,
        fb_pan_display: acornfb_pan_display,
-       fb_ioctl:       acornfb_ioctl,
 };
 
 static int
index 192cb278b06a780719d8e0b7d1bf27f6448ff4a1..ef0871369c81d94eda3e08e3b9c0a82c83e02145 100644 (file)
@@ -325,8 +325,6 @@ static int aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
 static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
                           struct fb_info *fb);
-static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                    u_long arg, int con, struct fb_info *info);
 static int aty128fb_rasterimg(struct fb_info *info, int start);
 
 
@@ -418,7 +416,6 @@ static struct fb_ops aty128fb_ops = {
        fb_get_cmap:    aty128fb_get_cmap,
        fb_set_cmap:    aty128fb_set_cmap,
        fb_pan_display: aty128fb_pan_display,
-       fb_ioctl:       aty128fb_ioctl,
        fb_rasterimg:   aty128fb_rasterimg,
 };
 
@@ -1587,17 +1584,6 @@ aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
     return 0;                
 }
 
-    /*
-     *  Frame Buffer Specific ioctls
-     */
-
-static int
-aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                    u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
 
 static int
 aty128fb_rasterimg(struct fb_info *info, int start)
index 974d2adc76d20d532a622aae9c9ce354ce619a29..96a3b9a7904e9225e114697bc08fa994319d8460 100644 (file)
@@ -121,14 +121,10 @@ static int chips_get_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
 static int chips_set_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
-static int chips_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
 static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
-static int chips_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info);
 
 static struct fb_ops chipsfb_ops = {
        owner:          THIS_MODULE,
@@ -137,8 +133,6 @@ static struct fb_ops chipsfb_ops = {
        fb_set_var:     chips_set_var,
        fb_get_cmap:    chips_get_cmap,
        fb_set_cmap:    chips_set_cmap,
-       fb_pan_display: chips_pan_display,
-       fb_ioctl:       chips_ioctl,
 };
 
 static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green,
@@ -187,14 +181,6 @@ static int chips_set_var(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-static int chips_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-       if (var->xoffset != 0 || var->yoffset != 0)
-               return -EINVAL;
-       return 0;
-}
-
 static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info)
 {
@@ -226,12 +212,6 @@ static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int chips_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static int chipsfbcon_switch(int con, struct fb_info *info)
 {
        struct fb_info_chips *p = (struct fb_info_chips *) info;
index a0999093fb5c77baba160a95d917be9b93b57f66..a88919d651c7b2b716baf88abb1fcd52fca9083e 100644 (file)
@@ -472,9 +472,6 @@ int clgenfb_setup (char *options);
 
 static int clgenfb_open (struct fb_info *info, int user);
 static int clgenfb_release (struct fb_info *info, int user);
-static int clgenfb_ioctl (struct inode *inode, struct file *file,
-                  unsigned int cmd, unsigned long arg, int con,
-                  struct fb_info *info);
 #if defined(CONFIG_FB_OF)
 int clgen_of_init (struct device_node *dp);
 #endif
@@ -490,7 +487,6 @@ static struct fb_ops clgenfb_ops = {
        fb_get_cmap:    fbgen_get_cmap,
        fb_set_cmap:    fbgen_set_cmap,
        fb_pan_display: fbgen_pan_display,
-       fb_ioctl:       clgenfb_ioctl,
 };
 
 /*--- Hardware Specific Routines -------------------------------------------*/
@@ -646,16 +642,6 @@ static int clgenfb_release (struct fb_info *info, int user)
        return 0;
 }
 
-/*--- handle /dev/fbx ioctl calls ------------------------------------------*/
-static int clgenfb_ioctl (struct inode *inode, struct file *file,
-                  unsigned int cmd, unsigned long arg, int con,
-                  struct fb_info *info)
-{
-       DPRINTK ("ENTER\n");
-       /* Nothing exciting here... */
-       DPRINTK ("EXIT\n");
-       return -EINVAL;
-}
 /**** END   Interface used by the World *************************************/
 /****************************************************************************/
 /**** BEGIN Hardware specific Routines **************************************/
index f6a70e3a4c4221795ff3fa11ee6e359d4f0c8e65..10453891d9878d68d85e3e0a6e12da52a1e25113 100644 (file)
@@ -122,8 +122,6 @@ static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
-static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info);
 
 
 static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
@@ -175,7 +173,6 @@ static struct fb_ops controlfb_ops = {
        fb_get_cmap:    control_get_cmap,
        fb_set_cmap:    control_set_cmap,
        fb_pan_display: control_pan_display,
-       fb_ioctl:       control_ioctl,
 };
 
 
@@ -331,12 +328,6 @@ static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 /********************  End of controlfb_ops implementation  ********************/
 /* (new one that is) */
 
index 7f9cac9a1b656ec396596319a83c23f1dfc9671b..0a1473520fab423735fcb1012be0a3731afb2d0f 100644 (file)
@@ -967,14 +967,6 @@ cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
 }
 
 
-static int
-cyber2000fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                 u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-
 /*
  *    Update the `var' structure (called by fbcon.c)
  *
@@ -1122,7 +1114,6 @@ static struct fb_ops cyber2000fb_ops = {
        fb_set_var:     cyber2000fb_set_var,
        fb_set_cmap:    cyber2000fb_set_cmap,
        fb_pan_display: cyber2000fb_pan_display,
-       fb_ioctl:       cyber2000fb_ioctl,
        fb_get_fix:     gen_get_fix,
        fb_get_var:     gen_get_var,
        fb_get_cmap:    gen_get_cmap,
index 396a7befc85f93f2654ca7fa65240e21b7903b61..20b8c4b2ae5496779f689b99f1eee481a3dbf75b 100644 (file)
@@ -251,10 +251,6 @@ static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
 static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
-static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info);
-static int cyberfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                        u_long arg, int con, struct fb_info *info);
 
 /*
  *    Interface to the low level console driver
@@ -1007,30 +1003,6 @@ static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-/*
- *    Pan or Wrap the Display
- *
- *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-
-/*
-    *   Cybervision Frame Buffer Specific ioctls
-    */
-
-static int cyberfb_ioctl(struct inode *inode, struct file *file,
-                        u_int cmd, u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-
 static struct fb_ops cyberfb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     cyberfb_get_fix,
@@ -1038,8 +1010,6 @@ static struct fb_ops cyberfb_ops = {
        fb_set_var:     cyberfb_set_var,
        fb_get_cmap:    cyberfb_get_cmap,
        fb_set_cmap:    cyberfb_set_cmap,
-       fb_pan_display: cyberfb_pan_display,
-       fb_ioctl:       cyberfb_ioctl,
 };
 
 int __init cyberfb_setup(char *options)
index 18ec1b79bed30d844b396dd34f8cbe14eeb99178..5d7ab81a5550baff6d05065edfbfc07a17e26c44 100644 (file)
@@ -121,10 +121,6 @@ static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
 static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                      unsigned long arg, int con, struct fb_info *info);
 
 static int dnfbcon_switch(int con,struct fb_info *info);
 static int dnfbcon_updatevar(int con,struct fb_info *info);
@@ -141,8 +137,6 @@ static struct fb_ops dn_fb_ops = {
        fb_set_var:     dn_fb_set_var,
        fb_get_cmap:    dn_fb_get_cmap,
        fb_set_cmap:    dn_fb_set_cmap,
-       fb_pan_display: dn_fb_pan_display,
-       fb_ioctl:       dn_fb_ioctl,
 };
 
 static int currcon=0;
@@ -266,24 +260,6 @@ static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
 
 }
 
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info) {
-
-       printk("panning not supported\n");
-
-       return -EINVAL;
-
-}
-
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                   unsigned long arg, int con, struct fb_info *info) {
-
-       printk("no IOCTLs as of yet.\n");
-
-       return -EINVAL;
-
-}
-
 static void dn_fb_set_disp(int con, struct fb_info *info) {
 
   struct fb_fix_screeninfo fix;
index 5452f1534b436250309dfaf09f3f93c7d0875cd4..fa2cb1e676dc36ae7835ed4477c430ece69ce18b 100644 (file)
@@ -122,10 +122,6 @@ static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
 static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                      unsigned long arg, int con, struct fb_info *info);
 
 static int dnfbcon_switch(int con,struct fb_info *info);
 static int dnfbcon_updatevar(int con,struct fb_info *info);
@@ -142,8 +138,6 @@ static struct fb_ops dn_fb_ops = {
        fb_set_var:     dn_fb_set_var,
        fb_get_cmap:    dn_fb_get_cmap,
        fb_set_cmap:    dn_fb_set_cmap,
-       fb_pan_display: dn_fb_pan_display,
-       fb_ioctl:       dn_fb_ioctl,
 };
 
 static int currcon=0;
@@ -267,24 +261,6 @@ static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
 
 }
 
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info) {
-
-       printk("panning not supported\n");
-
-       return -EINVAL;
-
-}
-
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                   unsigned long arg, int con, struct fb_info *info) {
-
-       printk("no IOCTLs as of yet.\n");
-
-       return -EINVAL;
-
-}
-
 static void dn_fb_set_disp(int con, struct fb_info *info) {
 
   struct fb_fix_screeninfo fix;
index 238f29555c24e5bcfa6476cfc1b6e38660934d4e..6fd59a64dfacaa3908fca15d62b52d1963bcdef9 100644 (file)
@@ -127,10 +127,6 @@ static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
 static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
                          struct fb_info *info);
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                      unsigned long arg, int con, struct fb_info *info);
 
 static int dnfbcon_switch(int con,struct fb_info *info);
 static int dnfbcon_updatevar(int con,struct fb_info *info);
@@ -147,8 +143,6 @@ static struct fb_ops dn_fb_ops = {
        fb_set_var:     dn_fb_set_var,
        fb_get_cmap:    dn_fb_get_cmap,
        fb_set_cmap:    dn_fb_set_cmap,
-       fb_pan_display: dn_fb_pan_display,
-       fb_ioctl:       dn_fb_ioctl,
 };
 
 static int currcon=0;
@@ -272,24 +266,6 @@ static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
 
 }
 
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info) {
-
-       printk("panning not supported\n");
-
-       return -EINVAL;
-
-}
-
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                   unsigned long arg, int con, struct fb_info *info) {
-
-       printk("no IOCTLs as of yet.\n");
-
-       return -EINVAL;
-
-}
-
 static void dn_fb_set_disp(int con, struct fb_info *info) {
 
   struct fb_fix_screeninfo fix;
index 4be9b41d84055e39de6c4cc5dd504d514bddf822..835c93d02f59263f3ba9581dbe1eaac6a0dada78 100644 (file)
@@ -190,17 +190,6 @@ int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
 }
 
 
-    /*
-     *  Frame Buffer Specific ioctls
-     */
-
-int fbgen_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-               unsigned long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
-
 /* ---- Helper functions --------------------------------------------------- */
 
 
index bf34ca0dad76767fbc19911b7bd2984a38fb1f10..9cb20fc0dc98f84d46c5eb517de706006d597196 100644 (file)
@@ -411,6 +411,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        case FBIOPAN_DISPLAY:
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
                        return -EFAULT;
+               if (fb->fb_pan_display == NULL)
+                       return (var.xoffset || var.yoffset) ? -EINVAL : 0;
                if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(info), info)))
                        return i;
                if (copy_to_user((void *) arg, &var, sizeof(var)))
@@ -450,6 +452,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                (*info->blank)(arg, info);
                return 0;
        default:
+               if (fb->fb_ioctl == NULL)
+                       return -EINVAL;
                return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
                                    info);
        }
index 4888735fef8be758412054edc4899d2a68bc96c5..d9f5c0579298a9d74279e30802ea628ac77b914b 100644 (file)
@@ -189,14 +189,10 @@ static int fm2fb_get_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
 static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
-static int fm2fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
 static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int fm2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
-static int fm2fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info);
 
 
     /*
@@ -227,8 +223,6 @@ static struct fb_ops fm2fb_ops = {
        fb_set_var:     fm2fb_set_var,
        fb_get_cmap:    fm2fb_get_cmap,
        fb_set_cmap:    fm2fb_set_cmap,
-       fb_pan_display: fm2fb_pan_display,
-       fb_ioctl:       fm2fb_ioctl,
 };
 
     /*
@@ -292,21 +286,6 @@ static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
 }
 
 
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int fm2fb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-    if (var->xoffset || var->yoffset)
-       return -EINVAL;
-    else
-       return 0;
-}
-
     /*
      *  Get the Colormap
      */
@@ -345,13 +324,6 @@ static int fm2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-static int fm2fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
-
     /*
      *  Initialisation
      */
index 447b1b613b9a25abd4430fedf0011521215d013f..1bbcc3fbdaa2acbc24bd14a7351d1552dd5464b2 100644 (file)
@@ -103,8 +103,6 @@ static int g364fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                           struct fb_info *info);
 static int g364fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                           struct fb_info *info);
-static int g364fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                       u_long arg, int con, struct fb_info *info);
 
 
 /*
@@ -134,7 +132,6 @@ static struct fb_ops g364fb_ops = {
        fb_get_cmap:    g364fb_get_cmap,
        fb_set_cmap:    g364fb_set_cmap,
        fb_pan_display: g364fb_pan_display,
-       fb_ioctl:       g364fb_ioctl,
 };
 
 
@@ -277,13 +274,6 @@ static int g364fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-static int g364fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                       u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
-
 /*
  *  Initialisation
  */
index 3a5e48d9edd44b48449c89897d1d0cf95d3f24bb..d2b09416b4b881bf1b5000fb345c66cc6e8f4714 100644 (file)
@@ -514,21 +514,6 @@ int hga_pan_display(struct fb_var_screeninfo *var, int con,
 }
 
     
-       /*
-        *  Frame Buffer Specific ioctls
-        */
-
-int hga_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-              unsigned long arg, int con, struct fb_info *info)
-{
-       CHKINFO(-EINVAL);
-       DPRINTK("hga_ioctl: con:%d\n", con);
-       return -EINVAL;
-}
-
-
-       
-       
 static struct fb_ops hgafb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     hga_get_fix,
@@ -537,7 +522,6 @@ static struct fb_ops hgafb_ops = {
        fb_get_cmap:    hga_get_cmap,
        fb_set_cmap:    hga_set_cmap,
        fb_pan_display: hga_pan_display,
-       fb_ioctl:       hga_ioctl,
 };
                
 
index a422a7fe2b82e1e3344687c198032a205ae5d02c..589823acd2704a3322f9291ab661e14b525d7f2b 100644 (file)
@@ -250,16 +250,6 @@ static int hitfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     return 0;
 }
 
-static int hitfb_pan_display(struct fb_var_screeninfo *var,
-                            struct hitfb_par *par, const struct fb_info *info)
-{
-    if (var->xoffset || var->yoffset)
-       return -EINVAL;
-    else
-       return 0;
-}
-
-
 static int hitfb_blank(int blank_mode, const struct fb_info *info)
 {
     return 0;
@@ -297,7 +287,7 @@ struct fbgen_hwswitch hitfb_switch = {
     hitfb_set_par,
     hitfb_getcolreg,
     hitfb_setcolreg,
-    hitfb_pan_display,
+    NULL,
     hitfb_blank,
     hitfb_set_disp
 };
@@ -309,8 +299,6 @@ static struct fb_ops hitfb_ops = {
        fb_set_var:     fbgen_set_var,
        fb_get_cmap:    fbgen_get_cmap,
        fb_set_cmap:    fbgen_set_cmap,
-       fb_pan_display: fbgen_pan_display,
-       fb_ioctl:       fbgen_ioctl,
 };
 
 
index ab3e2e08420df948bed3f1ca7141fa1c4d3fad22..4bfc4a9ef8247ce2316f83ecb392aaf60c08f262 100644 (file)
@@ -225,13 +225,6 @@ static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h)
        writeb(fb_bitmask, fb_regs + WMOVE);
 }
 
-static int hpfb_ioctl(struct inode *inode, struct file *file, 
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static int hpfb_switch(int con, struct fb_info *info)
 {
        do_fb_set_var(&fb_display[con].var,1);
@@ -279,7 +272,6 @@ static struct fb_ops hpfb_ops = {
        fb_set_var:     hpfb_set_var,
        fb_get_cmap:    hpfb_get_cmap,
        fb_set_cmap:    hpfb_set_cmap,
-       fb_ioctl:       hpfb_ioctl,
 };
 
 #define TOPCAT_FBOMSB  0x5d
index 5ce2f2648005f9b268f0f3e77f6c957e32a60c46..ac176a8cf8c47bbcfa7dec351ea97fb86f204e39 100644 (file)
@@ -431,19 +431,6 @@ static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
         return 0;
 }
 
-static int igafb_pan_display(struct fb_var_screeninfo *var, int con,
-                             struct fb_info *info)
-{
-        /* no panning */
-        return -EINVAL;
-}
-
-static int igafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 /*
  * Framebuffer option structure
  */
@@ -454,8 +441,6 @@ static struct fb_ops igafb_ops = {
        fb_set_var:     igafb_set_var,
        fb_get_cmap:    igafb_get_cmap,
        fb_set_cmap:    igafb_set_cmap,
-       fb_pan_display: igafb_pan_display,
-       fb_ioctl:       igafb_ioctl,
 #ifdef __sparc__
        fb_mmap:        igafb_mmap,
 #endif
index 627206e57634d04fe7c79b7d9fa7a8feec73ff69..a5c173aa2ea3bcb0be788427c7af1cfdef8253ca 100644 (file)
@@ -830,19 +830,6 @@ static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int macfb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static struct fb_ops macfb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     macfb_get_fix,
@@ -850,8 +837,6 @@ static struct fb_ops macfb_ops = {
        fb_set_var:     macfb_set_var,
        fb_get_cmap:    macfb_get_cmap,
        fb_set_cmap:    macfb_set_cmap,
-       fb_pan_display: macfb_pan_display,
-       fb_ioctl:       macfb_ioctl,
 };
 
 void macfb_setup(char *options, int *ints)
index d98ab4e0e28b724799db42a54f7075166e30e294..69bb8cc72937ef55a5027057c20aa05dfc85c526 100644 (file)
@@ -83,14 +83,10 @@ static int offb_get_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
 static int offb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
-static int offb_pan_display(struct fb_var_screeninfo *var, int con,
-                       struct fb_info *info);
 static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
 static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
-static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                           u_long arg, int con, struct fb_info *info);
 
 extern boot_infos_t *boot_infos;
 
@@ -127,8 +123,6 @@ static struct fb_ops offb_ops = {
        fb_set_var:     offb_set_var,
        fb_get_cmap:    offb_get_cmap,
        fb_set_cmap:    offb_set_cmap,
-       fb_pan_display: offb_pan_display,
-       fb_ioctl:       offb_ioctl,
 };
 
     /*
@@ -199,21 +193,6 @@ static int offb_set_var(struct fb_var_screeninfo *var, int con,
 }
 
 
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int offb_pan_display(struct fb_var_screeninfo *var, int con,
-                           struct fb_info *info)
-{
-    if (var->xoffset || var->yoffset)
-       return -EINVAL;
-    else
-       return 0;
-}
-
     /*
      *  Get the Colormap
      */
@@ -259,13 +238,6 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                     u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
-
 #ifdef CONFIG_FB_S3TRIO
 extern void s3triofb_init_of(struct device_node *dp);
 #endif /* CONFIG_FB_S3TRIO */
index 97b787d4f136912cce5f9d2dc3200a120f4f7990..3bbd7fe48d4170205f08733446cf4ca583f008cb 100644 (file)
@@ -107,14 +107,10 @@ static int platinum_get_var(struct fb_var_screeninfo *var, int con,
                            struct fb_info *fb);
 static int platinum_set_var(struct fb_var_screeninfo *var, int con,
                            struct fb_info *fb);
-static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
-                               struct fb_info *fb);
 static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                             struct fb_info *info);
 static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                             struct fb_info *info);
-static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                         u_long arg, int con, struct fb_info *info);
 
 
 /*
@@ -170,8 +166,6 @@ static struct fb_ops platinumfb_ops = {
        fb_set_var:     platinum_set_var,
        fb_get_cmap:    platinum_get_cmap,
        fb_set_cmap:    platinum_set_cmap,
-       fb_pan_display: platinum_pan_display,
-       fb_ioctl:       platinum_ioctl,
 };
 
 static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
@@ -299,20 +293,6 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
-                               struct fb_info *info)
-{
-    /*
-     *  Pan (or wrap, depending on the `vmode' field) the display using the
-     *  `xoffset' and `yoffset' fields of the `var' structure.
-     *  If the values don't fit, return -EINVAL.
-     */
-
-       if (var->xoffset != 0 || var->yoffset != 0)
-               return -EINVAL;
-       return 0;
-}
-
 static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                             struct fb_info *info)
 {
@@ -352,13 +332,6 @@ static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                         u_long arg, int con, struct fb_info *info)
-{
-       printk(KERN_ERR "platinum_ioctl not yet implemented\n");
-       return -EINVAL;
-}
-
 static int platinum_switch(int con, struct fb_info *fb)
 {
        struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
index 12175a1f89304224538e7255c0038c481ff9bb1c..2b798e05d01a1b9b08fae6cfe86c151edcabaa5f 100644 (file)
@@ -39,8 +39,6 @@ static int q40fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
                         struct fb_info *info);
 static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
                         struct fb_info *info);
-static int q40fb_pan_display(struct fb_var_screeninfo *var, int con,
-                           struct fb_info *info);
 static int q40fb_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, unsigned long arg, int con,
                      struct fb_info *info);
@@ -60,7 +58,6 @@ static struct fb_ops q40fb_ops = {
        fb_set_var:     q40fb_set_var,
        fb_get_cmap:    q40fb_get_cmap,
        fb_set_cmap:    q40fb_set_cmap,
-       fb_pan_display: q40fb_pan_display,
        fb_ioctl:       q40fb_ioctl,
 };
 
@@ -254,15 +251,6 @@ static int q40fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 #endif
 }
 
-static int q40fb_pan_display(struct fb_var_screeninfo *var, int con,
-                           struct fb_info *info)
-{
-       printk(KERN_ERR "panning not supported\n");
-
-       return -EINVAL;
-
-}
-
 static int q40fb_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, unsigned long arg, int con,
                      struct fb_info *info)
index 5dda9d19ca7ad5b6f601a2414eb49f266c353d45..ef39926ab43dde298efe597c63b3c48493414364 100644 (file)
@@ -277,11 +277,6 @@ static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
 static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
-static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info);
-static int retz3fb_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg, int con,
-                        struct fb_info *info);
 
 
 /*
@@ -1338,31 +1333,6 @@ static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-/*
- *    Pan or Wrap the Display
- *
- *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
-                               struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-
-/*
- *    RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3fb_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg, int con,
-                         struct fb_info *info)
-{
-       return -EINVAL;
-}
-
-
 static struct fb_ops retz3fb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     retz3fb_get_fix,
@@ -1370,8 +1340,6 @@ static struct fb_ops retz3fb_ops = {
        fb_set_var:     retz3fb_set_var,
        fb_get_cmap:    retz3fb_get_cmap,
        fb_set_cmap:    retz3fb_set_cmap,
-       fb_pan_display: retz3fb_pan_display,
-       fb_ioctl:       retz3fb_ioctl,
 };
 
 
index eb98ba112e0f5ba90c89044d0be269c1a9c1475c..df2d81b667eb901a7729158b4604bb7d46e6ccdc 100644 (file)
@@ -158,13 +158,10 @@ static struct sa1100fb_lcd_reg lcd_shadow;
 
 
 static int  sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
-static int  sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
-                         unsigned long arg, int con, struct fb_info *info);
 static int  sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
 static int  sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
 static int  sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
 static int  sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
-static int  sa1100fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);
  
 static int  sa1100fb_switch(int con, struct fb_info *info);
 static void sa1100fb_blank(int blank, struct fb_info *info);
@@ -180,8 +177,6 @@ static struct fb_ops sa1100fb_ops = {
        fb_set_var:     sa1100fb_set_var,
        fb_get_cmap:    sa1100fb_get_cmap,
        fb_set_cmap:    sa1100fb_set_cmap,
-       fb_pan_display: sa1100fb_pan_display,
-       fb_ioctl:       sa1100fb_ioctl,
 };
 
 
@@ -1095,15 +1090,6 @@ static void sa1100fb_enable_lcd_controller(void)
        restore_flags(flags);
 }
 
-static int
-sa1100fb_pan_display(struct fb_var_screeninfo *var, int con,
-                   struct fb_info *info)
-{
-       DPRINTK("entered\n");
-       return -EINVAL;
-}
-
-
 /*
  * sa1100fb_blank():
  *     Blank the display by setting all palette values to zero.  Note, the 
@@ -1217,13 +1203,3 @@ int __init sa1100fb_setup(char *options)
        return 0;
 }
 
-
-
-static int
-sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
-             unsigned long arg, int con, struct fb_info *info)
-{
-       return -ENOIOCTLCMD;
-}
-
-
index 408b2b000339848d3cfae7e1a8674d0d0291c415..63d2b7c76568a8079c7e1546a939c782bb38146e 100644 (file)
@@ -85,8 +85,6 @@ static int sbusfb_get_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
 static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
-static int sbusfb_pan_display(struct fb_var_screeninfo *var, int con,
-                       struct fb_info *info);
 static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
 static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
@@ -125,7 +123,6 @@ static struct fb_ops sbusfb_ops = {
        fb_set_var:     sbusfb_set_var,
        fb_get_cmap:    sbusfb_get_cmap,
        fb_set_cmap:    sbusfb_set_cmap,
-       fb_pan_display: sbusfb_pan_display,
        fb_ioctl:       sbusfb_ioctl,
        fb_mmap:        sbusfb_mmap,
 };
@@ -399,21 +396,6 @@ static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
        }
        return 0;
 
-}
-
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int sbusfb_pan_display(struct fb_var_screeninfo *var, int con,
-                             struct fb_info *info)
-{
-       if (var->xoffset || var->yoffset)
-               return -EINVAL;
-       else
-               return 0;
 }
 
     /*
index 0a180d5a629a83582fa6c17f153a1fc02291e430..7fcbf0bd5579ae4c81bb2d2da8a852e6780618f1 100644 (file)
@@ -97,14 +97,10 @@ static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con,
                           struct fb_info *info);
 static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
                           struct fb_info *info);
-static int sgivwfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info);
 static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
 static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
-static int sgivwfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                        u_long arg, int con, struct fb_info *info);
 static int sgivwfb_mmap(struct fb_info *info, struct file *file,
                         struct vm_area_struct *vma);
 
@@ -115,8 +111,6 @@ static struct fb_ops sgivwfb_ops = {
        fb_set_var:     sgivwfb_set_var,
        fb_get_cmap:    sgivwfb_get_cmap,
        fb_set_cmap:    sgivwfb_set_cmap,
-       fb_pan_display: sgivwfb_pan_display,
-       fb_ioctl:       sgivwfb_ioctl,
        fb_mmap:        sgivwfb_mmap,
 };
 
@@ -804,39 +798,6 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
   return 0;
 }
 
-/*
- *  Pan or Wrap the Display
- *
- *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int sgivwfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info)
-{
-#if 0
-  if (var->vmode & FB_VMODE_YWRAP) {
-    if (var->yoffset < 0 ||
-       var->yoffset >= fb_display[con].var.yres_virtual ||
-       var->xoffset)
-      return -EINVAL;
-  } else {
-    if (var->xoffset+fb_display[con].var.xres >
-       fb_display[con].var.xres_virtual ||
-       var->yoffset+fb_display[con].var.yres >
-       fb_display[con].var.yres_virtual)
-      return -EINVAL;
-  }
-  fb_display[con].var.xoffset = var->xoffset;
-  fb_display[con].var.yoffset = var->yoffset;
-  if (var->vmode & FB_VMODE_YWRAP)
-    fb_display[con].var.vmode |= FB_VMODE_YWRAP;
-  else
-    fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
-  return 0;
-#endif
-  return -EINVAL;
-}
-
 /*
  *  Get the Colormap
  */
@@ -873,15 +834,6 @@ static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
   return 0;
 }
 
-/*
- *  Virtual Frame Buffer Specific ioctls
- */
-static int sgivwfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                        u_long arg, int con, struct fb_info *info)
-{
-  return -EINVAL;
-}
-
 static int sgivwfb_mmap(struct fb_info *info, struct file *file,
                         struct vm_area_struct *vma)
 {
index 763ec0d4f2adac50a2574aa5ac384286ad4f5d8a..994e8732ef4155c755b15dbd3a642262892e18b1 100644 (file)
@@ -434,8 +434,6 @@ static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
-static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
 static int sisfb_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg, int con,
                       struct fb_info *info);
@@ -2598,17 +2596,6 @@ static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-/*
- *    Pan or Wrap the Display
- */
-
-static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-       /* not support virtual screen yet */
-       return -EINVAL;
-}
-
 static int sisfb_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg, int con,
                       struct fb_info *info)
@@ -2694,7 +2681,6 @@ static struct fb_ops sisfb_ops = {
        fb_set_var:     sisfb_set_var,
        fb_get_cmap:    sisfb_get_cmap,
        fb_set_cmap:    sisfb_set_cmap,
-       fb_pan_display: sisfb_pan_display,
        fb_ioctl:       sisfb_ioctl,
        fb_mmap:        sisfb_mmap,
 };
index 17efdadfe033f34dd7ac0bf84fd7664d63fc3e4c..f6cd0a21e5133a2aa374ffd982991c6dd60bf207 100644 (file)
@@ -390,7 +390,7 @@ static struct fb_ops xxxfb_ops = {
        fb_get_cmap:    fbgen_get_cmap,
        fb_set_cmap:    fbgen_set_cmap,
        fb_pan_display: fbgen_pan_display,
-       fb_ioctl:       fbgen_ioctl,
+       fb_ioctl:       xxxfb_ioctl,   /* optional */
 };
 
 
index be5de7bdb7b3d549eb2f35de300e5c32b5a7db9e..3723325be9d44fefe424aa5a255c18962caaa697 100644 (file)
@@ -76,14 +76,10 @@ static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
 static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info);
-static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
-                       struct fb_info *info);
 static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
 static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
-static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                           u_long arg, int con, struct fb_info *info);
 static void sun3fb_cursor(struct display *p, int mode, int x, int y);
 static void sun3fb_clear_margin(struct display *p, int s);
                            
@@ -114,8 +110,6 @@ static struct fb_ops sun3fb_ops = {
        fb_set_var:     sun3fb_set_var,
        fb_get_cmap:    sun3fb_get_cmap,
        fb_set_cmap:    sun3fb_set_cmap,
-       fb_pan_display: sun3fb_pan_display,
-       fb_ioctl:       sun3fb_ioctl,
 };
 
 static void sun3fb_clear_margin(struct display *p, int s)
@@ -230,21 +224,6 @@ static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
-                             struct fb_info *info)
-{
-       if (var->xoffset || var->yoffset)
-               return -EINVAL;
-       else
-               return 0;
-}
-
     /*
      *  Hardware cursor
      */
@@ -351,12 +330,6 @@ static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                       u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
     /*
      *  Setup: parse used options
      */
index 1ac719ee7f6e0ec1df36d516d66718487023c02f..7572891d6f751d68a64949fb3fa7629a7a703130 100644 (file)
@@ -279,8 +279,6 @@ static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                u_int *transp, struct fb_info *info);
 static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
                u_int transp, struct fb_info *info);
-static int tgafb_pan_display(const struct fb_var_screeninfo *var,
-               struct fb_info_gen *info);
 static int tgafb_blank(int blank, struct fb_info_gen *info);
 static void tgafb_set_disp(const void *fb_par, struct display *disp, 
                struct fb_info_gen *info);
@@ -780,16 +778,6 @@ static void tgafb_update_palette(void)
 #endif
 
 
-static int tgafb_pan_display(const struct fb_var_screeninfo *var, 
-                                    struct fb_info_gen *info)
-{
-    if (var->xoffset || var->yoffset)
-       return -EINVAL;
-    else
-       return 0;
-}
-
-
 static int tgafb_blank(int blank, struct fb_info_gen *info)
 {
     static int tga_vesa_blanked = 0;
@@ -869,7 +857,7 @@ static void tgafb_set_disp(const void *fb_par, struct display *disp,
 
 struct fbgen_hwswitch tgafb_hwswitch = {
     tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par,
-    tgafb_set_par, tgafb_getcolreg, tgafb_setcolreg, tgafb_pan_display, tgafb_blank, 
+    tgafb_set_par, tgafb_getcolreg, tgafb_setcolreg, NULL, tgafb_blank, 
     tgafb_set_disp
 };
 
@@ -890,8 +878,6 @@ static struct fb_ops tgafb_ops = {
        fb_set_var:     fbgen_set_var,
        fb_get_cmap:    fbgen_get_cmap,
        fb_set_cmap:    tgafb_set_cmap,
-       fb_pan_display: fbgen_pan_display,
-       fb_ioctl:       fbgen_ioctl,
 };
 
 
index 23fc97915ce8775b9533ad69e3c2799afb6346e1..6739cecf957e2eb34b5ccc860cf87e397485411f 100644 (file)
@@ -123,14 +123,10 @@ static int valkyrie_get_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
 static int valkyrie_set_var(struct fb_var_screeninfo *var, int con,
                         struct fb_info *info);
-static int valkyrie_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
 static int valkyrie_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 static int valkyrie_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
-static int valkyrie_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info);
 
 static int read_valkyrie_sense(struct fb_info_valkyrie *p);
 static inline int valkyrie_vram_reqd(int video_mode, int color_mode);
@@ -155,8 +151,6 @@ static struct fb_ops valkyriefb_ops = {
        fb_set_var:     valkyrie_set_var,
        fb_get_cmap:    valkyrie_get_cmap,
        fb_set_cmap:    valkyrie_set_cmap,
-       fb_pan_display: valkyrie_pan_display,
-       fb_ioctl:       valkyrie_ioctl,
 };
 
 static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green,
@@ -239,14 +233,6 @@ static int valkyrie_set_var(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-static int valkyrie_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-       if (var->xoffset != 0 || var->yoffset != 0)
-               return -EINVAL;
-       return 0;
-}
-
 static int valkyrie_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info)
 {
@@ -285,12 +271,6 @@ static int valkyrie_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int valkyrie_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static int valkyriefb_switch(int con, struct fb_info *fb)
 {
        struct fb_info_valkyrie *info = (struct fb_info_valkyrie *) fb;
index e4ee03a8298205529933fefb1ebaa42d25b683a9..fa19c744da623f61d9443fb0f20b43b4d86a2cfb 100644 (file)
@@ -438,13 +438,6 @@ static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int vesafb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static struct fb_ops vesafb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     vesafb_get_fix,
@@ -453,7 +446,6 @@ static struct fb_ops vesafb_ops = {
        fb_get_cmap:    vesafb_get_cmap,
        fb_set_cmap:    vesafb_set_cmap,
        fb_pan_display: vesafb_pan_display,
-       fb_ioctl:       vesafb_ioctl,
 };
 
 int vesafb_setup(char *options)
index 0d00b6f4a0a28c536af0f05535ed3cdacf637806..c51d33bed99f7568869a528d458d406bd3684394 100644 (file)
@@ -92,8 +92,6 @@ static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
 static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                        struct fb_info *info);
-static int vfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                    u_long arg, int con, struct fb_info *info);
 
 
     /*
@@ -129,7 +127,6 @@ static struct fb_ops vfb_ops = {
        fb_get_cmap:    vfb_get_cmap,
        fb_set_cmap:    vfb_set_cmap,
        fb_pan_display: vfb_pan_display,
-       fb_ioctl:       vfb_ioctl,
 };
 
     /*
@@ -377,17 +374,6 @@ static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-    /*
-     *  Virtual Frame Buffer Specific ioctls
-     */
-
-static int vfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                    u_long arg, int con, struct fb_info *info)
-{
-    return -EINVAL;
-}
-
-
 int __init vfb_setup(char *options)
 {
     char *this_opt;
index f6cb655e161c706d93b1ada768df9e5b1deb99b8..35197da609f8dd58f621d624cba371359c4610ca 100644 (file)
@@ -673,13 +673,6 @@ static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
        return 0;
 }
 
-static int vga16fb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info)
-{
-       return -EINVAL;
-}
-
 static struct fb_ops vga16fb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     vga16fb_get_fix,
@@ -688,7 +681,6 @@ static struct fb_ops vga16fb_ops = {
        fb_get_cmap:    vga16fb_get_cmap,
        fb_set_cmap:    vga16fb_set_cmap,
        fb_pan_display: vga16fb_pan_display,
-       fb_ioctl:       vga16fb_ioctl,
 };
 
 int vga16fb_setup(char *options)
index 7441b7fdc9d7c806c201a5693edd3fab46fe80a5..6be952607202dd2dab27d7cfb72ee65c138f0725 100644 (file)
@@ -308,10 +308,6 @@ static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
 static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info);
-static int virgefb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info);
-static int virgefb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                         u_long arg, int con, struct fb_info *info);
 
 
 /*
@@ -1072,30 +1068,6 @@ static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 }
 
 
-/*
- *    Pan or Wrap the Display
- *
- *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int virgefb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info)
-{
-       return(-EINVAL);
-}
-
-
-/*
- *      Cybervision Frame Buffer Specific ioctls
- */
-
-static int virgefb_ioctl(struct inode *inode, struct file *file,
-                        u_int cmd, u_long arg, int con, struct fb_info *info)
-{
-       return(-EINVAL);
-}
-
-
 static struct fb_ops virgefb_ops = {
        owner:          THIS_MODULE,
        fb_get_fix:     virgefb_get_fix,
@@ -1103,8 +1075,6 @@ static struct fb_ops virgefb_ops = {
        fb_set_var:     virgefb_set_var,
        fb_get_cmap:    virgefb_get_cmap,
        fb_set_cmap:    virgefb_set_cmap,
-       fb_pan_display: virgefb_pan_display,
-       fb_ioctl:       virgefb_ioctl,
 };
 
 
index 711beee06e4aed7928ba68613c035a68b38677f4..99ead4e51e8a523c666b3e9fb7b82a15a753e7e8 100644 (file)
@@ -85,7 +85,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
                target_inode = nd.dentry->d_inode;
        }
        
-       CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%d\n",
+       CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%x\n",
               target_inode->i_ino, target_inode->i_dev);
 
        /* return if it is not a Coda inode */
index 42d91c35fd3879342c7ed1a0fbfff1371743123f..15f7dad8fcac3ad0dec61de53b06d2f38d3c21cc 100644 (file)
@@ -732,7 +732,7 @@ put_it:
 /* Free list of dquots - called from inode.c */
 void put_dquot_list(struct list_head *tofree_head)
 {
-       struct list_head *act_head = tofree_head.next;
+       struct list_head *act_head = tofree_head->next;
        struct dquot *dquot;
 
        /* So now we have dquots on the list... Just free them */
index 70e806b02cc27e64bbc9891e983522c751d2a384..4580c87e0a303b85f2e210c40ba38cc1bfef3ea1 100644 (file)
@@ -223,20 +223,6 @@ repeat:
                        return NULL;
                }
        }
-       *err = -EFBIG;
-
-       /* Check file limits.. */
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY) {
-                       limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-                       if (new_block >= limit) {
-                               send_sig(SIGXFSZ, current, 0);
-                               *err = -EFBIG;
-                               return NULL;
-                       }
-               }
-       }
 
        if (inode->u.ext2_i.i_next_alloc_block == new_block)
                goal = inode->u.ext2_i.i_next_alloc_goal;
@@ -320,7 +306,6 @@ static struct buffer_head * block_getblk (struct inode * inode,
        u32 * p;
        struct buffer_head * result;
        int blocksize = inode->i_sb->s_blocksize;
-       unsigned long limit;
 
        result = NULL;  
        if (!bh)
@@ -347,16 +332,6 @@ repeat:
                        goto out;
                }
        }
-       *err = -EFBIG;
-
-       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit < RLIM_INFINITY) {
-               limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-               if (new_block >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       goto out;
-               }
-       }
 
        if (inode->u.ext2_i.i_next_alloc_block == new_block)
                goal = inode->u.ext2_i.i_next_alloc_goal;
index 038773b9459b08fa7d6d21bd1ed385ffbf8a073d..cabb08f763f00c92ae4a40603d36be37117423e7 100644 (file)
@@ -75,7 +75,7 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
                /* Fscking Microsoft marketing department. Their "32" is 28. */
                next &= 0xfffffff;
                if (next >= 0xffffff7) next = -1;
-               PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%d\n", b, nr, first, next));
+               PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%x\n", b, nr, first, next));
 
        } else if (MSDOS_SB(sb)->fat_bits == 16) {
                p_first = p_last = NULL; /* GCC needs that stuff */
index 1447554edf5db5f6d5ba5b2ac4adbe7936cae0b5..b1973918d2f023fae60ae0b0a45aa66e5b764662 100644 (file)
@@ -1225,7 +1225,6 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
        struct jffs_node *node;
        struct dentry *dentry = filp->f_dentry; 
        struct inode *inode = dentry->d_inode; 
-       unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
        int written = 0;
        loff_t pos;
        int err;
@@ -1282,22 +1281,6 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
        if (filp->f_flags & O_APPEND)
                pos = inode->i_size;
 
-
-       /*
-        * Check whether we've reached the file size limit.
-        */
-       err = -EFBIG;
-       if (limit != RLIM_INFINITY) {
-               if (pos >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       goto out;
-               }
-               if (count > limit - pos) {
-                       send_sig(SIGXFSZ, current, 0);
-                       count = limit - pos;
-               }
-       }
-       
        /* Things are going to be written so we could allocate and
           initialize the necessary data structures now.  */
        if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
index fac903800d6cceb58d38021efd4c319969bbba5b..b4962692354bc5c6ff980ca88d0a4d2cb54a0c20 100644 (file)
@@ -505,20 +505,6 @@ repeat:
                        return NULL;
                }
        }
-       *err = -EFBIG;
-
-       /* Check file limits.. */
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY) {
-                       limit >>= BLOCK_SIZE_BITS;
-                       if (new_block >= limit) {
-                               send_sig(SIGXFSZ, current, 0);
-                               *err = -EFBIG;
-                               return NULL;
-                       }
-               }
-       }
 
        tmp = minix_new_block(inode);
        if (!tmp) {
@@ -564,7 +550,6 @@ static struct buffer_head * V1_block_getblk(struct inode * inode,
        int tmp;
        unsigned short *p;
        struct buffer_head * result;
-       unsigned long limit;
 
        result = NULL;
        if (!bh)
@@ -590,16 +575,6 @@ repeat:
                        goto out;
                }
        }
-       *err = -EFBIG;
-
-       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit < RLIM_INFINITY) {
-               limit >>= BLOCK_SIZE_BITS;
-               if (new_block >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       goto out;
-               }
-       }
 
        tmp = minix_new_block(inode);
        if (!tmp)
@@ -741,20 +716,6 @@ repeat:
                        return NULL;
                }
        }
-       *err = -EFBIG;
-
-       /* Check file limits.. */
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY) {
-                       limit >>= BLOCK_SIZE_BITS;
-                       if (new_block >= limit) {
-                               send_sig(SIGXFSZ, current, 0);
-                               *err = -EFBIG;
-                               return NULL;
-                       }
-               }
-       }
 
        tmp = minix_new_block(inode);
        if (!tmp) {
@@ -800,7 +761,6 @@ static struct buffer_head * V2_block_getblk(struct inode * inode,
        int tmp;
        unsigned int *p;
        struct buffer_head * result;
-       unsigned long limit;
 
        result = NULL;
        if (!bh)
@@ -826,16 +786,6 @@ repeat:
                        goto out;
                }
        }
-       *err = -EFBIG;
-
-       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit < RLIM_INFINITY) {
-               limit >>= BLOCK_SIZE_BITS;
-               if (new_block >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       goto out;
-               }
-       }
 
        tmp = minix_new_block(inode);
        if (!tmp)
index 8653e20ab689e88e6be0b60f899b1957b72b90d2..b85a6419db800b5e55cd61edc5b16489d365267b 100644 (file)
@@ -292,13 +292,15 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
 
        /*
         * Uhhuh! Nasty case: the cache was re-populated while
-        * we waited on the semaphore. Need to revalidate, but
-        * we're going to return this entry regardless (same
-        * as if it was busy).
+        * we waited on the semaphore. Need to revalidate.
         */
        up(&dir->i_sem);
-       if (result->d_op && result->d_op->d_revalidate)
-               result->d_op->d_revalidate(result, flags);
+       if (result->d_op && result->d_op->d_revalidate) {
+               if (!result->d_op->d_revalidate(result, flags) && !d_invalidate(result)) {
+                       dput(result);
+                       result = ERR_PTR(-ENOENT);
+               }
+       }
        return result;
 }
 
index c47cc141791b5b2f2dde750576c2677d6bff0658..89389033483d94dea6bc4fafc3276f8c38389b94 100644 (file)
@@ -1,5 +1,9 @@
 ChangeLog for smbfs.
 
+2000-07-25 Urban Widmark <urban@svenskatest.se>
+
+       * proc.c: fix 3 places where bad server responses could cause an Oops.
+
 2000-07-15 Urban Widmark <urban@svenskatest.se>
 
        * *.c: more debug (%.*s) & indent fixes
index 68922335cc80289ff7d440fbb2eed9ac873ac020..e969320b798ada3b507792333497cc28eb22cd61 100644 (file)
@@ -947,7 +947,7 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
 {
        struct smb_sb_info *server = server_from_dentry(dentry);
        __u16 returned_count, data_len;
-       char *buf;
+       unsigned char *buf;
        int result;
 
        smb_lock_server(server);
@@ -965,10 +965,19 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
 
        buf = SMB_BUF(server->packet);
        data_len = WVAL(buf, 1);
+
+       /* we can NOT simply trust the data_len given by the server ... */
+       if (data_len > server->packet_size - (buf+3 - server->packet)) {
+               printk(KERN_ERR "smb_proc_read: invalid data length!! "
+                      "%d > %d - (%p - %p)\n",
+                      data_len, server->packet_size, buf+3, server->packet);
+               result = -EIO;
+               goto out;
+       }
+
        memcpy(data, buf+3, data_len);
 
-       if (returned_count != data_len)
-       {
+       if (returned_count != data_len) {
                printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");
                printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n",
                       returned_count, data_len);
@@ -1288,9 +1297,8 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
        entry->name = p + 9;
        len = strlen(entry->name);
        if (len > 12)
-       {
                len = 12;
-       }
+
        /*
         * Trim trailing blanks for Pathworks servers
         */
@@ -1298,8 +1306,7 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
                len--;
        entry->len = len;
 
-       switch (server->opt.case_handling)
-       {
+       switch (server->opt.case_handling) {
        case SMB_CASE_UPPER:
                str_upper(entry->name, len);
                break;
@@ -1309,7 +1316,7 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
        default:
                break;
        }
-       DEBUG1("len=%d, name=%s\n", len, entry->name);
+       DEBUG1("len=%d, name=%.*s\n", len, len, entry->name);
        return p + 22;
 }
 
@@ -1321,7 +1328,7 @@ static int
 smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
                       void *cachep)
 {
-       char *p;
+       unsigned char *p;
        int result;
        int i, first, entries_seen, entries;
        int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
@@ -1329,26 +1336,25 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
        __u16 count;
        char status[SMB_STATUS_SIZE];
        static struct qstr mask = { "*.*", 3, 0 };
+       unsigned char *last_status;
 
        VERBOSE("%s/%s, pos=%d\n", DENTRY_PATH(dir), fpos);
 
        smb_lock_server(server);
 
        /* N.B. We need to reinitialize the cache to restart */
-      retry:
+retry:
        smb_init_dircache(cachep);
        first = 1;
        entries = 0;
        entries_seen = 2; /* implicit . and .. */
 
-       while (1)
-       {
+       while (1) {
                p = smb_setup_header(server, SMBsearch, 2, 0);
                WSET(server->packet, smb_vwv0, entries_asked);
                WSET(server->packet, smb_vwv1, aDIR);
                *p++ = 4;
-               if (first == 1)
-               {
+               if (first == 1) {
                        p = smb_encode_path(server, p, dir, &mask);
                        *p++ = 5;
                        WSET(p, 0, 0);
@@ -1366,8 +1372,7 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
                smb_setup_bcc(server, p);
 
                result = smb_request_ok(server, SMBsearch, 1, -1);
-               if (result < 0)
-               {
+               if (result < 0) {
                        if ((server->rcls == ERRDOS) && 
                            (server->err  == ERRnofiles))
                                break;
@@ -1386,28 +1391,39 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
                        goto unlock_return;
                p += 7;
 
+
+               /* Make sure the response fits in the buffer. Fixed sized 
+                  entries means we don't have to check in the decode loop. */
+
+               last_status = SMB_BUF(server->packet) + 3 + (count - 1) *
+                       SMB_DIRINFO_SIZE;
+
+               if (last_status + SMB_DIRINFO_SIZE >=
+                   server->packet + server->packet_size) {
+                       printk(KERN_ERR "smb_proc_readdir_short: "
+                              "last dir entry outside buffer! "
+                              "%d@%p  %d@%p\n", SMB_DIRINFO_SIZE, last_status,
+                              server->packet_size, server->packet);
+                       goto unlock_return;
+               }
+
                /* Read the last entry into the status field. */
-               memcpy(status,
-                      SMB_BUF(server->packet) + 3 +
-                      (count - 1) * SMB_DIRINFO_SIZE,
-                      SMB_STATUS_SIZE);
+               memcpy(status, last_status, SMB_STATUS_SIZE);
+
 
                /* Now we are ready to parse smb directory entries. */
 
-               for (i = 0; i < count; i++)
-               {
+               for (i = 0; i < count; i++) {
                        struct cache_dirent this_ent, *entry = &this_ent;
 
                        p = smb_decode_dirent(server, p, entry);
-                       if (entries_seen == 2 && entry->name[0] == '.')
-                       {
+                       if (entries_seen == 2 && entry->name[0] == '.') {
                                if (entry->len == 1)
                                        continue;
                                if (entry->name[1] == '.' && entry->len == 2)
                                        continue;
                        }
-                       if (entries_seen >= fpos)
-                       {
+                       if (entries_seen >= fpos) {
                                DEBUG1("fpos=%u\n", entries_seen);
                                smb_add_to_cache(cachep, entry, entries_seen);
                                entries++;
@@ -1420,7 +1436,7 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
        }
        result = entries;
 
-    unlock_return:
+unlock_return:
        smb_unlock_server(server);
        return result;
 }
@@ -1511,7 +1527,8 @@ static int
 smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                      void *cachep)
 {
-       char *p, *mask, *lastname, *param = server->temp_buf;
+       unsigned char *p;
+       char *mask, *lastname, *param = server->temp_buf;
        __u16 command;
        int first, entries, entries_seen;
 
@@ -1539,7 +1556,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
 
        smb_lock_server(server);
 
-      retry:
+retry:
        /*
         * Encode the initial path
         */
@@ -1665,6 +1682,17 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                for (i = 0; i < ff_searchcount; i++) {
                        struct cache_dirent this_ent, *entry = &this_ent;
 
+                       /* make sure we stay within the buffer */
+                       if (p >= resp_data + resp_data_len) {
+                               printk(KERN_ERR "smb_proc_readdir_long: "
+                                      "dirent pointer outside buffer! "
+                                      "%p  %d@%p  %d@%p\n",
+                                      p, resp_data_len, resp_data,
+                                      server->packet_size, server->packet);
+                               result = -EIO; /* always a comm. error? */
+                               goto unlock_return;
+                       }
+
                        p = smb_decode_long_dirent(server, p, entry,
                                                        info_level);
 
@@ -1688,6 +1716,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                loop_count = 0;
        }
 
+unlock_return:
        smb_unlock_server(server);
        return entries;
 }
index e1d594f0bf32539cd702c7b1c82f2160dab62637..b7a1068ce97feb18801e83860f773a63ffdf0081 100644 (file)
@@ -685,20 +685,6 @@ repeat:
                        return NULL;
                }
        }
-       *err = -EFBIG;
-
-       /* Check file limits.. */
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY) {
-                       limit >>= sb->sv_block_size_bits;
-                       if (new_block >= limit) {
-                               send_sig(SIGXFSZ, current, 0);
-                               *err = -EFBIG;
-                               return NULL;
-                       }
-               }
-       }
 
        tmp = sysv_new_block(sb);
        if (!tmp) {
@@ -742,7 +728,6 @@ static struct buffer_head *block_getblk(struct inode *inode,
        u32 tmp, block;
        sysv_zone_t *p;
        struct buffer_head * result;
-       unsigned long limit;
 
        result = NULL;
        if (!bh)
@@ -771,16 +756,6 @@ repeat:
                        goto out;
                }
        }
-       *err = -EFBIG;
-
-       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit < RLIM_INFINITY) {
-               limit >>= sb->sv_block_size_bits;
-               if (new_block >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       goto out;
-               }
-       }
 
        block = sysv_new_block(sb);
        if (!block)
index 360c12ba0f55d56793ede79e1032b4d5bace737c..bbc4e30a5074f52015d914a4339a161544affc7a 100644 (file)
@@ -508,23 +508,6 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
        }
        udf_release_data(cbh);
 
-       *err = -EFBIG;
-
-       /* Check file limits.. */
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY)
-               {
-                       limit >>= inode->i_sb->s_blocksize_bits;
-                       if (block >= limit)
-                       {
-                               send_sig(SIGXFSZ, current, 0);
-                               *err = -EFBIG;
-                               return NULL;
-                       }
-               }
-       }
-
        /* if the current extent is not recorded but allocated, get the
                block in the extent corresponding to the requested block */
        if ((laarr[c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
index fffaa7d3ef33ffa10749d7ff0c9a8711483abc2d..771069834c4369e617d877986ec2742d2b6af3fe 100644 (file)
@@ -186,7 +186,6 @@ static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
        struct buffer_head * result;
-       unsigned long limit;
        unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
        unsigned tmp, goal;
        u32 * p, * p2;
@@ -221,16 +220,6 @@ repeat:
                        return NULL;
                }
        }
-       *err = -EFBIG;
-
-       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit < RLIM_INFINITY) {
-               limit >>= sb->s_blocksize_bits;
-               if (new_fragment >= limit) {
-                       send_sig(SIGXFSZ, current, 0);
-                       return NULL;
-               }
-       }
 
        lastblock = ufs_fragstoblks (lastfrag);
        lastblockoff = ufs_fragnum (lastfrag);
@@ -348,19 +337,7 @@ repeat:
                        goto out;
                }
        }
-       *err = -EFBIG;
-
-       {
-               unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-               if (limit < RLIM_INFINITY) {
-                       limit >>= sb->s_blocksize_bits;
-                       if (new_fragment >= limit) {
-                               brelse (bh);
-                               send_sig(SIGXFSZ, current, 0);
-                               return NULL;
-                       }
-               }
-       }
+
        if (block && (tmp = SWAB32(((u32*)bh->b_data)[block-1]) + uspi->s_fpb))
                goal = tmp + uspi->s_fpb;
        else
index 47cd4856cae664a82a9143aeb2481295e1eac0cd..d98013db93d578e19bce86fbe97f451ddcebbc15 100644 (file)
@@ -27,7 +27,7 @@
 
 struct e820map {
     int nr_map;
-    struct {
+    struct e820entry {
        long long addr;         /* start of memory segment */
        long long size;         /* size of memory segment */
        long type;              /* type of memory segment */
index 7f084b00c4b8ce657d47a1cd7a7387d2056f460f..cdb73bdea28ce0d6637c3ec08822cea938885c15 100644 (file)
@@ -7,8 +7,6 @@
  * usually from within the early stages of kernel boot.
  */
 
-#include <config/sh/standard/bios.h>
-
 
 extern void sh_bios_console_write(const char *buf, unsigned int len);
 extern void sh_bios_char_out(char ch);
index 896dadef5067b8c0aa07b3bd2676c3eff1c0cb58..fa8f9cded5ef43213ac852c62a6898ac67fa3342 100644 (file)
@@ -280,10 +280,10 @@ struct fb_ops {
     /* set colormap */
     int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
                       struct fb_info *info);
-    /* pan display */
+    /* pan display (optional) */
     int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
                          struct fb_info *info);
-    /* perform fb specific ioctl */
+    /* perform fb specific ioctl (optional) */
     int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
                    unsigned long arg, int con, struct fb_info *info);
     /* perform fb specific mmap */
@@ -384,9 +384,6 @@ extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                          struct fb_info *info);
 extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
                             struct fb_info *info);
-extern int fbgen_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg, int con,
-                      struct fb_info *info);
 
     /*
      *  Helper functions
index 62066f8b03c62ba890b6b296525b9a0a7e0bdc90..4043c0353a178b0b772fd3ef399773009e691601 100644 (file)
@@ -29,6 +29,7 @@
 #define I2C_H
 
 #include <linux/i2c-id.h>      /* id values of adapters et. al.        */
+#include <linux/types.h>
 
 
 struct i2c_msg;
@@ -49,7 +50,6 @@ struct i2c_msg;
 #else
 #include <asm/semaphore.h>
 #endif
-#include <linux/types.h>
 #include <linux/config.h>
 
 /* --- General options ------------------------------------------------        */
@@ -371,7 +371,6 @@ extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func);
 
 #endif /* __KERNEL__ */
 
-#include <linux/types.h>
 /*
  * I2C Message - used for pure i2c transaction, also from /dev interface
  */
index 74c36eadf9081980d3e3453f4044cdb996059291..b9f3ee75edd5c8933d22135d1e7e16883a4e7be5 100644 (file)
@@ -462,8 +462,8 @@ static void __init parse_options(char *line)
                } else {
                        if (args >= MAX_INIT_ARGS)
                                break;
-                        if(*line)
-                       argv_init[++args] = line;
+                       if (*line)
+                               argv_init[++args] = line;
                }
        }
        argv_init[args+1] = NULL;
index 83f1586d4bfa184e38f3f64ac8124606f17e46da..7b54fc58570fe7712a7573227abc0586482ea4c5 100644 (file)
@@ -939,9 +939,10 @@ void vmtruncate(struct inode * inode, loff_t offset)
        unsigned long partial, pgoff;
        struct vm_area_struct * mpnt;
        struct address_space *mapping = inode->i_mapping;
+       unsigned long limit;
 
        if (inode->i_size < offset)
-               goto out;
+               goto do_expand;
        inode->i_size = offset;
        truncate_inode_pages(mapping, offset);
        spin_lock(&mapping->i_shared_lock);
@@ -986,11 +987,29 @@ void vmtruncate(struct inode * inode, loff_t offset)
        } while ((mpnt = mpnt->vm_next_share) != NULL);
 out_unlock:
        spin_unlock(&mapping->i_shared_lock);
-out:
        /* this should go into ->truncate */
        inode->i_size = offset;
        if (inode->i_op && inode->i_op->truncate)
                inode->i_op->truncate(inode);
+       return;
+
+do_expand:
+       limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+       if (limit != RLIM_INFINITY) {
+               if (inode->i_size >= limit) {
+                       send_sig(SIGXFSZ, current, 0);
+                       goto out;
+               }
+               if (offset > limit) {
+                       send_sig(SIGXFSZ, current, 0);
+                       offset = limit;
+               }
+       }
+       inode->i_size = offset;
+       if (inode->i_op && inode->i_op->truncate)
+               inode->i_op->truncate(inode);
+out:
+       return;
 }