summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk@flint.arm.linux.org.uk>2002-04-04 11:45:09 +0100
committerRussell King <rmk@flint.arm.linux.org.uk>2002-04-04 11:45:09 +0100
commit94394e5bc92026a2ff31cd03e11e015adfdb3260 (patch)
tree8f24a3e60e98d45ba7416821aadb84508e18d79d /drivers
parent3f4d4f4e46865cb01d2e2717c6906e2ae079c042 (diff)
parent5e4b50795ee8c7659a1181cea4c98712e02ea63e (diff)
Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5
into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-rmk
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/acpi_tables.c1
-rw-r--r--drivers/atm/eni.c1
-rw-r--r--drivers/block/DAC960.c4
-rw-r--r--drivers/block/blkpg.c4
-rw-r--r--drivers/block/cciss.c1
-rw-r--r--drivers/block/cciss_scsi.c1
-rw-r--r--drivers/block/genhd.c72
-rw-r--r--drivers/block/loop.c9
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/rd.c5
-rw-r--r--drivers/cdrom/cdrom.c1
-rw-r--r--drivers/char/acquirewdt.c22
-rw-r--r--drivers/char/advantechwdt.c40
-rw-r--r--drivers/char/agp/agpgart_be.c119
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/cyclades.c38
-rw-r--r--drivers/char/drm/i810_dma.c2
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/eurotechwdt.c47
-rw-r--r--drivers/char/i810-tco.c32
-rw-r--r--drivers/char/ib700wdt.c39
-rw-r--r--drivers/char/ip2/i2lib.c2
-rw-r--r--drivers/char/machzwd.c47
-rw-r--r--drivers/char/mixcomwd.c74
-rw-r--r--drivers/char/mxser.c105
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/rocket.c176
-rw-r--r--drivers/char/sbc60xxwdt.c14
-rw-r--r--drivers/char/shwdt.c22
-rw-r--r--drivers/char/softdog.c33
-rw-r--r--drivers/char/sonypi.c140
-rw-r--r--drivers/char/sonypi.h27
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/tpqic02.c10
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/vme_scc.c14
-rw-r--r--drivers/char/wdt.c39
-rw-r--r--drivers/char/wdt977.c341
-rw-r--r--drivers/char/wdt_pci.c43
-rw-r--r--drivers/fc4/soc.c1
-rw-r--r--drivers/fc4/socal.c1
-rw-r--r--drivers/i2c/i2c-algo-bit.c4
-rw-r--r--drivers/i2c/i2c-dev.c8
-rw-r--r--drivers/i2c/i2c-proc.c4
-rw-r--r--drivers/ide/aec62xx.c38
-rw-r--r--drivers/ide/ali14xx.c4
-rw-r--r--drivers/ide/alim15x3.c32
-rw-r--r--drivers/ide/amd74xx.c22
-rw-r--r--drivers/ide/buddha.c4
-rw-r--r--drivers/ide/cmd640.c6
-rw-r--r--drivers/ide/cmd64x.c72
-rw-r--r--drivers/ide/cs5530.c8
-rw-r--r--drivers/ide/cy82c693.c14
-rw-r--r--drivers/ide/dtc2278.c4
-rw-r--r--drivers/ide/gayle.c4
-rw-r--r--drivers/ide/hpt34x.c27
-rw-r--r--drivers/ide/hpt366.c86
-rw-r--r--drivers/ide/ht6560b.c2
-rw-r--r--drivers/ide/icside.c40
-rw-r--r--drivers/ide/ide-cd.c54
-rw-r--r--drivers/ide/ide-disk.c376
-rw-r--r--drivers/ide/ide-dma.c38
-rw-r--r--drivers/ide/ide-features.c39
-rw-r--r--drivers/ide/ide-floppy.c40
-rw-r--r--drivers/ide/ide-geometry.c1
-rw-r--r--drivers/ide/ide-pci.c110
-rw-r--r--drivers/ide/ide-pmac.c46
-rw-r--r--drivers/ide/ide-pnp.c4
-rw-r--r--drivers/ide/ide-probe.c79
-rw-r--r--drivers/ide/ide-proc.c18
-rw-r--r--drivers/ide/ide-tape.c45
-rw-r--r--drivers/ide/ide-taskfile.c436
-rw-r--r--drivers/ide/ide.c633
-rw-r--r--drivers/ide/it8172.c14
-rw-r--r--drivers/ide/macide.c2
-rw-r--r--drivers/ide/ns87415.c20
-rw-r--r--drivers/ide/opti621.c6
-rw-r--r--drivers/ide/pdc202xx.c60
-rw-r--r--drivers/ide/pdc4030.c54
-rw-r--r--drivers/ide/pdcadma.c6
-rw-r--r--drivers/ide/piix.c22
-rw-r--r--drivers/ide/qd65xx.c22
-rw-r--r--drivers/ide/rz1000.c6
-rw-r--r--drivers/ide/serverworks.c26
-rw-r--r--drivers/ide/sis5513.c24
-rw-r--r--drivers/ide/sl82c105.c16
-rw-r--r--drivers/ide/trm290.c21
-rw-r--r--drivers/ide/umc8672.c4
-rw-r--r--drivers/ide/via82cxxx.c22
-rw-r--r--drivers/ieee1394/dv1394.c1
-rw-r--r--drivers/ieee1394/pcilynx.c3
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/isdn/avmb1/capifs.c7
-rw-r--r--drivers/isdn/avmb1/kcapi.c4
-rw-r--r--drivers/isdn/eicon/eicon_mod.c5
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1
-rw-r--r--drivers/isdn/hisax/hisax_isac.c1
-rw-r--r--drivers/md/lvm-snap.c37
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c2
-rw-r--r--drivers/media/video/videodev.c16
-rw-r--r--drivers/mtd/chips/sharp.c2
-rw-r--r--drivers/mtd/devices/blkmtd.c4
-rw-r--r--drivers/mtd/ftl.c16
-rw-r--r--drivers/mtd/mtdblock.c2
-rw-r--r--drivers/mtd/mtdblock_ro.c2
-rw-r--r--drivers/mtd/nand/nand_ecc.c2
-rw-r--r--drivers/mtd/nftlcore.c2
-rw-r--r--drivers/net/3c503.c10
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/8390.h4
-rw-r--r--drivers/net/Config.in3
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/Space.c320
-rw-r--r--drivers/net/ac3200.c10
-rw-r--r--drivers/net/acenic.c49
-rw-r--r--drivers/net/acenic.h9
-rw-r--r--drivers/net/aironet4500.h14
-rw-r--r--drivers/net/arcnet/arc-rimi.c2
-rw-r--r--drivers/net/arcnet/com90xx.c2
-rw-r--r--drivers/net/arlan.c14
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/daynaport.c26
-rw-r--r--drivers/net/de620.c15
-rw-r--r--drivers/net/dl2k.c135
-rw-r--r--drivers/net/dl2k.h5
-rw-r--r--drivers/net/e100/Makefile2
-rw-r--r--drivers/net/e100/e100.h31
-rw-r--r--drivers/net/e100/e100_config.c99
-rw-r--r--drivers/net/e100/e100_config.h7
-rw-r--r--drivers/net/e100/e100_main.c113
-rw-r--r--drivers/net/e100/e100_test.c467
-rw-r--r--drivers/net/e1000/LICENSE13
-rw-r--r--drivers/net/e1000/Makefile3
-rw-r--r--drivers/net/e1000/e1000.h55
-rw-r--r--drivers/net/e1000/e1000_ethtool.c85
-rw-r--r--drivers/net/e1000/e1000_hw.c3228
-rw-r--r--drivers/net/e1000/e1000_hw.h (renamed from drivers/net/e1000/e1000_mac.h)532
-rw-r--r--drivers/net/e1000/e1000_mac.c1821
-rw-r--r--drivers/net/e1000/e1000_main.c943
-rw-r--r--drivers/net/e1000/e1000_osdep.h13
-rw-r--r--drivers/net/e1000/e1000_param.c154
-rw-r--r--drivers/net/e1000/e1000_phy.c1485
-rw-r--r--drivers/net/e1000/e1000_phy.h422
-rw-r--r--drivers/net/e1000/e1000_proc.c118
-rw-r--r--drivers/net/e2100.c8
-rw-r--r--drivers/net/eepro100.c1
-rw-r--r--drivers/net/epic100.c12
-rw-r--r--drivers/net/es3210.c10
-rw-r--r--drivers/net/hamradio/6pack.c3
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c8
-rw-r--r--drivers/net/hamradio/dmascc.c1
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c2
-rw-r--r--drivers/net/hamradio/soundmodem/sm.h26
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk1200.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2400_7.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2400_8.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2666.c4
-rw-r--r--drivers/net/hamradio/soundmodem/sm_sbc.c4
-rw-r--r--drivers/net/hamradio/soundmodem/sm_wss.c4
-rw-r--r--drivers/net/hamradio/soundmodem/smdma.h18
-rw-r--r--drivers/net/hamradio/yam.c3
-rw-r--r--drivers/net/hp-plus.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c1
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lne390.c10
-rw-r--r--drivers/net/ne3210.c10
-rw-r--r--drivers/net/ns83820.c18
-rw-r--r--drivers/net/pcnet32.c10
-rw-r--r--drivers/net/sb1000.c40
-rw-r--r--drivers/net/sb1250-mac.c2673
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/smc-mca.c10
-rw-r--r--drivers/net/smc-ultra.c10
-rw-r--r--drivers/net/smc-ultra32.c6
-rw-r--r--drivers/net/strip.c1
-rw-r--r--drivers/net/sun3_82586.c1206
-rw-r--r--drivers/net/sun3_82586.h318
-rw-r--r--drivers/net/sungem.c468
-rw-r--r--drivers/net/sungem.h5
-rw-r--r--drivers/net/sunhme.c449
-rw-r--r--drivers/net/sunhme.h2
-rw-r--r--drivers/net/tc35815.c1779
-rw-r--r--drivers/net/tg3.c105
-rw-r--r--drivers/net/tg3.h2
-rw-r--r--drivers/net/tokenring/smctr.c4
-rw-r--r--drivers/net/wan/comx-hw-locomx.c4
-rw-r--r--drivers/net/wan/comx-hw-mixcom.c2
-rw-r--r--drivers/net/wan/comx-hw-munich.c32
-rw-r--r--drivers/net/wan/cosa.c7
-rw-r--r--drivers/net/wan/dscc4.c3
-rw-r--r--drivers/net/wan/hd6457x.c1
-rw-r--r--drivers/net/wan/sdla_ppp.c4
-rw-r--r--drivers/net/wd.c14
-rw-r--r--drivers/net/wireless/orinoco_plx.c25
-rw-r--r--drivers/parport/parport_mfc3.c1
-rw-r--r--drivers/pci/pci.c2
-rw-r--r--drivers/pci/pci.ids21
-rw-r--r--drivers/pcmcia/Config.in4
-rw-r--r--drivers/pcmcia/i82092.c4
-rw-r--r--drivers/pnp/pnpbios_core.c223
-rw-r--r--drivers/pnp/pnpbios_proc.c165
-rw-r--r--drivers/s390/block/dasd.c2
-rw-r--r--drivers/s390/block/dasd_int.h8
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/tapeblock.c2
-rw-r--r--drivers/sbus/audio/amd7930.c3
-rw-r--r--drivers/sbus/audio/cs4231.c6
-rw-r--r--drivers/sbus/char/aurora.c2
-rw-r--r--drivers/sbus/char/uctrl.c10
-rw-r--r--drivers/sbus/sbus.c6
-rw-r--r--drivers/scsi/3w-xxxx.c282
-rw-r--r--drivers/scsi/3w-xxxx.h29
-rw-r--r--drivers/scsi/53c7,8xx.c4
-rw-r--r--drivers/scsi/53c7xx.c4
-rw-r--r--drivers/scsi/NCR53C9x.c2
-rw-r--r--drivers/scsi/a2091.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux.c9
-rw-r--r--drivers/scsi/aic7xxx_old.c4
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/ide-scsi.c17
-rw-r--r--drivers/scsi/ppa.c2
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/tmscsim.c151
-rw-r--r--drivers/scsi/u14-34f.c4
-rw-r--r--drivers/tc/zs.c2
-rw-r--r--drivers/usb/Config.help69
-rw-r--r--drivers/usb/Config.in21
-rw-r--r--drivers/usb/Makefile22
-rw-r--r--drivers/usb/audio.c2
-rw-r--r--drivers/usb/catc.c4
-rw-r--r--drivers/usb/devices.c135
-rw-r--r--drivers/usb/hcd.c245
-rw-r--r--drivers/usb/hcd/ehci-hcd.c31
-rw-r--r--drivers/usb/hcd/ehci-hub.c7
-rw-r--r--drivers/usb/hcd/ehci-mem.c3
-rw-r--r--drivers/usb/hcd/ehci-q.c9
-rw-r--r--drivers/usb/hcd/ohci-dbg.c4
-rw-r--r--drivers/usb/hcd/ohci-hcd.c28
-rw-r--r--drivers/usb/hcd/ohci-hub.c2
-rw-r--r--drivers/usb/hcd/ohci-mem.c12
-rw-r--r--drivers/usb/hcd/ohci-q.c452
-rw-r--r--drivers/usb/hcd/ohci.h2
-rw-r--r--drivers/usb/hid-core.c11
-rw-r--r--drivers/usb/hid.h14
-rw-r--r--drivers/usb/hiddev.c38
-rw-r--r--drivers/usb/hpusbscsi.c117
-rw-r--r--drivers/usb/hpusbscsi.h12
-rw-r--r--drivers/usb/hub.c4
-rw-r--r--drivers/usb/inode.c6
-rw-r--r--drivers/usb/kaweth.c1
-rw-r--r--drivers/usb/konicawc.c195
-rw-r--r--drivers/usb/pegasus.c52
-rw-r--r--drivers/usb/pegasus.h2
-rw-r--r--drivers/usb/printer.c7
-rw-r--r--drivers/usb/rtl8150.c763
-rw-r--r--drivers/usb/serial/Config.help20
-rw-r--r--drivers/usb/serial/Config.in21
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/belkin_sa.c79
-rw-r--r--drivers/usb/serial/cyberjack.c59
-rw-r--r--drivers/usb/serial/digi_acceleport.c32
-rw-r--r--drivers/usb/serial/empeg.c64
-rw-r--r--drivers/usb/serial/ftdi_sio.c130
-rw-r--r--drivers/usb/serial/io_edgeport.c338
-rw-r--r--drivers/usb/serial/ipaq.c221
-rw-r--r--drivers/usb/serial/ir-usb.c83
-rw-r--r--drivers/usb/serial/keyspan.c30
-rw-r--r--drivers/usb/serial/keyspan_pda.c99
-rw-r--r--drivers/usb/serial/kl5kusb105.c184
-rw-r--r--drivers/usb/serial/mct_u232.c109
-rw-r--r--drivers/usb/serial/omninet.c64
-rw-r--r--drivers/usb/serial/pl2303.c145
-rw-r--r--drivers/usb/serial/safe_serial.c449
-rw-r--r--drivers/usb/serial/usb-serial.h10
-rw-r--r--drivers/usb/serial/usbserial.c450
-rw-r--r--drivers/usb/serial/visor.c108
-rw-r--r--drivers/usb/serial/visor.h2
-rw-r--r--drivers/usb/serial/whiteheat.c108
-rw-r--r--drivers/usb/storage/transport.h2
-rw-r--r--drivers/usb/tiglusb.c495
-rw-r--r--drivers/usb/tiglusb.h55
-rw-r--r--drivers/usb/uhci.c43
-rw-r--r--drivers/usb/usb-ohci.c108
-rw-r--r--drivers/usb/usb-ohci.h22
-rw-r--r--drivers/usb/usb-uhci.c4
-rw-r--r--drivers/usb/usb.c13
-rw-r--r--drivers/usb/usbnet.c5
-rw-r--r--drivers/usb/usbvideo.c13
-rw-r--r--drivers/usb/usbvideo.h2
-rw-r--r--drivers/video/amifb.c32
-rw-r--r--drivers/video/atafb.c66
-rw-r--r--drivers/video/aty/atyfb_base.c26
298 files changed, 19358 insertions, 9442 deletions
diff --git a/drivers/acpi/acpi_tables.c b/drivers/acpi/acpi_tables.c
index 490e488bc56b..403fa5c22601 100644
--- a/drivers/acpi/acpi_tables.c
+++ b/drivers/acpi/acpi_tables.c
@@ -32,6 +32,7 @@
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/acpi.h>
+#include <linux/err.h>
#define PREFIX "ACPI: "
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 638e8d0ef7ac..9f14ddc985a6 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -14,7 +14,6 @@
#include <linux/sonet.h>
#include <linux/skbuff.h>
#include <linux/time.h>
-#include <linux/sched.h> /* for xtime */
#include <linux/delay.h>
#include <linux/uio.h>
#include <linux/init.h>
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index d205bf2c4a8d..13fb4c7c4a16 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -5295,7 +5295,7 @@ static int DAC960_Open(Inode_T *Inode, File_T *File)
DAC960_ComputeGenericDiskInfo(Controller);
DAC960_RegisterDisk(Controller, LogicalDriveNumber);
}
- if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+ if (Controller->GenericDiskInfo.sizes[minor(Inode->i_rdev)] == 0)
return -ENXIO;
/*
Increment Controller and Logical Drive Usage Counts.
@@ -6902,3 +6902,5 @@ static void DAC960_DestroyProcEntries(void)
module_init(DAC960_Initialize);
module_exit(DAC960_Finalize);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c
index 264d9824535c..4992aa3cbcf9 100644
--- a/drivers/block/blkpg.c
+++ b/drivers/block/blkpg.c
@@ -247,8 +247,8 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
case BLKFLSBUF:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- fsync_dev(dev);
- invalidate_buffers(dev);
+ fsync_bdev(bdev);
+ invalidate_bdev(bdev, 0);
return 0;
case BLKSSZGET:
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index d87635dd23ea..9e747ec0d6cf 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -42,6 +42,7 @@
#include <linux/blk.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
+#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
#define DRIVER_NAME "Compaq CISS Driver (v 2.5.0)"
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 5adb5494a6d5..ceedd2d59575 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -32,6 +32,7 @@
#include "../scsi/hosts.h"
#include <asm/atomic.h>
#include <linux/timer.h>
+#include <linux/completion.h>
#include "cciss_scsi.h"
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index bf0cec7f6f39..e02323f8fd00 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -22,6 +22,7 @@
#include <linux/blk.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/seq_file.h>
static rwlock_t gendisk_lock;
@@ -142,39 +143,58 @@ get_nr_sects(kdev_t dev)
}
#ifdef CONFIG_PROC_FS
-int
-get_partition_list(char *page, char **start, off_t offset, int count)
+/* iterator */
+static void *part_start(struct seq_file *part, loff_t *pos)
{
- struct gendisk *gp;
- char buf[64];
- int len, n;
+ loff_t k = *pos;
+ struct gendisk *sgp;
- len = sprintf(page, "major minor #blocks name\n\n");
read_lock(&gendisk_lock);
- for (gp = gendisk_head; gp; gp = gp->next) {
- for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
- if (gp->part[n].nr_sects == 0)
- continue;
-
- len += snprintf(page + len, 63,
- "%4d %4d %10d %s\n",
- gp->major, n, gp->sizes[n],
- disk_name(gp, n, buf));
- if (len < offset)
- offset -= len, len = 0;
- else if (len >= offset + count)
- goto out;
- }
+ for (sgp = gendisk_head; sgp; sgp = sgp->next) {
+ if (!k--)
+ return sgp;
}
+ return NULL;
+}
-out:
+static void *part_next(struct seq_file *part, void *v, loff_t *pos)
+{
+ ++*pos;
+ return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *part, void *v)
+{
read_unlock(&gendisk_lock);
- *start = page + offset;
- len -= offset;
- if (len < 0)
- len = 0;
- return len > count ? count : len;
}
+
+static int show_partition(struct seq_file *part, void *v)
+{
+ struct gendisk *sgp = v;
+ int n;
+ char buf[64];
+
+ if (sgp == gendisk_head)
+ seq_puts(part, "major minor #blocks name\n\n");
+
+ /* show all non-0 size partitions of this disk */
+ for (n = 0; n < (sgp->nr_real << sgp->minor_shift); n++) {
+ if (sgp->part[n].nr_sects == 0)
+ continue;
+ seq_printf(part, "%4d %4d %10d %s\n",
+ sgp->major, n, sgp->sizes[n],
+ disk_name(sgp, n, buf));
+ }
+
+ return 0;
+}
+
+struct seq_operations partitions_op = {
+ start: part_start,
+ next: part_next,
+ stop: part_stop,
+ show: show_partition
+};
#endif
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index cfce7b234c57..cabf25eff926 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -36,6 +36,9 @@
* Al Viro too.
* Jens Axboe <axboe@suse.de>, Nov 2000
*
+ * Support up to 256 loop devices
+ * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
+ *
* Still To Fix:
* - Advisory locking is ignored here.
* - Should use an own CAP_* category instead of CAP_SYS_ADMIN
@@ -927,7 +930,7 @@ static struct block_device_operations lo_fops = {
* And now the modules code and kernel interface.
*/
MODULE_PARM(max_loop, "i");
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
MODULE_LICENSE("GPL");
int loop_register_transfer(struct loop_func_table *funcs)
@@ -963,9 +966,9 @@ int __init loop_init(void)
{
int i;
- if ((max_loop < 1) || (max_loop > 255)) {
+ if ((max_loop < 1) || (max_loop > 256)) {
printk(KERN_WARNING "loop: invalid max_loop (must be between"
- " 1 and 255), using default (8)\n");
+ " 1 and 256), using default (8)\n");
max_loop = 8;
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b13f0a88baaf..ff6805fc8a02 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -327,7 +327,7 @@ static void do_nbd_request(request_queue_t * q)
req = CURRENT;
#ifdef PARANOIA
if (!req)
- FAIL("que not empty but no request?");
+ FAIL("queue not empty but no request?");
#endif
dev = minor(req->rq_dev);
#ifdef PARANOIA
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index f9cf01e79412..543ead853271 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -405,9 +405,10 @@ static void __exit rd_cleanup (void)
for (i = 0 ; i < NUM_RAMDISKS; i++) {
struct block_device *bdev = rd_bdev[i];
rd_bdev[i] = NULL;
- if (bdev)
+ if (bdev) {
+ invalidate_bdev(bdev, 1);
blkdev_put(bdev, BDEV_FILE);
- destroy_buffers(mk_kdev(MAJOR_NR, i));
+ }
}
devfs_unregister (devfs_handle);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 14107f29c363..fc2fa884e1ed 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1107,6 +1107,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
/* Misc */
case DVD_INVALIDATE_AGID:
+ cgc.quiet = 1;
cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n");
setup_report_key(&cgc, ai->lsa.agid, 0x3f);
if ((ret = cdo->generic_packet(cdi, &cgc)))
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 37a3420c9285..a7ea69594e03 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -17,6 +17,9 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Can't add timeout - driver doesn't allow changing value
*/
#include <linux/config.h>
@@ -50,8 +53,14 @@ static spinlock_t acq_lock;
#define WDT_STOP 0x43
#define WDT_START 0x443
-#define WD_TIMO (100*60) /* 1 minute */
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/*
* Kernel methods.
@@ -126,10 +135,13 @@ static int acq_open(struct inode *inode, struct file *file)
spin_unlock(&acq_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
-
+
acq_is_open=1;
inb_p(WDT_START);
spin_unlock(&acq_lock);
@@ -144,9 +156,9 @@ static int acq_close(struct inode *inode, struct file *file)
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
spin_lock(&acq_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_STOP);
-#endif
+ if (!nowayout) {
+ inb_p(WDT_STOP);
+ }
acq_is_open=0;
spin_unlock(&acq_lock);
}
diff --git a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
index b40df81ce0ba..3e6940fb12d8 100644
--- a/drivers/char/advantechwdt.c
+++ b/drivers/char/advantechwdt.c
@@ -20,6 +20,9 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
*/
#include <linux/config.h>
@@ -56,8 +59,7 @@ static spinlock_t advwdt_lock;
* the manual says WDT_STOP is 0x43, not 0x443).
* (0x43 is also a write-only control register for the 8254 timer!)
*
- * TODO: module parameters to set the I/O port addresses and NOWAYOUT
- * option at load time.
+ * TODO: module parameters to set the I/O port addresses
*/
#define WDT_STOP 0x443
@@ -65,6 +67,19 @@ static spinlock_t advwdt_lock;
#define WD_TIMO 60 /* 1 minute */
+static int timeout = WD_TIMO; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Kernel methods.
*/
@@ -73,7 +88,7 @@ static void
advwdt_ping(void)
{
/* Write a watchdog value */
- outb_p(WD_TIMO, WDT_START);
+ outb_p(timeout, WDT_START);
}
static ssize_t
@@ -135,6 +150,9 @@ advwdt_open(struct inode *inode, struct file *file)
spin_unlock(&advwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -153,9 +171,9 @@ advwdt_close(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&advwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_STOP);
-#endif
+ if (!nowayout) {
+ inb_p(WDT_STOP);
+ }
advwdt_is_open = 0;
spin_unlock(&advwdt_lock);
}
@@ -207,11 +225,21 @@ static struct notifier_block advwdt_notifier = {
0
};
+static void __init
+advwdt_validate_timeout(void)
+{
+ if (timeout < 1 || timeout > 63) {
+ timeout = WD_TIMO;
+ printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout);
+ }
+}
+
static int __init
advwdt_init(void)
{
printk("WDT driver for Advantech single board computer initialising.\n");
+ advwdt_validate_timeout();
spin_lock_init(&advwdt_lock);
misc_register(&advwdt_miscdev);
#if WDT_START != WDT_STOP
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index fdd404f50e0f..de7f2eda96ac 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -397,7 +397,7 @@ int agp_unbind_memory(agp_memory * curr)
static void agp_generic_agp_enable(u32 mode)
{
struct pci_dev *device = NULL;
- u32 command, scratch, cap_id;
+ u32 command, scratch;
u8 cap_ptr;
pci_read_config_dword(agp_bridge.dev,
@@ -410,34 +410,8 @@ static void agp_generic_agp_enable(u32 mode)
*/
- pci_for_each_dev(device)
- {
- /*
- * Enable AGP devices. Most will be VGA display but
- * some may be coprocessors on non VGA devices too
- */
-
- if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
- (device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
- continue;
-
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00) {
/*
* Ok, here we have a AGP device. Disable impossible
@@ -506,25 +480,8 @@ static void agp_generic_agp_enable(u32 mode)
* command registers.
*/
- while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
- device)) != NULL) {
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00)
pci_write_config_dword(device, cap_ptr + 8, command);
}
@@ -809,9 +766,9 @@ static unsigned long agp_generic_alloc_page(void)
struct page * page;
page = alloc_page(GFP_KERNEL);
- if (page == NULL) {
+ if (page == NULL)
return 0;
- }
+
get_page(page);
LockPage(page);
atomic_inc(&agp_bridge.current_memory_agp);
@@ -823,10 +780,9 @@ static void agp_generic_destroy_page(unsigned long addr)
void *pt = (void *) addr;
struct page *page;
- if (pt == NULL) {
+ if (pt == NULL)
return;
- }
-
+
page = virt_to_page(pt);
put_page(page);
UnlockPage(page);
@@ -3318,24 +3274,8 @@ static void serverworks_agp_enable(u32 mode)
*/
- pci_for_each_dev(device)
- {
- /*
- * Enable AGP devices. Most will be VGA display but
- * some may be coprocessors on non VGA devices too
- */
-
- if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
- (device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
- continue;
-
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00) {
do {
pci_read_config_dword(device,
@@ -3413,25 +3353,8 @@ static void serverworks_agp_enable(u32 mode)
* command registers.
*/
- while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
- device)) != NULL) {
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00)
pci_write_config_dword(device, cap_ptr + 8, command);
}
@@ -3881,7 +3804,6 @@ static int __init agp_find_supported_device(void)
{
struct pci_dev *dev = NULL;
u8 cap_ptr = 0x00;
- u32 cap_id, scratch;
if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
return -ENODEV;
@@ -4022,20 +3944,7 @@ static int __init agp_find_supported_device(void)
#endif /* CONFIG_AGP_SWORKS */
/* find capndx */
- pci_read_config_dword(dev, 0x04, &scratch);
- if (!(scratch & 0x00100000))
- return -ENODEV;
-
- pci_read_config_byte(dev, 0x34, &cap_ptr);
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(dev, cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
if (cap_ptr == 0x00)
return -ENODEV;
agp_bridge.capndx = cap_ptr;
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index fe21688ca37f..9db606a2a9c9 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -36,7 +36,7 @@
#if LINUX_VERSION_CODE < 0x20300
/* These probably want adding to <linux/compatmac.h> */
-#define init_waitqueue_head(x) do { *(x) = NULL; } while (0);
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0)
#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x
#define __setup(x,y) /* */
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 47f973633f60..0d7a56ad5ff6 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -4965,6 +4965,8 @@ cy_detect_pci(void)
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
unsigned char Ze_irq[NR_CARDS];
+ struct resource *resource;
+ unsigned long res_start, res_len;
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
@@ -5012,7 +5014,15 @@ cy_detect_pci(void)
/* Although we don't use this I/O region, we should
request it from the kernel anyway, to avoid problems
with other drivers accessing it. */
- request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
+ resource = request_region(cy_pci_phys1,
+ CyPCI_Yctl, "Cyclom-Y");
+ if (resource == NULL) {
+ printk(KERN_ERR "cyclades: failed to allocate IO "
+ "resource at 0x%lx\n", cy_pci_phys1);
+ continue;
+ }
+ res_start = cy_pci_phys1;
+ res_len = CyPCI_Yctl;
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5083,7 +5093,11 @@ cy_detect_pci(void)
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_pci_nchan/4;
-
+ cy_card[j].resource = resource;
+ cy_card[j].res_start = res_start;
+ cy_card[j].res_len = res_len;
+ resource = NULL; /* For next card */
+
/* enable interrupts in the PCI interface */
plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
switch (plx_ver) {
@@ -5162,8 +5176,16 @@ cy_detect_pci(void)
/* Although we don't use this I/O region, we should
request it from the kernel anyway, to avoid problems
with other drivers accessing it. */
- request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
-
+ resource = request_region(cy_pci_phys1,
+ CyPCI_Zctl, "Cyclades-Z");
+ if (resource == NULL) {
+ printk(KERN_ERR "cyclades: failed ot allocate IO resource "
+ "at 0x%lx\n", cy_pci_phys1);
+ continue;
+ }
+ res_start = cy_pci_phys1;
+ res_len = CyPCI_Zctl;
+
if (mailbox == ZE_V1) {
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
if (ZeIndex == NR_CARDS) {
@@ -5261,6 +5283,10 @@ cy_detect_pci(void)
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = -1;
+ cy_card[j].resource = resource;
+ cy_card[j].res_start = res_start;
+ cy_card[j].res_len = res_len;
+ resource = NULL; /* For next card */
/* print message */
#ifdef CONFIG_CYZ_INTR
@@ -5279,7 +5305,7 @@ cy_detect_pci(void)
printk("%d channels starting from port %d.\n",
cy_pci_nchan,cy_next_channel);
cy_next_channel += cy_pci_nchan;
- }
+ }
}
for (; ZeIndex != 0 && i < NR_CARDS; i++) {
@@ -5787,6 +5813,8 @@ cy_cleanup_module(void)
#endif /* CONFIG_CYZ_INTR */
)
free_irq(cy_card[i].irq, &cy_card[i]);
+ if (cy_card[i].resource)
+ release_region(cy_card[i].res_start, cy_card[i].res_len);
}
}
if (tmp_buf) {
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 8629e0e5fa09..86a97333cb7f 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -73,7 +73,7 @@
*(volatile unsigned int *)(virt + outring) = n; \
outring += 4; \
outring &= ringmask; \
-} while (0);
+} while (0)
static inline void i810_print_status_page(drm_device_t *dev)
{
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 97f842cb21ab..c6a9c355eb4c 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -2161,7 +2161,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
diff --git a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c
index 2907315b6155..698a2e3eca2f 100644
--- a/drivers/char/eurotechwdt.c
+++ b/drivers/char/eurotechwdt.c
@@ -20,6 +20,10 @@
* "AS-IS" and at no charge.
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>*
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
*/
#include <linux/config.h>
@@ -45,7 +49,6 @@
#include <linux/smp_lock.h>
static int eurwdt_is_open;
-static int eurwdt_timeout;
static spinlock_t eurwdt_lock;
/*
@@ -58,6 +61,18 @@ static int irq = 10;
static char *ev = "int";
#define WDT_TIMEOUT 60 /* 1 minute */
+static int timeout = WDT_TIMEOUT;
+
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/*
@@ -116,6 +131,15 @@ MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')");
* Programming support
*/
+static void __init eurwdt_validate_timeout(void)
+{
+ if (timeout < 0 || timeout > 255) {
+ timeout = WDT_TIMEOUT;
+ printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n",
+ timeout);
+ }
+}
+
static inline void eurwdt_write_reg(u8 index, u8 data)
{
outb(index, io);
@@ -189,7 +213,7 @@ void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void eurwdt_ping(void)
{
/* Write the watchdog default value */
- eurwdt_set_timeout(eurwdt_timeout);
+ eurwdt_set_timeout(timeout);
}
/**
@@ -263,7 +287,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
if (time < 0 || time > 255)
return -EINVAL;
- eurwdt_timeout = time;
+ timeout = time;
eurwdt_set_timeout(time);
return 0;
}
@@ -287,9 +311,11 @@ static int eurwdt_open(struct inode *inode, struct file *file)
spin_unlock(&eurwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
eurwdt_is_open = 1;
- eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */
/* Activate the WDT */
eurwdt_activate_timer();
@@ -323,12 +349,12 @@ static int eurwdt_open(struct inode *inode, struct file *file)
static int eurwdt_release(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- eurwdt_disable_timer();
-#endif
- eurwdt_is_open = 0;
+ if (!nowayout) {
+ eurwdt_disable_timer();
+ }
+ eurwdt_is_open = 0;
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
}
return 0;
@@ -422,7 +448,8 @@ static void __exit eurwdt_exit(void)
static int __init eurwdt_init(void)
{
int ret;
-
+
+ eurwdt_validate_timeout();
ret = misc_register(&eurwdt_miscdev);
if (ret) {
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
diff --git a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
index 90c8e4878f5b..5b20720551c2 100644
--- a/drivers/char/i810-tco.c
+++ b/drivers/char/i810-tco.c
@@ -1,5 +1,5 @@
/*
- * i810-tco 0.02: TCO timer driver for i810 chipsets
+ * i810-tco 0.03: TCO timer driver for i810 chipsets
*
* (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
* http://www.kernelconcepts.de
@@ -28,6 +28,9 @@
* Initial Version 0.01
* 20000728 Nils Faerber
* 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ * 20011214 Matt Domsch <Matt_Domsch@dell.com>
+ * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Didn't add timeout option as i810_margin already exists.
*/
#include <linux/module.h>
@@ -60,6 +63,18 @@ static spinlock_t tco_lock; /* Guards the hardware */
static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
MODULE_PARM (i810_margin, "i");
+MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 2<n<64. Default = 50 (30 seconds)");
+
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Timer active flag
@@ -167,6 +182,9 @@ static int i810tco_open (struct inode *inode, struct file *file)
if (timer_alive)
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Reload and activate timer
*/
@@ -181,10 +199,10 @@ static int i810tco_release (struct inode *inode, struct file *file)
/*
* Shut off the timer.
*/
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- tco_timer_stop ();
- timer_alive = 0;
-#endif
+ if (nowayout) {
+ tco_timer_stop ();
+ timer_alive = 0;
+ }
return 0;
}
@@ -342,8 +360,8 @@ static int __init watchdog_init (void)
tco_timer_reload ();
printk (KERN_INFO
- "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
- (int) (i810_margin * 6 / 10), TCOBASE);
+ "i810 TCO timer: V0.03, timer margin: %d sec (0x%04x), nowayout: %d\n",
+ (int) (i810_margin * 6 / 10), TCOBASE, nowayout);
return 0;
}
diff --git a/drivers/char/ib700wdt.c b/drivers/char/ib700wdt.c
index 91fb96ca5eb8..8f7c1671d4a7 100644
--- a/drivers/char/ib700wdt.c
+++ b/drivers/char/ib700wdt.c
@@ -25,6 +25,10 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ *
*/
#include <linux/config.h>
@@ -92,15 +96,36 @@ static spinlock_t ibwdt_lock;
#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */
+static int timeout_val = WD_TIMO; /* value in table */
+static int timeout = 30; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Kernel methods.
*/
+static void __init
+ibwdt_validate_timeout(void)
+{
+ timeout_val = (30 - timeout) / 2;
+ if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO;
+}
+
static void
ibwdt_ping(void)
{
/* Write a watchdog value */
- outb_p(WD_TIMO, WDT_START);
+ outb_p(timeout_val, WDT_START);
}
static ssize_t
@@ -162,6 +187,9 @@ ibwdt_open(struct inode *inode, struct file *file)
spin_unlock(&ibwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -181,9 +209,9 @@ ibwdt_close(struct inode *inode, struct file *file)
lock_kernel();
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&ibwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- outb_p(WD_TIMO, WDT_STOP);
-#endif
+ if (!nowayout) {
+ outb_p(timeout_val, WDT_STOP);
+ }
ibwdt_is_open = 0;
spin_unlock(&ibwdt_lock);
}
@@ -201,7 +229,7 @@ ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the WDT off */
- outb_p(WD_TIMO, WDT_STOP);
+ outb_p(timeout_val, WDT_STOP);
}
return NOTIFY_DONE;
}
@@ -241,6 +269,7 @@ ibwdt_init(void)
{
printk("WDT driver for IB700 single board computer initialising.\n");
+ ibwdt_validate_timeout();
spin_lock_init(&ibwdt_lock);
misc_register(&ibwdt_miscdev);
#if WDT_START != WDT_STOP
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 9572ee2076a9..4955f59d2eda 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -1330,7 +1330,7 @@ i2DrainOutput(i2ChanStrPtr pCh, int timeout)
// if expires == 0 then timer poped, then do not need to del_timer
if ((timeout > 0) && pCh->BookmarkTimer.expires &&
- (pCh->BookmarkTimer.expires > jiffies)) {
+ time_before(jiffies, pCh->BookmarkTimer.expires)) {
del_timer( &(pCh->BookmarkTimer) );
pCh->BookmarkTimer.expires = 0;
diff --git a/drivers/char/machzwd.c b/drivers/char/machzwd.c
index 8765b677a6dc..85ba8321a564 100644
--- a/drivers/char/machzwd.c
+++ b/drivers/char/machzwd.c
@@ -24,6 +24,8 @@
* a system RESET and it starts wd#2 that unconditionaly will RESET
* the system when the counter reaches zero.
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
#include <linux/config.h>
@@ -103,6 +105,15 @@ MODULE_LICENSE("GPL");
MODULE_PARM(action, "i");
MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
#define PFX "machzwd"
static struct watchdog_info zf_info = {
@@ -307,23 +318,23 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
* no need to check for close confirmation
* no way to disable watchdog ;)
*/
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- size_t ofs;
-
- /*
- * note: just in case someone wrote the magic character
- * five months ago...
- */
- zf_expect_close = 0;
-
- /* now scan */
- for(ofs = 0; ofs != count; ofs++){
- if(buf[ofs] == 'V'){
- zf_expect_close = 1;
- dprintk("zf_expect_close 1\n");
+ if (!nowayout) {
+ size_t ofs;
+
+ /*
+ * note: just in case someone wrote the magic character
+ * five months ago...
+ */
+ zf_expect_close = 0;
+
+ /* now scan */
+ for(ofs = 0; ofs != count; ofs++){
+ if(buf[ofs] == 'V'){
+ zf_expect_close = 1;
+ dprintk("zf_expect_close 1\n");
+ }
}
}
-#endif
/*
* Well, anyhow someone wrote to us,
* we should return that favour
@@ -386,9 +397,9 @@ static int zf_open(struct inode *inode, struct file *file)
return -EBUSY;
}
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
zf_is_open = 1;
spin_unlock(&zf_lock);
diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
index 3f6e87a7c0d2..bbcb881ef1b0 100644
--- a/drivers/char/mixcomwd.c
+++ b/drivers/char/mixcomwd.c
@@ -27,10 +27,13 @@
*
* Version 0.4 (99/11/15):
* - support for one more type board
+ *
+ * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
+ * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
*/
-#define VERSION "0.4"
+#define VERSION "0.5"
#include <linux/module.h>
#include <linux/config.h>
@@ -57,26 +60,30 @@ static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
static long mixcomwd_opened; /* long req'd for setbit --RR */
static int watchdog_port;
-
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
static int mixcomwd_timer_alive;
static struct timer_list mixcomwd_timer;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
static void mixcomwd_ping(void)
{
outb_p(55,watchdog_port);
return;
}
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
static void mixcomwd_timerfun(unsigned long d)
{
mixcomwd_ping();
mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
}
-#endif
/*
* Allow only one person to hold it open
@@ -89,31 +96,32 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
}
mixcomwd_ping();
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- del_timer(&mixcomwd_timer);
- mixcomwd_timer_alive=0;
- }
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ } else {
+ if(mixcomwd_timer_alive) {
+ del_timer(&mixcomwd_timer);
+ mixcomwd_timer_alive=0;
+ }
+ }
return 0;
}
static int mixcomwd_release(struct inode *inode, struct file *file)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- printk(KERN_ERR "mixcomwd: release called while internal timer alive");
- return -EBUSY;
+ if (!nowayout) {
+ if(mixcomwd_timer_alive) {
+ printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+ return -EBUSY;
+ }
+ init_timer(&mixcomwd_timer);
+ mixcomwd_timer.expires=jiffies + 5 * HZ;
+ mixcomwd_timer.function=mixcomwd_timerfun;
+ mixcomwd_timer.data=0;
+ mixcomwd_timer_alive=1;
+ add_timer(&mixcomwd_timer);
}
- init_timer(&mixcomwd_timer);
- mixcomwd_timer.expires=jiffies + 5 * HZ;
- mixcomwd_timer.function=mixcomwd_timerfun;
- mixcomwd_timer.data=0;
- mixcomwd_timer_alive=1;
- add_timer(&mixcomwd_timer);
-#endif
-
clear_bit(0,&mixcomwd_opened);
return 0;
}
@@ -145,9 +153,9 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
{
case WDIOC_GETSTATUS:
status=mixcomwd_opened;
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- status|=mixcomwd_timer_alive;
-#endif
+ if (!nowayout) {
+ status|=mixcomwd_timer_alive;
+ }
if (copy_to_user((int *)arg, &status, sizeof(int))) {
return -EFAULT;
}
@@ -252,14 +260,14 @@ static int __init mixcomwd_init(void)
static void __exit mixcomwd_exit(void)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
- " probably reboot!\n");
- del_timer(&mixcomwd_timer);
- mixcomwd_timer_alive=0;
+ if (!nowayout) {
+ if(mixcomwd_timer_alive) {
+ printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+ " probably reboot!\n");
+ del_timer(&mixcomwd_timer);
+ mixcomwd_timer_alive=0;
+ }
}
-#endif
release_region(watchdog_port,1);
misc_deregister(&mixcomwd_miscdev);
}
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 12a0fd3ccc25..6d0512e0f597 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -32,6 +32,9 @@
* version : 1.2
*
* Fixes for C104H/PCI by Tim Hockin <thockin@sun.com>
+ * Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards
+ * by Damian Wrobel <dwrobel@ertel.com.pl>
+ *
*/
#include <linux/config.h>
@@ -61,7 +64,7 @@
#include <asm/bitops.h>
#include <asm/uaccess.h>
-#define MXSER_VERSION "1.2"
+#define MXSER_VERSION "1.2.1"
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
@@ -114,10 +117,22 @@
#ifndef PCI_DEVICE_ID_C104
#define PCI_DEVICE_ID_C104 0x1040
#endif
+#ifndef PCI_DEVICE_ID_CP132
+#define PCI_DEVICE_ID_CP132 0x1320
+#endif
+#ifndef PCI_DEVICE_ID_CP114
+#define PCI_DEVICE_ID_CP114 0x1141
+#endif
+#ifndef PCI_DEVICE_ID_CT114
+#define PCI_DEVICE_ID_CT114 0x1140
+#endif
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
+#define CI134_ASIC_ID 3
+#define CI132_ASIC_ID 4
#define CI104J_ASIC_ID 5
+#define C102_ASIC_ID 0xB
enum {
MXSER_BOARD_C168_ISA = 0,
@@ -125,6 +140,12 @@ enum {
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
MXSER_BOARD_C104_PCI,
+ MXSER_BOARD_C102_ISA,
+ MXSER_BOARD_CI132,
+ MXSER_BOARD_CI134,
+ MXSER_BOARD_CP132_PCI,
+ MXSER_BOARD_CP114_PCI,
+ MXSER_BOARD_CT114_PCI
};
static char *mxser_brdname[] =
@@ -134,6 +155,12 @@ static char *mxser_brdname[] =
"CI-104J series",
"C168H/PCI series",
"C104H/PCI series",
+ "C102 series",
+ "CI-132 series",
+ "CI-134 series",
+ "CP-132 series",
+ "CP-114 series",
+ "CT-114 series"
};
static int mxser_numports[] =
@@ -143,6 +170,12 @@ static int mxser_numports[] =
4,
8,
4,
+ 2,
+ 2,
+ 4,
+ 2,
+ 4,
+ 4
};
/*
@@ -163,6 +196,12 @@ static struct pci_device_id mxser_pcibrds[] = {
MXSER_BOARD_C168_PCI },
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
MXSER_BOARD_C104_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CP132_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CP114_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CT114_PCI },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -613,38 +652,35 @@ int mxser_init(void)
n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
index = 0;
for (b = 0; b < n; b++) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor,
- mxser_pcibrds[b].device, pdev);
- if (!pdev || pci_enable_device(pdev))
- continue;
- hwconf.pdev = pdev;
- printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
- mxser_brdname[mxser_pcibrds[b].driver_data],
- pdev->bus->number, PCI_SLOT(pdev->devfn));
- if (m >= MXSER_BOARDS) {
- printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
- } else {
- retval = mxser_get_PCI_conf(pdev,
- mxser_pcibrds[b].driver_data, &hwconf);
- if (retval < 0) {
- if (retval == MXSER_ERR_IRQ)
- printk("Invalid interrupt number,board not configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk("Invalid interrupt number,board not configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk("Invalid interrupt vector,board not configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk("Invalid I/O address,board not configured\n");
+ while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev))
+ {
+ if (pci_enable_device(pdev))
continue;
-
+ hwconf.pdev = pdev;
+ printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+ mxser_brdname[mxser_pcibrds[b].driver_data],
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+ if (m >= MXSER_BOARDS) {
+ printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
+ } else {
+ retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].driver_data, &hwconf);
+ if (retval < 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk("Invalid interrupt vector,board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk("Invalid I/O address,board not configured\n");
+ continue;
+ }
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+ mxser_getcfg(m, &hwconf);
+ m++;
}
- if (mxser_initbrd(m, &hwconf) < 0)
- continue;
- mxser_getcfg(m, &hwconf);
- m++;
-
}
-
}
}
#endif
@@ -2306,6 +2342,12 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->board_type = MXSER_BOARD_C168_ISA;
else if (id == C104_ASIC_ID)
hwconf->board_type = MXSER_BOARD_C104_ISA;
+ else if (id == C102_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_C102_ISA;
+ else if (id == CI132_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_CI132;
+ else if (id == CI134_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_CI134;
else if (id == CI104J_ASIC_ID)
hwconf->board_type = MXSER_BOARD_CI104J;
else
@@ -2417,7 +2459,8 @@ static int mxser_program_mode(int port)
(void) inb(port);
restore_flags(flags);
id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID))
+ if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID) &&
+ (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID))
return (-1);
for (i = 0, j = 0; i < 4; i++) {
n = inb(port + 2);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 79b5dfebb9aa..2dcd1ef698a5 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -322,7 +322,7 @@ ssize_t rw_raw_dev(int rw, struct file *filp, char *buf,
if (err)
break;
- err = brw_kiovec(rw, 1, &iobuf, dev, &blocknr, sector_size);
+ err = brw_kiovec(rw, 1, &iobuf, raw_devices[minor].binding, &blocknr, sector_size);
if (rw == READ && err > 0)
mark_dirty_kiobuf(iobuf, err);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7eb8b68269fb..d6710f5b0294 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -42,10 +42,6 @@
#include <linux/config.h>
#include <linux/version.h>
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -63,15 +59,8 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
-#ifdef ENABLE_PCI
#include <linux/pci.h>
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-#include <linux/bios32.h>
-#endif
-#endif
-#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
-#endif
#include "rocket_int.h"
#ifdef LOCAL_ROCKET_H
@@ -154,7 +143,6 @@ static unsigned long time_stat_long;
static unsigned long time_counter;
#endif
-#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
MODULE_AUTHOR("Theodore Ts'o");
MODULE_DESCRIPTION("Comtrol Rocketport driver");
MODULE_LICENSE("GPL");
@@ -170,39 +158,8 @@ MODULE_PARM(controller, "i");
MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
MODULE_PARM(support_low_speed, "i");
MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");
-#endif
-
-#if (LINUX_VERSION_CODE < 131336)
-int copy_from_user(void *to, const void *from_user, unsigned long len)
-{
- int error;
-
- error = verify_area(VERIFY_READ, from_user, len);
- if (error)
- return len;
- memcpy_fromfs(to, from_user, len);
- return 0;
-}
-
-int copy_to_user(void *to_user, const void *from, unsigned long len)
-{
- int error;
-
- error = verify_area(VERIFY_WRITE, to_user, len);
- if (error)
- return len;
- memcpy_tofs(to_user, from, len);
- return 0;
-}
-
-static inline int signal_pending(struct task_struct *p)
-{
- return (p->signal & ~p->blocked) != 0;
-}
-#else
#include <asm/uaccess.h>
-#endif
/*
* tmp_buf is used as a temporary buffer by rp_write. We need to
@@ -497,7 +454,7 @@ static void rp_do_poll(unsigned long dummy)
continue;
ctlp= sCtlNumToCtlPtr(ctrl);
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
if(ctlp->BusType == isPCI)
CtlMask= sPCIGetControllerIntStatus(ctlp);
else
@@ -611,12 +568,6 @@ static void init_r_port(int board, int aiop, int chan)
rp_table[line] = info;
}
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300,
- 600, 1200, 1800, 2400, 4800, 9600, 19200,
- 38400, 57600, 115200, 230400, 460800, 0 };
-#endif
/*
* This routine configures a rocketport port so according to its
@@ -627,9 +578,6 @@ static void configure_r_port(struct r_port *info)
unsigned cflag;
unsigned long flags;
int bits, baud;
-#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */
- int i;
-#endif
CHANNEL_t *cp;
if (!info->tty || !info->tty->termios)
@@ -665,31 +613,9 @@ static void configure_r_port(struct r_port *info)
}
/* baud rate */
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i == 15) {
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
- i += 1;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
- i += 2;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
- i += 3;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
- i += 4;
- }
- baud = baud_table[i] ? baud_table[i] : 9600;
-#else
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600;
-#endif
info->cps = baud / bits;
sSetBaud(cp, (rp_baud_base/baud) - 1);
@@ -990,7 +916,6 @@ static int rp_open(struct tty_struct *tty, struct file * filp)
info->flags |= ROCKET_INITIALIZED;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
/*
* Set up the tty->alt_speed kludge
*/
@@ -1002,7 +927,6 @@ static int rp_open(struct tty_struct *tty, struct file * filp)
info->tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->tty->alt_speed = 460800;
-#endif
configure_r_port(info);
if (tty->termios->c_cflag & CBAUD) {
@@ -1094,10 +1018,8 @@ static void rp_close(struct tty_struct *tty, struct file * filp)
* If transmission was throttled by the application request,
* just flush the xmit buffer.
*/
-#if (LINUX_VERSION_CODE >= 131343)
if (tty->flow_stopped)
rp_flush_buffer(tty);
-#endif
/*
* Wait for the transmit buffer to clear
@@ -1218,17 +1140,6 @@ static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios)
/*
* Here are the routines used by rp_ioctl
*/
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static void send_break( struct r_port * info, int duration)
-{
- current->state = TASK_INTERRUPTIBLE;
- cli();
- sSendBreak(&info->channel);
- schedule_timeout(duration);
- sClrBreak(&info->channel);
- sti();
-}
-#else
static void rp_break(struct tty_struct *tty, int break_state)
{
struct r_port * info = (struct r_port *)tty->driver_data;
@@ -1245,7 +1156,6 @@ static void rp_break(struct tty_struct *tty, int break_state)
}
restore_flags(flags);
}
-#endif
static int get_modem_info(struct r_port * info, unsigned int *value)
{
@@ -1348,7 +1258,6 @@ static int set_config(struct r_port * info, struct rocket_config * new_info)
info->close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
info->tty->alt_speed = 57600;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
@@ -1357,7 +1266,6 @@ static int set_config(struct r_port * info, struct rocket_config * new_info)
info->tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->tty->alt_speed = 460800;
-#endif
configure_r_port(info);
return 0;
@@ -1389,54 +1297,13 @@ static int rp_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct r_port * info = (struct r_port *)tty->driver_data;
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- int retval, tmp;
-#endif
if (cmd != RCKP_GET_PORTS &&
rocket_paranoia_check(info, tty->device, "rp_ioctl"))
return -ENODEV;
switch (cmd) {
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, HZ/4); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCGSOFTCAR:
- tmp = C_CLOCAL(tty) ? 1 : 0;
- if (copy_to_user((void *)arg, &tmp, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
- if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (tmp ? CLOCAL : 0));
- return 0;
-#endif
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
@@ -1877,36 +1744,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
sFlushTxFIFO(cp);
}
-#ifdef ENABLE_PCI
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-/* For compatibility */
-static struct pci_dev *pci_find_slot(unsigned char bus,
- unsigned char device_fn)
-{
- unsigned short vendor_id, device_id;
- int ret, error;
- static struct pci_dev ret_struct;
-
- error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
- &vendor_id);
- ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
- &device_id);
- if (error == 0)
- error = ret;
-
- if (error) {
- printk("PCI RocketPort error: %s not initializing due to error"
- "reading configuration space\n",
- pcibios_strerror(error));
- return(0);
- }
-
- memset(&ret_struct, 0, sizeof(ret_struct));
- ret_struct.device = device_id;
-
- return &ret_struct;
-}
-#endif
+#ifdef CONFIG_PCI
int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
{
@@ -1915,10 +1753,6 @@ int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
char *str;
CONTROLLER_t *ctlp;
struct pci_dev *dev = pci_find_slot(bus, device_fn);
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
- int ret;
- unsigned int port;
-#endif
if (!dev)
return 0;
@@ -2161,7 +1995,7 @@ int __init rp_init(void)
if(init_ISA(i, &reserved_controller))
isa_boards_found++;
}
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
if (pcibios_present()) {
if(isa_boards_found < NUM_BOARDS)
pci_boards_found = init_PCI(isa_boards_found);
@@ -2219,13 +2053,9 @@ int __init rp_init(void)
rocket_driver.stop = rp_stop;
rocket_driver.start = rp_start;
rocket_driver.hangup = rp_hangup;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
rocket_driver.break_ctl = rp_break;
-#endif
-#if (LINUX_VERSION_CODE >= 131343)
rocket_driver.send_xchar = rp_send_xchar;
rocket_driver.wait_until_sent = rp_wait_until_sent;
-#endif
/*
* The callout device is just like normal device except for
diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
index ff9a572b13a4..ac7aeda9bfb5 100644
--- a/drivers/char/sbc60xxwdt.c
+++ b/drivers/char/sbc60xxwdt.c
@@ -109,6 +109,15 @@ static unsigned long next_heartbeat;
static int wdt_is_open;
static int wdt_expect_close;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Whack the dog
*/
@@ -202,6 +211,9 @@ static int fop_open(struct inode * inode, struct file * file)
/* Just in case we're already talking to someone... */
if(wdt_is_open)
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/* Good, fire up the show */
wdt_is_open = 1;
wdt_startup();
@@ -216,7 +228,7 @@ static int fop_close(struct inode * inode, struct file * file)
{
if(minor(inode->i_rdev) == WATCHDOG_MINOR)
{
- if(wdt_expect_close)
+ if(wdt_expect_close && !nowayout)
wdt_turnoff();
else {
del_timer(&timer);
diff --git a/drivers/char/shwdt.c b/drivers/char/shwdt.c
index c636eccc2c1a..be73b1e2f5b5 100644
--- a/drivers/char/shwdt.c
+++ b/drivers/char/shwdt.c
@@ -9,6 +9,9 @@
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -88,6 +91,15 @@ static struct watchdog_info sh_wdt_info;
static struct timer_list timer;
static unsigned long next_heartbeat;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/**
* sh_wdt_write_cnt - Write to Counter
*
@@ -175,6 +187,10 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(0, &sh_is_open))
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
+
sh_wdt_start();
break;
@@ -196,9 +212,9 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
static int sh_wdt_close(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- sh_wdt_stop();
-#endif
+ if (!nowayout) {
+ sh_wdt_stop();
+ }
clear_bit(0, &sh_is_open);
}
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index 7635904d932c..bbc0c8a396c0 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -1,5 +1,5 @@
/*
- * SoftDog 0.05: A Software Watchdog Device
+ * SoftDog 0.06: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
* http://www.redhat.com
@@ -26,6 +26,10 @@
*
* 19980911 Alan Cox
* Made SMP safe for 2.3.x
+ *
+ * 20011214 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Didn't add timeout option, as soft_margin option already exists.
*/
#include <linux/module.h>
@@ -46,6 +50,15 @@
static int soft_margin = TIMER_MARGIN; /* in seconds */
MODULE_PARM(soft_margin,"i");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
MODULE_LICENSE("GPL");
/*
@@ -83,9 +96,9 @@ static int softdog_open(struct inode *inode, struct file *file)
{
if(timer_alive)
return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate timer
*/
@@ -98,11 +111,11 @@ static int softdog_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we defined ...NOWAYOUT
+ * Lock it in if it's a module and we set nowayout
*/
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- del_timer(&watchdog_ticktock);
-#endif
+ if(!nowayout) {
+ del_timer(&watchdog_ticktock);
+ }
timer_alive=0;
return 0;
}
@@ -159,7 +172,7 @@ static struct miscdevice softdog_miscdev = {
fops: &softdog_fops,
};
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d sec\n";
+static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n";
static int __init watchdog_init(void)
{
@@ -170,7 +183,7 @@ static int __init watchdog_init(void)
if (ret)
return ret;
- printk(banner, soft_margin);
+ printk(banner, soft_margin, nowayout);
return 0;
}
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 92bc9c5c4d6a..ced9b9edcb3b 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -109,25 +109,29 @@ static inline int sonypi_emptyq(void) {
return result;
}
-static void sonypi_ecrset(u16 addr, u16 value) {
-
- wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
- outw_p(0x81, SONYPI_CST_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(addr, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(value, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
+static void sonypi_ecrset(u8 addr, u8 value) {
+
+ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+ outb_p(0x81, SONYPI_CST_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(addr, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(value, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
}
-static u16 sonypi_ecrget(u16 addr) {
+static u8 sonypi_ecrget(u8 addr) {
+
+ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+ outb_p(0x80, SONYPI_CST_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(addr, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ return inb_p(SONYPI_DATA_IOPORT);
+}
- wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
- outw_p(0x80, SONYPI_CST_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(addr, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- return inw_p(SONYPI_DATA_IOPORT);
+static u16 sonypi_ecrget16(u8 addr) {
+ return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
}
/* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -286,19 +290,38 @@ static void sonypi_camera_on(void) {
sonypi_device.camera_power = 1;
}
+/* sets the bluetooth subsystem power state */
+static void sonypi_setbluetoothpower(u8 state) {
+
+ state = (state != 0);
+ if (sonypi_device.bluetooth_power && state)
+ return;
+ if (!sonypi_device.bluetooth_power && !state)
+ return;
+
+ sonypi_call2(0x96, state);
+ sonypi_call1(0x93);
+ sonypi_device.bluetooth_power = state;
+}
+
/* Interrupt handler: some event is available */
void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
u8 v1, v2, event = 0;
int i;
u8 sonypi_jogger_ev, sonypi_fnkey_ev;
+ u8 sonypi_capture_ev, sonypi_bluetooth_ev;
if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
+ sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
+ sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
}
else {
sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
+ sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
+ sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
}
v1 = inb_p(sonypi_device.ioport1);
@@ -318,7 +341,7 @@ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
goto found;
}
}
- if ((v2 & SONYPI_CAPTURE_EV) == SONYPI_CAPTURE_EV) {
+ if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
for (i = 0; sonypi_captureev[i].event; i++)
if (sonypi_captureev[i].data == v1) {
event = sonypi_captureev[i].event;
@@ -332,7 +355,7 @@ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
goto found;
}
}
- if ((v2 & SONYPI_BLUETOOTH_EV) == SONYPI_BLUETOOTH_EV) {
+ if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
for (i = 0; sonypi_blueev[i].event; i++)
if (sonypi_blueev[i].data == v1) {
event = sonypi_blueev[i].event;
@@ -510,24 +533,74 @@ static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
unsigned int cmd, unsigned long arg) {
int ret = 0;
- u8 val;
+ u8 val8;
+ u16 val16;
down(&sonypi_device.lock);
switch (cmd) {
- case SONYPI_IOCGBRT:
- val = sonypi_ecrget(0x96) & 0xff;
- if (copy_to_user((u8 *)arg, &val, sizeof(val))) {
- ret = -EFAULT;
- goto out;
- }
- break;
- case SONYPI_IOCSBRT:
- if (copy_from_user(&val, (u8 *)arg, sizeof(val))) {
- ret = -EFAULT;
- goto out;
- }
- sonypi_ecrset(0x96, val);
- break;
+ case SONYPI_IOCGBRT:
+ val8 = sonypi_ecrget(0x96);
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCSBRT:
+ if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ sonypi_ecrset(0x96, val8);
+ break;
+ case SONYPI_IOCGBAT1CAP:
+ val16 = sonypi_ecrget16(0xb2);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT1REM:
+ val16 = sonypi_ecrget16(0xa2);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT2CAP:
+ val16 = sonypi_ecrget16(0xba);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT2REM:
+ val16 = sonypi_ecrget16(0xaa);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBATFLAGS:
+ val8 = sonypi_ecrget(0x81) & 0x07;
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBLUE:
+ val8 = sonypi_device.bluetooth_power;
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCSBLUE:
+ if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ sonypi_setbluetoothpower(val8);
+ break;
default:
ret = -EINVAL;
}
@@ -562,6 +635,7 @@ static int __devinit sonypi_probe(struct pci_dev *pcidev) {
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
sonypi_initq();
init_MUTEX(&sonypi_device.lock);
+ sonypi_device.bluetooth_power = 0;
if (pcidev && pci_enable_device(pcidev)) {
printk(KERN_ERR "sonypi: pci_enable_device failed\n");
diff --git a/drivers/char/sonypi.h b/drivers/char/sonypi.h
index 9d836086060f..3937c1eb1dbc 100644
--- a/drivers/char/sonypi.h
+++ b/drivers/char/sonypi.h
@@ -34,8 +34,8 @@
#ifdef __KERNEL__
-#define SONYPI_DRIVER_MAJORVERSION 1
-#define SONYPI_DRIVER_MINORVERSION 8
+#define SONYPI_DRIVER_MAJORVERSION 1
+#define SONYPI_DRIVER_MINORVERSION 10
#include <linux/types.h>
#include <linux/pci.h>
@@ -132,15 +132,17 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
#define SONYPI_CAMERA_ROMVERSION 9
/* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV 0x10
-#define SONYPI_TYPE2_JOGGER_EV 0x08
-#define SONYPI_CAPTURE_EV 0x60
-#define SONYPI_TYPE1_FNKEY_EV 0x20
-#define SONYPI_TYPE2_FNKEY_EV 0x08
-#define SONYPI_BLUETOOTH_EV 0x30
-#define SONYPI_TYPE1_PKEY_EV 0x40
-#define SONYPI_BACK_EV 0x08
-#define SONYPI_LID_EV 0x38
+#define SONYPI_TYPE1_JOGGER_EV 0x10
+#define SONYPI_TYPE2_JOGGER_EV 0x08
+#define SONYPI_TYPE1_CAPTURE_EV 0x60
+#define SONYPI_TYPE2_CAPTURE_EV 0x08
+#define SONYPI_TYPE1_FNKEY_EV 0x20
+#define SONYPI_TYPE2_FNKEY_EV 0x08
+#define SONYPI_TYPE1_BLUETOOTH_EV 0x30
+#define SONYPI_TYPE2_BLUETOOTH_EV 0x08
+#define SONYPI_TYPE1_PKEY_EV 0x40
+#define SONYPI_BACK_EV 0x08
+#define SONYPI_LID_EV 0x38
struct sonypi_event {
u8 data;
@@ -203,6 +205,8 @@ static struct sonypi_event sonypi_pkeyev[] = {
/* The set of possible bluetooth events */
static struct sonypi_event sonypi_blueev[] = {
{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+ { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+ { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
{ 0x00, 0x00 }
};
@@ -241,6 +245,7 @@ struct sonypi_device {
u16 ioport2;
u16 region_size;
int camera_power;
+ int bluetooth_power;
struct semaphore lock;
struct sonypi_queue queue;
int open_count;
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 80a73a1de70e..db06f5ad2b10 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -2458,7 +2458,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
}
/*
- * We have verfied that the board is actually present, so now we
+ * We have verified that the board is actually present, so now we
* can complete the setup.
*/
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index de1c67b8e9db..c50bc7247424 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -925,9 +925,9 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
static char *driver_name = "SyncLink serial driver";
static char *driver_version = "$Revision: 3.12 $";
-static int __init synclink_init_one (struct pci_dev *dev,
+static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
-static void __exit synclink_remove_one (struct pci_dev *dev);
+static void synclink_remove_one (struct pci_dev *dev);
static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 4e5cfcf6a60f..24b490623b14 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2748,7 +2748,9 @@ static int qic02_get_resources(void)
* the config parameters have been set using MTSETCONFIG.
*/
- if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE)) {
+ /* Grab the IO region. */
+ if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
+ TPQIC02_NAME)) {
printk(TPQIC02_NAME
": IO space at 0x%x [%d ports] already reserved\n",
QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
@@ -2762,6 +2764,7 @@ static int qic02_get_resources(void)
printk(TPQIC02_NAME
": can't allocate IRQ%d for QIC-02 tape\n",
QIC02_TAPE_IRQ);
+ release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY;
}
@@ -2771,13 +2774,10 @@ static int qic02_get_resources(void)
": can't allocate DMA%d for QIC-02 tape\n",
QIC02_TAPE_DMA);
free_irq(QIC02_TAPE_IRQ, NULL);
+ release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY;
}
- /* Grab the IO region. We already made sure it's available. */
- request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
- TPQIC02_NAME);
-
/* Setup the page-address for the dma transfer. */
buffaddr =
(void *) __get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 9fdd57eff81c..d77cfdb24515 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -569,6 +569,8 @@ void disassociate_ctty(int on_exit)
struct task_struct *p;
int tty_pgrp = -1;
+ lock_kernel();
+
if (tty) {
tty_pgrp = tty->pgrp;
if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
@@ -578,6 +580,7 @@ void disassociate_ctty(int on_exit)
kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
}
+ unlock_kernel();
return;
}
if (tty_pgrp > 0) {
@@ -595,6 +598,7 @@ void disassociate_ctty(int on_exit)
if (p->session == current->session)
p->tty = NULL;
read_unlock(&tasklist_lock);
+ unlock_kernel();
}
void stop_tty(struct tty_struct *tty)
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 45bbbc747834..c59fc297f803 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -214,7 +214,7 @@ static int mvme147_scc_init(void)
{
struct scc_port *port;
- printk("SCC: MVME147 Serial Driver\n");
+ printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -284,7 +284,7 @@ static int mvme162_scc_init(void)
if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
return (-ENODEV);
- printk("SCC: MVME162 Serial Driver\n");
+ printk(KERN_INFO "SCC: MVME162 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -352,7 +352,7 @@ static int bvme6000_scc_init(void)
{
struct scc_port *port;
- printk("SCC: BVME6000 Serial Driver\n");
+ printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -449,7 +449,7 @@ static void scc_rx_int(int irq, void *data, struct pt_regs *fp)
ch = SCCread_NB(RX_DATA_REG);
if (!tty) {
- printk ("scc_rx_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
return;
}
@@ -487,7 +487,7 @@ static void scc_spcond_int(int irq, void *data, struct pt_regs *fp)
SCC_ACCESS_INIT(port);
if (!tty) {
- printk ("scc_spcond_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
SCCwrite(COMMAND_REG, CR_ERROR_RESET);
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
return;
@@ -533,7 +533,7 @@ static void scc_tx_int(int irq, void *data, struct pt_regs *fp)
SCC_ACCESS_INIT(port);
if (!port->gs.tty) {
- printk ("scc_tx_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
@@ -719,7 +719,7 @@ static int scc_set_real_termios (void *ptr)
else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
(MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
(MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
- printk("SCC: Bad speed requested, %d\n", baud);
+ printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
return 0;
}
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index f98face6a689..1fb85c7c70eb 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -15,7 +15,7 @@
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * Release 0.08.
+ * Release 0.09.
*
* Fixes
* Dave Gregorich : Modularisation and minor bugs
@@ -27,6 +27,7 @@
* Tim Hockin : Added insmod parameters, comment cleanup
* Parameterized timeout
* Tigran Aivazian : Restructured wdt_init() to handle failures
+ * Matt Domsch : added nowayout and timeout module options
*/
#include <linux/config.h>
@@ -62,6 +63,26 @@ static int irq=11;
#define WD_TIMO (100*60) /* 1 minute */
+static int timeout_val = WD_TIMO; /* value passed to card */
+static int timeout = 60; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdt_validate_timeout(void)
+{
+ timeout_val = timeout * 100;
+}
+
#ifndef MODULE
/**
@@ -216,7 +237,7 @@ static void wdt_ping(void)
/* Write a watchdog value */
inb_p(WDT_DC);
wdt_ctr_mode(1,2);
- wdt_ctr_load(1,WD_TIMO); /* Timeout */
+ wdt_ctr_load(1,timeout_val); /* Timeout */
outb_p(0, WDT_DC);
}
@@ -339,6 +360,9 @@ static int wdt_open(struct inode *inode, struct file *file)
case WATCHDOG_MINOR:
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -348,7 +372,7 @@ static int wdt_open(struct inode *inode, struct file *file)
wdt_ctr_mode(1,2);
wdt_ctr_mode(2,0);
wdt_ctr_load(0, 8948); /* count at 100Hz */
- wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */
+ wdt_ctr_load(1,timeout_val); /* Timeout */
wdt_ctr_load(2,65535);
outb_p(0, WDT_DC); /* Enable */
return 0;
@@ -375,10 +399,10 @@ static int wdt_release(struct inode *inode, struct file *file)
{
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_DC); /* Disable counters */
- wdt_ctr_load(2,0); /* 0 length reset pulses now */
-#endif
+ if (!nowayout) {
+ inb_p(WDT_DC); /* Disable counters */
+ wdt_ctr_load(2,0); /* 0 length reset pulses now */
+ }
clear_bit(0, &wdt_is_open);
}
return 0;
@@ -484,6 +508,7 @@ static int __init wdt_init(void)
{
int ret;
+ wdt_validate_timeout();
ret = misc_register(&wdt_miscdev);
if (ret) {
printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c
index 7f9dde05cf26..0e32706edf89 100644
--- a/drivers/char/wdt977.c
+++ b/drivers/char/wdt977.c
@@ -1,5 +1,5 @@
/*
- * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip
+ * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip
*
* (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
*
@@ -11,8 +11,13 @@
* 2 of the License, or (at your option) any later version.
*
* -----------------------
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
+ * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
+ * from minutes to seconds.
*/
-
+
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
@@ -21,56 +26,123 @@
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
+#include <asm/uaccess.h>
#define WATCHDOG_MINOR 130
-static int timeout = 3;
+#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */
+
+static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */
+static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */
static int timer_alive;
static int testmode;
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60");
+MODULE_PARM(testmode, "i");
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */
+int kick_wdog(void)
+{
+ /*
+ * Refresh the timer.
+ */
+
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ /* select device Aux2 (device=8) and kicks watchdog reg F2 */
+ /* F2 has the timeout in minutes */
+
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF2,0x370);
+ outb(timeoutM,0x371);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
+
+ return 0;
+}
+
+
/*
* Allow only one person to hold it open
*/
-
+
static int wdt977_open(struct inode *inode, struct file *file)
{
+
if(timer_alive)
return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+
+ /* convert seconds to minutes, rounding up */
+ timeoutM = timeout + 59;
+ timeoutM /= 60;
+
+ if (nowayout)
+ {
+ MOD_INC_USE_COUNT;
+
+ /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */
+ if (!timeoutM) timeoutM = DEFAULT_TIMEOUT;
+ }
timer_alive++;
- //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
- if (timeout>255)
- timeout = 255;
-
- printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout);
-
- // unlock the SuperIO chip
- outb(0x87,0x370);
- outb(0x87,0x370);
-
- //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
- //F2 has the timeout in minutes
- //F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
- // at timeout, and to reset timer on kbd/mouse activity (not now)
- //F4 is used to just clear the TIMEOUT'ed state (bit 0)
-
+ if (machine_is_netwinder())
+ {
+ /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+ * this limits the max timeout to half of device max of 255 minutes...
+ */
+ timeoutM += timeoutM;
+ }
+
+ /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */
+ if (timeoutM > 255) timeoutM = 255;
+
+ /* convert seconds to minutes */
+ printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n",
+ machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60,
+ nowayout, testmode);
+
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
+ * F2 has the timeout in minutes
+ * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
+ * at timeout, and to reset timer on kbd/mouse activity (not impl.)
+ * F4 is used to just clear the TIMEOUT'ed state (bit 0)
+ */
outb(0x07,0x370);
outb(0x08,0x371);
outb(0xF2,0x370);
- outb(timeout,0x371);
+ outb(timeoutM,0x371);
outb(0xF3,0x370);
- outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED
+ outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */
outb(0xF4,0x370);
outb(0x00,0x371);
-
- //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+
+ /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+ /* in test mode watch the bit 1 on F4 to indicate "triggered" */
if (!testmode)
{
outb(0x07,0x370);
@@ -78,9 +150,9 @@ static int wdt977_open(struct inode *inode, struct file *file)
outb(0xE6,0x370);
outb(0x08,0x371);
}
-
- // lock the SuperIO chip
- outb(0xAA,0x370);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
return 0;
}
@@ -89,84 +161,163 @@ static int wdt977_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we defined ...NOWAYOUT
+ * Lock it in if it's a module and we set nowayout
*/
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-
- // unlock the SuperIO chip
- outb(0x87,0x370);
- outb(0x87,0x370);
-
- //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
- //F3 is reset to its default state
- //F4 can clear the TIMEOUT'ed state (bit 0) - back to default
- //We can not use GP17 as a PowerLed, as we use its usage as a RedLed
-
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF2,0x370);
- outb(0xFF,0x371);
- outb(0xF3,0x370);
- outb(0x00,0x371);
- outb(0xF4,0x370);
- outb(0x00,0x371);
- outb(0xF2,0x370);
- outb(0x00,0x371);
-
- //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
- outb(0x07,0x370);
- outb(0x07,0x371);
- outb(0xE6,0x370);
- outb(0x08,0x371);
-
- // lock the SuperIO chip
- outb(0xAA,0x370);
+ if (!nowayout)
+ {
+ lock_kernel();
- timer_alive=0;
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
- printk(KERN_INFO "Watchdog: shutdown.\n");
-#endif
+ /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+ * F3 is reset to its default state
+ * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+ * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+ */
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF2,0x370);
+ outb(0xFF,0x371);
+ outb(0xF3,0x370);
+ outb(0x00,0x371);
+ outb(0xF4,0x370);
+ outb(0x00,0x371);
+ outb(0xF2,0x370);
+ outb(0x00,0x371);
+
+ /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+ outb(0x07,0x370);
+ outb(0x07,0x371);
+ outb(0xE6,0x370);
+ outb(0x08,0x371);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
+
+ timer_alive=0;
+ unlock_kernel();
+
+ printk(KERN_INFO "Wdt977 Watchdog: shutdown\n");
+ }
return 0;
}
-static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+
+/*
+ * wdt977_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
- //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
- if (timeout>255)
- timeout = 255;
+ if(count)
+ {
+ kick_wdog();
+ return 1;
+ }
+ return 0;
+}
- /*
- * Refresh the timer.
- */
-
- //we have a hw bug somewhere, so each 977 minute is actually only 30sec
- //as such limit the max timeout to half of max of 255 minutes...
-// if (timeout>126)
-// timeout = 126;
-
- // unlock the SuperIO chip
- outb(0x87,0x370);
- outb(0x87,0x370);
-
- //select device Aux2 (device=8) and kicks watchdog reg F2
- //F2 has the timeout in minutes
-
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF2,0x370);
- outb(timeout,0x371);
-
- // lock the SuperIO chip
- outb(0xAA,0x370);
-
- return 1;
+/*
+ * wdt977_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ */
+
+static int wdt977_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+static struct watchdog_info ident = {
+ identity : "Winbond 83977"
+};
+
+int temp;
+
+ switch(cmd)
+ {
+ default:
+ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int *) arg);
+
+ case WDIOC_GETSTATUS:
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ /* select device Aux2 (device=8) and read watchdog reg F4 */
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF4,0x370);
+ temp = inb(0x371);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
+
+ /* return info if "expired" in test mode */
+ return put_user(temp & 1, (int *) arg);
+
+ case WDIOC_KEEPALIVE:
+ kick_wdog();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (copy_from_user(&temp, (int *) arg, sizeof(int)))
+ return -EFAULT;
+
+ /* convert seconds to minutes, rounding up */
+ temp += 59;
+ temp /= 60;
+
+ /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+ * this limits the max timeout to half of device max of 255 minutes...
+ */
+ if (machine_is_netwinder())
+ {
+ temp += temp;
+ }
+
+ /* Sanity check */
+ if (temp < 0 || temp > 255)
+ return -EINVAL;
+
+ if (!temp && nowayout)
+ return -EINVAL;
+
+ timeoutM = temp;
+ kick_wdog();
+ return 0;
+ }
}
+
static struct file_operations wdt977_fops=
{
owner: THIS_MODULE,
write: wdt977_write,
+ ioctl: wdt977_ioctl,
open: wdt977_open,
release: wdt977_release,
};
@@ -184,9 +335,9 @@ static int __init nwwatchdog_init(void)
return -ENODEV;
misc_register(&wdt977_miscdev);
- printk(KERN_INFO "NetWinder Watchdog sleeping.\n");
+ printk(KERN_INFO "Wdt977 Watchdog sleeping.\n");
return 0;
-}
+}
static void __exit nwwatchdog_exit(void)
{
diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
index 9097fe935726..62d3ffef2752 100644
--- a/drivers/char/wdt_pci.c
+++ b/drivers/char/wdt_pci.c
@@ -15,7 +15,7 @@
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * Release 0.08.
+ * Release 0.09.
*
* Fixes
* Dave Gregorich : Modularisation and minor bugs
@@ -30,6 +30,7 @@
* Alan Cox : Split ISA and PCI cards into two drivers
* Jeff Garzik : PCI cleanups
* Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
+ * Matt Domsch : added nowayout and timeout module options
*/
#include <linux/config.h>
@@ -83,6 +84,26 @@ static int irq=11;
#define WD_TIMO (100*60) /* 1 minute */
+static int timeout_val = WD_TIMO; /* value passed to card */
+static int timeout = 60; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdtpci_validate_timeout(void)
+{
+ timeout_val = timeout * 100;
+}
+
#ifndef MODULE
/**
@@ -232,7 +253,7 @@ static void wdtpci_ping(void)
/* Write a watchdog value */
inb_p(WDT_DC);
wdtpci_ctr_mode(1,2);
- wdtpci_ctr_load(1,WD_TIMO); /* Timeout */
+ wdtpci_ctr_load(1,timeout_val); /* Timeout */
outb_p(0, WDT_DC);
}
@@ -357,9 +378,9 @@ static int wdtpci_open(struct inode *inode, struct file *file)
{
return -EBUSY;
}
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -385,7 +406,7 @@ static int wdtpci_open(struct inode *inode, struct file *file)
wdtpci_ctr_mode(1,2);
wdtpci_ctr_mode(2,1);
wdtpci_ctr_load(0,20833); /* count at 100Hz */
- wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+ wdtpci_ctr_load(1,timeout_val); /* Timeout */
/* DO NOT LOAD CTR2 on PCI card! -- JPN */
outb_p(0, WDT_DC); /* Enable */
return 0;
@@ -412,10 +433,10 @@ static int wdtpci_release(struct inode *inode, struct file *file)
{
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_DC); /* Disable counters */
- wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
-#endif
+ if (!nowayout) {
+ inb_p(WDT_DC); /* Disable counters */
+ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
+ }
clear_bit(0, &wdt_is_open );
}
return 0;
@@ -617,6 +638,8 @@ static int __init wdtpci_init(void)
if (rc < 1)
return -ENODEV;
+
+ wdtpci_validate_timeout();
return 0;
}
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
index 19aee0628adf..796c219de262 100644
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -742,7 +742,6 @@ static void __exit soc_cleanup(void)
for_each_soc(s) {
irq = s->port[0].fc.irq;
- disable_irq (irq);
free_irq (irq, s);
fcp_release(&(s->port[0].fc), 2);
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
index 447a4de67f6a..c923d5ce169f 100644
--- a/drivers/fc4/socal.c
+++ b/drivers/fc4/socal.c
@@ -881,7 +881,6 @@ static void __exit socal_cleanup(void)
for_each_socal(s) {
irq = s->port[0].fc.irq;
- disable_irq (irq);
free_irq (irq, s);
fcp_release(&(s->port[0].fc), 2);
diff --git a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
index a576ffe4c239..e8e2fe6b1a8f 100644
--- a/drivers/i2c/i2c-algo-bit.c
+++ b/drivers/i2c/i2c-algo-bit.c
@@ -49,7 +49,7 @@
/* respectively. This makes sure that the algorithm works. Some chips */
/* might not like this, as they have an internal timeout of some mils */
/*
-#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
cond_resched();
*/
@@ -117,7 +117,7 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
* while they are processing data internally.
*/
setscl(adap,1);
- if (start+adap->timeout <= jiffies) {
+ if (time_after_eq(jiffies, start+adap->timeout)) {
return -ETIMEDOUT;
}
cond_resched();
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 3b001b5db0e2..0ce05f165b27 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -141,7 +141,7 @@ loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
#ifdef DEBUG
struct inode *inode = file->f_dentry->d_inode;
printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
- MINOR(inode->i_rdev),(long) offset,origin);
+ minor(inode->i_rdev),(long) offset,origin);
#endif /* DEBUG */
return -ESPIPE;
}
@@ -165,7 +165,7 @@ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
return -ENOMEM;
#ifdef DEBUG
- printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev),
count);
#endif
@@ -197,7 +197,7 @@ static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
}
#ifdef DEBUG
- printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev),
count);
#endif
ret = i2c_master_send(client,tmp,count);
@@ -218,7 +218,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
#ifdef DEBUG
printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
- MINOR(inode->i_rdev),cmd, arg);
+ minor(inode->i_rdev),cmd, arg);
#endif /* DEBUG */
switch ( cmd ) {
diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c
index 0145f779ad86..993504452410 100644
--- a/drivers/i2c/i2c-proc.c
+++ b/drivers/i2c/i2c-proc.c
@@ -119,6 +119,10 @@ int i2c_create_name(char **name, const char *prefix,
sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr);
}
*name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
+ if (!*name) {
+ printk (KERN_WARNING "i2c_create_name: not enough memory\n");
+ return -ENOMEM;
+ }
strcpy(*name, name_buffer);
return 0;
}
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
index 1f4c535ec563..185d17ecc382 100644
--- a/drivers/ide/aec62xx.c
+++ b/drivers/ide/aec62xx.c
@@ -220,7 +220,7 @@ static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_
static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
unsigned short d_conf = 0x0000;
@@ -256,10 +256,10 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
- byte ultra_pci = hwif->channel ? 0x45 : 0x44;
+ byte ultra_pci = hwif->unit ? 0x45 : 0x44;
int err = 0;
byte drive_conf = 0x00;
byte ultra_conf = 0x00;
@@ -293,7 +293,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
return ((int) aec6210_tune_chipset(drive, speed));
} else {
return ((int) aec6260_tune_chipset(drive, speed));
@@ -304,7 +304,7 @@ static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte unit = (drive->select.b.unit & 0x01);
unsigned long dma_base = hwif->dma_base;
byte speed = -1;
@@ -349,7 +349,7 @@ static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte unit = (drive->select.b.unit & 0x01);
unsigned long dma_base = hwif->dma_base;
byte speed = -1;
@@ -396,7 +396,7 @@ static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP850UF:
return config_aec6210_chipset_for_dma(drive, ultra);
case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -418,7 +418,7 @@ static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
else
speed = XFER_PIO_0 + min_t(byte, pio, 4);
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP850UF:
(void) aec6210_tune_chipset(drive, speed);
case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -435,7 +435,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -476,7 +476,7 @@ fast_ata_pio:
no_dma_set:
aec62xx_tune_drive(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -489,16 +489,16 @@ int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return config_drive_xfer_rate(drive);
case ide_dma_lostirq:
case ide_dma_timeout:
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP860:
case PCI_DEVICE_ID_ARTOP_ATP860R:
// {
// int i = 0;
// byte reg49h = 0;
-// pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+// pci_read_config_byte(drive->channel->pci_dev, 0x49, &reg49h);
// for (i=0;i<256;i++)
-// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h|0x10);
+// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h & ~0x10);
// }
// return 0;
default:
@@ -530,16 +530,16 @@ unsigned int __init pci_init_aec62xx (struct pci_dev *dev)
return dev->irq;
}
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
+unsigned int __init ata66_aec62xx(struct ata_channel *hwif)
{
- byte mask = hwif->channel ? 0x02 : 0x01;
+ byte mask = hwif->unit ? 0x02 : 0x01;
byte ata66 = 0;
pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
return ((ata66 & mask) ? 0 : 1);
}
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
+void __init ide_init_aec62xx(struct ata_channel *hwif)
{
#ifdef CONFIG_AEC62XX_TUNING
hwif->tuneproc = &aec62xx_tune_drive;
@@ -555,7 +555,7 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif)
#endif /* CONFIG_AEC62XX_TUNING */
}
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_aec62xx(struct ata_channel *hwif, unsigned long dmabase)
{
#ifdef CONFIG_AEC62XX_TUNING
unsigned long flags;
@@ -565,7 +565,7 @@ void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
__cli(); /* local CPU only */
pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
- pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+ pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->unit ? 0xF0 : 0x0F));
__restore_flags(flags); /* local CPU only */
#endif /* CONFIG_AEC62XX_TUNING */
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
index dd93eeb487c1..10861d49571a 100644
--- a/drivers/ide/ali14xx.c
+++ b/drivers/ide/ali14xx.c
@@ -134,7 +134,7 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4);
/* stuff timing parameters into controller registers */
- driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+ driveNum = (drive->channel->index << 1) + drive->select.b.unit;
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
outb_p(regOn, basePort);
@@ -214,7 +214,7 @@ void __init init_ali14xx (void)
ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
/* initialize controller registers */
if (!initRegisters()) {
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index a7a8fe6a1afb..b6a8e10b89e8 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -242,13 +242,13 @@ static struct pci_dev *isa_dev;
static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
{
struct ata_timing *t;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int s_time, a_time, c_time;
byte s_clc, a_clc, r_clc;
unsigned long flags;
- int port = hwif->index ? 0x5c : 0x58;
- int portFIFO = hwif->channel ? 0x55 : 0x54;
+ int port = hwif->unit ? 0x5c : 0x58;
+ int portFIFO = hwif->unit ? 0x55 : 0x54;
byte cd_dma_fifo = 0;
if (pio == 255)
@@ -305,11 +305,11 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
byte tmpbyte = 0x00;
- int m5229_udma = hwif->channel? 0x57 : 0x56;
+ int m5229_udma = hwif->unit ? 0x57 : 0x56;
int err = 0;
if (speed < XFER_UDMA_0) {
@@ -431,10 +431,10 @@ static byte ali15x3_can_ultra (ide_drive_t *drive)
static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- ide_dma_action_t dma_func = ide_dma_on;
- byte can_ultra_dma = ali15x3_can_ultra(drive);
+ struct hd_driveid *id = drive->id;
+ struct ata_channel *hwif = drive->channel;
+ ide_dma_action_t dma_func = ide_dma_on;
+ byte can_ultra_dma = ali15x3_can_ultra(drive);
if ((m5229_revision<=0x20) && (drive->type != ATA_DISK))
return hwif->dmaproc(ide_dma_off_quietly, drive);
@@ -537,7 +537,7 @@ unsigned int __init pci_init_ali15x3(struct pci_dev *dev)
* of UDMA66 transfers. It doesn't check the drives.
* But see note 2 below!
*/
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+unsigned int __init ata66_ali15x3(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ata66 = 0;
@@ -597,7 +597,7 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
/*
* Allow ata66 if cable of current channel has 80 pins
*/
- ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+ ata66 = (hwif->unit)?cable_80_pin[1]:cable_80_pin[0];
} else {
/*
* revision 0x20 (1543-E, 1543-F)
@@ -632,14 +632,14 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
return(ata66);
}
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+void __init ide_init_ali15x3(struct ata_channel *hwif)
{
#ifndef CONFIG_SPARC64
byte ideic, inmir;
byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
1, 11, 0, 12, 0, 14, 0, 15 };
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
if (isa_dev) {
/*
@@ -651,14 +651,14 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
ideic = ideic & 0x03;
/* get IRQ for IDE Controller */
- if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
+ if ((hwif->unit && ideic == 0x03) || (!hwif->unit && !ideic)) {
/*
* get SIRQ1 routing table
*/
pci_read_config_byte(isa_dev, 0x44, &inmir);
inmir = inmir & 0x0f;
hwif->irq = irq_routing_table[inmir];
- } else if (hwif->channel && !(ideic & 0x01)) {
+ } else if (hwif->unit && !(ideic & 0x01)) {
/*
* get SIRQ2 routing table
*/
@@ -690,7 +690,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_ali15x3(struct ata_channel *hwif, unsigned long dmabase)
{
if ((dmabase) && (m5229_revision < 0x20)) {
return;
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
index c1c036e36fb4..6c9e0ec54be3 100644
--- a/drivers/ide/amd74xx.c
+++ b/drivers/ide/amd74xx.c
@@ -226,7 +226,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timi
static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
int T, UT;
@@ -247,7 +247,7 @@ static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
- amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+ amd_set_speed(drive->channel->pci_dev, drive->dn, &t);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -263,7 +263,7 @@ static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
static void amd74xx_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+ if (!((amd_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -287,7 +287,7 @@ int amd74xx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
@@ -297,7 +297,7 @@ int amd74xx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
amd_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -409,12 +409,12 @@ unsigned int __init pci_init_amd74xx(struct pci_dev *dev, const char *name)
return 0;
}
-unsigned int __init ata66_amd74xx(ide_hwif_t *hwif)
+unsigned int __init ata66_amd74xx(struct ata_channel *hwif)
{
- return ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+ return ((amd_enabled & amd_80w) >> hwif->unit) & 1;
}
-void __init ide_init_amd74xx(ide_hwif_t *hwif)
+void __init ide_init_amd74xx(struct ata_channel *hwif)
{
int i;
@@ -426,7 +426,7 @@ void __init ide_init_amd74xx(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -445,8 +445,8 @@ void __init ide_init_amd74xx(ide_hwif_t *hwif)
* We allow the BM-DMA driver only work on enabled interfaces.
*/
-void __init ide_dmacapable_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_amd74xx(struct ata_channel *hwif, unsigned long dmabase)
{
- if ((amd_enabled >> hwif->channel) & 1)
+ if ((amd_enabled >> hwif->unit) & 1)
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index 404ddc0ae6ed..b7881df057e8 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -116,7 +116,7 @@ typedef enum BuddhaType_Enum BuddhaType;
* Check and acknowledge the interrupt status
*/
-static int buddha_ack_intr(ide_hwif_t *hwif)
+static int buddha_ack_intr(struct ata_channel *hwif)
{
unsigned char ch;
@@ -126,7 +126,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif)
return 1;
}
-static int xsurf_ack_intr(ide_hwif_t *hwif)
+static int xsurf_ack_intr(struct ata_channel *hwif)
{
unsigned char ch;
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index 27413c647376..65aaf22b781c 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -187,7 +187,7 @@ static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) *
/*
* These are initialized to point at the devices we control
*/
-static ide_hwif_t *cmd_hwif0, *cmd_hwif1;
+static struct ata_channel *cmd_hwif0, *cmd_hwif1;
static ide_drive_t *cmd_drives[4];
/*
@@ -429,7 +429,7 @@ static void __init setup_device_ptrs (void)
cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
for (i = 0; i < MAX_HWIFS; i++) {
- ide_hwif_t *hwif = &ide_hwifs[i];
+ struct ata_channel *hwif = &ide_hwifs[i];
if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
cmd_hwif0 = hwif;
@@ -795,7 +795,7 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif1->chipset = ide_cmd640;
cmd_hwif0->mate = cmd_hwif1;
cmd_hwif1->mate = cmd_hwif0;
- cmd_hwif1->channel = 1;
+ cmd_hwif1->unit = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index 39391d7c80e1..8f041daba052 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -211,7 +211,7 @@ static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2,
static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
{
unsigned long flags;
- ide_drive_t *drives = HWIF(drive)->drives;
+ ide_drive_t *drives = drive->channel->drives;
byte temp_b;
static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
static const byte recovery_counts[] =
@@ -224,7 +224,7 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
{ DRWTIM0, DRWTIM1 },
{ DRWTIM2, DRWTIM3 }
};
- int channel = (int) HWIF(drive)->channel;
+ int channel = drive->channel->unit;
int slave = (drives != drive); /* Is this really the best way to determine this?? */
cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
@@ -260,10 +260,10 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
* Program the address_setup clocks into ARTTIM reg,
* and then the active/recovery counts into the DRWTIM reg
*/
- (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
- (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
+ (void) pci_read_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], &temp_b);
+ (void) pci_write_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave],
((byte) setup_count) | (temp_b & 0x3f));
- (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
+ (void) pci_write_config_byte(drive->channel->pci_dev, drwtim_regs[channel][slave],
(byte) ((active_count << 4) | recovery_count));
cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
@@ -333,10 +333,10 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
setup_count, active_count, recovery_count);
}
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
+static byte cmd680_taskfile_timing(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
- byte addr_mask = (hwif->channel) ? 0xB2 : 0xA2;
+ byte addr_mask = (hwif->unit) ? 0xB2 : 0xA2;
unsigned short timing;
pci_read_config_word(dev, addr_mask, &timing);
@@ -353,7 +353,7 @@ static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte drive_pci;
unsigned short speedt;
@@ -394,10 +394,10 @@ static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
u8 unit = (drive->select.b.unit & 0x01);
- u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 addr_mask = (hwif->unit) ? 0x84 : 0x80;
u8 speed = 0x00;
u8 mode_pci = 0x00;
u8 channel_timings = cmd680_taskfile_timing(hwif);
@@ -420,7 +420,7 @@ static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
config_cmd680_chipset_for_pio(drive, set_speed);
} else {
config_cmd64x_chipset_for_pio(drive, set_speed);
@@ -430,13 +430,13 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
u8 unit = (drive->select.b.unit & 0x01);
- u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
- u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+ u8 pciU = (hwif->unit) ? UDIDETCR1 : UDIDETCR0;
+ u8 pciD = (hwif->unit) ? BMIDESR1 : BMIDESR0;
u8 regU = 0;
u8 regD = 0;
@@ -498,9 +498,9 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
- u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 addr_mask = (hwif->unit) ? 0x84 : 0x80;
u8 unit = (drive->select.b.unit & 0x01);
u8 dma_pci = 0;
u8 udma_pci = 0;
@@ -615,7 +615,7 @@ speed_break :
static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte speed = 0x00;
@@ -741,7 +741,7 @@ static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680)
return (config_cmd680_chipset_for_dma(drive));
return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
}
@@ -749,7 +749,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned int class_rev = 0;
byte can_ultra_33 = 0;
@@ -822,7 +822,7 @@ fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive, 1);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
@@ -841,9 +841,9 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte dma_stat = 0;
byte dma_alt_stat = 0;
- byte mask = (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
- unsigned long dma_base = HWIF(drive)->dma_base;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ byte mask = (drive->channel->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ unsigned long dma_base = drive->channel->dma_base;
+ struct pci_dev *dev = drive->channel->pci_dev;
byte jack_slap = ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
switch (func) {
@@ -856,8 +856,8 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
if (jack_slap) {
byte dma_intr = 0;
- byte dma_mask = (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- byte dma_reg = (HWIF(drive)->channel) ? ARTTIM2 : CFR;
+ byte dma_mask = (drive->channel->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ byte dma_reg = (drive->channel->unit) ? ARTTIM2 : CFR;
(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
/*
* DAMN BMIDE is not connected to PCI space!
@@ -891,7 +891,7 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
*/
static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
byte dma_stat;
@@ -917,8 +917,8 @@ static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
static int cmd680_busproc (ide_drive_t * drive, int state)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
- u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ struct ata_channel *hwif = drive->channel;
+ u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
u32 stat_config = 0;
pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
@@ -950,8 +950,8 @@ static int cmd680_busproc (ide_drive_t * drive, int state)
static void cmd680_reset (ide_drive_t *drive)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
- u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ struct ata_channel *hwif = drive->channel;
+ u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
byte reset = 0;
pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
@@ -1081,25 +1081,25 @@ unsigned int __init pci_init_cmd64x(struct pci_dev *dev)
return cmd64x_pci_init (dev);
}
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+unsigned int cmd680_ata66(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ byte addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
return (ata66 & 0x01) ? 1 : 0;
}
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
+unsigned int cmd64x_ata66(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte mask = (hwif->channel) ? 0x02 : 0x01;
+ byte mask = (hwif->unit) ? 0x02 : 0x01;
pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
return (ata66 & mask) ? 1 : 0;
}
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init ata66_cmd64x(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->device == PCI_DEVICE_ID_CMD_680)
@@ -1107,7 +1107,7 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
return cmd64x_ata66(hwif);
}
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
+void __init ide_init_cmd64x(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int class_rev;
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index 23756d92f12d..34526fa33404 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -101,7 +101,7 @@ static unsigned int cs5530_pio_timings[2][5] =
* After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
*/
#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->unit ? 0x30 : 0x20))
/*
* cs5530_tuneproc() handles selection/setting of PIO modes
@@ -112,7 +112,7 @@ static unsigned int cs5530_pio_timings[2][5] =
*/
static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "autotune" */
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int format, basereg = CS5530_BASEREG(hwif);
if (pio == 255)
@@ -134,7 +134,7 @@ static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "aut
static int cs5530_config_dma (ide_drive_t *drive)
{
int udma_ok = 1, mode = 0;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int unit = drive->select.b.unit;
ide_drive_t *mate = &hwif->drives[unit^1];
struct hd_driveid *id = drive->id;
@@ -344,7 +344,7 @@ unsigned int __init pci_init_cs5530(struct pci_dev *dev)
* This gets invoked by the IDE driver once for each channel,
* and performs channel-specific pre-initialization before drive probing.
*/
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
+void __init ide_init_cs5530(struct ata_channel *hwif)
{
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index 0634335e84a9..c4a17c00a107 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -192,7 +192,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */
mode = drive->id->tDMA;
- index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+ index = (drive->channel->unit == 0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
#if CY82C693_DEBUG_LOGS
/* for debug let's show the previous values */
@@ -200,7 +200,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
OUT_BYTE(index, CY82_INDEX_PORT);
data = IN_BYTE(CY82_DATA_PORT);
- printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
+ printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, (data&0x3), ((data>>2)&1));
#endif /* CY82C693_DEBUG_LOGS */
data = (byte)mode|(byte)(single<<2);
@@ -209,7 +209,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
OUT_BYTE(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, mode, single);
#endif /* CY82C693_DEBUG_INFO */
/*
@@ -271,7 +271,7 @@ static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
*/
static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
pio_clocks_t pclk;
unsigned int addrCtrl;
@@ -318,7 +318,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
}
- printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_LOGS */
/* first let's calc the pio modes */
@@ -371,7 +371,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
}
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_INFO */
}
@@ -431,7 +431,7 @@ unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
/*
* the init function - called for each ide channel once
*/
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
+void __init ide_init_cy82c693(struct ata_channel *hwif)
{
hwif->chipset = ide_cy82c693;
hwif->tuneproc = cy82c693_tune_drive;
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
index bc0aac09a474..b2cf501d9bc3 100644
--- a/drivers/ide/dtc2278.c
+++ b/drivers/ide/dtc2278.c
@@ -89,7 +89,7 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio)
* 32bit I/O has to be enabled for *both* drives at the same time.
*/
drive->io_32bit = 1;
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+ drive->channel->drives[!drive->select.b.unit].io_32bit = 1;
}
void __init init_dtc2278 (void)
@@ -126,5 +126,5 @@ void __init init_dtc2278 (void)
ide_hwifs[1].drives[1].no_unmask = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
}
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 5a5e8c04dc3f..543e38df9b5c 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -84,7 +84,7 @@ int ide_doubler = 0; /* support IDE doublers? */
* Check and acknowledge the interrupt status
*/
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+static int gayle_ack_intr_a4000(struct ata_channel *hwif)
{
unsigned char ch;
@@ -94,7 +94,7 @@ static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
return 1;
}
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+static int gayle_ack_intr_a1200(struct ata_channel *hwif)
{
unsigned char ch;
diff --git a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
index 2d0e82cb266e..4e0e971ac4dd 100644
--- a/drivers/ide/hpt34x.c
+++ b/drivers/ide/hpt34x.c
@@ -98,12 +98,12 @@ static void hpt34x_clear_chipset (ide_drive_t *drive)
unsigned int reg1 = 0, tmp1 = 0;
unsigned int reg2 = 0, tmp2 = 0;
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
- tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+ pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
+ tmp1 = ((0x00 << (3 * drive->dn)) | (reg1 & ~(7 << (3 * drive->dn))));
tmp2 = (reg2 & ~(0x11 << drive->dn));
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+ pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+ pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
}
static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
@@ -122,13 +122,13 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
lo_speed >>= 5;
}
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+ pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
tmp2 = ((hi_speed << drive->dn) | reg2);
err = ide_config_drive_speed(drive, speed);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+ pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+ pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -254,7 +254,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -301,7 +301,7 @@ no_dma_set:
dma_func = ide_dma_off;
#endif /* CONFIG_HPT34X_AUTODMA */
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -314,7 +314,7 @@ no_dma_set:
int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
unsigned int count, reading = 0;
byte dma_stat;
@@ -334,6 +334,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
drive->waiting_for_dma = 1;
if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */
OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
return 0;
@@ -408,7 +409,7 @@ unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
return dev->irq;
}
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
+void __init ide_init_hpt34x(struct ata_channel *hwif)
{
hwif->tuneproc = &hpt34x_tune_drive;
hwif->speedproc = &hpt34x_tune_chipset;
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 364d41263909..0703504f96f7 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -485,7 +485,7 @@ static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_lis
static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ byte regfast = (drive->channel->unit) ? 0x55 : 0x51;
/*
* since the channel is always 0 it does not matter.
*/
@@ -497,11 +497,11 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
/*
* Disable the "fast interrupt" prediction.
*/
- pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
+ pci_read_config_byte(drive->channel->pci_dev, regfast, &drive_fast);
if (drive_fast & 0x02)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
+ pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast & ~0x20);
- pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, regtime, &reg1);
/* detect bus speed by looking at control reg timing: */
switch((reg1 >> 8) & 7) {
case 5:
@@ -531,18 +531,18 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
}
reg2 &= ~0x80000000;
- pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
+ pci_write_config_dword(drive->channel->pci_dev, regtime, reg2);
}
static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
{
- byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ byte regfast = (drive->channel->unit) ? 0x55 : 0x51;
unsigned int list_conf = 0;
unsigned int drive_conf = 0;
unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
byte drive_pci = 0x40 + (drive->dn * 4);
byte new_fast, drive_fast = 0;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct pci_dev *dev = drive->channel->pci_dev;
/*
* Disable the "fast interrupt" prediction.
@@ -561,7 +561,7 @@ static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
new_fast |= 0x01;
#endif
if (new_fast != drive_fast)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
+ pci_write_config_byte(drive->channel->pci_dev, regfast, new_fast);
list_conf = pci_bus_clock_list(speed,
(struct chipset_bus_clock_list_entry *)
@@ -585,7 +585,7 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
if (!drive->init_speed)
drive->init_speed = speed;
- if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+ if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
hpt370_tune_chipset(drive, speed);
} else {
hpt366_tune_chipset(drive, speed);
@@ -670,7 +670,7 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if ((id->dma_ultra & 0x0020) &&
(!check_in_drive_lists(drive, bad_ata100_5)) &&
(HPT370_ALLOW_ATA100_5) &&
- (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
+ (pci_rev_check_hpt3xx(drive->channel->pci_dev)) &&
(ultra66)) {
speed = XFER_UDMA_5;
} else if ((id->dma_ultra & 0x0010) &&
@@ -720,23 +720,23 @@ void hpt3xx_intrproc (ide_drive_t *drive)
if (drive->quirk_list) {
/* drives in the quirk_list may not like intr setups/cleanups */
} else {
- OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+ OUT_BYTE((drive)->ctl|2, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
}
}
void hpt3xx_maskproc (ide_drive_t *drive, int mask)
{
if (drive->quirk_list) {
- if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+ if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
byte reg5a = 0;
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
+ pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5a);
if (((reg5a & 0x10) >> 4) != mask)
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ pci_write_config_byte(drive->channel->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
} else {
if (mask) {
- disable_irq(HWIF(drive)->irq);
+ disable_irq(drive->channel->irq);
} else {
- enable_irq(HWIF(drive)->irq);
+ enable_irq(drive->channel->irq);
}
}
} else {
@@ -750,7 +750,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -791,7 +791,7 @@ no_dma_set:
config_chipset_for_pio(drive);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -803,7 +803,7 @@ no_dma_set:
int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
- unsigned long dma_base = HWIF(drive)->dma_base;
+ unsigned long dma_base = drive->channel->dma_base;
switch (func) {
case ide_dma_check:
@@ -812,21 +812,21 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
dma_stat = inb(dma_base+2);
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
case ide_dma_lostirq:
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
+ pci_read_config_byte(drive->channel->pci_dev, 0x50, &reg50h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x52, &reg52h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5ah);
printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
drive->name,
ide_dmafunc_verbose(func),
reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+ pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10);
/* fall through to a reset */
#if 0
case ide_dma_begin:
case ide_dma_end:
/* reset the chips state over and over.. */
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+ pci_write_config_byte(drive->channel->pci_dev, 0x51, 0x13);
#endif
break;
case ide_dma_timeout:
@@ -838,10 +838,10 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
- byte regstate = hwif->channel ? 0x54 : 0x50;
- byte reginfo = hwif->channel ? 0x56 : 0x52;
+ byte regstate = hwif->unit ? 0x54 : 0x50;
+ byte reginfo = hwif->unit ? 0x56 : 0x52;
byte dma_stat;
switch (func) {
@@ -899,23 +899,23 @@ int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
void hpt3xx_reset (ide_drive_t *drive)
{
#if 0
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- byte reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
+ unsigned long high_16 = pci_resource_start(drive->channel->pci_dev, 4);
+ byte reset = (drive->channel->unit) ? 0x80 : 0x40;
byte reg59h = 0;
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x59, &reg59h);
+ pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h|reset);
+ pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h);
#endif
}
#if 0
static int hpt3xx_tristate (ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
- byte reset = (hwif->channel) ? 0x80 : 0x40;
- byte state_reg = (hwif->channel) ? 0x57 : 0x53;
+ byte reset = (hwif->unit) ? 0x80 : 0x40;
+ byte state_reg = (hwif->unit) ? 0x57 : 0x53;
byte reg59h = 0;
byte regXXh = 0;
@@ -951,7 +951,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
#define TRISTATE_BIT 0x8000
static int hpt370_busproc(ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte tristate, resetmask, bus_reg;
u16 tri_reg;
@@ -960,7 +960,7 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
hwif->bus_state = state;
- if (hwif->channel) {
+ if (hwif->unit) {
/* secondary channel */
tristate = 0x56;
resetmask = 0x80;
@@ -1136,10 +1136,10 @@ unsigned int __init pci_init_hpt366(struct pci_dev *dev)
return dev->irq;
}
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
+unsigned int __init ata66_hpt366(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte regmask = (hwif->channel) ? 0x01 : 0x02;
+ byte regmask = (hwif->unit) ? 0x01 : 0x02;
pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
#ifdef DEBUG
@@ -1150,7 +1150,7 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
return ((ata66 & regmask) ? 0 : 1);
}
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
+void __init ide_init_hpt366(struct ata_channel *hwif)
{
int hpt_rev;
@@ -1210,12 +1210,12 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_hpt366(struct ata_channel *hwif, unsigned long dmabase)
{
byte masterdma = 0, slavedma = 0;
byte dma_new = 0, dma_old = inb(dmabase+2);
- byte primary = hwif->channel ? 0x4b : 0x43;
- byte secondary = hwif->channel ? 0x4f : 0x47;
+ byte primary = hwif->unit ? 0x4b : 0x43;
+ byte secondary = hwif->unit ? 0x4f : 0x47;
unsigned long flags;
__save_flags(flags); /* local CPU only */
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index 7a71ef13db40..4212382f45d6 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -321,7 +321,7 @@ void __init init_ht6560b (void)
ide_hwifs[1].serialized = 1; /* is this needed? */
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
/*
* Setting default configurations for drives
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index 598cb6c98d88..4b73826053da 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -224,7 +224,7 @@ static iftype_t __init icside_identifyif (struct expansion_card *ec)
#define NR_ENTRIES 256
#define TABLE_SIZE (NR_ENTRIES * 8)
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
{
request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
struct scatterlist *sg = hwif->sg_table;
@@ -245,16 +245,16 @@ static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
static int
icside_build_dmatable(ide_drive_t *drive, int reading)
{
- return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+ return drive->channel->sg_nents = ide_build_sglist(drive->channel, HWGROUP(drive)->rq);
}
/* Teardown mappings after DMA has completed. */
static void icside_destroy_dmatable(ide_drive_t *drive)
{
- struct scatterlist *sg = HWIF(drive)->sg_table;
- int nents = HWIF(drive)->sg_nents;
+ struct scatterlist *sg = drive->channel->sg_table;
+ int nents = drive->channel->sg_nents;
- pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+ pci_unmap_sg(NULL, sg, nents, drive->channel->sg_dma_direction);
}
/*
@@ -333,7 +333,7 @@ static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
int i;
byte stat, dma_stat;
- dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
@@ -356,7 +356,7 @@ static int
icside_dma_check(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int autodma = hwif->autodma;
int xfer_mode = XFER_PIO_2;
int func = ide_dma_off_quietly;
@@ -397,7 +397,7 @@ icside_dma_verbose(ide_drive_t *drive)
static int
icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int count, reading = 0;
switch (func) {
@@ -436,7 +436,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
*/
set_dma_speed(hwif->hw.dma, drive->drive_data);
- set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+ set_dma_sg(hwif->hw.dma, drive->channel->sg_table, count);
set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
: DMA_MODE_WRITE);
@@ -444,6 +444,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
IDE_COMMAND_REG);
@@ -473,7 +474,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
+icside_setup_dma(struct ata_channel *hwif, int autodma)
{
printk(" %s: SG-DMA", hwif->name);
@@ -498,7 +499,7 @@ failed:
return 0;
}
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
{
if (hwif->sg_table) {
kfree(hwif->sg_table);
@@ -507,10 +508,10 @@ void ide_release_dma(ide_hwif_t *hwif)
}
#endif
-static ide_hwif_t *
+static struct ata_channel *
icside_find_hwif(unsigned long dataport)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
int index;
for (index = 0; index < MAX_HWIFS; ++index) {
@@ -530,11 +531,11 @@ found:
return hwif;
}
-static ide_hwif_t *
+static struct ata_channel *
icside_setup(unsigned long base, struct cardinfo *info, int irq)
{
unsigned long port = base + info->dataoffset;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
hwif = icside_find_hwif(base);
if (hwif) {
@@ -562,7 +563,7 @@ icside_setup(unsigned long base, struct cardinfo *info, int irq)
static int __init icside_register_v5(struct expansion_card *ec, int autodma)
{
unsigned long slot_port;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
slot_port = ecard_address(ec, ECARD_MEMC, 0);
@@ -584,7 +585,8 @@ static int __init icside_register_v5(struct expansion_card *ec, int autodma)
static int __init icside_register_v6(struct expansion_card *ec, int autodma)
{
unsigned long slot_port, port;
- ide_hwif_t *hwif, *mate;
+ struct ata_channel *hwif;
+ struct ata_channel *mate;
int sel = 0;
slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
@@ -620,7 +622,7 @@ static int __init icside_register_v6(struct expansion_card *ec, int autodma)
hwif->hw.dma = ec->dma;
hwif->hw.priv = (void *)
(port + ICS_ARCIN_V6_INTRSTAT_1);
- hwif->channel = 0;
+ hwif->unit = 0;
icside_setup_dma(hwif, autodma);
}
if (mate) {
@@ -629,7 +631,7 @@ static int __init icside_register_v6(struct expansion_card *ec, int autodma)
mate->hw.dma = ec->dma;
mate->hw.priv = (void *)
(port + ICS_ARCIN_V6_INTRSTAT_2);
- mate->channel = 1;
+ mate->unit = 1;
icside_setup_dma(mate, autodma);
}
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index c0b2d7057be0..e5ab895df4d0 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -723,9 +723,9 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
if (info->dma) {
if (info->cmd == READ) {
- info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+ info->dma = !drive->channel->dmaproc(ide_dma_read, drive);
} else if (info->cmd == WRITE) {
- info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+ info->dma = !drive->channel->dmaproc(ide_dma_write, drive);
} else {
printk("ide-cd: DMA set, but not allowed\n");
}
@@ -740,11 +740,12 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
if (IDE_CONTROL_REG)
OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-
+
if (info->dma)
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
return ide_started;
@@ -787,6 +788,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
}
/* Arm the interrupt handler. */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
/* Send the command to the device. */
@@ -899,8 +901,8 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive)))
+ drive->channel->dmaproc(ide_dma_off, drive);
}
if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -1005,7 +1007,9 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
/* Done moving data!
Wait for another interrupt. */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+
return ide_started;
}
@@ -1335,6 +1339,8 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
}
/* Now we wait for another interrupt. */
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
return ide_started;
}
@@ -1476,9 +1482,9 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+ if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive))) {
printk("ide-cd: write dma error\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
}
}
@@ -1559,6 +1565,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
}
/* re-arm handler */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
return ide_started;
}
@@ -2021,14 +2028,14 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
/* Now try to get the total cdrom capacity. */
minor = (drive->select.b.unit) << PARTN_BITS;
- dev = mk_kdev(HWIF(drive)->major, minor);
+ dev = mk_kdev(drive->channel->major, minor);
stat = cdrom_get_last_written(dev, &toc->capacity);
if (stat)
stat = cdrom_read_capacity(drive, &toc->capacity, sense);
if (stat)
toc->capacity = 0x1fffff;
- HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+ drive->channel->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
/* Remember that we've read this stuff. */
@@ -2487,7 +2494,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
struct cdrom_device_info *devinfo = &info->devinfo;
int minor = (drive->select.b.unit) << PARTN_BITS;
- devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
+ devinfo->dev = mk_kdev(drive->channel->major, minor);
devinfo->ops = &ide_cdrom_dops;
devinfo->mask = 0;
*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2519,7 +2526,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
*/
devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
+ drive->channel->major, minor,
S_IFBLK | S_IRUGO | S_IWUGO,
ide_fops, NULL);
@@ -2661,7 +2668,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
- (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+ (void) drive->channel->dmaproc(ide_dma_verbose, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
@@ -2684,8 +2691,8 @@ int ide_cdrom_setup (ide_drive_t *drive)
/*
* default to read-only always and fix latter at the bottom
*/
- set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
- set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+ set_device_ro(mk_kdev(drive->channel->major, minor), 1);
+ set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2807,7 +2814,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
nslots = ide_cdrom_probe_capabilities (drive);
if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
- set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
+ set_device_ro(mk_kdev(drive->channel->major, minor), 0);
if (ide_cdrom_register (drive, nslots)) {
printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2854,7 +2861,7 @@ void ide_cdrom_release (struct inode *inode, struct file *file,
static
int ide_cdrom_check_media_change (ide_drive_t *drive)
{
- return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
+ return cdrom_media_changed(mk_kdev (drive->channel->major,
(drive->select.b.unit) << PARTN_BITS));
}
@@ -2875,14 +2882,14 @@ void ide_cdrom_revalidate (ide_drive_t *drive)
/* for general /dev/cdrom like mounting, one big disc */
drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
- HWIF(drive)->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
+ drive->channel->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
/*
* reset block size, ide_revalidate_disk incorrectly sets it to
* 1024 even for CDROM's
*/
- blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
- set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+ blk_size[drive->channel->major] = drive->channel->gd->sizes;
+ set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
}
static
@@ -2984,15 +2991,14 @@ int ide_cdrom_init(void)
memset (info, 0, sizeof (struct cdrom_info));
drive->driver_data = info;
- /* ATA-PATTERN */
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
if (ide_cdrom_setup (drive)) {
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
if (ide_cdrom_cleanup (drive))
printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
continue;
}
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
failed--;
}
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 5f598354bd6a..7a721387251d 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -51,7 +51,7 @@
#include <asm/io.h>
#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+#define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
#else
#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */
#endif
@@ -106,51 +106,7 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
return 0; /* lba_capacity value may be bad */
}
-static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block);
-
-/*
- * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
- * otherwise, to address sectors. It also takes care of issuing special
- * DRIVE_CMDs.
- */
-static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
-{
- /*
- * Wait until all request have bin finished.
- */
-
- while (drive->blocked) {
- yield();
- // panic("ide: Request while drive blocked?");
- }
-
- if (!(rq->flags & REQ_CMD)) {
- blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
- ide_end_request(drive, 0);
- return ide_stopped;
- }
-
- if (IS_PDC4030_DRIVE) {
- extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
-
- return promise_rw_disk(drive, rq, block);
- }
-
- /* 48-bit LBA */
- if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
- return lba48_do_request(drive, rq, block);
-
- /* 28-bit LBA */
- if (drive->select.b.lba)
- return lba28_do_request(drive, rq, block);
-
- /* 28-bit CHS */
- return chs_do_request(drive, rq, block);
-}
-
-static task_ioreg_t get_command(ide_drive_t *drive, int cmd)
+static u8 get_command(ide_drive_t *drive, int cmd)
{
int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
@@ -158,20 +114,38 @@ static task_ioreg_t get_command(ide_drive_t *drive, int cmd)
lba48bit = drive->addressing;
#endif
- if (cmd == READ) {
- if (drive->using_dma)
- return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
- else if (drive->mult_count)
- return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
- else
- return (lba48bit) ? WIN_READ_EXT : WIN_READ;
- } else if (cmd == WRITE) {
- if (drive->using_dma)
- return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
- else if (drive->mult_count)
- return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
- else
- return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+ if (lba48bit) {
+ if (cmd == READ) {
+ if (drive->using_dma)
+ return WIN_READDMA_EXT;
+ else if (drive->mult_count)
+ return WIN_MULTREAD_EXT;
+ else
+ return WIN_READ_EXT;
+ } else if (cmd == WRITE) {
+ if (drive->using_dma)
+ return WIN_WRITEDMA_EXT;
+ else if (drive->mult_count)
+ return WIN_MULTWRITE_EXT;
+ else
+ return WIN_WRITE_EXT;
+ }
+ } else {
+ if (cmd == READ) {
+ if (drive->using_dma)
+ return WIN_READDMA;
+ else if (drive->mult_count)
+ return WIN_MULTREAD;
+ else
+ return WIN_READ;
+ } else if (cmd == WRITE) {
+ if (drive->using_dma)
+ return WIN_WRITEDMA;
+ else if (drive->mult_count)
+ return WIN_MULTWRITE;
+ else
+ return WIN_WRITE;
+ }
}
return WIN_NOP;
}
@@ -183,27 +157,27 @@ static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, un
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
unsigned int track = (block / drive->sect);
unsigned int sect = (block % drive->sect) + 1;
unsigned int head = (track % drive->head);
unsigned int cyl = (track / drive->head);
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;
taskfile.sector_count = sectors;
+
taskfile.sector_number = sect;
taskfile.low_cylinder = cyl;
taskfile.high_cylinder = (cyl>>8);
+
taskfile.device_head = head;
taskfile.device_head |= drive->select.all;
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -214,14 +188,17 @@ static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, un
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
}
static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -231,22 +208,22 @@ static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq,
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = sectors;
taskfile.sector_number = block;
- taskfile.low_cylinder = (block>>=8);
- taskfile.high_cylinder = (block>>=8);
- taskfile.device_head = ((block>>8)&0x0f);
+ taskfile.low_cylinder = (block >>= 8);
+
+ taskfile.high_cylinder = (block >>= 8);
+
+ taskfile.device_head = ((block >> 8) & 0x0f);
taskfile.device_head |= drive->select.all;
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -257,14 +234,17 @@ static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq,
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
}
/*
@@ -280,10 +260,8 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
sectors = rq->nr_sectors;
if (sectors == 65536)
@@ -297,16 +275,18 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
hobfile.sector_count = 0x00;
}
- taskfile.sector_number = block; /* low lba */
- taskfile.low_cylinder = (block>>=8); /* mid lba */
- taskfile.high_cylinder = (block>>=8); /* hi lba */
- hobfile.sector_number = (block>>=8); /* low lba */
- hobfile.low_cylinder = (block>>=8); /* mid lba */
- hobfile.high_cylinder = (block>>=8); /* hi lba */
+ taskfile.sector_number = block; /* low lba */
+ taskfile.low_cylinder = (block >>= 8); /* mid lba */
+ taskfile.high_cylinder = (block >>= 8); /* hi lba */
+
+ hobfile.sector_number = (block >>= 8); /* low lba */
+ hobfile.low_cylinder = (block >>= 8); /* mid lba */
+ hobfile.high_cylinder = (block >>= 8); /* hi lba */
+
taskfile.device_head = drive->select.all;
hobfile.device_head = taskfile.device_head;
hobfile.control = (drive->ctl|0x80);
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -317,14 +297,57 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
+}
+
+/*
+ * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
+ * otherwise, to address sectors. It also takes care of issuing special
+ * DRIVE_CMDs.
+ */
+static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+ /*
+ * Wait until all request have bin finished.
+ */
+
+ while (drive->blocked) {
+ yield();
+ printk("ide: Request while drive blocked?");
+ }
+
+ if (!(rq->flags & REQ_CMD)) {
+ blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
+ ide_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ if (IS_PDC4030_DRIVE) {
+ extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ return promise_rw_disk(drive, rq, block);
+ }
+
+ /* 48-bit LBA */
+ if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
+ return lba48_do_request(drive, rq, block);
+
+ /* 28-bit LBA */
+ if (drive->select.b.lba)
+ return lba28_do_request(drive, rq, block);
+
+ /* 28-bit CHS */
+ return chs_do_request(drive, rq, block);
}
static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -333,10 +356,14 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr
if (drive->removable && drive->usage == 1) {
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
check_disk_change(inode->i_rdev);
+
taskfile.command = WIN_DOORLOCK;
+
/*
* Ignore the return code from door_lock,
* since the open() has already succeeded,
@@ -353,13 +380,14 @@ static int idedisk_flushcache(ide_drive_t *drive)
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
- if (drive->id->cfs_enable_2 & 0x2400) {
- taskfile.command = WIN_FLUSH_CACHE_EXT;
- } else {
- taskfile.command = WIN_FLUSH_CACHE;
- }
+ if (drive->id->cfs_enable_2 & 0x2400)
+ taskfile.command = WIN_FLUSH_CACHE_EXT;
+ else
+ taskfile.command = WIN_FLUSH_CACHE;
+
return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
}
@@ -368,9 +396,12 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t
if (drive->removable && !drive->usage) {
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
invalidate_bdev(inode->i_bdev, 0);
+
taskfile.command = WIN_DOORUNLOCK;
if (drive->doorlocking &&
ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
@@ -404,21 +435,23 @@ static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX;
- args.handler = task_no_data_intr;
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_READ_NATIVE_MAX;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
- | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
- | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
- | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ if ((args.taskfile.command & 0x01) == 0) {
+ addr = ((args.taskfile.device_head & 0x0f) << 24)
+ | (args.taskfile.high_cylinder << 16)
+ | (args.taskfile.low_cylinder << 8)
+ | args.taskfile.sector_number;
}
+
addr++; /* since the return value is (maxlba - 1), we add 1 */
+
return addr;
}
@@ -430,24 +463,26 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT;
- args.handler = task_no_data_intr;
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_READ_NATIVE_MAX_EXT;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
- ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
- (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
- u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
- ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
- (args.tfRegister[IDE_SECTOR_OFFSET]);
+ if ((args.taskfile.command & 0x01) == 0) {
+ u32 high = (args.hobfile.high_cylinder << 16) |
+ (args.hobfile.low_cylinder << 8) |
+ args.hobfile.sector_number;
+ u32 low = (args.taskfile.high_cylinder << 16) |
+ (args.taskfile.low_cylinder << 8) |
+ args.taskfile.sector_number;
addr = ((__u64)high << 24) | low;
}
+
addr++; /* since the return value is (maxlba - 1), we add 1 */
+
return addr;
}
@@ -464,20 +499,22 @@ static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long a
addr_req--;
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
- args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
- args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
- args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX;
- args.handler = task_no_data_intr;
+
+ args.taskfile.sector_number = (addr_req >> 0);
+ args.taskfile.low_cylinder = (addr_req >> 8);
+ args.taskfile.high_cylinder = (addr_req >> 16);
+
+ args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
+ args.taskfile.command = WIN_SET_MAX;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, read new maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
- | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
- | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
- | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ if ((args.taskfile.command & 0x01) == 0) {
+ addr_set = ((args.taskfile.device_head & 0x0f) << 24)
+ | (args.taskfile.high_cylinder << 16)
+ | (args.taskfile.low_cylinder << 8)
+ | args.taskfile.sector_number;
}
addr_set++;
return addr_set;
@@ -491,27 +528,31 @@ static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsign
addr_req--;
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
- args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
- args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT;
- args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40;
- args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
- args.handler = task_no_data_intr;
+
+ args.taskfile.sector_number = (addr_req >> 0);
+ args.taskfile.low_cylinder = (addr_req >>= 8);
+ args.taskfile.high_cylinder = (addr_req >>= 8);
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_SET_MAX_EXT;
+
+ args.hobfile.sector_number = (addr_req >>= 8);
+ args.hobfile.low_cylinder = (addr_req >>= 8);
+ args.hobfile.high_cylinder = (addr_req >>= 8);
+
+ args.hobfile.device_head = 0x40;
+ args.hobfile.control = (drive->ctl | 0x80);
+
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
- ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
- (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
- u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
- ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
- (args.tfRegister[IDE_SECTOR_OFFSET]);
+ if ((args.taskfile.command & 0x01) == 0) {
+ u32 high = (args.hobfile.high_cylinder << 16) |
+ (args.hobfile.low_cylinder << 8) |
+ args.hobfile.sector_number;
+ u32 low = (args.taskfile.high_cylinder << 16) |
+ (args.taskfile.low_cylinder << 8) |
+ args.taskfile.sector_number;
addr_set = ((__u64)high << 24) | low;
}
return addr_set;
@@ -572,10 +613,10 @@ static void init_idedisk_capacity (ide_drive_t *drive)
drive->select.b.lba = 1;
drive->id->lba_capacity_2 = capacity_2;
}
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
printk("%s: setmax_ext LBA %llu, native %llu\n",
drive->name, set_max_ext, capacity_2);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
}
drive->bios_cyl = drive->cyl;
drive->capacity48 = capacity_2;
@@ -598,10 +639,10 @@ static void init_idedisk_capacity (ide_drive_t *drive)
drive->select.b.lba = 1;
drive->id->lba_capacity = capacity;
}
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
printk("%s: setmax LBA %lu, native %lu\n",
drive->name, set_max, capacity);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
}
drive->capacity = capacity;
@@ -643,7 +684,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
taskfile.command = WIN_SPECIFY;
handler = set_geometry_intr;;
}
- do_taskfile(drive, &taskfile, &hobfile, handler);
+ ata_taskfile(drive, &taskfile, &hobfile, handler, NULL, NULL);
} else if (s->b.recalibrate) {
s->b.recalibrate = 0;
if (!IS_PDC4030_DRIVE) {
@@ -653,7 +694,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->sect;
taskfile.command = WIN_RESTORE;
- do_taskfile(drive, &taskfile, &hobfile, recal_intr);
+ ata_taskfile(drive, &taskfile, &hobfile, recal_intr, NULL, NULL);
}
} else if (s->b.set_multmode) {
s->b.set_multmode = 0;
@@ -666,7 +707,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->mult_req;
taskfile.command = WIN_SETMULT;
- do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
+ ata_taskfile(drive, &taskfile, &hobfile, set_multmode_intr, NULL, NULL);
}
} else if (s->all) {
int special = s->all;
@@ -915,6 +956,9 @@ static int idedisk_suspend(struct device *dev, u32 state, u32 level)
* already been done...
*/
+ if (level != SUSPEND_SAVE_STATE)
+ return 0;
+
/* wait until all commands are finished */
printk("ide_disk_suspend()\n");
while (HWGROUP(drive)->handler)
@@ -934,6 +978,9 @@ static int idedisk_suspend(struct device *dev, u32 state, u32 level)
static int idedisk_resume(struct device *dev, u32 level)
{
ide_drive_t *drive = dev->driver_data;
+
+ if (level != RESUME_RESTORE_STATE)
+ return 0;
if (!drive->blocked)
panic("ide: Resume but not suspended?\n");
@@ -979,7 +1026,7 @@ static void idedisk_setup(ide_drive_t *drive)
}
}
for (i = 0; i < MAX_DRIVES; ++i) {
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive != &hwif->drives[i])
continue;
@@ -997,7 +1044,7 @@ static void idedisk_setup(ide_drive_t *drive)
sprintf(drive->device.bus_id, "%d", drvid);
sprintf(drive->device.name, "ide-disk");
drive->device.driver = &idedisk_devdrv;
- drive->device.parent = &HWIF(drive)->device;
+ drive->device.parent = &drive->channel->dev;
drive->device.driver_data = drive;
device_register(&drive->device);
}
@@ -1045,11 +1092,11 @@ static void idedisk_setup(ide_drive_t *drive)
if (id->buf_size)
printk (" w/%dKiB Cache", id->buf_size/2);
- printk(", CHS=%d/%d/%d",
+ printk(", CHS=%d/%d/%d",
drive->bios_cyl, drive->bios_head, drive->bios_sect);
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
- (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+ (void) drive->channel->dmaproc(ide_dma_verbose, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
@@ -1074,8 +1121,11 @@ static void idedisk_setup(ide_drive_t *drive)
(void) probe_lba_addressing(drive, 1);
}
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
{
+ if (!drive)
+ return 0;
+
put_device(&drive->device);
if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
if (idedisk_flushcache(drive))
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 9fade24a9c08..b221a3bf3ad1 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -204,7 +204,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
{
byte stat, dma_stat;
- dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
@@ -219,7 +219,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
return ide_error(drive, "dma_intr", stat);
}
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
{
request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
struct scatterlist *sg = hwif->sg_table;
@@ -238,7 +238,7 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
}
-static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_raw_build_sglist(struct ata_channel *hwif, struct request *rq)
{
struct scatterlist *sg = hwif->sg_table;
int nents = 0;
@@ -285,7 +285,7 @@ static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
*/
int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int *table = hwif->dmatable_cpu;
#ifdef CONFIG_BLK_DEV_TRM290
unsigned int is_trm290_chipset = (hwif->chipset == ide_trm290);
@@ -371,11 +371,11 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
/* Teardown mappings after DMA has completed. */
void ide_destroy_dmatable (ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- struct scatterlist *sg = HWIF(drive)->sg_table;
- int nents = HWIF(drive)->sg_nents;
+ struct pci_dev *dev = drive->channel->pci_dev;
+ struct scatterlist *sg = drive->channel->sg_table;
+ int nents = drive->channel->sg_nents;
- pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+ pci_unmap_sg(dev, sg, nents, drive->channel->sg_dma_direction);
}
/*
@@ -462,7 +462,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
{
int config_allows_dma = 1;
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
#ifdef CONFIG_IDEDMA_ONLYDISK
if (drive->type != ATA_DISK)
@@ -502,7 +502,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
*/
static int dma_timer_expiry(ide_drive_t *drive)
{
- byte dma_stat = inb(HWIF(drive)->dma_base+2);
+ byte dma_stat = inb(drive->channel->dma_base+2);
#ifdef DEBUG
printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
@@ -525,11 +525,11 @@ static void ide_toggle_bounce(ide_drive_t *drive, int on)
{
u64 addr = BLK_BOUNCE_HIGH;
- if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+ if (on && drive->type == ATA_DISK && drive->channel->highmem) {
if (!PCI_DMA_BUS_IS_PHYS)
addr = BLK_BOUNCE_ANY;
else
- addr = HWIF(drive)->pci_dev->dma_mask;
+ addr = drive->channel->pci_dev->dma_mask;
}
blk_queue_bounce_limit(&drive->queue, addr);
@@ -553,7 +553,7 @@ static void ide_toggle_bounce(ide_drive_t *drive, int on)
*/
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
byte unit = (drive->select.b.unit & 0x01);
unsigned int count, reading = 0, set_high = 1;
@@ -588,17 +588,19 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
drive->waiting_for_dma = 1;
if (drive->type != ATA_DISK)
return 0;
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
ide_task_t *args = HWGROUP(drive)->rq->special;
- OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+ OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
} else if (drive->addressing) {
OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
} else {
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
}
- return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+ return drive->channel->dmaproc(ide_dma_begin, drive);
case ide_dma_begin:
/* Note that this is done *after* the cmd has
* been issued to the drive, as per the BM-IDE spec.
@@ -644,7 +646,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/*
* Needed for allowing full modular support of ide-driver
*/
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
{
if (!hwif->dma_base)
return;
@@ -660,7 +662,7 @@ void ide_release_dma(ide_hwif_t *hwif)
kfree(hwif->sg_table);
hwif->sg_table = NULL;
}
- if ((hwif->dma_extra) && (hwif->channel == 0))
+ if ((hwif->dma_extra) && (hwif->unit == 0))
release_region((hwif->dma_base + 16), hwif->dma_extra);
release_region(hwif->dma_base, 8);
hwif->dma_base = 0;
@@ -669,7 +671,7 @@ void ide_release_dma(ide_hwif_t *hwif)
/*
* This can be called for a dynamically installed interface. Don't __init it
*/
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+void ide_setup_dma(struct ata_channel *hwif, unsigned long dma_base, unsigned int num_ports)
{
printk(" %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
if (check_region(dma_base, num_ports)) {
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index 840abbaff138..748b1e629740 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -2,7 +2,7 @@
* linux/drivers/block/ide-features.c Version 0.04 June 9, 2000
*
* Copyright (C) 1999-2000 Linus Torvalds & authors (see below)
- *
+ *
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
*
* Extracts if ide.c to address the evolving transfer rate code for
@@ -134,7 +134,7 @@ int ide_driveid_update (ide_drive_t *drive)
struct hd_driveid *id;
unsigned long timeout, flags;
- SELECT_MASK(HWIF(drive), drive, 1);
+ SELECT_MASK(drive->channel, drive, 1);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
ide_delay_50ms();
@@ -142,20 +142,20 @@ int ide_driveid_update (ide_drive_t *drive)
timeout = jiffies + WAIT_WORSTCASE;
do {
if (0 < (signed long)(jiffies - timeout)) {
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
return 0; /* drive timed-out */
}
ide_delay_50ms(); /* give drive a breather */
} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */
if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
printk("%s: CHECK for good STATUS\n", drive->name);
return 0;
}
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only; some systems need this */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
if (!id) {
__restore_flags(flags); /* local CPU only */
@@ -186,11 +186,11 @@ int ide_driveid_update (ide_drive_t *drive)
*/
int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
{
- if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
- (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
- (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
- if (!HWIF(drive)->udma_four) {
- printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
+ if ((args->taskfile.command == WIN_SETFEATURES) &&
+ (args->taskfile.sector_number > XFER_UDMA_2) &&
+ (args->taskfile.feature == SETFEATURES_XFER)) {
+ if (!drive->channel->udma_four) {
+ printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->channel->name);
return 1;
}
#ifndef CONFIG_IDEDMA_IVB
@@ -213,9 +213,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
*/
int set_transfer (ide_drive_t *drive, ide_task_t *args)
{
- if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
- (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
- (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+ if ((args->taskfile.command == WIN_SETFEATURES) &&
+ (args->taskfile.sector_number >= XFER_SW_DMA_0) &&
+ (args->taskfile.feature == SETFEATURES_XFER) &&
(drive->id->dma_ultra ||
drive->id->dma_mword ||
drive->id->dma_1word))
@@ -229,7 +229,7 @@ int set_transfer (ide_drive_t *drive, ide_task_t *args)
*/
byte eighty_ninty_three (ide_drive_t *drive)
{
- return ((byte) ((HWIF(drive)->udma_four) &&
+ return ((byte) ((drive->channel->udma_four) &&
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
#endif /* CONFIG_IDEDMA_IVB */
@@ -249,8 +249,9 @@ byte eighty_ninty_three (ide_drive_t *drive)
*/
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- int i, error = 1;
+ struct ata_channel *hwif = drive->channel;
+ int i;
+ int error = 1;
byte stat;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
@@ -269,8 +270,8 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
*/
disable_irq(hwif->irq); /* disable_irq_nosync ?? */
udelay(1);
- SELECT_DRIVE(HWIF(drive), drive);
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_DRIVE(drive->channel, drive);
+ SELECT_MASK(drive->channel, drive, 0);
udelay(1);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
@@ -310,7 +311,7 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
}
}
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
enable_irq(hwif->irq);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 7581132da95b..e988e17cee69 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -902,7 +902,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+ if (drive->channel->dmaproc(ide_dma_end, drive)) {
set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
@@ -945,7 +945,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
return ide_stopped;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -968,6 +968,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
idefloppy_discard_data (drive,bcount.all);
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
return ide_started;
}
@@ -990,7 +991,9 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+
return ide_started;
}
@@ -1014,8 +1017,11 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
return ide_stopped;
}
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */
atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+
return ide_started;
}
@@ -1055,17 +1061,19 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
return ide_stopped;
}
- /*
+ /*
* The following delay solves a problem with ATAPI Zip 100 drives where the
* Busy flag was apparently being deasserted before the unit was ready to
* receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
- * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
+ * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
* not be actually used until after the packet is moved in about 50 msec.
*/
- ide_set_handler (drive,
- &idefloppy_pc_intr, /* service routine for packet command */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler (drive,
+ &idefloppy_pc_intr, /* service routine for packet command */
floppy->ticks, /* wait this long before "failing" */
&idefloppy_transfer_pc2); /* fail == transfer_pc2 */
+
return ide_started;
}
@@ -1117,10 +1125,10 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
- (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) drive->channel->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
- dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok=!drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (IDE_CONTROL_REG)
@@ -1133,7 +1141,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1143,8 +1151,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
} else {
pkt_xfer_routine = &idefloppy_transfer_pc; /* immediate */
}
-
+
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
return ide_started;
@@ -1156,7 +1165,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
static void idefloppy_rw_callback (ide_drive_t *drive)
{
-#if IDEFLOPPY_DEBUG_LOG
+#if IDEFLOPPY_DEBUG_LOG
printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
#endif /* IDEFLOPPY_DEBUG_LOG */
@@ -2004,7 +2013,7 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
(void) idefloppy_get_capacity (drive);
idefloppy_add_settings(drive);
for (i = 0; i < MAX_DRIVES; ++i) {
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive != &hwif->drives[i]) continue;
hwif->gd->de_arr[i] = drive->de;
@@ -2109,10 +2118,9 @@ int idefloppy_init (void)
kfree (floppy);
continue;
}
- /* ATA-PATTERN */
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
idefloppy_setup (drive, floppy);
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
failed--;
}
diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
index 7a203365420a..0671559114b1 100644
--- a/drivers/ide/ide-geometry.c
+++ b/drivers/ide/ide-geometry.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
+#include <linux/types.h>
#include <linux/ide.h>
#include <linux/mc146818rtc.h>
#include <asm/io.h>
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index d8c32aca8a7b..486f3bca98cd 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -39,45 +39,45 @@
#ifdef CONFIG_BLK_DEV_AEC62XX
extern unsigned int pci_init_aec62xx(struct pci_dev *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_aec62xx(struct ata_channel *);
+extern void ide_init_aec62xx(struct ata_channel *);
+extern void ide_dmacapable_aec62xx(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_ALI15X3
extern unsigned int pci_init_ali15x3(struct pci_dev *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_ali15x3(struct ata_channel *);
+extern void ide_init_ali15x3(struct ata_channel *);
+extern void ide_dmacapable_ali15x3(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_AMD74XX
extern unsigned int pci_init_amd74xx(struct pci_dev *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_amd74xx(struct ata_channel *);
+extern void ide_init_amd74xx(struct ata_channel *);
+extern void ide_dmacapable_amd74xx(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_CMD64X
extern unsigned int pci_init_cmd64x(struct pci_dev *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_cmd64x(struct ata_channel *);
+extern void ide_init_cmd64x(struct ata_channel *);
+extern void ide_dmacapable_cmd64x(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_CY82C693
extern unsigned int pci_init_cy82c693(struct pci_dev *);
-extern void ide_init_cy82c693(ide_hwif_t *);
+extern void ide_init_cy82c693(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_CS5530
extern unsigned int pci_init_cs5530(struct pci_dev *);
-extern void ide_init_cs5530(ide_hwif_t *);
+extern void ide_init_cs5530(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_HPT34X
extern unsigned int pci_init_hpt34x(struct pci_dev *);
-extern void ide_init_hpt34x(ide_hwif_t *);
+extern void ide_init_hpt34x(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_HPT366
@@ -85,9 +85,9 @@ extern byte hpt363_shared_irq;
extern byte hpt363_shared_pin;
extern unsigned int pci_init_hpt366(struct pci_dev *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_hpt366(struct ata_channel *);
+extern void ide_init_hpt366(struct ata_channel *);
+extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long);
#else
/* FIXME: those have to be killed */
static byte hpt363_shared_irq;
@@ -95,69 +95,69 @@ static byte hpt363_shared_pin;
#endif
#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
+extern void ide_init_ns87415(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
+extern void ide_init_opti621(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_PDC_ADMA
extern unsigned int pci_init_pdcadma(struct pci_dev *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_pdcadma(struct ata_channel *);
+extern void ide_init_pdcadma(struct ata_channel *);
+extern void ide_dmacapable_pdcadma(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_PDC202XX
extern unsigned int pci_init_pdc202xx(struct pci_dev *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
+extern unsigned int ata66_pdc202xx(struct ata_channel *);
+extern void ide_init_pdc202xx(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_PIIX
extern unsigned int pci_init_piix(struct pci_dev *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-extern void ide_dmacapable_piix(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_piix(struct ata_channel *);
+extern void ide_init_piix(struct ata_channel *);
+extern void ide_dmacapable_piix(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_IT8172
extern unsigned int pci_init_it8172(struct pci_dev *);
-extern void ide_init_it8172(ide_hwif_t *);
+extern void ide_init_it8172(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
+extern void ide_init_rz1000(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SVWKS
extern unsigned int pci_init_svwks(struct pci_dev *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
+extern unsigned int ata66_svwks(struct ata_channel *);
+extern void ide_init_svwks(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SIS5513
extern unsigned int pci_init_sis5513(struct pci_dev *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
+extern unsigned int ata66_sis5513(struct ata_channel *);
+extern void ide_init_sis5513(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SL82C105
extern unsigned int pci_init_sl82c105(struct pci_dev *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
+extern void dma_init_sl82c105(struct ata_channel *, unsigned long);
+extern void ide_init_sl82c105(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
+extern void ide_init_trm290(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_VIA82CXXX
extern unsigned int pci_init_via82cxxx(struct pci_dev *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_via82cxxx(struct ata_channel *);
+extern void ide_init_via82cxxx(struct ata_channel *);
+extern void ide_dmacapable_via82cxxx(struct ata_channel *, unsigned long);
#endif
typedef struct ide_pci_enablebit_s {
@@ -181,9 +181,9 @@ typedef struct ide_pci_device_s {
unsigned short vendor;
unsigned short device;
unsigned int (*init_chipset)(struct pci_dev *dev);
- unsigned int (*ata66_check)(ide_hwif_t *hwif);
- void (*init_hwif)(ide_hwif_t *hwif);
- void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
+ unsigned int (*ata66_check)(struct ata_channel *hwif);
+ void (*init_hwif)(struct ata_channel *hwif);
+ void (*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
ide_pci_enablebit_t enablebits[2];
unsigned int bootable;
unsigned int extra;
@@ -229,6 +229,7 @@ static ide_pci_device_t pci_chipsets[] __initdata = {
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+ {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
#endif
#ifdef CONFIG_BLK_DEV_RZ1000
{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL, ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
@@ -328,10 +329,10 @@ static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *de
* Match a PCI IDE port against an entry in ide_hwifs[],
* based on io_base port if possible.
*/
-static ide_hwif_t __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
+static struct ata_channel __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
{
int h;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
/*
* Look for a hwif with matching io_base specified using
@@ -430,7 +431,7 @@ static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name)
/*
* Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
*/
-static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char *name)
+static unsigned long __init get_dma_base(struct ata_channel *hwif, int extra, const char *name)
{
unsigned long dma_base = 0;
struct pci_dev *dev = hwif->pci_dev;
@@ -441,7 +442,7 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
*/
if (hwif->mate && hwif->mate->dma_base)
- dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ dma_base = hwif->mate->dma_base - (hwif->unit ? 0 : 8);
else
dma_base = pci_resource_start(dev, 4);
@@ -451,7 +452,7 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
request_region(dma_base + 16, extra, name);
- dma_base += hwif->channel ? 8 : 0;
+ dma_base += hwif->unit ? 8 : 0;
hwif->dma_extra = extra;
if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
@@ -484,11 +485,11 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
/*
* Setup DMA transfers on a channel.
*/
-static void __init setup_channel_dma(ide_hwif_t *hwif, struct pci_dev *dev,
+static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev,
ide_pci_device_t *d,
int port,
u8 class_rev,
- int pciirq, ide_hwif_t **mate,
+ int pciirq, struct ata_channel **mate,
int autodma, unsigned short *pcicmd)
{
unsigned long dma_base;
@@ -535,14 +536,15 @@ static int __init setup_host_channel(struct pci_dev *dev,
ide_pci_device_t *d,
int port,
u8 class_rev,
- int pciirq, ide_hwif_t **mate,
+ int pciirq,
+ struct ata_channel **mate,
int autodma,
unsigned short *pcicmd)
{
unsigned long base = 0;
unsigned long ctl = 0;
ide_pci_enablebit_t *e = &(d->enablebits[port]);
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
u8 tmp;
if (port == 1) {
@@ -608,7 +610,7 @@ controller_ok:
hwif->chipset = ide_pci;
hwif->pci_dev = dev;
- hwif->channel = port;
+ hwif->unit = port;
if (!hwif->irq)
hwif->irq = pciirq;
@@ -669,7 +671,7 @@ static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
int pciirq = 0;
unsigned short pcicmd = 0;
unsigned short tried_config = 0;
- ide_hwif_t *mate = NULL;
+ struct ata_channel *mate = NULL;
unsigned int class_rev;
#ifdef CONFIG_IDEDMA_AUTO
diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
index 3a717a5f695d..5223f54a51e1 100644
--- a/drivers/ide/ide-pmac.c
+++ b/drivers/ide/ide-pmac.c
@@ -71,6 +71,9 @@ enum {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+# define BAD_DMA_DRIVE 0
+# define GOOD_DMA_DRIVE 1
+
typedef struct {
int accessTime;
int cycleTime;
@@ -124,10 +127,10 @@ struct pmu_sleep_notifier idepmac_sleep_notifier = {
static int
pmac_ide_find(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_ioreg_t base;
int i;
-
+
for (i=0; i<pmac_ide_count; i++) {
base = pmac_ide[i].regbase;
if (base && base == hwif->io_ports[0])
@@ -258,8 +261,8 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
save_flags(flags);
cli();
udelay(1);
- SELECT_DRIVE(HWIF(drive), drive);
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_DRIVE(drive->channel, drive);
+ SELECT_MASK(drive->channel, drive, 0);
udelay(1);
if(wait_for_ready(drive)) {
printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
@@ -507,7 +510,7 @@ pmac_ide_probe(void)
struct device_node *p, **pp, *removables, **rp;
unsigned long base;
int irq, big_delay;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
if (_machine != _MACH_Pmac)
return;
@@ -928,12 +931,12 @@ pmac_ide_check_dma(ide_drive_t *drive)
int enable = 1;
drive->using_dma = 0;
-
+
idx = pmac_ide_find(drive);
if (idx < 0)
return 0;
-
- if (drive->media == ide_floppy)
+
+ if (drive->type == ATA_FLOPPY)
enable = 0;
if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
enable = 0;
@@ -942,9 +945,9 @@ pmac_ide_check_dma(ide_drive_t *drive)
udma = 0;
ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
-
+
if(enable) {
- if (ata4 && (drive->media == ide_disk) &&
+ if (ata4 && (drive->type == ATA_DISK) &&
(id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
/* UltraDMA modes. */
drive->using_dma = pmac_ide_udma_enable(drive, idx);
@@ -991,8 +994,9 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
return 1;
drive->waiting_for_dma = 1;
- if (drive->media != ide_disk)
+ if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
IDE_COMMAND_REG);
@@ -1051,12 +1055,12 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
{
int j;
-
+
/* FIXME: We only handle the master IDE disk, we shoud
* try to fix CD-ROMs here
*/
- switch (drive->media) {
- case ide_disk:
+ switch (drive->type) {
+ case ATA_DISK:
/* Spin down the drive */
outb(0xa0, base+0x60);
outb(0x0, base+0x30);
@@ -1064,7 +1068,7 @@ static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
outb(0x0, base+0x40);
outb(0x0, base+0x50);
outb(0xe0, base+0x70);
- outb(0x2, base+0x160);
+ outb(0x2, base+0x160);
for (j = 0; j < 10; j++) {
int status;
mdelay(100);
@@ -1073,10 +1077,10 @@ static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
break;
}
break;
- case ide_cdrom:
+ case ATA_ROM:
// todo
break;
- case ide_floppy:
+ case ATA_FLOPPY:
// todo
break;
}
@@ -1094,7 +1098,7 @@ static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
DRIVER(drive)->media_change(drive);
/* We kick the VFS too (see fix in ide.c revalidate) */
- check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+ check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
/* We re-enable DMA on the drive if it was active. */
@@ -1198,7 +1202,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
break;
case PBOOK_SLEEP_NOW:
for (i = 0; i < pmac_ide_count; ++i) {
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int unlock = 0;
@@ -1258,8 +1262,8 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
mdelay(IDE_WAKEUP_DELAY_MS);
for (i = 0; i < pmac_ide_count; ++i) {
- ide_hwif_t *hwif;
- ide_drive_t *drive;
+ struct ata_channel *hwif;
+ ide_drive_t *drive;
int j, used_dma;
if ((base = pmac_ide[i].regbase) == 0)
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 462de4501072..818689eab6a6 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -13,7 +13,7 @@
*
* You should have received a copy of the GNU General Public License
* (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/ide.h>
@@ -57,7 +57,7 @@ struct pnp_dev_t {
static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
{
hw_regs_t hw;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
int index;
if (!enable)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 69444ac9a65d..a7857ced574b 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -118,7 +118,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
byte type = (id->config >> 8) & 0x1f;
printk("ATAPI ");
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+ if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
printk(" -- not supported on 2nd Promise port\n");
goto err_misc;
}
@@ -167,12 +167,16 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
*/
if (id->config & (1<<7))
drive->removable = 1;
+
/*
- * Prevent long system lockup probing later for non-existant
- * slave drive if the hwif is actually a flash memory card of some variety:
+ * FIXME: This is just plain ugly or plain unnecessary.
+ *
+ * Prevent long system lockup probing later for non-existant slave
+ * drive if the hwif is actually a flash memory card of some variety:
*/
+
if (drive_is_flashcard(drive)) {
- ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+ ide_drive_t *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
if (!mate->ata_flash) {
mate->present = 0;
mate->noprobe = 1;
@@ -182,8 +186,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
printk("ATA DISK drive\n");
/* Initialize our quirk list. */
- if (HWIF(drive)->quirkproc)
- drive->quirk_list = HWIF(drive)->quirkproc(drive);
+ if (drive->channel->quirkproc)
+ drive->quirk_list = drive->channel->quirkproc(drive);
return;
@@ -232,7 +236,7 @@ static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap */
#if CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030) {
+ if (drive->channel->chipset == ide_pdc4030) {
/* DC4030 hosted drives need their own identify... */
extern int pdc4030_identify(ide_drive_t *);
if (pdc4030_identify(drive)) {
@@ -270,7 +274,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
int autoprobe = 0;
unsigned long cookie = 0;
- if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+ if (IDE_CONTROL_REG && !drive->channel->irq) {
autoprobe = 1;
cookie = probe_irq_on();
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */
@@ -284,9 +288,9 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
GET_STAT(); /* clear drive IRQ */
udelay(5);
irq = probe_irq_off(cookie);
- if (!HWIF(drive)->irq) {
+ if (!drive->channel->irq) {
if (irq > 0)
- HWIF(drive)->irq = irq;
+ drive->channel->irq = irq;
else /* Mmmm.. multiple IRQs.. don't know which was ours */
printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
}
@@ -314,7 +318,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
static int do_probe (ide_drive_t *drive, byte cmd)
{
int rc;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive->present) { /* avoid waiting for inappropriate probes */
if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
return 4;
@@ -369,12 +373,12 @@ static int do_probe (ide_drive_t *drive, byte cmd)
/*
*
*/
-static void enable_nest (ide_drive_t *drive)
+static void enable_nest(ide_drive_t *drive)
{
unsigned long timeout;
- printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
- SELECT_DRIVE(HWIF(drive), drive);
+ printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
+ SELECT_DRIVE(drive->channel, drive);
ide_delay_50ms();
OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
timeout = jiffies + WAIT_WORSTCASE;
@@ -427,7 +431,7 @@ static inline void probe_for_drive (ide_drive_t *drive)
* ordered sanely. We deal with the CONTROL register
* separately.
*/
-static int hwif_check_regions (ide_hwif_t *hwif)
+static int hwif_check_regions(struct ata_channel *hwif)
{
int region_errors = 0;
@@ -453,20 +457,20 @@ static int hwif_check_regions (ide_hwif_t *hwif)
return(region_errors);
}
-static void hwif_register (ide_hwif_t *hwif)
+static void hwif_register(struct ata_channel *hwif)
{
/* Register this hardware interface within the global device tree.
*/
- sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
- sprintf(hwif->device.name, "ide");
- hwif->device.driver_data = hwif;
+ sprintf(hwif->dev.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
+ sprintf(hwif->dev.name, "ide");
+ hwif->dev.driver_data = hwif;
#ifdef CONFIG_BLK_DEV_IDEPCI
if (hwif->pci_dev)
- hwif->device.parent = &hwif->pci_dev->dev;
+ hwif->dev.parent = &hwif->pci_dev->dev;
else
#endif
- hwif->device.parent = NULL; /* Would like to do = &device_legacy */
- device_register(&hwif->device);
+ hwif->dev.parent = NULL; /* Would like to do = &device_legacy */
+ device_register(&hwif->dev);
if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
@@ -503,7 +507,7 @@ static void hwif_register (ide_hwif_t *hwif)
* This routine only knows how to look for drive units 0 and 1
* on an interface, so any setting of MAX_DRIVES > 2 won't work here.
*/
-static void probe_hwif (ide_hwif_t *hwif)
+static void probe_hwif(struct ata_channel *hwif)
{
unsigned int unit;
unsigned long flags;
@@ -513,7 +517,7 @@ static void probe_hwif (ide_hwif_t *hwif)
if (
#if CONFIG_BLK_DEV_PDC4030
- (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
+ (hwif->chipset != ide_pdc4030 || hwif->unit == 0) &&
#endif
hwif_check_regions(hwif)) {
int msgout = 0;
@@ -562,7 +566,7 @@ static void probe_hwif (ide_hwif_t *hwif)
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
- ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+ ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
if (tuneproc != NULL && drive->autotune == 1)
tuneproc(drive, 255); /* auto-tune PIO mode */
}
@@ -583,7 +587,7 @@ static void ide_init_queue(ide_drive_t *drive)
/* IDE can do up to 128K per request, pdc4030 needs smaller limit */
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030)
+ if (drive->channel->chipset == ide_pdc4030)
max_sectors = 127;
#endif
blk_queue_max_sectors(q, max_sectors);
@@ -608,9 +612,10 @@ static void ide_init_queue(ide_drive_t *drive)
*
* This routine detects and reports such situations, but does not fix them.
*/
-static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+static void save_match(struct ata_channel *hwif, struct ata_channel *new,
+ struct ata_channel **match)
{
- ide_hwif_t *m = *match;
+ struct ata_channel *m = *match;
if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
if (!new->hwgroup)
@@ -635,12 +640,12 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
* but anything else has led to problems on some machines. We re-enable
* interrupts as much as we can safely do in most places.
*/
-static int init_irq (ide_hwif_t *hwif)
+static int init_irq(struct ata_channel *hwif)
{
unsigned long flags;
unsigned int index;
ide_hwgroup_t *hwgroup, *new_hwgroup;
- ide_hwif_t *match = NULL;
+ struct ata_channel *match = NULL;
/* Allocate the buffer and potentially sleep first */
@@ -655,7 +660,7 @@ static int init_irq (ide_hwif_t *hwif)
* Group up with any other hwifs that share our irq(s).
*/
for (index = 0; index < MAX_HWIFS; index++) {
- ide_hwif_t *h = &ide_hwifs[index];
+ struct ata_channel *h = &ide_hwifs[index];
if (h->hwgroup) { /* scan only initialized hwif's */
if (hwif->irq == h->irq) {
hwif->sharing_irq = h->sharing_irq = 1;
@@ -736,7 +741,7 @@ static int init_irq (ide_hwif_t *hwif)
ide_init_queue(drive);
}
if (!hwgroup->hwif) {
- hwgroup->hwif = HWIF(hwgroup->drive);
+ hwgroup->hwif = hwgroup->drive->channel;
#ifdef DEBUG
printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
#endif
@@ -770,7 +775,7 @@ static int init_irq (ide_hwif_t *hwif)
* structures needed for the routines in genhd.c. ide_geninit() gets called
* somewhat later, during the partition check.
*/
-static void init_gendisk (ide_hwif_t *hwif)
+static void init_gendisk(struct ata_channel *hwif)
{
struct gendisk *gd;
unsigned int unit, minors, i;
@@ -819,11 +824,11 @@ static void init_gendisk (ide_hwif_t *hwif)
for (unit = 0; unit < MAX_DRIVES; ++unit) {
char name[80];
ide_add_generic_settings(hwif->drives + unit);
- hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+ hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit);
sprintf (name, "host%d/bus%d/target%d/lun%d",
- (hwif->channel && hwif->mate) ?
+ (hwif->unit && hwif->mate) ?
hwif->mate->index : hwif->index,
- hwif->channel, unit, hwif->drives[unit].lun);
+ hwif->unit, unit, hwif->drives[unit].lun);
if (hwif->drives[unit].present)
hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
}
@@ -840,7 +845,7 @@ err_kmalloc_gd:
return;
}
-static int hwif_init (ide_hwif_t *hwif)
+static int hwif_init(struct ata_channel *hwif)
{
if (!hwif->present)
return 0;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 83f517e2ae5c..a80053ba45f5 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -138,7 +138,7 @@ static int ide_getdigit(char c)
static int proc_ide_read_imodel
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
const char *name;
@@ -167,7 +167,7 @@ static int proc_ide_read_imodel
static int proc_ide_read_mate
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
if (hwif && hwif->mate && hwif->mate->present)
@@ -180,10 +180,10 @@ static int proc_ide_read_mate
static int proc_ide_read_channel
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
- page[0] = hwif->channel ? '1' : '0';
+ page[0] = hwif->unit ? '1' : '0';
page[1] = '\n';
len = 2;
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
@@ -435,7 +435,7 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
}
}
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+static void create_proc_ide_drives(struct ata_channel *hwif)
{
int d;
struct proc_dir_entry *ent;
@@ -465,7 +465,7 @@ static void create_proc_ide_drives(ide_hwif_t *hwif)
}
}
-static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+static void destroy_proc_ide_device(struct ata_channel *hwif, ide_drive_t *drive)
{
struct ata_operations *driver = drive->driver;
@@ -479,7 +479,7 @@ static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
}
}
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void destroy_proc_ide_drives(struct ata_channel *hwif)
{
int d;
@@ -503,7 +503,7 @@ void create_proc_ide_interfaces(void)
int h;
for (h = 0; h < MAX_HWIFS; h++) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if (!hwif->present)
continue;
@@ -522,7 +522,7 @@ static void destroy_proc_ide_interfaces(void)
int h;
for (h = 0; h < MAX_HWIFS; h++) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
int exist = (hwif->proc != NULL);
#if 0
if (!hwif->present)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 6cb614447191..804c0f9dc19f 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2058,7 +2058,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+ if (drive->channel->dmaproc(ide_dma_end, drive)) {
/*
* A DMA error is sometimes expected. For example,
* if the tape is crossing a filemark during a
@@ -2132,7 +2132,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
return ide_stopped;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -2155,7 +2155,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
idetape_discard_data (drive, bcount.all);
- ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
#if IDETAPE_DEBUG_LOG
@@ -2181,7 +2182,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (tape->debug_level >= 2)
printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
#endif
- ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */
return ide_started;
}
@@ -2255,6 +2257,7 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
return ide_stopped;
}
tape->cmd_start_time = jiffies;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */
atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
return ide_started;
@@ -2309,10 +2312,10 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
- (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) drive->channel->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
- dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (IDE_CONTROL_REG)
@@ -2324,10 +2327,11 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
return ide_started;
@@ -3103,10 +3107,10 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
idetape_read_position_result_t *result;
-//#if IDETAPE_DEBUG_LOG
-// if (tape->debug_level >= 4)
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_LOG */
if (!tape->pc->error) {
result = (idetape_read_position_result_t *) tape->pc->buffer;
@@ -3280,10 +3284,10 @@ static int idetape_read_position (ide_drive_t *drive)
idetape_pc_t pc;
int position;
-//#if IDETAPE_DEBUG_LOG
-// if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+#endif /* IDETAPE_DEBUG_LOG */
#ifdef NO_LONGER_REQUIRED
idetape_flush_tape_buffers(drive);
@@ -5997,13 +6001,13 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->onstream = 1;
drive->dsc_overlap = 1;
#ifdef CONFIG_BLK_DEV_IDEPCI
- if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
+ if (!tape->onstream && drive->channel->pci_dev != NULL) {
/*
* These two ide-pci host adapters appear to need DSC overlap disabled.
* This probably needs further analysis.
*/
- if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
- (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+ if ((drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+ (drive->channel->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
drive->dsc_overlap = 0;
}
@@ -6099,8 +6103,7 @@ static int idetape_cleanup (ide_drive_t *drive)
idetape_chrdevs[minor].drive = NULL;
restore_flags (flags); /* all CPUs (overkill?) */
- /* FIXME: this appears to be totally wrong! */
- ata_ops(drive)->busy = 0;
+ MOD_DEC_USE_COUNT;
ide_unregister_subdriver (drive);
drive->driver_data = NULL;
@@ -6255,12 +6258,12 @@ int idetape_init (void)
idetape_chrdevs[minor].drive = drive;
tape->de_r =
devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
+ drive->channel->major, minor,
S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
tape->de_n =
devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor + 128,
+ drive->channel->major, minor + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
devfs_register_tape (tape->de_r);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 29ccab91a897..33a33670aebb 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -33,7 +33,7 @@
#define DEBUG_TASKFILE 0 /* unset when fixed */
#if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
#else
#define DTF(x...)
#endif
@@ -48,14 +48,14 @@ static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
if (rq->bio)
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
else
- return rq->buffer + task_rq_offset(rq);
+ return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}
static inline void ide_unmap_rq(struct request *rq, char *to,
unsigned long *flags)
{
if (rq->bio)
- bio_kunmap_irq(to, flags);
+ bio_kunmap_irq(to, flags);
}
static void bswap_data (void *buffer, int wcount)
@@ -98,8 +98,8 @@ void ata_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
* for handling polled ide transfers
*/
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
return;
}
@@ -138,8 +138,8 @@ void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
{
byte io_32bit;
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
return;
}
@@ -180,8 +180,8 @@ void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
*/
void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
return;
}
@@ -200,8 +200,8 @@ void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount
void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
return;
}
@@ -243,7 +243,7 @@ int drive_is_ready(ide_drive_t *drive)
{
byte stat = 0;
if (drive->waiting_for_dma)
- return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+ return drive->channel->dmaproc(ide_dma_test_irq, drive);
#if 0
/* need to guarantee 400ns since last command was issued */
udelay(1);
@@ -288,83 +288,124 @@ void ata_poll_drive_ready(ide_drive_t *drive)
break;
}
}
-static ide_startstop_t bio_mulout_intr(ide_drive_t *drive);
-/*
- * Handler for command write multiple
- * Called directly from execute_drive_cmd for the first bunch of sectors,
- * afterwards only by the ISR
- */
-static ide_startstop_t task_mulout_intr(ide_drive_t *drive)
+static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
+{
+ ide_task_t *args = rq->special;
+ ide_startstop_t startstop;
+
+ /*
+ * assign private copy for multi-write
+ */
+ memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+
+ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
+ return startstop;
+
+ ata_poll_drive_ready(drive);
+ return args->handler(drive);
+}
+
+static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
{
- unsigned int msect, nsect;
byte stat = GET_STAT();
byte io_32bit = drive->io_32bit;
- struct request *rq = HWGROUP(drive)->rq;
+ struct request *rq = &HWGROUP(drive)->wrq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- char *pBuf = NULL;
- unsigned long flags;
+ int mcount = drive->mult_count;
+ ide_startstop_t startstop;
/*
* (ks/hs): Handle last IRQ on multi-sector transfer,
* occurs after all data was sent in this chunk
*/
- if (rq->current_nr_sectors == 0) {
- if (stat & (ERR_STAT|DRQ_STAT))
- return ide_error(drive, "task_mulout_intr", stat);
+ if (!rq->nr_sectors) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ startstop = ide_error(drive, "task_mulout_intr", stat);
+ memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+ return startstop;
+ }
- /*
- * there may be more, ide_do_request will restart it if
- * necessary
- */
- ide_end_request(drive, 1);
+ __ide_end_request(drive, 1, rq->hard_nr_sectors);
+ rq->bio = NULL;
return ide_stopped;
}
- if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
- if (stat & (ERR_STAT|DRQ_STAT)) {
- return ide_error(drive, "task_mulout_intr", stat);
+ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+ if (stat & (ERR_STAT | DRQ_STAT)) {
+ startstop = ide_error(drive, "task_mulout_intr", stat);
+ memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+ return startstop;
}
+
/* no data yet, so wait for another interrupt */
if (hwgroup->handler == NULL)
- ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
return ide_started;
}
- /* (ks/hs): See task_mulin_intr */
- msect = drive->mult_count;
- nsect = rq->current_nr_sectors;
- if (nsect > msect)
- nsect = msect;
+ do {
+ char *buffer;
+ int nsect = rq->current_nr_sectors;
+ unsigned long flags;
+
+ if (nsect > mcount)
+ nsect = mcount;
+ mcount -= nsect;
+
+ buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+ rq->sector += nsect;
+ rq->nr_sectors -= nsect;
+ rq->current_nr_sectors -= nsect;
+
+ /* Do we move to the next bio after this? */
+ if (!rq->current_nr_sectors) {
+ /* remember to fix this up /jens */
+ struct bio *bio = rq->bio->bi_next;
+
+ /* end early if we ran out of requests */
+ if (!bio) {
+ mcount = 0;
+ } else {
+ rq->bio = bio;
+ rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+ }
+ }
+
+ /*
+ * Ok, we're all setup for the interrupt
+ * re-entering us on the last transfer.
+ */
+ taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
+ bio_kunmap_irq(buffer, &flags);
+ } while (mcount);
- pBuf = ide_map_rq(rq, &flags);
- DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
- pBuf, nsect, rq->current_nr_sectors);
- drive->io_32bit = 0;
- taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
- ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
- /* Are we sure that this as all been already transfered? */
- rq->current_nr_sectors -= nsect;
if (hwgroup->handler == NULL)
- ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
return ide_started;
}
-ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t ata_taskfile(ide_drive_t *drive,
+ struct hd_drive_task_hdr *taskfile,
+ struct hd_drive_hob_hdr *hobfile,
+ ide_handler_t *handler,
+ ide_pre_handler_t *prehandler,
+ struct request *rq
+ )
{
- task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
- hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
struct hd_driveid *id = drive->id;
- byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+ u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;
/* (ks/hs): Moved to start, do not use for multiple out commands */
- if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) {
+ if (handler != task_mulout_intr) {
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
}
if ((id->command_set_2 & 0x0400) &&
@@ -386,67 +427,24 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task)
OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
- if (task->handler != NULL) {
- ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+ if (handler != NULL) {
+ ide_set_handler(drive, handler, WAIT_CMD, NULL);
OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
/*
* Warning check for race between handler and prehandler for
* writing first block of data. however since we are well
* inside the boundaries of the seek, we should be okay.
*/
- if (task->prehandler != NULL) {
- return task->prehandler(drive, task->rq);
- }
+ if (prehandler != NULL)
+ return prehandler(drive, rq);
} else {
/* for dma commands we down set the handler */
- if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ if (drive->using_dma && !(drive->channel->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
}
return ide_started;
}
-void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile,
- struct hd_drive_hob_hdr *hobfile,
- ide_handler_t *handler)
-{
- struct hd_driveid *id = drive->id;
- byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
- /* (ks/hs): Moved to start, do not use for multiple out commands */
- if (*handler != task_mulout_intr && handler != bio_mulout_intr) {
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
- }
-
- if ((id->command_set_2 & 0x0400) &&
- (id->cfs_enable_2 & 0x0400) &&
- (drive->addressing == 1)) {
- OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
- OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
- OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
- OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
- OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
- }
-
- OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
- OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
- /* refers to number of sectors to transfer */
- OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
- /* refers to sector offset or start sector */
- OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
- OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
- OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
- if (handler != NULL) {
- ide_set_handler (drive, handler, WAIT_CMD, NULL);
- OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
- } else {
- /* for dma commands we down set the handler */
- if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
- }
-}
-
/*
* This is invoked on completion of a WIN_SETMULT cmd.
*/
@@ -567,8 +565,8 @@ static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq
}
/* (ks/hs): Fixed Multi Write */
- if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
- (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+ if ((args->taskfile.command != WIN_MULTWRITE) &&
+ (args->taskfile.command != WIN_MULTWRITE_EXT)) {
unsigned long flags;
char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
@@ -616,107 +614,6 @@ static ide_startstop_t task_out_intr(ide_drive_t *drive)
return ide_started;
}
-static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq)
-{
- ide_task_t *args = rq->special;
- ide_startstop_t startstop;
-
- /*
- * assign private copy for multi-write
- */
- memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
-
- if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
- return startstop;
-
- ata_poll_drive_ready(drive);
- return args->handler(drive);
-}
-
-
-static ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
-{
- byte stat = GET_STAT();
- byte io_32bit = drive->io_32bit;
- struct request *rq = &HWGROUP(drive)->wrq;
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
- int mcount = drive->mult_count;
- ide_startstop_t startstop;
-
- /*
- * (ks/hs): Handle last IRQ on multi-sector transfer,
- * occurs after all data was sent in this chunk
- */
- if (!rq->nr_sectors) {
- if (stat & (ERR_STAT|DRQ_STAT)) {
- startstop = ide_error(drive, "bio_mulout_intr", stat);
- memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
- return startstop;
- }
-
- __ide_end_request(drive, 1, rq->hard_nr_sectors);
- HWGROUP(drive)->wrq.bio = NULL;
- return ide_stopped;
- }
-
- if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
- if (stat & (ERR_STAT | DRQ_STAT)) {
- startstop = ide_error(drive, "bio_mulout_intr", stat);
- memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
- return startstop;
- }
-
- /* no data yet, so wait for another interrupt */
- if (hwgroup->handler == NULL)
- ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
- return ide_started;
- }
-
- do {
- char *buffer;
- int nsect = rq->current_nr_sectors;
- unsigned long flags;
-
- if (nsect > mcount)
- nsect = mcount;
- mcount -= nsect;
-
- buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
- rq->sector += nsect;
- rq->nr_sectors -= nsect;
- rq->current_nr_sectors -= nsect;
-
- /* Do we move to the next bio after this? */
- if (!rq->current_nr_sectors) {
- /* remember to fix this up /jens */
- struct bio *bio = rq->bio->bi_next;
-
- /* end early early we ran out of requests */
- if (!bio) {
- mcount = 0;
- } else {
- rq->bio = bio;
- rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
- }
- }
-
- /*
- * Ok, we're all setup for the interrupt
- * re-entering us on the last transfer.
- */
- taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
- bio_kunmap_irq(buffer, &flags);
- } while (mcount);
-
- drive->io_32bit = io_32bit;
- rq->errors = 0;
- if (hwgroup->handler == NULL)
- ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
- return ide_started;
-}
-
/*
* Handler for command with Read Multiple
*/
@@ -774,12 +671,12 @@ static ide_startstop_t task_mulin_intr(ide_drive_t *drive)
/* Called by ioctl to feature out type of command being called */
void ide_cmd_type_parser(ide_task_t *args)
{
- struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+ struct hd_drive_task_hdr *taskfile = &args->taskfile;
args->prehandler = NULL;
args->handler = NULL;
- switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+ switch(args->taskfile.command) {
case WIN_IDENTIFY:
case WIN_PIDENTIFY:
args->handler = task_in_intr;
@@ -814,8 +711,8 @@ void ide_cmd_type_parser(ide_task_t *args)
case CFA_WRITE_MULTI_WO_ERASE:
case WIN_MULTWRITE:
case WIN_MULTWRITE_EXT:
- args->prehandler = pre_bio_out_intr;
- args->handler = bio_mulout_intr;
+ args->prehandler = pre_task_mulout_intr;
+ args->handler = task_mulout_intr;
args->command_type = IDE_DRIVE_TASK_RAW_WRITE;
return;
@@ -830,9 +727,11 @@ void ide_cmd_type_parser(ide_task_t *args)
case WIN_SMART:
if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
args->prehandler = pre_task_out_intr;
- args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
- args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
- switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+
+ args->taskfile.low_cylinder = SMART_LCYL_PASS;
+ args->taskfile.high_cylinder = SMART_HCYL_PASS;
+
+ switch(args->taskfile.feature) {
case SMART_READ_VALUES:
case SMART_READ_THRESHOLDS:
case SMART_READ_LOG_SECTOR:
@@ -870,7 +769,7 @@ void ide_cmd_type_parser(ide_task_t *args)
#endif
case WIN_SETFEATURES:
args->handler = task_no_data_intr;
- switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+ switch(args->taskfile.feature) {
case SETFEATURES_XFER:
args->command_type = IDE_DRIVE_TASK_SET_XFER;
return;
@@ -960,7 +859,7 @@ void ide_cmd_type_parser(ide_task_t *args)
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-static void ide_init_drive_taskfile (struct request *rq)
+static void init_taskfile_request(struct request *rq)
{
memset(rq, 0, sizeof(*rq));
rq->flags = REQ_DRIVE_TASKFILE;
@@ -968,37 +867,25 @@ static void ide_init_drive_taskfile (struct request *rq)
/*
* This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
+ * This is an internal call and nobody in user-space has a
* reason to call this taskfile.
*
* ide_raw_taskfile is the one that user-space executes.
*/
+
int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
{
struct request rq;
+ /* FIXME: This is on stack! */
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_DATA_OFFSET] = taskfile->data;
- args.tfRegister[IDE_FEATURE_OFFSET] = taskfile->feature;
- args.tfRegister[IDE_NSECTOR_OFFSET] = taskfile->sector_count;
- args.tfRegister[IDE_SECTOR_OFFSET] = taskfile->sector_number;
- args.tfRegister[IDE_LCYL_OFFSET] = taskfile->low_cylinder;
- args.tfRegister[IDE_HCYL_OFFSET] = taskfile->high_cylinder;
- args.tfRegister[IDE_SELECT_OFFSET] = taskfile->device_head;
- args.tfRegister[IDE_COMMAND_OFFSET] = taskfile->command;
-
- args.hobRegister[IDE_DATA_OFFSET_HOB] = hobfile->data;
- args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
- args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
- args.hobRegister[IDE_SECTOR_OFFSET_HOB] = hobfile->sector_number;
- args.hobRegister[IDE_LCYL_OFFSET_HOB] = hobfile->low_cylinder;
- args.hobRegister[IDE_HCYL_OFFSET_HOB] = hobfile->high_cylinder;
- args.hobRegister[IDE_SELECT_OFFSET_HOB] = hobfile->device_head;
- args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
-
- ide_init_drive_taskfile(&rq);
+ args.taskfile = *taskfile;
+ args.hobfile = *hobfile;
+
+ init_taskfile_request(&rq);
+
/* This is kept for internal use only !!! */
ide_cmd_type_parser(&args);
if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
@@ -1006,64 +893,33 @@ int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, st
rq.buffer = buf;
rq.special = &args;
+
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *args, byte *buf)
{
struct request rq;
- ide_init_drive_taskfile(&rq);
+ init_taskfile_request(&rq);
rq.buffer = buf;
if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
- rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+ rq.current_nr_sectors = rq.nr_sectors
+ = (args->hobfile.sector_count << 8)
+ | args->taskfile.sector_count;
rq.special = args;
+
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
/*
- * The taskfile glue table
- *
- * reqtask.data_phase reqtask.req_cmd
- * args.command_type args.handler
- *
- * TASKFILE_P_OUT_DMAQ ?? ??
- * TASKFILE_P_IN_DMAQ ?? ??
- * TASKFILE_P_OUT_DMA ?? ??
- * TASKFILE_P_IN_DMA ?? ??
- * TASKFILE_P_OUT ?? ??
- * TASKFILE_P_IN ?? ??
- *
- * TASKFILE_OUT_DMAQ IDE_DRIVE_TASK_RAW_WRITE NULL
- * TASKFILE_IN_DMAQ IDE_DRIVE_TASK_IN NULL
- *
- * TASKFILE_OUT_DMA IDE_DRIVE_TASK_RAW_WRITE NULL
- * TASKFILE_IN_DMA IDE_DRIVE_TASK_IN NULL
- *
- * TASKFILE_IN_OUT ?? ??
- *
- * TASKFILE_MULTI_OUT IDE_DRIVE_TASK_RAW_WRITE task_mulout_intr
- * TASKFILE_MULTI_IN IDE_DRIVE_TASK_IN task_mulin_intr
- *
- * TASKFILE_OUT IDE_DRIVE_TASK_RAW_WRITE task_out_intr
- * TASKFILE_OUT IDE_DRIVE_TASK_OUT task_out_intr
- *
- * TASKFILE_IN IDE_DRIVE_TASK_IN task_in_intr
- * TASKFILE_NO_DATA IDE_DRIVE_TASK_NO_DATA task_no_data_intr
- *
- * IDE_DRIVE_TASK_SET_XFER task_no_data_intr
- * IDE_DRIVE_TASK_INVALID
- *
- */
-
-/*
- * Issue ATA command and wait for completion. use for implementing commands in
+ * Issue ATA command and wait for completion. Use for implementing commands in
* kernel.
*
* The caller has to make sure buf is never NULL!
*/
-static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf)
+static int ide_wait_cmd(ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *argbuf)
{
struct request rq;
@@ -1072,10 +928,10 @@ static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int
memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * sectors);
ide_init_drive_cmd(&rq);
rq.buffer = argbuf;
- *argbuf++ = cmd;
- *argbuf++ = nsect;
- *argbuf++ = feature;
- *argbuf++ = sectors;
+ argbuf[0] = cmd;
+ argbuf[1] = nsect;
+ argbuf[2] = feature;
+ argbuf[3] = sectors;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
@@ -1083,7 +939,8 @@ static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int
int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int err = 0;
- byte args[4], *argbuf = args;
+ u8 args[4];
+ u8 *argbuf = args;
byte xfer_rate = 0;
int argsize = 4;
ide_task_t tfargs;
@@ -1096,13 +953,13 @@ int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, un
if (copy_from_user(args, (void *)arg, 4))
return -EFAULT;
- tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
- tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
- tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1];
- tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+ tfargs.taskfile.feature = args[2];
+ tfargs.taskfile.sector_count = args[3];
+ tfargs.taskfile.sector_number = args[1];
+ tfargs.taskfile.low_cylinder = 0x00;
+ tfargs.taskfile.high_cylinder = 0x00;
+ tfargs.taskfile.device_head = 0x00;
+ tfargs.taskfile.command = args[0];
if (args[3]) {
argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
@@ -1121,8 +978,8 @@ int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, un
if (!err && xfer_rate) {
/* active-retuning-calls future */
- if ((HWIF(drive)->speedproc) != NULL)
- HWIF(drive)->speedproc(drive, xfer_rate);
+ if ((drive->channel->speedproc) != NULL)
+ drive->channel->speedproc(drive, xfer_rate);
ide_driveid_update(drive);
}
abort:
@@ -1162,8 +1019,7 @@ EXPORT_SYMBOL(atapi_input_bytes);
EXPORT_SYMBOL(atapi_output_bytes);
EXPORT_SYMBOL(taskfile_input_data);
EXPORT_SYMBOL(taskfile_output_data);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
+EXPORT_SYMBOL(ata_taskfile);
EXPORT_SYMBOL(recal_intr);
EXPORT_SYMBOL(set_geometry_intr);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6cf6d4e8b9d0..75f0f19c21f0 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -223,7 +223,7 @@ int noautodma = 0;
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
-ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
+struct ata_channel ide_hwifs[MAX_HWIFS]; /* master data repository */
#if (DISK_RECOVERY_TIME > 0)
/*
@@ -244,19 +244,19 @@ static unsigned long read_timer (void)
__restore_flags(flags); /* local CPU only */
return (t - i);
}
-#endif /* DISK_RECOVERY_TIME */
+#endif
-static inline void set_recovery_timer (ide_hwif_t *hwif)
+static inline void set_recovery_timer(struct ata_channel *channel)
{
#if (DISK_RECOVERY_TIME > 0)
- hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
+ channel->last_time = read_timer();
+#endif
}
/*
* Do not even *think* about calling this!
*/
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+static void init_hwif_data(struct ata_channel *hwif, unsigned int index)
{
static const byte ide_major[] = {
IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
@@ -267,7 +267,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
hw_regs_t hw;
/* bulk initialize hwif & drive info with zeros */
- memset(hwif, 0, sizeof(ide_hwif_t));
+ memset(hwif, 0, sizeof(struct ata_channel));
memset(&hw, 0, sizeof(hw_regs_t));
/* fill in any non-zero initial values */
@@ -288,7 +288,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
drive->type = ATA_DISK;
drive->select.all = (unit<<4)|0xa0;
- drive->hwif = hwif;
+ drive->channel = hwif;
drive->ctl = 0x08;
drive->ready_stat = READY_STAT;
drive->bad_wstat = BAD_W_STAT;
@@ -445,13 +445,13 @@ static void ata_pre_reset (ide_drive_t *drive)
if (drive->using_dma) {
/* check the DMA crc count */
if (drive->crc_count) {
- HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
- if ((HWIF(drive)->speedproc) != NULL)
- HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+ drive->channel->dmaproc(ide_dma_off_quietly, drive);
+ if ((drive->channel->speedproc) != NULL)
+ drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
if (drive->current_speed >= XFER_SW_DMA_0)
- HWIF(drive)->dmaproc(ide_dma_on, drive);
+ drive->channel->dmaproc(ide_dma_on, drive);
} else
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
}
}
@@ -483,7 +483,7 @@ static ide_startstop_t ata_special (ide_drive_t *drive)
printk("%s: ata_special: 0x%02x\n", drive->name, s->all);
#endif
if (s->b.set_tune) {
- ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+ ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
s->b.set_tune = 0;
if (tuneproc != NULL)
tuneproc(drive, drive->tune_req);
@@ -507,9 +507,9 @@ static ide_startstop_t ata_special (ide_drive_t *drive)
extern struct block_device_operations ide_fops[];
/*
- * ide_geninit() is called exactly *once* for each interface.
+ * This is called exactly *once* for each channel.
*/
-void ide_geninit (ide_hwif_t *hwif)
+void ide_geninit(struct ata_channel *hwif)
{
unsigned int unit;
struct gendisk *gd = hwif->gd;
@@ -542,13 +542,14 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
- SELECT_DRIVE(HWIF(drive),drive);
+ SELECT_DRIVE(drive->channel,drive);
udelay (10);
if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
- if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
@@ -569,11 +570,12 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
@@ -632,7 +634,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
__save_flags(flags); /* local CPU only */
@@ -645,6 +647,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
__restore_flags (flags); /* local CPU only */
return ide_started;
@@ -679,7 +682,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
}
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/*
* Some weird controller like resetting themselves to a strange
@@ -737,27 +741,25 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
ide_task_t *args = (ide_task_t *) rq->special;
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
if (args) {
- if (args->tf_in_flags.b.data) {
- unsigned short data = IN_WORD(IDE_DATA_REG);
- args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
- args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF;
- }
- args->tfRegister[IDE_ERROR_OFFSET] = err;
- args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
- args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG);
- args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG);
- args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG);
- args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG);
- args->tfRegister[IDE_STATUS_OFFSET] = stat;
+ args->taskfile.feature = err;
+ args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+ args->taskfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+ args->taskfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+ args->taskfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
+ args->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
+ args->taskfile.command = stat;
if ((drive->id->command_set_2 & 0x0400) &&
(drive->id->cfs_enable_2 & 0x0400) &&
(drive->addressing == 1)) {
- OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
- args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
- args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
- args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG);
- args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG);
- args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG);
+ /* The following command goes to the hob file! */
+
+ OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+ args->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
+ args->hobfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+
+ args->hobfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+ args->hobfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+ args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
}
}
}
@@ -933,10 +935,11 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
*/
void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, WAIT_CMD, NULL);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive),drive,0);
+ SELECT_MASK(drive->channel, drive, 0);
OUT_BYTE(nsect,IDE_NSECTOR_REG);
OUT_BYTE(cmd,IDE_COMMAND_REG);
}
@@ -978,7 +981,7 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
byte stat;
int i;
unsigned long flags;
@@ -1020,90 +1023,6 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, by
}
/*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
- if (rq->flags & REQ_DRIVE_TASKFILE) {
- ide_task_t *args = rq->special;
-
- if (!(args))
- goto args_error;
-
- do_taskfile(drive,
- (struct hd_drive_task_hdr *)&args->tfRegister,
- (struct hd_drive_hob_hdr *)&args->hobRegister,
- args->handler);
-
- if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
- (args->command_type == IDE_DRIVE_TASK_OUT)) &&
- args->prehandler && args->handler)
- return args->prehandler(drive, rq);
- return ide_started;
-
- } else if (rq->flags & REQ_DRIVE_TASK) {
- byte *args = rq->buffer;
- byte sel;
-
- if (!(args)) goto args_error;
-#ifdef DEBUG
- printk("%s: DRIVE_TASK_CMD ", drive->name);
- printk("cmd=0x%02x ", args[0]);
- printk("fr=0x%02x ", args[1]);
- printk("ns=0x%02x ", args[2]);
- printk("sc=0x%02x ", args[3]);
- printk("lcyl=0x%02x ", args[4]);
- printk("hcyl=0x%02x ", args[5]);
- printk("sel=0x%02x\n", args[6]);
-#endif
- OUT_BYTE(args[1], IDE_FEATURE_REG);
- OUT_BYTE(args[3], IDE_SECTOR_REG);
- OUT_BYTE(args[4], IDE_LCYL_REG);
- OUT_BYTE(args[5], IDE_HCYL_REG);
- sel = (args[6] & ~0x10);
- if (drive->select.b.unit)
- sel |= 0x10;
- OUT_BYTE(sel, IDE_SELECT_REG);
- ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- return ide_started;
- } else if (rq->flags & REQ_DRIVE_CMD) {
-
- byte *args = rq->buffer;
- if (!(args)) goto args_error;
-#ifdef DEBUG
- printk("%s: DRIVE_CMD ", drive->name);
- printk("cmd=0x%02x ", args[0]);
- printk("sc=0x%02x ", args[1]);
- printk("fr=0x%02x ", args[2]);
- printk("xx=0x%02x\n", args[3]);
-#endif
- if (args[0] == WIN_SMART) {
- OUT_BYTE(0x4f, IDE_LCYL_REG);
- OUT_BYTE(0xc2, IDE_HCYL_REG);
- OUT_BYTE(args[2],IDE_FEATURE_REG);
- OUT_BYTE(args[1],IDE_SECTOR_REG);
- ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- return ide_started;
- }
- OUT_BYTE(args[2],IDE_FEATURE_REG);
- ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- return ide_started;
- }
-
-args_error:
- /*
- * NULL is actually a valid way of waiting for
- * all current requests to be flushed from the queue.
- */
-#ifdef DEBUG
- printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
- ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- return ide_stopped;
-}
-
-/*
* start_request() initiates handling of a new I/O request
*/
static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
@@ -1111,7 +1030,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
ide_startstop_t startstop;
unsigned long block;
unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
BUG_ON(!(rq->flags & REQ_STARTED));
@@ -1150,9 +1069,100 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
return startstop;
}
+
+ /* FIXME: We can see nicely here that all commands should be submitted
+ * through the request queue and that the special field in drive should
+ * go as soon as possible!
+ */
+
if (!drive->special.all) {
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
- return execute_drive_cmd(drive, rq);
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ /* This issues a special drive command, usually
+ * initiated by ioctl() from the external hdparm
+ * program.
+ */
+
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+
+ if (!(args))
+ goto args_error;
+
+ ata_taskfile(drive,
+ &args->taskfile,
+ &args->hobfile,
+ args->handler, NULL, NULL);
+
+ if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+ (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+ args->prehandler && args->handler)
+ return args->prehandler(drive, rq);
+ return ide_started;
+
+ } else if (rq->flags & REQ_DRIVE_TASK) {
+ byte *args = rq->buffer;
+ byte sel;
+
+ if (!(args)) goto args_error;
+#ifdef DEBUG
+ printk("%s: DRIVE_TASK_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("fr=0x%02x ", args[1]);
+ printk("ns=0x%02x ", args[2]);
+ printk("sc=0x%02x ", args[3]);
+ printk("lcyl=0x%02x ", args[4]);
+ printk("hcyl=0x%02x ", args[5]);
+ printk("sel=0x%02x\n", args[6]);
+#endif
+ OUT_BYTE(args[1], IDE_FEATURE_REG);
+ OUT_BYTE(args[3], IDE_SECTOR_REG);
+ OUT_BYTE(args[4], IDE_LCYL_REG);
+ OUT_BYTE(args[5], IDE_HCYL_REG);
+ sel = (args[6] & ~0x10);
+ if (drive->select.b.unit)
+ sel |= 0x10;
+ OUT_BYTE(sel, IDE_SELECT_REG);
+ ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ return ide_started;
+ } else if (rq->flags & REQ_DRIVE_CMD) {
+ byte *args = rq->buffer;
+ if (!(args)) goto args_error;
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("sc=0x%02x ", args[1]);
+ printk("fr=0x%02x ", args[2]);
+ printk("xx=0x%02x\n", args[3]);
+#endif
+ if (args[0] == WIN_SMART) {
+ OUT_BYTE(0x4f, IDE_LCYL_REG);
+ OUT_BYTE(0xc2, IDE_HCYL_REG);
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ OUT_BYTE(args[1],IDE_SECTOR_REG);
+ ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+
+ return ide_started;
+ }
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ return ide_started;
+ }
+
+args_error:
+ /*
+ * NULL is actually a valid way of waiting for all
+ * current requests to be flushed from the queue.
+ */
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ return ide_stopped;
+ }
+
+ /* The normal way of execution is to pass execute the request
+ * handler.
+ */
if (ata_ops(drive)) {
if (ata_ops(drive)->do_request)
@@ -1194,55 +1204,34 @@ ide_startstop_t restart_request (ide_drive_t *drive)
* ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies.
*/
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+void ide_stall_queue(ide_drive_t *drive, unsigned long timeout)
{
if (timeout > WAIT_WORSTCASE)
timeout = WAIT_WORSTCASE;
- drive->sleep = timeout + jiffies;
+ drive->PADAM_sleep = timeout + jiffies;
}
-#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
-
/*
* choose_drive() selects the next drive which will be serviced.
*/
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+static inline ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
{
ide_drive_t *drive, *best;
-repeat:
best = NULL;
drive = hwgroup->drive;
do {
- if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+ if (!list_empty(&drive->queue.queue_head)
+ && (!drive->PADAM_sleep || time_after_eq(drive->PADAM_sleep, jiffies))) {
if (!best
- || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
- || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+ || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep)))
+ || (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time)))
{
if (!blk_queue_plugged(&drive->queue))
best = drive;
}
}
} while ((drive = drive->next) != hwgroup->drive);
- if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
- long t = (signed long)(WAKEUP(best) - jiffies);
- if (t >= WAIT_MIN_SLEEP) {
- /*
- * We *may* have some time to spare, but first let's see if
- * someone can potentially benefit from our nice mood today..
- */
- drive = best->next;
- do {
- if (!drive->sleep
- && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
- && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
- {
- ide_stall_queue(best, min(t, 10L * WAIT_MIN_SLEEP));
- goto repeat;
- }
- } while ((drive = drive->next) != best);
- }
- }
return best;
}
@@ -1278,8 +1267,8 @@ repeat:
*/
static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
{
- ide_drive_t *drive;
- ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ struct ata_channel *hwif;
ide_startstop_t startstop;
struct request *rq;
@@ -1294,8 +1283,8 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
hwgroup->rq = NULL;
drive = hwgroup->drive;
do {
- if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
- sleep = drive->sleep;
+ if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
+ sleep = drive->PADAM_sleep;
} while ((drive = drive->next) != hwgroup->drive);
if (sleep) {
/*
@@ -1304,7 +1293,7 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
* play fairly with us, just in case there are big differences
* in relative throughputs.. don't want to hog the cpu too much.
*/
- if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
+ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP;
#if 1
if (timer_pending(&hwgroup->timer))
@@ -1320,7 +1309,7 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
}
return; /* no more work for this hwgroup (for now) */
}
- hwif = HWIF(drive);
+ hwif = drive->channel;
if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
/* set nIEN for previous hwif */
@@ -1331,8 +1320,8 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
}
hwgroup->hwif = hwif;
hwgroup->drive = drive;
- drive->sleep = 0;
- drive->service_start = jiffies;
+ drive->PADAM_sleep = 0;
+ drive->PADAM_service_start = jiffies;
if (blk_queue_plugged(&drive->queue))
BUG();
@@ -1366,11 +1355,12 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
/*
* Returns the queue which corresponds to a given device.
*/
-request_queue_t *ide_get_queue (kdev_t dev)
+request_queue_t *ide_get_queue(kdev_t dev)
{
- ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
+ struct ata_channel *channel = (struct ata_channel *)blk_dev[major(dev)].data;
- return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+ /* FIXME: ALLERT: This discriminates between master and slave! */
+ return &channel->drives[DEVICE_NR(dev) & 1].queue;
}
/*
@@ -1388,7 +1378,7 @@ void do_ide_request(request_queue_t *q)
*/
void ide_dma_timeout_retry(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct request *rq;
/*
@@ -1461,7 +1451,7 @@ void ide_timer_expiry(unsigned long data)
printk("ide_timer_expiry: hwgroup->drive was NULL\n");
hwgroup->handler = NULL;
} else {
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_startstop_t startstop;
/* paranoia */
if (!test_and_set_bit(IDE_BUSY, &hwgroup->flags))
@@ -1483,7 +1473,7 @@ void ide_timer_expiry(unsigned long data)
* mask the specific IRQ:
*/
spin_unlock(&ide_lock);
- hwif = HWIF(drive);
+ hwif = drive->channel;
#if DISABLE_IRQ_NOSYNC
disable_irq_nosync(hwif->irq);
#else
@@ -1506,7 +1496,7 @@ void ide_timer_expiry(unsigned long data)
startstop = ide_error(drive, "irq timeout", GET_STAT());
}
set_recovery_timer(hwif);
- drive->service_time = jiffies - drive->service_start;
+ drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
enable_irq(hwif->irq);
spin_lock_irq(&ide_lock);
if (startstop == ide_stopped)
@@ -1540,10 +1530,10 @@ void ide_timer_expiry(unsigned long data)
* accidentally invoked as a result of any valid command completion interrupt.
*
*/
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+static void unexpected_intr(int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
- ide_hwif_t *hwif = hwgroup->hwif;
+ struct ata_channel *hwif = hwgroup->hwif;
/*
* handle the unexpected interrupt
@@ -1568,11 +1558,11 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
/*
* entry point for all interrupts, caller does __cli() for us
*/
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+void ide_intr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
ide_handler_t *handler;
ide_startstop_t startstop;
@@ -1611,7 +1601,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* Whack the status register, just in case we have a leftover pending IRQ.
*/
IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
}
goto out_lock;
}
@@ -1650,8 +1640,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* same irq as is currently being serviced here, and Linux
* won't allow another of the same (on any CPU) until we return.
*/
- set_recovery_timer(HWIF(drive));
- drive->service_time = jiffies - drive->service_start;
+ set_recovery_timer(drive->channel);
+ drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
if (startstop == ide_stopped) {
if (hwgroup->handler == NULL) { /* paranoia */
clear_bit(IDE_BUSY, &hwgroup->flags);
@@ -1675,7 +1665,7 @@ ide_drive_t *get_info_ptr(kdev_t i_rdev)
int h;
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if (hwif->present && major == hwif->major) {
int unit = DEVICE_NR(i_rdev);
if (unit < MAX_DRIVES) {
@@ -1699,41 +1689,39 @@ void ide_init_drive_cmd (struct request *rq)
}
/*
- * This function issues a special IDE device request
- * onto the request queue.
+ * This function issues a special IDE device request onto the request queue.
*
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
+ * If action is ide_wait, then the rq is queued at the end of the request
+ * queue, and the function sleeps until it has been processed. This is for use
+ * when invoked from an ioctl handler.
*
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed. This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
+ * If action is ide_preempt, then the rq is queued at the head of the request
+ * queue, displacing the currently-being-processed request and this function
+ * returns immediately without waiting for the new rq to be completed. This is
+ * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom
+ * driver code.
*
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed. As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
+ * If action is ide_next, then the rq is queued immediately after the
+ * currently-being-processed-request (if any), and the function returns without
+ * waiting for the new rq to be completed. As above, This is VERY DANGEROUS,
+ * and is intended for careful use by the ATAPI tape/cdrom driver code.
*
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * If action is ide_end, then the rq is queued at the end of the request queue,
+ * and the function returns immediately without waiting for the new rq to be
+ * completed. This is again intended for careful use by the ATAPI tape/cdrom
+ * driver code.
*/
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- unsigned int major = HWIF(drive)->major;
+ unsigned int major = drive->channel->major;
request_queue_t *q = &drive->queue;
struct list_head *queue_head = &q->queue_head;
DECLARE_COMPLETION(wait);
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+ if (drive->channel->chipset == ide_pdc4030 && rq->buffer != NULL)
return -ENOSYS; /* special drive cmds not supported */
#endif
rq->errors = 0;
@@ -1812,7 +1800,7 @@ int ide_revalidate_disk (kdev_t i_rdev)
*/
void revalidate_drives(void)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int h;
@@ -1935,29 +1923,28 @@ ide_proc_entry_t generic_subdriver_entries[] = {
* Note that we only release the standard ports, and do not even try to handle
* any extra ports allocated for weird IDE interface chipsets.
*/
-static void hwif_unregister(ide_hwif_t *hwif)
+static void hwif_unregister(struct ata_channel *hwif)
{
if (hwif->straight8) {
ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
- goto jump_eight;
- }
- if (hwif->io_ports[IDE_DATA_OFFSET])
- ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
- if (hwif->io_ports[IDE_ERROR_OFFSET])
- ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
- if (hwif->io_ports[IDE_NSECTOR_OFFSET])
- ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
- if (hwif->io_ports[IDE_SECTOR_OFFSET])
- ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
- if (hwif->io_ports[IDE_LCYL_OFFSET])
- ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
- if (hwif->io_ports[IDE_HCYL_OFFSET])
- ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
- if (hwif->io_ports[IDE_SELECT_OFFSET])
- ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
- if (hwif->io_ports[IDE_STATUS_OFFSET])
- ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
+ } else {
+ if (hwif->io_ports[IDE_DATA_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+ if (hwif->io_ports[IDE_ERROR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+ if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+ if (hwif->io_ports[IDE_SECTOR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+ if (hwif->io_ports[IDE_LCYL_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+ if (hwif->io_ports[IDE_HCYL_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+ if (hwif->io_ports[IDE_SELECT_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+ if (hwif->io_ports[IDE_STATUS_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+ }
if (hwif->io_ports[IDE_CONTROL_OFFSET])
ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
@@ -1966,23 +1953,22 @@ jump_eight:
#endif
}
-void ide_unregister(ide_hwif_t *hwif)
+void ide_unregister(struct ata_channel *channel)
{
struct gendisk *gd;
ide_drive_t *drive, *d;
- ide_hwif_t *g;
ide_hwgroup_t *hwgroup;
- int irq_count = 0, unit, i;
+ int unit, i;
unsigned long flags;
unsigned int p, minor;
- ide_hwif_t old_hwif;
+ struct ata_channel old_hwif;
spin_lock_irqsave(&ide_lock, flags);
- if (!hwif->present)
+ if (!channel->present)
goto abort;
- put_device(&hwif->device);
+ put_device(&channel->dev);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &hwif->drives[unit];
+ drive = &channel->drives[unit];
if (!drive->present)
continue;
if (drive->busy || drive->usage)
@@ -1995,43 +1981,47 @@ void ide_unregister(ide_hwif_t *hwif)
ide_unregister_subdriver(drive);
}
}
- hwif->present = 0;
+ channel->present = 0;
/*
* All clear? Then blow away the buffer cache
*/
spin_unlock_irqrestore(&ide_lock, flags);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &hwif->drives[unit];
+ drive = &channel->drives[unit];
if (!drive->present)
continue;
minor = drive->select.b.unit << PARTN_BITS;
for (p = 0; p < (1<<PARTN_BITS); ++p) {
if (drive->part[p].nr_sects > 0) {
- kdev_t devp = mk_kdev(hwif->major, minor+p);
+ kdev_t devp = mk_kdev(channel->major, minor+p);
invalidate_device(devp, 0);
}
}
}
#ifdef CONFIG_PROC_FS
- destroy_proc_ide_drives(hwif);
+ destroy_proc_ide_drives(channel);
#endif
spin_lock_irqsave(&ide_lock, flags);
- hwgroup = hwif->hwgroup;
+ hwgroup = channel->hwgroup;
/*
* free the irq if we were the only hwif using it
*/
- g = hwgroup->hwif;
- do {
- if (g->irq == hwif->irq)
- ++irq_count;
- g = g->next;
- } while (g != hwgroup->hwif);
- if (irq_count == 1)
- free_irq(hwif->irq, hwgroup);
+ {
+ struct ata_channel *g;
+ int irq_count = 0;
- hwif_unregister(hwif);
+ g = hwgroup->hwif;
+ do {
+ if (g->irq == channel->irq)
+ ++irq_count;
+ g = g->next;
+ } while (g != hwgroup->hwif);
+ if (irq_count == 1)
+ free_irq(channel->irq, hwgroup);
+ }
+ hwif_unregister(channel);
/*
* Remove us from the hwgroup, and free
@@ -2039,7 +2029,7 @@ void ide_unregister(ide_hwif_t *hwif)
*/
d = hwgroup->drive;
for (i = 0; i < MAX_DRIVES; ++i) {
- drive = &hwif->drives[i];
+ drive = &channel->drives[i];
if (drive->de) {
devfs_unregister (drive->de);
drive->de = NULL;
@@ -2060,27 +2050,27 @@ void ide_unregister(ide_hwif_t *hwif)
}
if (d->present)
hwgroup->drive = d;
- while (hwgroup->hwif->next != hwif)
+ while (hwgroup->hwif->next != channel)
hwgroup->hwif = hwgroup->hwif->next;
- hwgroup->hwif->next = hwif->next;
- if (hwgroup->hwif == hwif)
+ hwgroup->hwif->next = channel->next;
+ if (hwgroup->hwif == channel)
kfree(hwgroup);
else
- hwgroup->hwif = HWIF(hwgroup->drive);
+ hwgroup->hwif = hwgroup->drive->channel;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
- ide_release_dma(hwif);
+ ide_release_dma(channel);
#endif
/*
* Remove us from the kernel's knowledge
*/
- unregister_blkdev(hwif->major, hwif->name);
- kfree(blksize_size[hwif->major]);
- blk_dev[hwif->major].data = NULL;
- blk_dev[hwif->major].queue = NULL;
- blk_clear(hwif->major);
- gd = hwif->gd;
+ unregister_blkdev(channel->major, channel->name);
+ kfree(blksize_size[channel->major]);
+ blk_dev[channel->major].data = NULL;
+ blk_dev[channel->major].queue = NULL;
+ blk_clear(channel->major);
+ gd = channel->gd;
if (gd) {
del_gendisk(gd);
kfree(gd->sizes);
@@ -2090,45 +2080,45 @@ void ide_unregister(ide_hwif_t *hwif)
if (gd->flags)
kfree (gd->flags);
kfree(gd);
- hwif->gd = NULL;
+ channel->gd = NULL;
}
/*
- * Reinitialize the hwif handler, but preserve any special methods for
+ * Reinitialize the channel handler, but preserve any special methods for
* it.
*/
- old_hwif = *hwif;
- init_hwif_data(hwif, hwif->index);
- hwif->hwgroup = old_hwif.hwgroup;
- hwif->tuneproc = old_hwif.tuneproc;
- hwif->speedproc = old_hwif.speedproc;
- hwif->selectproc = old_hwif.selectproc;
- hwif->resetproc = old_hwif.resetproc;
- hwif->intrproc = old_hwif.intrproc;
- hwif->maskproc = old_hwif.maskproc;
- hwif->quirkproc = old_hwif.quirkproc;
- hwif->rwproc = old_hwif.rwproc;
- hwif->ideproc = old_hwif.ideproc;
- hwif->dmaproc = old_hwif.dmaproc;
- hwif->busproc = old_hwif.busproc;
- hwif->bus_state = old_hwif.bus_state;
- hwif->dma_base = old_hwif.dma_base;
- hwif->dma_extra = old_hwif.dma_extra;
- hwif->config_data = old_hwif.config_data;
- hwif->select_data = old_hwif.select_data;
- hwif->proc = old_hwif.proc;
+ old_hwif = *channel;
+ init_hwif_data(channel, channel->index);
+ channel->hwgroup = old_hwif.hwgroup;
+ channel->tuneproc = old_hwif.tuneproc;
+ channel->speedproc = old_hwif.speedproc;
+ channel->selectproc = old_hwif.selectproc;
+ channel->resetproc = old_hwif.resetproc;
+ channel->intrproc = old_hwif.intrproc;
+ channel->maskproc = old_hwif.maskproc;
+ channel->quirkproc = old_hwif.quirkproc;
+ channel->rwproc = old_hwif.rwproc;
+ channel->ideproc = old_hwif.ideproc;
+ channel->dmaproc = old_hwif.dmaproc;
+ channel->busproc = old_hwif.busproc;
+ channel->bus_state = old_hwif.bus_state;
+ channel->dma_base = old_hwif.dma_base;
+ channel->dma_extra = old_hwif.dma_extra;
+ channel->config_data = old_hwif.config_data;
+ channel->select_data = old_hwif.select_data;
+ channel->proc = old_hwif.proc;
#ifndef CONFIG_BLK_DEV_IDECS
- hwif->irq = old_hwif.irq;
+ channel->irq = old_hwif.irq;
#endif
- hwif->major = old_hwif.major;
- hwif->chipset = old_hwif.chipset;
- hwif->autodma = old_hwif.autodma;
- hwif->udma_four = old_hwif.udma_four;
+ channel->major = old_hwif.major;
+ channel->chipset = old_hwif.chipset;
+ channel->autodma = old_hwif.autodma;
+ channel->udma_four = old_hwif.udma_four;
#ifdef CONFIG_BLK_DEV_IDEPCI
- hwif->pci_dev = old_hwif.pci_dev;
+ channel->pci_dev = old_hwif.pci_dev;
#endif
- hwif->straight8 = old_hwif.straight8;
+ channel->straight8 = old_hwif.straight8;
abort:
spin_unlock_irqrestore(&ide_lock, flags);
}
@@ -2173,10 +2163,11 @@ void ide_setup_ports ( hw_regs_t *hw,
* Register an IDE interface, specifing exactly the registers etc
* Set init=1 iff calling before probes have taken place.
*/
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp)
{
- int h, retry = 1;
- ide_hwif_t *hwif;
+ int h;
+ int retry = 1;
+ struct ata_channel *hwif;
do {
for (h = 0; h < MAX_HWIFS; ++h) {
@@ -2193,7 +2184,9 @@ int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
for (h = 0; h < MAX_HWIFS; ++h)
ide_unregister(&ide_hwifs[h]);
} while (retry--);
+
return -1;
+
found:
ide_unregister(hwif);
if (hwif->present)
@@ -2375,8 +2368,8 @@ static int set_io_32bit(ide_drive_t *drive, int arg)
{
drive->io_32bit = arg;
#ifdef CONFIG_BLK_DEV_DTC2278
- if (HWIF(drive)->chipset == ide_dtc2278)
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+ if (drive->channel->chipset == ide_dtc2278)
+ drive->channel->drives[!drive->select.b.unit].io_32bit = arg;
#endif /* CONFIG_BLK_DEV_DTC2278 */
return 0;
}
@@ -2385,9 +2378,9 @@ static int set_using_dma (ide_drive_t *drive, int arg)
{
if (!drive->driver)
return -EPERM;
- if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+ if (!drive->id || !(drive->id->capability & 1) || !drive->channel->dmaproc)
return -EPERM;
- if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+ if (drive->channel->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
return -EIO;
return 0;
}
@@ -2396,14 +2389,14 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
{
struct request rq;
- if (!HWIF(drive)->tuneproc)
+ if (!drive->channel->tuneproc)
return -ENOSYS;
if (drive->special.b.set_tune)
return -EBUSY;
ide_init_drive_cmd(&rq);
drive->tune_req = (byte) arg;
drive->special.b.set_tune = 1;
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ ide_do_drive_cmd(drive, &rq, ide_wait);
return 0;
}
@@ -2414,7 +2407,6 @@ void ide_add_generic_settings (ide_drive_t *drive)
*/
ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
- ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL);
ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL);
ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
@@ -2540,10 +2532,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GET_NICE:
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
- drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
- drive->nice0 << IDE_NICE_0 |
- drive->nice1 << IDE_NICE_1 |
- drive->nice2 << IDE_NICE_2,
+ drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
(long *) arg);
case HDIO_DRIVE_CMD:
@@ -2558,7 +2547,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+ if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
return -EPERM;
drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
/* Only CD-ROM's and tapes support DSC overlap. */
@@ -2566,7 +2555,6 @@ static int ide_ioctl (struct inode *inode, struct file *file,
drive->dsc_overlap = 0;
return -EPERM;
}
- drive->nice1 = (arg >> IDE_NICE_1) & 1;
return 0;
case BLKGETSIZE:
case BLKGETSIZE64:
@@ -2591,15 +2579,15 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (put_user(HWIF(drive)->bus_state, (long *)arg))
+ if (put_user(drive->channel->bus_state, (long *)arg))
return -EFAULT;
return 0;
case HDIO_SET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (HWIF(drive)->busproc)
- HWIF(drive)->busproc(drive, (int)arg);
+ if (drive->channel->busproc)
+ drive->channel->busproc(drive, (int)arg);
return 0;
default:
@@ -2802,7 +2790,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
int __init ide_setup (char *s)
{
int i, vals[3];
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
unsigned int hw, unit;
const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
@@ -3116,7 +3104,7 @@ ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations
unsigned int unit, index, i;
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
if (!hwif->present)
continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -3146,7 +3134,7 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
}
/* FIXME: This will be pushed to the drivers! Thus allowing us to
- * save one parameter here eparate this out.
+ * save one parameter here separate this out.
*/
drive->driver = driver;
@@ -3154,7 +3142,7 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
restore_flags(flags); /* all CPUs */
/* FIXME: Check what this magic number is supposed to be about? */
if (drive->autotune != 2) {
- if (HWIF(drive)->dmaproc != NULL) {
+ if (drive->channel->dmaproc != NULL) {
/*
* Force DMAing for the beginning of the check. Some
@@ -3164,13 +3152,12 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
* PARANOIA!!!
*/
- HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
- HWIF(drive)->dmaproc(ide_dma_check, drive);
+ drive->channel->dmaproc(ide_dma_off_quietly, drive);
+ drive->channel->dmaproc(ide_dma_check, drive);
}
/* Only CD-ROMs and tape drives support DSC overlap. */
drive->dsc_overlap = (drive->next != drive
&& (drive->type == ATA_ROM || drive->type == ATA_TAPE));
- drive->nice1 = 1;
}
drive->revalidate = 1;
drive->suspend_reset = 0;
@@ -3193,10 +3180,19 @@ int ide_unregister_subdriver(ide_drive_t *drive)
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
- if (drive->usage || drive->busy || !ata_ops(drive) || ata_ops(drive)->busy) {
+
+#if 0
+ if (__MOD_IN_USE(ata_ops(drive)->owner)) {
+ restore_flags(flags);
+ return 1;
+ }
+#endif
+
+ if (drive->usage || drive->busy || !ata_ops(drive)) {
restore_flags(flags); /* all CPUs */
return 1;
}
+
#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
pnpide_init(0);
#endif
@@ -3207,7 +3203,10 @@ int ide_unregister_subdriver(ide_drive_t *drive)
#endif
auto_remove_settings(drive);
drive->driver = NULL;
+ drive->present = 0;
+
restore_flags(flags); /* all CPUs */
+
return 0;
}
@@ -3297,7 +3296,7 @@ EXPORT_SYMBOL(get_info_ptr);
static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int i, unit;
@@ -3316,6 +3315,7 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event,
hwif = &ide_hwifs[i];
if (!hwif->present)
continue;
+
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
if (!drive->present)
@@ -3479,12 +3479,13 @@ static int __init ata_module_init(void)
initializing = 0;
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
- if (hwif->present)
- ide_geninit(hwif);
+ struct ata_channel *channel = &ide_hwifs[h];
+ if (channel->present)
+ ide_geninit(channel);
}
register_reboot_notifier(&ide_notifier);
+
return 0;
}
diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c
index 12b6faee1148..6e6a86439fa0 100644
--- a/drivers/ide/it8172.c
+++ b/drivers/ide/it8172.c
@@ -53,7 +53,7 @@ static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
static int it8172_config_drive_for_dma (ide_drive_t *drive);
static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
#endif
-void __init ide_init_it8172 (ide_hwif_t *hwif);
+void __init ide_init_it8172(struct ata_channel *channel);
static void it8172_tune_drive (ide_drive_t *drive, byte pio)
@@ -61,7 +61,7 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
unsigned long flags;
u16 master_data;
u32 slave_data;
- int is_slave = (&HWIF(drive)->drives[1] == drive);
+ int is_slave = (&drive->channel->drives[1] == drive);
int master_port = 0x40;
int slave_port = 0x44;
@@ -70,8 +70,8 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
else
pio = min_t(byte, pio, 4);
- pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
- pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data);
+ pci_read_config_word(drive->channel->pci_dev, master_port, &master_data);
+ pci_read_config_dword(drive->channel->pci_dev, slave_port, &slave_data);
/*
* FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
@@ -94,7 +94,7 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
save_flags(flags);
cli();
- pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
+ pci_write_config_word(drive->channel->pci_dev, master_port, master_data);
restore_flags(flags);
}
@@ -133,7 +133,7 @@ static byte it8172_dma_2_pio (byte xfer_rate)
static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
@@ -231,7 +231,7 @@ unsigned int __init pci_init_it8172 (struct pci_dev *dev)
}
-void __init ide_init_it8172 (ide_hwif_t *hwif)
+void __init ide_init_it8172(struct ata_channel *hwif)
{
struct pci_dev* dev = hwif->pci_dev;
unsigned long cmdBase, ctrlBase;
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
index d28eac48044d..6b74ade155d0 100644
--- a/drivers/ide/macide.c
+++ b/drivers/ide/macide.c
@@ -69,7 +69,7 @@ static int macide_offsets[IDE_NR_PORTS] = {
IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL
};
-int macide_ack_intr(ide_hwif_t* hwif)
+int macide_ack_intr(struct ata_channel *hwif)
{
if (*ide_ifr & 0x20) {
*ide_ifr &= ~0x20;
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
index c29dd4a5655f..787cc4bf0bfb 100644
--- a/drivers/ide/ns87415.c
+++ b/drivers/ide/ns87415.c
@@ -28,12 +28,12 @@ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
/*
* This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
+ * the IRQ associated with the port (drive->channel),
* and selects either PIO or DMA handshaking for the next I/O operation.
*/
static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
struct pci_dev *dev = hwif->pci_dev;
unsigned long flags;
@@ -43,12 +43,12 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
new = *old;
/* Adjust IRQ enable bit */
- bit = 1 << (8 + hwif->channel);
+ bit = 1 << (8 + hwif->unit);
new = drive->present ? (new & ~bit) : (new | bit);
/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
- bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
- other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+ bit = 1 << (20 + drive->select.b.unit + (hwif->unit << 1));
+ other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->unit << 1));
new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
if (new != *old) {
@@ -84,7 +84,7 @@ static void ns87415_selectproc (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte dma_stat;
switch (func) {
@@ -112,7 +112,7 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
+void __init ide_init_ns87415(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ctrl, using_inta;
@@ -138,9 +138,9 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
(void) pci_read_config_dword(dev, 0x40, &ctrl);
(void) pci_read_config_byte(dev, 0x09, &progif);
/* is irq in "native" mode? */
- using_inta = progif & (1 << (hwif->channel << 1));
+ using_inta = progif & (1 << (hwif->unit << 1));
if (!using_inta)
- using_inta = ctrl & (1 << (4 + hwif->channel));
+ using_inta = ctrl & (1 << (4 + hwif->unit));
if (hwif->mate) {
hwif->select_data = hwif->mate->select_data;
} else {
@@ -180,7 +180,7 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
outb(0x60, hwif->dma_base + 2);
if (!using_inta)
- hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index 4b5c901c10fe..7003b8d6d70f 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -142,7 +142,7 @@ static void compute_pios(ide_drive_t *drive, byte pio)
*/
{
int d;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (pio == PIO_DONT_KNOW)
drive->drive_data = min(ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0, OPTI621_MAX_PIO);
@@ -252,7 +252,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
pio_clocks_t first, second;
int ax, drdy;
byte cycle1, cycle2, misc;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
/* sets drive->drive_data for both drives */
compute_pios(drive, pio);
@@ -310,7 +310,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
/*
* ide_init_opti621() is called once for each hwif found at boot.
*/
-void __init ide_init_opti621 (ide_hwif_t *hwif)
+void __init ide_init_opti621(struct ata_channel *hwif)
{
hwif->drives[0].drive_data = PIO_DONT_KNOW;
hwif->drives[1].drive_data = PIO_DONT_KNOW;
diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
index 9d072763b8fa..1ff23c4b4f2c 100644
--- a/drivers/ide/pdc202xx.c
+++ b/drivers/ide/pdc202xx.c
@@ -217,6 +217,9 @@ static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
case PCI_DEVICE_ID_PROMISE_20275:
p += sprintf(p, "\n PDC20275 Chipset.\n");
break;
+ case PCI_DEVICE_ID_PROMISE_20276:
+ p += sprintf(p, "\n PDC20276 Chipset.\n");
+ break;
case PCI_DEVICE_ID_PROMISE_20269:
p += sprintf(p, "\n PDC20269 TX2 Chipset.\n");
break;
@@ -236,6 +239,7 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
char *p = buffer;
switch(bmide_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
@@ -395,8 +399,8 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ struct ata_channel *hwif = drive->channel;
+ struct pci_dev *dev = hwif->pci_dev;
unsigned int drive_conf;
int err;
@@ -519,14 +523,14 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
#ifdef CONFIG_BLK_DEV_IDEDMA
unsigned long indexreg = (hwif->dma_base + 1);
unsigned long datareg = (hwif->dma_base + 3);
#else
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
- unsigned long indexreg = high_16 + (hwif->channel ? 0x09 : 0x01);
+ unsigned long indexreg = high_16 + (hwif->unit ? 0x09 : 0x01);
unsigned long datareg = (indexreg + 2);
#endif /* CONFIG_BLK_DEV_IDEDMA */
byte thold = 0x10;
@@ -660,6 +664,7 @@ static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
OUT_BYTE(0xac, datareg);
break;
default:
+ ;
}
if (!drive->init_speed)
@@ -698,7 +703,7 @@ static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
unsigned long dma_base = hwif->dma_base;
@@ -720,8 +725,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
byte udma_100 = 0;
byte udma_133 = 0;
- byte mask = hwif->channel ? 0x08 : 0x02;
- unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10);
+ byte mask = hwif->unit ? 0x08 : 0x02;
+ unsigned short c_mask = hwif->unit ? (1<<11) : (1<<10);
byte ultra_66 = ((id->dma_ultra & 0x0010) ||
(id->dma_ultra & 0x0008)) ? 1 : 0;
@@ -732,6 +737,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
switch(dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
udma_133 = (udma_66) ? 1 : 0;
udma_100 = (udma_66) ? 1 : 0;
@@ -786,14 +792,14 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
#ifdef DEBUG
- printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
+ printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->unit ? "Secondary" : "Primary");
printk(" Switching to Ultra33 mode.\n");
#endif /* DEBUG */
/* Primary : zero out second bit */
/* Secondary : zero out fourth bit */
if (!jumpbit)
OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
- printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->unit ? "Secondary":"Primary");
printk("%s reduced to Ultra33 mode.\n", drive->name);
udma_66 = 0; udma_100 = 0; udma_133 = 0;
} else {
@@ -918,7 +924,7 @@ jumpbit_is_set:
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_dma_action_t dma_func = ide_dma_off_quietly;
if (id && (id->capability & 1) && hwif->autodma) {
@@ -963,7 +969,7 @@ no_dma_set:
(void) config_chipset_for_pio(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
int pdc202xx_quirkproc (ide_drive_t *drive)
@@ -981,14 +987,15 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
byte newchip = 0;
byte clock = 0;
byte hardware48hack = 0;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
- unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00);
+ unsigned long atapi_reg = high_16 + (hwif->unit ? 0x24 : 0x00);
unsigned long dma_base = hwif->dma_base;
switch (dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268R:
case PCI_DEVICE_ID_PROMISE_20268:
@@ -1016,7 +1023,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
struct request *rq = HWGROUP(drive)->rq;
unsigned long word_count = 0;
- outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+ outb(clock|(hwif->unit ? 0x08 : 0x02), high_16 + 0x11);
word_count = (rq->nr_sectors << 8);
word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
outl(word_count, atapi_reg);
@@ -1026,7 +1033,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
if ((drive->addressing) && (hardware48hack)) {
outl(0, atapi_reg); /* zero out extra */
clock = IN_BYTE(high_16 + 0x11);
- OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+ OUT_BYTE(clock & ~(hwif->unit ? 0x08:0x02), high_16 + 0x11);
}
break;
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
@@ -1035,7 +1042,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return (dma_stat & 4) == 4;
sc1d = IN_BYTE(high_16 + 0x001d);
- if (HWIF(drive)->channel) {
+ if (drive->channel->unit) {
if ((sc1d & 0x50) == 0x50) goto somebody_else;
else if ((sc1d & 0x40) == 0x40)
return (dma_stat & 4) == 4;
@@ -1048,8 +1055,8 @@ somebody_else:
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
case ide_dma_lostirq:
case ide_dma_timeout:
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
+ if (drive->channel->resetproc != NULL)
+ drive->channel->resetproc(drive);
default:
break;
}
@@ -1064,12 +1071,12 @@ void pdc202xx_new_reset (ide_drive_t *drive)
OUT_BYTE(0x00,IDE_CONTROL_REG);
mdelay(1000);
printk("PDC202XX: %s channel reset.\n",
- HWIF(drive)->channel ? "Secondary" : "Primary");
+ drive->channel->unit ? "Secondary" : "Primary");
}
void pdc202xx_reset (ide_drive_t *drive)
{
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
+ unsigned long high_16 = pci_resource_start(drive->channel->pci_dev, 4);
byte udma_speed_flag = IN_BYTE(high_16 + 0x001f);
OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
@@ -1077,7 +1084,7 @@ void pdc202xx_reset (ide_drive_t *drive)
OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
mdelay(2000); /* 2 seconds ?! */
printk("PDC202XX: %s channel reset.\n",
- HWIF(drive)->channel ? "Secondary" : "Primary");
+ drive->channel->unit ? "Secondary" : "Primary");
}
/*
@@ -1088,7 +1095,7 @@ void pdc202xx_reset (ide_drive_t *drive)
static int pdc202xx_tristate (ide_drive_t * drive, int state)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
byte sc1f = inb(high_16 + 0x001f);
@@ -1121,6 +1128,7 @@ unsigned int __init pci_init_pdc202xx(struct pci_dev *dev)
switch (dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268R:
case PCI_DEVICE_ID_PROMISE_20268:
@@ -1208,13 +1216,14 @@ fttk_tx_series:
return dev->irq;
}
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
+unsigned int __init ata66_pdc202xx(struct ata_channel *hwif)
{
- unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+ unsigned short mask = (hwif->unit) ? (1<<11) : (1<<10);
unsigned short CIS;
switch(hwif->pci_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
@@ -1226,13 +1235,14 @@ unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
}
}
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
+void __init ide_init_pdc202xx(struct ata_channel *hwif)
{
hwif->tuneproc = &pdc202xx_tune_drive;
hwif->quirkproc = &pdc202xx_quirkproc;
switch(hwif->pci_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
diff --git a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
index 04e6ad2871bd..70408f3573a2 100644
--- a/drivers/ide/pdc4030.c
+++ b/drivers/ide/pdc4030.c
@@ -99,7 +99,7 @@ static void promise_selectproc (ide_drive_t *drive)
{
unsigned int number;
- number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+ number = (drive->channel->unit << 1) + drive->select.b.unit;
OUT_BYTE(number,IDE_FEATURE_REG);
}
@@ -155,10 +155,10 @@ void __init init_pdc4030 (void)
* setup_pdc4030()
* Completes the setup of a Promise DC4030 controller card, once found.
*/
-int __init setup_pdc4030 (ide_hwif_t *hwif)
+int __init setup_pdc4030(struct ata_channel *hwif)
{
ide_drive_t *drive;
- ide_hwif_t *hwif2;
+ struct ata_channel *hwif2;
struct dc_ident ident;
int i;
ide_startstop_t startstop;
@@ -226,13 +226,13 @@ int __init setup_pdc4030 (ide_hwif_t *hwif)
hwif->chipset = hwif2->chipset = ide_pdc4030;
hwif->mate = hwif2;
hwif2->mate = hwif;
- hwif2->channel = 1;
+ hwif2->unit = 1;
hwif->selectproc = hwif2->selectproc = &promise_selectproc;
hwif->serialized = hwif2->serialized = 1;
/* Shift the remaining interfaces down by one */
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
- ide_hwif_t *h = &ide_hwifs[i];
+ struct ata_channel *h = &ide_hwifs[i];
#ifdef DEBUG
printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
@@ -263,7 +263,7 @@ int __init setup_pdc4030 (ide_hwif_t *hwif)
* Tests for the presence of a DC4030 Promise card on this interface
* Returns: 1 if found, 0 if not found
*/
-int __init detect_pdc4030(ide_hwif_t *hwif)
+int __init detect_pdc4030(struct ata_channel *hwif)
{
ide_drive_t *drive = &hwif->drives[0];
@@ -288,7 +288,7 @@ int __init detect_pdc4030(ide_hwif_t *hwif)
void __init ide_probe_for_pdc4030(void)
{
unsigned int index;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
if (enable_promise_support == 0)
return;
@@ -394,6 +394,7 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
if (GET_STAT() & BUSY_STAT) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
return ide_started; /* continue polling... */
}
@@ -476,6 +477,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
return ide_started; /* continue polling... */
}
@@ -489,6 +491,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
*/
promise_multwrite(drive, 4);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -523,6 +526,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
if (promise_multwrite(drive, rq->nr_sectors - 4))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
return ide_started;
} else {
@@ -533,6 +537,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
if (promise_multwrite(drive, rq->nr_sectors))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
@@ -549,14 +554,21 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
*/
ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
{
- struct request *rq = HWGROUP(drive)->rq;
- task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ struct request *rq = HWGROUP(drive)->rq;
+ struct hd_drive_task_hdr *taskfile = &task->taskfile;
unsigned long timeout;
byte stat;
+ /* Check that it's a regular command. If not, bomb out early. */
+ if (!(rq->flags & REQ_CMD)) {
+ blk_dump_rq_flags(rq, "pdc4030 bad flags");
+ ide_end_request(drive, 0);
+ return ide_stopped;
+ }
+
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
@@ -568,20 +580,12 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-/* Check that it's a regular command. If not, bomb out early. */
- if (!(rq->flags & REQ_CMD)) {
- blk_dump_rq_flags(rq, "pdc4030 bad flags");
- ide_end_request(drive, 0);
- return ide_stopped;
- }
-
switch (rq_data_dir(rq)) {
case READ:
- OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
/*
* The card's behaviour is odd at this point. If the data is
* available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the
+ * generated by the card. If this is the case, we need to call the
* "interrupt" handler (promise_read_intr) directly. Otherwise, if
* an interrupt is going to occur, bit0 of the SELECT register will
* be high, so we can set the handler the just return and be interrupted.
@@ -600,6 +604,7 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
printk(KERN_DEBUG "%s: read: waiting for "
"interrupt\n", drive->name);
#endif
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
return ide_started;
}
@@ -612,7 +617,6 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
case WRITE: {
ide_startstop_t startstop;
- OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
/*
* Strategy on write is:
* look for the DRQ that should have been immediately asserted
@@ -624,7 +628,7 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
printk(KERN_ERR "%s: no DRQ after issuing "
"PROMISE_WRITE\n", drive->name);
return startstop;
- }
+ }
if (!drive->unmask)
__cli(); /* local CPU only */
HWGROUP(drive)->wrq = *rq; /* scratchpad */
@@ -652,15 +656,13 @@ ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigne
taskfile.device_head = ((block>>8)&0x0f)|drive->select.all;
taskfile.command = (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ memset(&args.hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
ide_cmd_type_parser(&args);
/* We don't use the generic inerrupt handlers here? */
args.prehandler = NULL;
args.handler = NULL;
- args.rq = rq;
- args.block = block;
- rq->special = NULL;
rq->special = &args;
return do_pdc4030_io(drive, &args);
diff --git a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
index 49fd0042e0a1..9be48339c1a6 100644
--- a/drivers/ide/pdcadma.c
+++ b/drivers/ide/pdcadma.c
@@ -82,12 +82,12 @@ unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+unsigned int __init ata66_pdcadma(struct ata_channel *channel)
{
return 1;
}
-void __init ide_init_pdcadma (ide_hwif_t *hwif)
+void __init ide_init_pdcadma(struct ata_channel *hwif)
{
hwif->autodma = 0;
hwif->dma_base = 0;
@@ -101,7 +101,7 @@ void __init ide_init_pdcadma (ide_hwif_t *hwif)
// }
}
-void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_pdcadma(struct ata_channel *hwif, unsigned long dmabase)
{
// ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index 384ea0b2380a..8e023e8d3d28 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -316,7 +316,7 @@ static void piix_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_tim
static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
int err, T, UT, umul;
@@ -341,7 +341,7 @@ static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
ata_timing_merge(&p, &t, &t, IDE_TIMING_ALL);
}
- piix_set_speed(HWIF(drive)->pci_dev, drive->dn, &t, umul);
+ piix_set_speed(drive->channel->pci_dev, drive->dn, &t, umul);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -357,7 +357,7 @@ static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
static void piix_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((piix_enabled >> HWIF(drive)->channel) & 1))
+ if (!((piix_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -381,7 +381,7 @@ int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO |
@@ -392,7 +392,7 @@ int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
piix_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -533,12 +533,12 @@ unsigned int __init pci_init_piix(struct pci_dev *dev, const char *name)
return 0;
}
-unsigned int __init ata66_piix(ide_hwif_t *hwif)
+unsigned int __init ata66_piix(struct ata_channel *hwif)
{
- return ((piix_enabled & piix_80w) >> hwif->channel) & 1;
+ return ((piix_enabled & piix_80w) >> hwif->unit) & 1;
}
-void __init ide_init_piix(ide_hwif_t *hwif)
+void __init ide_init_piix(struct ata_channel *hwif)
{
int i;
@@ -550,7 +550,7 @@ void __init ide_init_piix(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -570,9 +570,9 @@ void __init ide_init_piix(ide_hwif_t *hwif)
* and only if DMA is safe with the chip and bridge.
*/
-void __init ide_dmacapable_piix(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_piix(struct ata_channel *hwif, unsigned long dmabase)
{
- if (((piix_enabled >> hwif->channel) & 1)
+ if (((piix_enabled >> hwif->unit) & 1)
&& !(piix_config->flags & PIIX_NODMA))
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index 609afe5bbd67..8f9a2cc0e679 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -125,11 +125,11 @@ static void qd_select (ide_drive_t *drive)
* qd6500_compute_timing
*
* computes the timing value where
- * lower nibble represents active time, in count of VLB clocks
- * upper nibble represents recovery time, in count of VLB clocks
+ * lower nibble represents active time, in count of VLB clocks
+ * upper nibble represents recovery time, in count of VLB clocks
*/
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+static byte qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time)
{
byte active_cycle,recovery_cycle;
@@ -208,7 +208,7 @@ static int qd_timing_ok (ide_drive_t drives[])
static void qd_set_timing (ide_drive_t *drive, byte timing)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
drive->drive_data &= 0xff00;
drive->drive_data |= timing;
@@ -240,7 +240,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
recovery_time = drive->id->eide_pio - 120;
}
- qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
+ qd_set_timing(drive,qd6500_compute_timing(drive->channel, active_time,recovery_time));
}
/*
@@ -250,7 +250,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
{
struct ata_timing *t;
- int base = HWIF(drive)->select_data;
+ int base = drive->channel->select_data;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
@@ -291,9 +291,9 @@ static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
printk(KERN_INFO "%s: PIO mode%d\n", drive->name, pio - XFER_PIO_0);
}
- if (!HWIF(drive)->channel && drive->type != ATA_DISK) {
+ if (!drive->channel->unit && drive->type != ATA_DISK) {
qd_write_reg(0x5f,QD_CONTROL_PORT);
- printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
+ printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name, drive->channel->name);
}
qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
@@ -348,7 +348,7 @@ int __init probe (int base)
index = ! (config & QD_CONFIG_IDE_BASEPORT);
if ((config & 0xf0) == QD_CONFIG_QD6500) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
if (qd_testreg(base)) return 1; /* bad register */
@@ -392,7 +392,7 @@ int __init probe (int base)
config, control, QD_ID3);
if (control & QD_CONTR_SEC_DISABLED) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
/* secondary disabled */
printk(KERN_INFO "%s: qd6580: single IDE board\n",
@@ -420,7 +420,7 @@ int __init probe (int base)
ide_hwifs[i].chipset = ide_qd65xx;
ide_hwifs[i].mate = &ide_hwifs[i^1];
- ide_hwifs[i].channel = i;
+ ide_hwifs[i].unit = i;
ide_hwifs[i].select_data = base;
ide_hwifs[i].config_data = config | (control <<8);
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
index 644ed6038a44..10caa414157e 100644
--- a/drivers/ide/rz1000.c
+++ b/drivers/ide/rz1000.c
@@ -28,7 +28,7 @@
#ifdef CONFIG_BLK_DEV_IDEPCI
-void __init ide_init_rz1000 (ide_hwif_t *hwif) /* called from ide-pci.c */
+void __init ide_init_rz1000(struct ata_channel *hwif) /* called from ide-pci.c */
{
unsigned short reg;
struct pci_dev *dev = hwif->pci_dev;
@@ -62,7 +62,7 @@ static void __init init_rz1000 (struct pci_dev *dev, const char *name)
printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
} else {
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
&& (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
{
@@ -71,7 +71,7 @@ static void __init init_rz1000 (struct pci_dev *dev, const char *name)
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
- hwif->channel = 1;
+ hwif->unit = 1;
printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
}
}
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
index 1e4396c6dec2..1760885e2479 100644
--- a/drivers/ide/serverworks.c
+++ b/drivers/ide/serverworks.c
@@ -243,7 +243,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
byte dma_modes[] = { 0x77, 0x21, 0x20 };
byte pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
byte csb5 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
@@ -255,7 +255,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
byte drive_pci = 0x00;
byte drive_pci2 = 0x00;
- byte drive_pci3 = hwif->channel ? 0x57 : 0x56;
+ byte drive_pci3 = hwif->unit ? 0x57 : 0x56;
byte ultra_enable = 0x00;
byte ultra_timing = 0x00;
@@ -413,7 +413,7 @@ static void svwks_tune_drive (ide_drive_t *drive, byte pio)
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct pci_dev *dev = drive->channel->pci_dev;
byte udma_66 = eighty_ninty_three(drive);
int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
@@ -436,7 +436,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -477,7 +477,7 @@ fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
@@ -487,7 +487,7 @@ static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
return config_drive_xfer_rate(drive);
case ide_dma_end:
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
if(inb(dma_base+0x02)&1)
@@ -584,13 +584,13 @@ unsigned int __init pci_init_svwks(struct pci_dev *dev)
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_dell(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- return ((1 << (hwif->channel + 14)) &
+ return ((1 << (hwif->unit + 14)) &
dev->subsystem_device) ? 1 : 0;
return 0;
}
@@ -601,18 +601,18 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
*
* WARNING: this only works on Alpine hardware!
*/
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_cobalt(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- return ((1 << (hwif->channel + 14)) &
+ return ((1 << (hwif->unit + 14)) &
dev->subsystem_device) ? 1 : 0;
return 0;
}
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+unsigned int __init ata66_svwks(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -627,10 +627,10 @@ unsigned int __init ata66_svwks (ide_hwif_t *hwif)
return 0;
}
-void __init ide_init_svwks (ide_hwif_t *hwif)
+void __init ide_init_svwks(struct ata_channel *hwif)
{
if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
hwif->tuneproc = &svwks_tune_drive;
hwif->speedproc = &svwks_tune_chipset;
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index bf0cf8dab58b..9b45da0205f7 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -434,7 +434,7 @@ extern char *ide_xfer_verbose (byte xfer_rate);
/* Enables per-drive prefetch and postwrite */
static void config_drive_art_rwp (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte reg4bh = 0;
@@ -460,7 +460,7 @@ static void config_drive_art_rwp (ide_drive_t *drive)
/* Set per-drive active and recovery time */
static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte timing, drive_pci, test1, test2;
@@ -560,7 +560,7 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte drive_pci, reg;
@@ -640,12 +640,12 @@ static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
#ifdef CONFIG_BLK_DEV_IDEDMA
/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ * ((id->hw_config & 0x4000|0x2000) && (drive->channel->udma_four))
*/
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+ struct ata_channel *hwif = drive->channel;
byte speed = 0;
@@ -700,7 +700,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_off_quietly;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -740,7 +740,7 @@ no_dma_set:
(void) config_chipset_for_pio(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/* initiates/aborts (U)DMA read/write operations on a drive. */
@@ -841,10 +841,10 @@ unsigned int __init pci_init_sis5513(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+unsigned int __init ata66_sis5513(struct ata_channel *hwif)
{
byte reg48h = 0, ata66 = 0;
- byte mask = hwif->channel ? 0x20 : 0x10;
+ byte mask = hwif->unit ? 0x20 : 0x10;
pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
if (dma_capability >= ATA_66) {
@@ -853,10 +853,10 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
return ata66;
}
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
+void __init ide_init_sis5513(struct ata_channel *hwif)
{
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
hwif->tuneproc = &sis5513_tune_drive;
hwif->speedproc = &sis5513_tune_chipset;
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index fd60ffe2cd07..158070c4150c 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -57,13 +57,13 @@ static unsigned int get_timing_sl82c105(struct ata_timing *t)
*/
static void config_for_pio(ide_drive_t *drive, int pio, int report)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
struct ata_timing *t;
unsigned short drv_ctrl = 0x909;
unsigned int xfer_mode, reg;
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+ reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
if (pio == 255)
xfer_mode = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
@@ -95,12 +95,12 @@ static void config_for_pio(ide_drive_t *drive, int pio, int report)
*/
static int config_for_dma(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned short drv_ctrl = 0x909;
unsigned int reg;
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+ reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
drv_ctrl = 0x0240;
@@ -120,7 +120,7 @@ static int sl82c105_check_drive(ide_drive_t *drive)
do {
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (!hwif->autodma)
break;
@@ -146,7 +146,7 @@ static int sl82c105_check_drive(ide_drive_t *drive)
}
} while (0);
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -232,7 +232,7 @@ unsigned int __init pci_init_sl82c105(struct pci_dev *dev)
return dev->irq;
}
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+void __init dma_init_sl82c105(struct ata_channel *hwif, unsigned long dma_base)
{
unsigned int rev;
byte dma_state;
@@ -261,7 +261,7 @@ void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
/*
* Initialise the chip
*/
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
+void __init ide_init_sl82c105(struct ata_channel *hwif)
{
hwif->tuneproc = tune_sl82c105;
}
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
index 70dffe8906e8..50675cfeed52 100644
--- a/drivers/ide/trm290.c
+++ b/drivers/ide/trm290.c
@@ -141,7 +141,7 @@
static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int reg;
unsigned long flags;
@@ -153,14 +153,14 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
if (reg != hwif->select_data) {
hwif->select_data = reg;
- outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */
+ outb(0x51|(hwif->unit<<3), hwif->config_data+1); /* set PIO/DMA */
outw(reg & 0xff, hwif->config_data);
}
/* enable IRQ if not probing */
if (drive->present) {
reg = inw(hwif->config_data+3) & 0x13;
- reg &= ~(1 << hwif->channel);
+ reg &= ~(1 << hwif->unit);
outw(reg, hwif->config_data+3);
}
@@ -175,7 +175,7 @@ static void trm290_selectproc (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int count, reading = 2, writing = 0;
switch (func) {
@@ -194,6 +194,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
return 0;
@@ -216,7 +217,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/*
* Invoked from ide-dma.c at boot time.
*/
-void __init ide_init_trm290 (ide_hwif_t *hwif)
+void __init ide_init_trm290(struct ata_channel *hwif)
{
unsigned int cfgbase = 0;
unsigned long flags;
@@ -237,7 +238,7 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
/* put config reg into first byte of hwif->select_data */
- outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+ outb(0x51|(hwif->unit<<3), hwif->config_data+1);
hwif->select_data = 0x21; /* select PIO as default */
outb(hwif->select_data, hwif->config_data);
reg = inb(hwif->config_data+3); /* get IRQ info */
@@ -246,10 +247,10 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
__restore_flags(flags); /* local CPU only */
if ((reg & 0x10))
- hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
- ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &trm290_dmaproc;
@@ -264,10 +265,10 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
* for the control basereg, so this kludge ensures that we use only
* values that are known to work. Ugh. -ml
*/
- unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+ unsigned short old, compat = hwif->unit ? 0x374 : 0x3f4;
static unsigned short next_offset = 0;
- outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+ outb(0x54|(hwif->unit<<3), hwif->config_data+1);
old = inw(hwif->config_data) & ~1;
if (old != compat && inb(old+2) == 0xff) {
compat += (next_offset += 0x400); /* leave lower 10 bits untouched */
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
index 8f9d98236c54..bb70bc74fab2 100644
--- a/drivers/ide/umc8672.c
+++ b/drivers/ide/umc8672.c
@@ -111,7 +111,7 @@ static void umc_set_speeds (byte speeds[])
static void tune_umc (ide_drive_t *drive, byte pio)
{
unsigned long flags;
- ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+ ide_hwgroup_t *hwgroup = ide_hwifs[drive->channel->index ^ 1].hwgroup;
if (pio == 255)
pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
@@ -160,5 +160,5 @@ void __init init_umc8672 (void) /* called from ide.c */
ide_hwifs[1].tuneproc = &tune_umc;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
}
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 38eb933105c9..d750057899e2 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -302,7 +302,7 @@ static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timi
static int via_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
unsigned int T, UT;
@@ -328,7 +328,7 @@ static int via_set_drive(ide_drive_t *drive, unsigned char speed)
ata_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
}
- via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+ via_set_speed(drive->channel->pci_dev, drive->dn, &t);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -344,7 +344,7 @@ static int via_set_drive(ide_drive_t *drive, unsigned char speed)
static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((via_enabled >> HWIF(drive)->channel) & 1))
+ if (!((via_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -368,7 +368,7 @@ int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
@@ -379,7 +379,7 @@ int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
via_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -523,12 +523,12 @@ unsigned int __init pci_init_via82cxxx(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
+unsigned int __init ata66_via82cxxx(struct ata_channel *hwif)
{
- return ((via_enabled & via_80w) >> hwif->channel) & 1;
+ return ((via_enabled & via_80w) >> hwif->unit) & 1;
}
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
+void __init ide_init_via82cxxx(struct ata_channel *hwif)
{
int i;
@@ -540,7 +540,7 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -559,8 +559,8 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif)
* We allow the BM-DMA driver to only work on enabled interfaces.
*/
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_via82cxxx(struct ata_channel *hwif, unsigned long dmabase)
{
- if ((via_enabled >> hwif->channel) & 1)
+ if ((via_enabled >> hwif->unit) & 1)
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 0a763bc07c60..9055970fa97f 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -100,7 +100,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 6194e0ceb9d7..5519f5146272 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -56,7 +56,6 @@
#define PRINTD(level, card, fmt, args...) do {} while (0)
#endif
-
static struct hpsb_host_driver *lynx_driver;
static unsigned int card_id;
@@ -636,7 +635,7 @@ static void aux_setup_pcls(struct ti_lynx *lynx)
static int mem_open(struct inode *inode, struct file *file)
{
- int cid = MINOR(inode->i_rdev);
+ int cid = minor(inode->i_rdev);
enum { t_rom, t_aux, t_ram } type;
struct memdata *md;
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 1f895a169813..6faed1df70e7 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
index b2d4aedff998..1974ff61c5eb 100644
--- a/drivers/isdn/avmb1/capifs.c
+++ b/drivers/isdn/avmb1/capifs.c
@@ -235,10 +235,9 @@ static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
unsigned int maxncci = 512;
char *this_char, *value;
- this_char = NULL;
- if ( options )
- this_char = strtok(options,",");
- for ( ; this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index 6ef1f9f33db6..5f6e530b1149 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -102,8 +102,8 @@ static char capi_manufakturer[64] = "AVM Berlin";
#define APPL(a) (&applications[(a)-1])
#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
#define APPL_IS_FREE(a) (APPL(a)->applid == 0)
-#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
-#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0)
+#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0)
#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index c0f818d0c5e2..3a578a2ac8a5 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -665,8 +665,11 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
else
cnt = skb->len;
- if (user)
+ if (user) {
+ spin_unlock_irqrestore(&eicon_lock, flags);
copy_to_user(p, skb->data, cnt);
+ spin_lock_irqsave(&eicon_lock, flags);
+ }
else
memcpy(p, skb->data, cnt);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index 77c9a77d61d0..478f94730b6c 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -65,6 +65,7 @@ MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
static int protocol = 2; /* EURO-ISDN Default */
MODULE_PARM(protocol, "i");
+MODULE_LICENSE("GPL");
// ----------------------------------------------------------------------
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
index 29a96edf399f..77f1320fc269 100644
--- a/drivers/isdn/hisax/hisax_isac.c
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -44,6 +44,7 @@ static char *ISACVer[] = {
MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+MODULE_LICENSE("GPL");
#define DBG_WARN 0x0001
#define DBG_IRQ 0x0002
diff --git a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c
index d904ddf9f91c..ae149d7bb431 100644
--- a/drivers/md/lvm-snap.c
+++ b/drivers/md/lvm-snap.c
@@ -302,6 +302,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
{
const char * reason;
kdev_t snap_phys_dev;
+ struct block_device *org_bdev, *snap_bdev;
unsigned long org_start, snap_start, virt_start, pe_off;
int idx = lv_snap->u.lv_remap_ptr, chunk_size = lv_snap->u.lv_chunk_size;
struct kiobuf * iobuf;
@@ -321,6 +322,15 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_start = lv_snap->u.lv_block_exception[idx].rsector_new;
+ org_bdev = bdget(kdev_t_to_nr(org_phys_dev));
+ if (!org_bdev)
+ goto fail_enomem;
+ snap_bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+ if (!snap_bdev) {
+ bdput(org_bdev);
+ goto fail_enomem;
+ }
+
#ifdef DEBUG_SNAPSHOT
printk(KERN_INFO
"%s -- COW: "
@@ -356,7 +366,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
nr_sectors, blksize_org))
goto fail_prepare;
- if (brw_kiovec(READ, 1, &iobuf, org_phys_dev,
+ if (brw_kiovec(READ, 1, &iobuf, org_bdev,
lv_snap->blocks, blksize_org) != (nr_sectors<<9))
goto fail_raw_read;
@@ -364,7 +374,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
nr_sectors, blksize_snap))
goto fail_prepare;
- if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &iobuf, snap_bdev,
lv_snap->blocks, blksize_snap) !=(nr_sectors<<9))
goto fail_raw_write;
}
@@ -387,16 +397,21 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
if (lv_snap->u.lv_remap_ptr * 100 / lv_snap->u.lv_remap_end >= lv_snap->lv_snapshot_use_rate)
wake_up_interruptible(&lv_snap->lv_snapshot_wait);
}
+ bdput(snap_bdev);
+ bdput(org_bdev);
return 0;
/* slow path */
out:
+ bdput(snap_bdev);
+ bdput(org_bdev);
+ out1:
lvm_drop_snapshot(vg, lv_snap, reason);
return 1;
fail_out_of_space:
reason = "out of space";
- goto out;
+ goto out1;
fail_raw_read:
reason = "read error";
goto out;
@@ -405,7 +420,9 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
goto out;
fail_blksize:
reason = "blocksize error";
- goto out;
+ fail_enomem:
+ reason = "out of memory";
+ goto out1;
fail_prepare:
reason = "couldn't prepare kiovec blocks "
@@ -569,6 +586,7 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
ulong blocks[1];
kdev_t snap_phys_dev;
+ struct block_device *bdev;
lv_block_exception_t *be;
struct kiobuf * COW_table_iobuf = lv_snap->lv_COW_table_iobuf;
lv_COW_table_disk_t * lv_COW_table =
@@ -581,6 +599,8 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
+ bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+
blksize_snap = block_size(snap_phys_dev);
COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
@@ -611,7 +631,7 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
COW_table_iobuf->length = blksize_snap;
- if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
blocks, blksize_snap) != blksize_snap)
goto fail_raw_write;
@@ -629,25 +649,30 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
idx++;
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
+ bdput(bdev);
+ bdev = bdget(kdev_t_to_nr(snap_phys_dev));
blksize_snap = block_size(snap_phys_dev);
blocks[0] = snap_pe_start >> (blksize_snap >> 10);
} else blocks[0]++;
- if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
blocks, blksize_snap) !=
blksize_snap)
goto fail_raw_write;
}
out:
+ bdput(bdev);
return 0;
fail_raw_write:
*reason = "write error";
+ bdput(bdev);
return 1;
fail_pv_get_number:
*reason = "_pv_get_number failed";
+ bdput(bdev);
return 1;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5e542a243ea4..800cb26a70c5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3768,7 +3768,7 @@ static int __init md_setup(char *str)
printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
return 0;
} else if (md_setup_args.device_names[minor]) {
- printk(KERN_WARNING "md: md=%d, Specified more then once. "
+ printk(KERN_WARNING "md: md=%d, Specified more than once. "
"Replacing previous definition.\n", minor);
}
switch (get_option(&str, &level)) { /* RAID Personality */
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index fe72982f1ce6..818fa08f0f59 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -385,7 +385,7 @@ static struct pci_driver gemtek_pci_driver =
name: "gemtek_pci",
id_table: gemtek_pci_id,
probe: gemtek_pci_probe,
- remove: __devexit_p(gemtek_pci_remove)
+ remove: __devexit_p(gemtek_pci_remove),
};
static int __init gemtek_pci_init_module( void )
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index d69f8378ca79..834d86e45f49 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -107,20 +107,18 @@ static int video_open(struct inode *inode, struct file *file)
}
/*
- * ioctl helper function -- handles userspace copying
+ * helper function -- handles userspace copying for ioctl arguments
*/
int
-video_generic_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg))
{
- struct video_device *vfl = video_devdata(file);
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
-
- if (vfl->kernel_ioctl == NULL)
- return -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
@@ -147,7 +145,7 @@ video_generic_ioctl(struct inode *inode, struct file *file,
}
/* call driver */
- err = vfl->kernel_ioctl(inode, file, cmd, parg);
+ err = func(inode, file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
@@ -512,7 +510,7 @@ module_exit(videodev_exit)
EXPORT_SYMBOL(video_register_device);
EXPORT_SYMBOL(video_unregister_device);
EXPORT_SYMBOL(video_devdata);
-EXPORT_SYMBOL(video_generic_ioctl);
+EXPORT_SYMBOL(video_usercopy);
EXPORT_SYMBOL(video_exclusive_open);
EXPORT_SYMBOL(video_exclusive_release);
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 2c52149cace0..85df53b919f9 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -440,7 +440,7 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
timeo = jiffies + HZ;
- while(jiffies<timeo){
+ while(time_before(jiffies, timeo)){
map->write32(map,CMD_READ_STATUS,adr);
status = map->read32(map,adr);
if((status & SR_READY)==SR_READY){
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
index cadcc6ccae9c..fccc6c7a4afb 100644
--- a/drivers/mtd/devices/blkmtd.c
+++ b/drivers/mtd/devices/blkmtd.c
@@ -264,7 +264,7 @@ static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page)
DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
- err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
+ err = brw_kiovec(READ, 1, &iobuf, rawdevice->binding, blocks, rawdevice->sector_size);
DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
iobuf->locked = 0;
free_kiovec(1, &iobuf);
@@ -401,7 +401,7 @@ static int write_queue_task(void *data)
iobuf->nr_pages = cpagecnt;
iobuf->length = cursectors << item->rawdevice->sector_bits;
DEBUG(3, "blkmtd: write_task: about to kiovec\n");
- err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
+ err = brw_kiovec(WRITE, 1, &iobuf, item->rawdevice->binding, blocks, item->rawdevice->sector_size);
DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
if(err != (cursectors << item->rawdevice->sector_bits)) {
/* if an error occured - set this to exit the loop */
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 1fc63d360def..947b797d19f2 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -195,7 +195,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg);
static int ftl_open(struct inode *inode, struct file *file);
static release_t ftl_close(struct inode *inode, struct file *file);
-static int ftl_reread_partitions(int minor);
+static int ftl_reread_partitions(kdev_t dev);
static void ftl_erase_callback(struct erase_info *done);
@@ -842,7 +842,7 @@ static u_int32_t find_free(partition_t *part)
static int ftl_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
partition_t *partition;
if (minor>>4 >= MAX_MTD_DEVICES)
@@ -878,7 +878,7 @@ static int ftl_open(struct inode *inode, struct file *file)
static release_t ftl_close(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
partition_t *part = myparts[minor >> 4];
int i;
@@ -1114,7 +1114,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
struct hd_geometry *geo = (struct hd_geometry *)arg;
- int ret = 0, minor = MINOR(inode->i_rdev);
+ int ret = 0, minor = minor(inode->i_rdev);
partition_t *part= myparts[minor >> 4];
u_long sect;
@@ -1139,7 +1139,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
break;
case BLKRRPART:
- ret = ftl_reread_partitions(minor);
+ ret = ftl_reread_partitions(inode->i_rdev);
break;
case BLKROSET:
case BLKROGET:
@@ -1161,7 +1161,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
static int ftl_reread_partitions(kdev_t dev)
{
- int minor = MINOR(dev);
+ int minor = minor(dev);
partition_t *part = myparts[minor >> 4];
int res;
@@ -1197,7 +1197,7 @@ static void do_ftl_request(request_arg_t)
// sti();
INIT_REQUEST;
- minor = MINOR(CURRENT->rq_dev);
+ minor = minor(CURRENT->rq_dev);
part = myparts[minor >> 4];
if (part) {
@@ -1369,7 +1369,7 @@ static void __exit cleanup_ftl(void)
unregister_blkdev(FTL_MAJOR, "ftl");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
- bklk_clear(FTL_MAJOR);
+ blk_clear(FTL_MAJOR);
del_gendisk(&ftl_gendisk);
}
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 8dfec3a98ea9..08782d2c84f7 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -541,7 +541,7 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
return -EACCES;
#endif
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->b_rdev, 0);
down(&mtdblk->cache_sem);
write_cached_data(mtdblk);
up(&mtdblk->cache_sem);
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 79f4a0132a2a..a3f4c6c8e83d 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -222,7 +222,7 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
if(!capable(CAP_SYS_ADMIN)) return -EACCES;
#endif
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
if (mtd->sync)
mtd->sync(mtd);
return 0;
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index baaefc344070..419352a59a9a 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -207,3 +207,5 @@ int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
EXPORT_SYMBOL(nand_calculate_ecc);
EXPORT_SYMBOL(nand_correct_data);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 2b60ed1319e4..8fdf2171aa7a 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -796,7 +796,7 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
case BLKFLSBUF:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
if (nftl->mtd->sync)
nftl->mtd->sync(nftl->mtd);
return 0;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 945476049d31..b66a44a74f32 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -263,13 +263,13 @@ el2_probe1(struct net_device *dev, int ioaddr)
#endif /* EL2MEMTEST */
if (dev->mem_start)
- dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + EL2_MEMSIZE;
if (wordlength) { /* No Tx pages to skip over to get to Rx */
- dev->rmem_start = dev->mem_start;
+ ei_status.rmem_start = dev->mem_start;
ei_status.name = "3c503/16";
} else {
- dev->rmem_start = TX_PAGES*256 + dev->mem_start;
+ ei_status.rmem_start = TX_PAGES*256 + dev->mem_start;
ei_status.name = "3c503";
}
}
@@ -549,7 +549,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
unsigned short int *buf;
unsigned short word;
- int end_of_ring = dev->rmem_end;
+ int end_of_ring = ei_status.rmem_end;
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
@@ -559,7 +559,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index c49bf4769745..ed6c39fae6ca 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1383,7 +1383,7 @@ static inline void elp_init(struct net_device *dev)
/*
* memory information
*/
- dev->mem_start = dev->mem_end = dev->rmem_end = dev->rmem_start = 0;
+ dev->mem_start = dev->mem_end = 0;
}
/************************************************************
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index a098e7f1399d..91db251922b5 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -51,8 +51,6 @@ extern int ei_open(struct net_device *dev);
extern int ei_close(struct net_device *dev);
extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-/* Most of these entries should be in 'struct net_device' (or most of the
- things in there should be here!) */
/* You have one of these per-board */
struct ei_device {
const char *name;
@@ -60,6 +58,8 @@ struct ei_device {
void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
void (*block_output)(struct net_device *, int, const unsigned char *, int);
void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+ unsigned long rmem_start;
+ unsigned long rmem_end;
unsigned char mcfilter[8];
unsigned open:1;
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index c715ce2ec6a8..29ffbae9923b 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -57,6 +57,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
if [ "$CONFIG_MIPS_AU1000" = "y" ]; then
bool ' MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET
fi
+ if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+ tristate ' SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
+ fi
if [ "$CONFIG_SGI_IP27" = "y" ]; then
bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
fi
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f423ce03e25a..ba862018f2a2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o mii.o
obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_TC35815) += tc35815.o
ifeq ($(CONFIG_SK98LIN),y)
obj-y += sk98lin/sk98lin.o
@@ -133,6 +134,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
+obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
@@ -153,6 +155,7 @@ obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_AT1500) += lance.o
obj-$(CONFIG_LANCE) += lance.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_SUN3LANCE) += sun3lance.o
obj-$(CONFIG_DEFXX) += defxx.o
obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 671588da6342..db7a696ea7ce 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -12,6 +12,8 @@
* Donald J. Becker, <becker@scyld.com>
*
* Changelog:
+ * Paul Gortmaker (03/2002)
+ - struct init cleanup, enable multiple ISA autoprobes.
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
* - fix sbni: s/device/net_device/
* Paul Gortmaker (06/98):
@@ -86,6 +88,7 @@ extern int smc_init( struct net_device * );
extern int sgiseeq_probe(struct net_device *);
extern int atarilance_probe(struct net_device *);
extern int sun3lance_probe(struct net_device *);
+extern int sun3_82586_probe(struct net_device *);
extern int apne_probe(struct net_device *);
extern int bionet_probe(struct net_device *);
extern int pamsnet_probe(struct net_device *);
@@ -332,6 +335,9 @@ static struct devprobe m68k_probes[] __initdata = {
#ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */
{sun3lance_probe, 0},
#endif
+#ifdef CONFIG_SUN3_82586 /* sun3 onboard Intel 82586 chip */
+ {sun3_82586_probe, 0},
+#endif
#ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */
{apne_probe, 0},
#endif
@@ -410,14 +416,7 @@ static int __init ethif_probe(struct net_device *dev)
return 0;
if (probe_list(dev, mca_probes) == 0)
return 0;
- /*
- * Backwards compatibility - an I/O of 0xffe0 was used to indicate
- * that we shouldn't do a bunch of potentially risky ISA probes
- * for ethN (N>1). Since the widespread use of modules, *nobody*
- * compiles a kernel with all the ISA drivers built in anymore,
- * and so we should delete this check in linux 2.3 - Paul G.
- */
- if (base_addr != 0xffe0 && probe_list(dev, isa_probes) == 0)
+ if (probe_list(dev, isa_probes) == 0)
return 0;
if (probe_list(dev, parport_probes) == 0)
return 0;
@@ -466,74 +465,102 @@ static int fcif_probe(struct net_device *dev)
#ifdef CONFIG_ETHERTAP
- static struct net_device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
-# undef NEXT_DEV
-# define NEXT_DEV (&tap0_dev)
+static struct net_device tap0_dev = {
+ name: "tap0",
+ base_addr: NETLINK_TAPBASE,
+ next: NEXT_DEV,
+ init: ethertap_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&tap0_dev)
#endif
#ifdef CONFIG_SDLA
- extern int sdla_init(struct net_device *);
- static struct net_device sdla0_dev = { "sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, };
-
-# undef NEXT_DEV
-# define NEXT_DEV (&sdla0_dev)
+extern int sdla_init(struct net_device *);
+static struct net_device sdla0_dev = {
+ name: "sdla0",
+ next: NEXT_DEV,
+ init: sdla_init,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&sdla0_dev)
#endif
#if defined(CONFIG_LTPC)
- extern int ltpc_probe(struct net_device *);
- static struct net_device dev_ltpc = {
- "lt0",
- 0, 0, 0, 0,
- 0x0, 0,
- 0, 0, 0, NEXT_DEV, ltpc_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&dev_ltpc)
+extern int ltpc_probe(struct net_device *);
+static struct net_device dev_ltpc = {
+ name: "lt0",
+ next: NEXT_DEV,
+ init: ltpc_probe
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&dev_ltpc)
#endif /* LTPC */
#if defined(CONFIG_COPS)
- extern int cops_probe(struct net_device *);
- static struct net_device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe };
- static struct net_device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe };
- static struct net_device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&cops0_dev)
+extern int cops_probe(struct net_device *);
+static struct net_device cops2_dev = {
+ name: "lt2",
+ next: NEXT_DEV,
+ init: cops_probe,
+};
+static struct net_device cops1_dev = {
+ name: "lt1",
+ next: &cops2_dev,
+ init: cops_probe,
+};
+static struct net_device cops0_dev = {
+ name: "lt0",
+ next: &cops1_dev,
+ init: cops_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&cops0_dev)
#endif /* COPS */
-
-/* The first device defaults to I/O base '0', which means autoprobe. */
-#ifndef ETH0_ADDR
-# define ETH0_ADDR 0
-#endif
-#ifndef ETH0_IRQ
-# define ETH0_IRQ 0
-#endif
-
-/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
- which means "don't do ISA probes". Distributions don't ship kernels with
- all ISA drivers compiled in anymore, so its probably no longer an issue. */
-
-#define ETH_NOPROBE_ADDR 0xffe0
-
static struct net_device eth7_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+ name: "eth%d",
+ next: NEXT_DEV,
+ init: ethif_probe,
+};
static struct net_device eth6_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth7_dev,
+ init: ethif_probe,
+};
static struct net_device eth5_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth6_dev,
+ init: ethif_probe,
+};
static struct net_device eth4_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth5_dev,
+ init: ethif_probe,
+};
static struct net_device eth3_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth4_dev,
+ init: ethif_probe,
+};
static struct net_device eth2_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth3_dev,
+ init: ethif_probe,
+};
static struct net_device eth1_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
-
+ name: "eth%d",
+ next: &eth2_dev,
+ init: ethif_probe,
+};
static struct net_device eth0_dev = {
- "eth%d", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth1_dev,
+ init: ethif_probe,
+};
-# undef NEXT_DEV
-# define NEXT_DEV (&eth0_dev)
+#undef NEXT_DEV
+#define NEXT_DEV (&eth0_dev)
@@ -558,75 +585,153 @@ trif_probe(struct net_device *dev)
return 0;
}
static struct net_device tr7_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe };
+ name: "tr%d",
+ next: NEXT_DEV,
+ init: trif_probe,
+};
static struct net_device tr6_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe };
+ name: "tr%d",
+ next: &tr7_dev,
+ init: trif_probe,
+};
static struct net_device tr5_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe };
+ name: "tr%d",
+ next: &tr6_dev,
+ init: trif_probe,
+};
static struct net_device tr4_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe };
+ name: "tr%d",
+ next: &tr5_dev,
+ init: trif_probe,
+};
static struct net_device tr3_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe };
+ name: "tr%d",
+ next: &tr4_dev,
+ init: trif_probe,
+};
static struct net_device tr2_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe };
+ name: "tr%d",
+ next: &tr3_dev,
+ init: trif_probe,
+};
static struct net_device tr1_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe };
+ name: "tr%d",
+ next: &tr2_dev,
+ init: trif_probe,
+};
static struct net_device tr0_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&tr0_dev)
+ name: "tr%d",
+ next: &tr1_dev,
+ init: trif_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&tr0_dev)
#endif
#ifdef CONFIG_FDDI
- static struct net_device fddi7_dev =
- {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe};
- static struct net_device fddi6_dev =
- {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe};
- static struct net_device fddi5_dev =
- {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe};
- static struct net_device fddi4_dev =
- {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe};
- static struct net_device fddi3_dev =
- {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe};
- static struct net_device fddi2_dev =
- {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe};
- static struct net_device fddi1_dev =
- {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe};
- static struct net_device fddi0_dev =
- {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe};
+static struct net_device fddi7_dev = {
+ name: "fddi7",
+ next: NEXT_DEV,
+ init: fddiif_probe
+};
+static struct net_device fddi6_dev = {
+ name: "fddi6",
+ next: &fddi7_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi5_dev = {
+ name: "fddi5",
+ next: &fddi6_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi4_dev = {
+ name: "fddi4",
+ next: &fddi5_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi3_dev = {
+ name: "fddi3",
+ next: &fddi4_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi2_dev = {
+ name: "fddi2",
+ next: &fddi3_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi1_dev = {
+ name: "fddi1",
+ next: &fddi2_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi0_dev = {
+ name: "fddi0",
+ next: &fddi1_dev,
+ init: fddiif_probe
+};
#undef NEXT_DEV
#define NEXT_DEV (&fddi0_dev)
#endif
#ifdef CONFIG_NET_FC
- static struct net_device fc1_dev = {
- "fc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fcif_probe};
- static struct net_device fc0_dev = {
- "fc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fc1_dev, fcif_probe};
-# undef NEXT_DEV
-# define NEXT_DEV (&fc0_dev)
+static struct net_device fc1_dev = {
+ name: "fc1",
+ next: NEXT_DEV,
+ init: fcif_probe
+};
+static struct net_device fc0_dev = {
+ name: "fc0",
+ next: &fc1_dev,
+ init: fcif_probe
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&fc0_dev)
#endif
#ifdef CONFIG_SBNI
- static struct net_device sbni7_dev =
- {"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
- static struct net_device sbni6_dev =
- {"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
- static struct net_device sbni5_dev =
- {"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
- static struct net_device sbni4_dev =
- {"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
- static struct net_device sbni3_dev =
- {"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
- static struct net_device sbni2_dev =
- {"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
- static struct net_device sbni1_dev =
- {"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
- static struct net_device sbni0_dev =
- {"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+static struct net_device sbni7_dev = {
+ name: "sbni7",
+ next: NEXT_DEV,
+ init: sbni_probe,
+};
+static struct net_device sbni6_dev =
+ name: "sbni6",
+ next: &sbni7_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni5_dev =
+ name: "sbni5",
+ next: &sbni6_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni4_dev =
+ name: "sbni4",
+ next: &sbni5_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni3_dev =
+ name: "sbni3",
+ next: &sbni4_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni2_dev =
+ name: "sbni2",
+ next: &sbni3_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni1_dev =
+ name: "sbni1",
+ next: &sbni2_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni0_dev =
+ name: "sbni0",
+ next: &sbni1_dev,
+ init: sbni_probe,
+};
#undef NEXT_DEV
#define NEXT_DEV (&sbni0_dev)
@@ -638,8 +743,11 @@ static struct net_device tr0_dev = {
*/
extern int loopback_init(struct net_device *dev);
-struct net_device loopback_dev =
- {"lo", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, loopback_init};
+struct net_device loopback_dev = {
+ name: "lo",
+ next: NEXT_DEV,
+ init: loopback_init
+};
/*
* The @dev_base list is protected by @dev_base_lock and the rtln
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index ced6b5033411..4a730e250400 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -226,8 +226,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
AC_STOP_PG/4, dev->mem_start);
}
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (AC_STOP_PG - AC_START_PG)*256;
ei_status.name = "AC3200";
@@ -302,12 +302,12 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk
{
unsigned long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 7f9390dd4863..4a890e944b3f 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -65,7 +65,10 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/sockios.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#include <linux/if_vlan.h>
+#endif
#ifdef SIOCETHTOOL
#include <linux/ethtool.h>
@@ -320,9 +323,11 @@ static inline void tasklet_init(struct tasklet_struct *tasklet,
#if (defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)) && \
defined(NETIF_F_HW_VLAN_RX)
-#define ACENIC_DO_VLAN 1
+#define ACENIC_DO_VLAN 1
+#define ACE_RCB_VLAN_FLAG RCB_FLG_VLAN_ASSIST
#else
-#define ACENIC_DO_VLAN 0
+#define ACENIC_DO_VLAN 0
+#define ACE_RCB_VLAN_FLAG 0
#endif
#include "acenic.h"
@@ -563,7 +568,7 @@ static int tx_ratio[ACE_MAX_MOD_PARMS];
static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
static char version[] __initdata =
- "acenic.c: v0.88 03/14/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
+ "acenic.c: v0.89 03/15/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
static struct net_device *root_dev;
@@ -1461,10 +1466,8 @@ static int __init ace_init(struct net_device *dev)
set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
- info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_std_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ info->rx_std_ctrl.flags =
+ RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
memset(ap->rx_std_ring, 0,
RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1479,10 +1482,8 @@ static int __init ace_init(struct net_device *dev)
(ap->rx_ring_base_dma +
(sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
info->rx_jumbo_ctrl.max_len = 0;
- info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_jumbo_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ info->rx_jumbo_ctrl.flags =
+ RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
memset(ap->rx_jumbo_ring, 0,
RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1504,10 +1505,7 @@ static int __init ace_init(struct net_device *dev)
RX_JUMBO_RING_ENTRIES))));
info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
info->rx_mini_ctrl.flags =
- RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_mini_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
ap->rx_mini_ring[i].flags =
@@ -1554,7 +1552,7 @@ static int __init ace_init(struct net_device *dev)
}
info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
- tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
+ tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
/*
* The Tigon I does not like having the TX ring in host memory ;-(
@@ -1564,9 +1562,6 @@ static int __init ace_init(struct net_device *dev)
#if TX_COAL_INTS_ONLY
tmp |= RCB_FLG_COAL_INT_ONLY;
#endif
-#if ACENIC_DO_VLAN
- tmp |= RCB_FLG_VLAN_ASSIST;
-#endif
info->tx_ctrl.flags = tmp;
set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
@@ -1592,7 +1587,7 @@ static int __init ace_init(struct net_device *dev)
ace_set_rxtx_parms(dev, 0);
if (board_idx == BOARD_IDX_OVERFLOW) {
- printk(KERN_WARNING "%s: more then %i NICs detected, "
+ printk(KERN_WARNING "%s: more than %i NICs detected, "
"ignoring module parameters!\n",
dev->name, ACE_MAX_MOD_PARMS);
} else if (board_idx >= 0) {
@@ -2181,14 +2176,6 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
}
-#if ACENIC_DO_VLAN
-static int ace_vlan_rx(struct ace_private *ap, struct sk_buff *skb, u16 vlan_tag)
-{
- return vlan_hwaccel_rx(skb, ap->vlgrp, vlan_tag);
-}
-#endif
-
-
static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
{
struct ace_private *ap = dev->priv;
@@ -2274,11 +2261,9 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
}
/* send it up */
-
#if ACENIC_DO_VLAN
- if (ap->vlgrp != NULL &&
- (bd_flags & BD_FLG_VLAN_TAG)) {
- ace_vlan_rx(ap, skb, retdesc->vlan);
+ if (ap->vlgrp && (bd_flags & BD_FLG_VLAN_TAG)) {
+ vlan_hwaccel_rx(skb, ap->vlgrp, retdesc->vlan);
} else
#endif
netif_rx(skb);
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index 8933695b83a9..61eeecf8887a 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -642,10 +642,6 @@ struct ace_private
struct ace_skb *skb;
dma_addr_t info_dma; /* 32/64 bit */
-#if ACENIC_DO_VLAN
- struct vlan_group *vlgrp;
-#endif
-
int version, link;
int promisc, mcast_all;
@@ -655,7 +651,6 @@ struct ace_private
struct tx_desc *tx_ring;
u32 tx_prd;
volatile u32 tx_ret_csm;
- struct timer_list timer;
int tx_ring_entries;
/*
@@ -675,6 +670,10 @@ struct ace_private
struct rx_desc *rx_mini_ring;
struct rx_desc *rx_return_ring;
+#if ACENIC_DO_VLAN
+ struct vlan_group *vlgrp;
+#endif
+
int tasklet_pending, jumbo;
struct tasklet_struct ace_tasklet;
diff --git a/drivers/net/aironet4500.h b/drivers/net/aironet4500.h
index 9f64d4ad3bf3..24eebfa6ecca 100644
--- a/drivers/net/aironet4500.h
+++ b/drivers/net/aironet4500.h
@@ -450,7 +450,7 @@ struct awc_fid_queue {
};
-extern __inline__ void
+static __inline__ void
awc_fid_queue_init(struct awc_fid_queue * queue){
unsigned long flags;
@@ -463,7 +463,7 @@ awc_fid_queue_init(struct awc_fid_queue * queue){
spin_unlock_irqrestore(&queue->spinlock,flags);
};
-extern inline void
+static inline void
awc_fid_queue_push_tail( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -488,7 +488,7 @@ awc_fid_queue_push_tail( struct awc_fid_queue * queue,
};
-extern inline void
+static inline void
awc_fid_queue_push_head( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -513,7 +513,7 @@ awc_fid_queue_push_head( struct awc_fid_queue * queue,
-extern inline void
+static inline void
awc_fid_queue_rm( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -541,7 +541,7 @@ awc_fid_queue_rm( struct awc_fid_queue * queue,
}
};
-extern inline void
+static inline void
awc_fid_queue_remove( struct awc_fid_queue * queue,
struct awc_fid * fid){
unsigned long flags;
@@ -555,7 +555,7 @@ awc_fid_queue_remove( struct awc_fid_queue * queue,
-extern inline struct awc_fid *
+static inline struct awc_fid *
awc_fid_queue_pop_head( struct awc_fid_queue * queue){
unsigned long flags;
@@ -575,7 +575,7 @@ awc_fid_queue_pop_head( struct awc_fid_queue * queue){
-extern inline struct awc_fid *
+static inline struct awc_fid *
awc_fid_queue_pop_tail( struct awc_fid_queue * queue){
unsigned long flags;
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index 571670eaeb84..b2f16c36b2c2 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -153,8 +153,6 @@ static int __init arcrimi_found(struct net_device *dev)
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
- dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
- dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* initialize the rest of the device structure. */
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index fd92d5e808f6..9d208f400df7 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -447,8 +447,6 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq,
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
- dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
- dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* Initialize the rest of the device structure. */
memset(lp, 0, sizeof(struct arcnet_local));
diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c
index 1bc62e2ecd26..968a7692104b 100644
--- a/drivers/net/arlan.c
+++ b/drivers/net/arlan.c
@@ -128,7 +128,7 @@ int arlan_command(struct net_device * dev, int command);
EXPORT_SYMBOL(arlan_command);
-extern inline long long arlan_time(void)
+static inline long long arlan_time(void)
{
struct timeval timev;
do_gettimeofday(&timev);
@@ -186,7 +186,7 @@ extern inline long long arlan_time(void)
-extern inline int arlan_drop_tx(struct net_device *dev)
+static inline int arlan_drop_tx(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -554,7 +554,7 @@ command_busy_end:
};
-extern inline void arlan_command_process(struct net_device *dev)
+static inline void arlan_command_process(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -575,7 +575,7 @@ extern inline void arlan_command_process(struct net_device *dev)
}
-extern inline void arlan_retransmit_now(struct net_device *dev)
+static inline void arlan_retransmit_now(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1405,7 +1405,7 @@ bad_end:
}
-extern inline int DoNotReTransmitCrap(struct net_device *dev)
+static inline int DoNotReTransmitCrap(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1415,7 +1415,7 @@ extern inline int DoNotReTransmitCrap(struct net_device *dev)
}
-extern inline int DoNotWaitReTransmitCrap(struct net_device *dev)
+static inline int DoNotWaitReTransmitCrap(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1424,7 +1424,7 @@ extern inline int DoNotWaitReTransmitCrap(struct net_device *dev)
return 0;
}
-extern inline void arlan_queue_retransmit(struct net_device *dev)
+static inline void arlan_queue_retransmit(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 01d144e50a80..ccd7c8e138c2 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -465,7 +465,7 @@ err_out:
#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */
/* Delay between EEPROM clock transitions. */
-#define eeprom_delay() do {} while (0);
+#define eeprom_delay() do { } while (0)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 5a31cfe28fd9..c3904af3bbe3 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -667,7 +667,7 @@ static void atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs)
}
num_tx_since_rx++;
} else if (num_tx_since_rx > 8
- && jiffies > dev->last_rx + HZ) {
+ && time_after(jiffies, dev->last_rx + HZ)) {
if (net_debug > 2)
printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and "
"%ld jiffies status %02x CMR1 %02x.\n", dev->name,
diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c
index cc13e328cae6..ea424dcb7437 100644
--- a/drivers/net/daynaport.c
+++ b/drivers/net/daynaport.c
@@ -513,14 +513,14 @@ static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_
ei_status.tx_start_page = CABLETRON_TX_START_PG;
ei_status.rx_start_page = CABLETRON_RX_START_PG;
ei_status.stop_page = CABLETRON_RX_STOP_PG;
- dev->rmem_start = dev->mem_start;
- dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+ ei_status.rmem_start = dev->mem_start;
+ ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
} else {
ei_status.tx_start_page = WD_START_PG;
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->rmem_end = dev->mem_end;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_end = dev->mem_end;
}
if(promoff==-1) /* Use nubus resources ? */
@@ -779,14 +779,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
* is word per long onto our space.
*/
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
count -= semi_count;
dayna_memcpy_fromcard(dev, skb->data + semi_count,
- dev->rmem_start - dev->mem_start, count);
+ ei_status.rmem_start - dev->mem_start, count);
}
else
{
@@ -820,14 +820,14 @@ static void sane_block_input(struct net_device *dev, int count, struct sk_buff *
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
count -= semi_count;
memcpy(skb->data + semi_count,
- (char *)dev->rmem_start, count);
+ (char *)ei_status.rmem_start, count);
}
else
{
@@ -881,14 +881,14 @@ static void slow_sane_block_input(struct net_device *dev, int count, struct sk_b
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
count -= semi_count;
word_memcpy_fromcard(skb->data + semi_count,
- (char *)dev->rmem_start, count);
+ (char *)ei_status.rmem_start, count);
}
else
{
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 98d821621501..e8ec685354d4 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -449,11 +449,17 @@ static int de620_open(struct net_device *dev)
return ret;
}
- if (adapter_init(dev))
- return -EIO;
+ if (adapter_init(dev)) {
+ ret = -EIO;
+ goto out_free_irq;
+ }
netif_start_queue(dev);
return 0;
+
+out_free_irq:
+ free_irq(dev->irq, dev);
+ return ret;
}
/************************************************
@@ -850,7 +856,10 @@ int __init de620_probe(struct net_device *dev)
return -EBUSY;
}
#endif
- request_region(dev->base_addr, 3, "de620");
+ if (!request_region(dev->base_addr, 3, "de620")) {
+ printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
+ return -EBUSY;
+ }
/* else, got it! */
printk(", Ethernet Address: %2.2X",
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 8869df646b2a..62414c0ce4af 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1,6 +1,6 @@
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
/*
- Copyright (c) 2001 by D-Link Corporation
+ Copyright (c) 2001,2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
@@ -27,12 +27,14 @@
Added tx_coalesce paramter.
1.07 2002/01/03 Fixed miscount of RX frame error.
1.08 2002/01/17 Fixed the multicast bug.
+ 1.09 2002/03/07 Move rx-poll-now to re-fill loop.
+ Added rio_timer() to watch rx buffers.
*/
#include "dl2k.h"
static char version[] __devinitdata =
- KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
+ KERN_INFO "D-Link DL2000-based linux driver v1.09 2002/03/07\n";
#define MAX_UNITS 8
static int mtu[MAX_UNITS];
@@ -42,9 +44,10 @@ static char *media[MAX_UNITS];
static int tx_flow[MAX_UNITS];
static int rx_flow[MAX_UNITS];
static int copy_thresh;
-static int rx_coalesce = DEFAULT_RXC;
-static int rx_timeout = DEFAULT_RXT;
-static int tx_coalesce = DEFAULT_TXC;
+static int rx_coalesce; /* Rx frame count each interrupt */
+static int rx_timeout; /* Rx DMA wait time in 64ns increments */
+static int tx_coalesce = DEFAULT_TXC; /* HW xmit count each TxComplete [1-8] */
+
MODULE_AUTHOR ("Edward Peng");
MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
@@ -71,6 +74,7 @@ static int max_intrloop = 50;
static int multicast_filter_limit = 0x40;
static int rio_open (struct net_device *dev);
+static void rio_timer (unsigned long data);
static void tx_timeout (struct net_device *dev);
static void alloc_list (struct net_device *dev);
static int start_xmit (struct sk_buff *skb, struct net_device *dev);
@@ -146,6 +150,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->chip_id = chip_idx;
np->pdev = pdev;
spin_lock_init (&np->lock);
+ spin_lock_init (&np->rx_lock);
/* Parse manual configuration */
np->an_enable = 1;
@@ -260,6 +265,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->an_enable = 1;
mii_set_media (dev);
}
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
/* Reset all logic functions */
writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
@@ -340,7 +346,7 @@ parse_eeprom (struct net_device *dev)
}
/* Check CRC */
- crc = ~ether_crc_le(256 - 4, sromdata);
+ crc = ~ether_crc_le(256 - 4, sromdata);
if (psrom->crc != crc) {
printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
return -1;
@@ -421,8 +427,10 @@ rio_open (struct net_device *dev)
ioaddr + RxDMAIntCtrl);
}
/* Set RIO to poll every N*320nsec. */
- writeb (0xff, ioaddr + RxDMAPollPeriod);
+ writeb (0x20, ioaddr + RxDMAPollPeriod);
writeb (0xff, ioaddr + TxDMAPollPeriod);
+ writeb (0x30, ioaddr + RxDMABurstThresh);
+ writeb (0x30, ioaddr + RxDMAUrgentThresh);
netif_start_queue (dev);
writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
/* VLAN supported */
@@ -445,9 +453,59 @@ rio_open (struct net_device *dev)
/* clear statistics */
get_stats (dev);
+ init_timer (&np->timer);
+ np->timer.expires = jiffies + 1*HZ;
+ np->timer.data = (unsigned long) dev;
+ np->timer.function = &rio_timer;
+ add_timer (&np->timer);
return 0;
}
+static void
+rio_timer (unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct netdev_private *np = dev->priv;
+ unsigned int entry;
+ int next_tick = 1*HZ;
+ unsigned long flags;
+ /* Recover rx ring exhausted error */
+ if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
+ printk(KERN_INFO "Try to recover rx ring exhausted...\n");
+ spin_lock_irqsave(&np->rx_lock, flags);
+ /* Re-allocate skbuffs to fill the descriptor ring */
+ for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+ struct sk_buff *skb;
+ entry = np->old_rx % RX_RING_SIZE;
+ /* Dropped packets don't need to re-allocate */
+ if (np->rx_skbuff[entry] == NULL) {
+ skb = dev_alloc_skb (np->rx_buf_sz);
+ if (skb == NULL) {
+ np->rx_ring[entry].fraginfo = 0;
+ printk (KERN_INFO
+ "%s: Still unable to re-allocate Rx skbuff.#%d\n",
+ dev->name, entry);
+ break;
+ }
+ np->rx_skbuff[entry] = skb;
+ skb->dev = dev;
+ /* 16 byte align the IP header */
+ skb_reserve (skb, 2);
+ np->rx_ring[entry].fraginfo =
+ cpu_to_le64 (pci_map_single
+ (np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE));
+ }
+ np->rx_ring[entry].fraginfo |=
+ cpu_to_le64 (np->rx_buf_sz) << 48;
+ np->rx_ring[entry].status = 0;
+ } /* end for */
+ spin_unlock_irqrestore (&np->rx_lock, flags);
+ } /* end if */
+ np->timer.expires = jiffies + next_tick;
+ add_timer(&np->timer);
+}
+
static void
tx_timeout (struct net_device *dev)
{
@@ -499,16 +557,14 @@ alloc_list (struct net_device *dev)
np->tx_ring[i].status = cpu_to_le64 (TFDDone);
np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
((i+1)%TX_RING_SIZE) *
- sizeof (struct
- netdev_desc));
+ sizeof (struct netdev_desc));
}
/* Initialize Rx descriptors */
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
((i + 1) % RX_RING_SIZE) *
- sizeof (struct
- netdev_desc));
+ sizeof (struct netdev_desc));
np->rx_ring[i].status = 0;
np->rx_ring[i].fraginfo = 0;
np->rx_skbuff[i] = 0;
@@ -529,8 +585,8 @@ alloc_list (struct net_device *dev)
skb_reserve (skb, 2); /* 16 byte align the IP header. */
/* Rubicon now supports 40 bits of addressing space. */
np->rx_ring[i].fraginfo =
- cpu_to_le64 (pci_map_single
- (np->pdev, skb->tail, np->rx_buf_sz,
+ cpu_to_le64 ( pci_map_single (
+ np->pdev, skb->tail, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
}
@@ -773,6 +829,8 @@ receive_packet (struct net_device *dev)
int entry = np->cur_rx % RX_RING_SIZE;
int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
int rx_shift;
+
+ spin_lock (&np->rx_lock);
if (np->old_rx > RX_RING_SIZE) {
rx_shift = RX_RING_SIZE;
np->old_rx -= rx_shift;
@@ -828,12 +886,14 @@ receive_packet (struct net_device *dev)
skb_put (skb, pkt_len);
}
skb->protocol = eth_type_trans (skb, dev);
-#if 0
+#if 0
/* Checksum done by hw, but csum value unavailable. */
- if (!(frame_status & (TCPError | UDPError | IPError))) {
+ if (np->pci_rev_id >= 0x0c &&
+ !(frame_status & (TCPError | UDPError | IPError))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ }
#endif
+
netif_rx (skb);
dev->last_rx = jiffies;
}
@@ -849,9 +909,10 @@ receive_packet (struct net_device *dev)
skb = dev_alloc_skb (np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
- printk (KERN_ERR
- "%s: Allocate Rx buffer error!",
- dev->name);
+ printk (KERN_INFO
+ "%s: receive_packet: "
+ "Unable to re-allocate Rx skbuff.#%d\n",
+ dev->name, entry);
break;
}
np->rx_skbuff[entry] = skb;
@@ -866,13 +927,12 @@ receive_packet (struct net_device *dev)
np->rx_ring[entry].fraginfo |=
cpu_to_le64 (np->rx_buf_sz) << 48;
np->rx_ring[entry].status = 0;
+ /* RxDMAPollNow */
+ writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+ dev->base_addr + DMACtrl);
}
-
- /* RxDMAPollNow */
- writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
- dev->base_addr + DMACtrl);
-
DEBUG_RFD_DUMP (np, 2);
+ spin_unlock(&np->rx_lock);
return 0;
}
@@ -1006,7 +1066,7 @@ set_multicast (struct net_device *dev)
hash_table[0] = hash_table[1] = 0;
/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
- hash_table[1] |= 0x02000000;
+ hash_table[1] |= cpu_to_le32(0x02000000);
if (dev->flags & IFF_PROMISC) {
/* Receive all frames promiscuously. */
rx_mode = ReceiveAllFrames;
@@ -1020,11 +1080,16 @@ set_multicast (struct net_device *dev)
rx_mode =
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist=mclist->next) {
+ i++, mclist=mclist->next) {
+
crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
- for (index=0, bit=0; bit<6; bit++, crc<<=1) {
- if (crc & 0x80000000) index |= 1 << bit;
- }
+
+ /* The inverted high significant 6 bits of CRC are
+ used as an index to hashtable */
+ for (index = 0, bit = 0; bit < 6; bit++)
+ if (test_bit(31 - bit, &crc))
+ set_bit(bit, &index);
+
hash_table[index / 32] |= (1 << (index % 32));
}
} else {
@@ -1094,6 +1159,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
np->old_rx);
break;
case SIOCDEVPRIVATE + 8:
+ printk("TX ring:\n");
for (i = 0; i < TX_RING_SIZE; i++) {
desc = &np->tx_ring[i];
printk
@@ -1629,7 +1695,8 @@ rio_close (struct net_device *dev)
writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
synchronize_irq ();
free_irq (dev->irq, dev);
-
+ del_timer_sync (&np->timer);
+
/* Free all the skbuffs in the queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].status = 0;
@@ -1679,10 +1746,10 @@ rio_remove1 (struct pci_dev *pdev)
}
static struct pci_driver rio_driver = {
- name:"dl2k",
- id_table:rio_pci_tbl,
- probe:rio_probe1,
- remove: __devexit_p(rio_remove1),
+ name: "dl2k",
+ id_table: rio_pci_tbl,
+ probe: rio_probe1,
+ remove: __devexit_p(rio_remove1),
};
static int __init
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 0ee3bbb817b5..656832f2ca1d 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -1,6 +1,6 @@
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
/*
- Copyright (c) 2001 by D-Link Corporation
+ Copyright (c) 2001, 2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
@@ -649,6 +649,7 @@ struct netdev_private {
dma_addr_t rx_ring_dma;
struct pci_dev *pdev;
spinlock_t lock;
+ spinlock_t rx_lock;
struct net_device_stats stats;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
unsigned int speed; /* Operating speed */
@@ -664,9 +665,11 @@ struct netdev_private {
unsigned int tx_flow:1; /* Tx flow control enable */
unsigned int rx_flow:1; /* Rx flow control enable */
unsigned int phy_media:1; /* 1: fiber, 0: copper */
+ unsigned char pci_rev_id; /* PCI revision ID */
struct netdev_desc *last_tx; /* Last Tx descriptor used. */
unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */
unsigned long cur_tx, old_tx;
+ struct timer_list timer;
int wake_polarity;
char name[256]; /* net device description */
u8 duplex_polarity;
diff --git a/drivers/net/e100/Makefile b/drivers/net/e100/Makefile
index 587a0f1ff5ed..066956eac1a2 100644
--- a/drivers/net/e100/Makefile
+++ b/drivers/net/e100/Makefile
@@ -10,7 +10,7 @@
O_TARGET := e100.o
obj-y := e100_main.o e100_config.o e100_proc.o e100_phy.o \
- e100_eeprom.o
+ e100_eeprom.o e100_test.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
index 4295e9c85712..cd380d8f027c 100644
--- a/drivers/net/e100/e100.h
+++ b/drivers/net/e100/e100.h
@@ -899,6 +899,15 @@ struct cfg_params {
int PollingMaxWork;
u32 b_params;
};
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data{
+ dma_addr_t dma_handle;
+ tcb_t *tcb;
+ rfd_t *rfd;
+
+};
+#endif
+
struct e100_private {
u32 flags; /* board management flags */
@@ -988,6 +997,9 @@ struct e100_private {
u32 wolopts;
u16 ip_lbytes;
#endif
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data loopback;
+#endif
#ifdef CONFIG_PM
u32 pci_state[16];
@@ -1028,4 +1040,23 @@ extern void e100_deisolate_driver(struct e100_private *bdp,
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
u32 reset_cmd);
+#ifdef ETHTOOL_TEST
+
+#define ROM_TEST_FAIL 0x01
+#define REGISTER_TEST_FAIL 0x02
+#define SELF_TEST_FAIL 0x04
+#define TEST_TIMEOUT 0x08
+
+enum test_offsets {
+ E100_EEPROM_TEST_FAIL = 0,
+ E100_CHIP_TIMEOUT,
+ E100_ROM_TEST_FAIL,
+ E100_REG_TEST_FAIL,
+ E100_MAC_TEST_FAIL,
+ E100_LPBK_MAC_FAIL,
+ E100_LPBK_PHY_FAIL,
+ E100_MAX_TEST_RES
+};
+#endif
+
#endif
diff --git a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c
index 2606aff405cc..c965393db4e2 100644
--- a/drivers/net/e100/e100_config.c
+++ b/drivers/net/e100/e100_config.c
@@ -593,3 +593,102 @@ e100_config_wol(struct e100_private *bdp)
}
#endif
+#ifdef ETHTOOL_TEST
+/**
+ * e100_config_loopback_mode
+ * @bdp: atapter's private data struct
+ * @mode: loopback mode(phy/mac/none)
+ *
+ */
+unsigned char
+e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
+{
+ unsigned char bc_changed = false;
+ u8 config_byte;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ switch (mode) {
+ case NO_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_NORMAL;
+ break;
+ case MAC_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_INTERNAL;
+ break;
+ case PHY_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
+ break;
+ default:
+ printk(KERN_NOTICE "e100_config_loopback_mode: "
+ "Invalid argument 'mode': %d\n", mode);
+ goto exit;
+ }
+
+ if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
+
+ bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
+ bdp->config[10] |= config_byte;
+ E100_CONFIG(bdp, 10);
+ bc_changed = true;
+ }
+
+exit:
+ spin_unlock_bh(&(bdp->config_lock));
+ return bc_changed;
+}
+unsigned char
+e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
+{
+ unsigned char bc_changed = false;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ if (enable) {
+ if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
+
+ bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
+ E100_CONFIG(bdp, 6);
+ bc_changed = true;
+ }
+
+ } else {
+ if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
+
+ bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
+ E100_CONFIG(bdp, 6);
+ bc_changed = true;
+ }
+ }
+ spin_unlock_bh(&(bdp->config_lock));
+
+ return bc_changed;
+}
+unsigned char
+e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
+{
+ unsigned char bc_changed = false;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ if (enable) {
+ if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
+
+ bdp->config[7] |= CB_CFIG_DYNTBD_EN;
+ E100_CONFIG(bdp, 7);
+ bc_changed = true;
+ }
+
+ } else {
+ if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
+
+ bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
+ E100_CONFIG(bdp, 7);
+ bc_changed = true;
+ }
+ }
+ spin_unlock_bh(&(bdp->config_lock));
+
+ return bc_changed;
+}
+#endif
+
diff --git a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h
index a46e531e564f..6172ce27ef4b 100644
--- a/drivers/net/e100/e100_config.h
+++ b/drivers/net/e100/e100_config.h
@@ -190,6 +190,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CB_CFIG_LONG_RX_OK BIT_3
+#define NO_LOOPBACK 0
+#define MAC_LOOPBACK 0x01
+#define PHY_LOOPBACK 0x02
+
/* function prototypes */
extern void e100_config_init(struct e100_private *bdp);
extern unsigned char e100_force_config(struct e100_private *bdp);
@@ -201,5 +205,8 @@ extern void e100_config_mulcast_enbl(struct e100_private *bdp,
unsigned char enable);
extern void e100_config_ifs(struct e100_private *bdp);
extern void e100_config_force_dplx(struct e100_private *bdp);
+extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
+extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
+extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
#endif /* _E100_CONFIG_INC_ */
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index 3dcc137c218f..7b8c32f351f9 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -147,6 +147,23 @@ static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
static u16 e100_get_ip_lbytes(struct net_device *dev);
extern void e100_config_wol(struct e100_private *bdp);
#endif
+#ifdef ETHTOOL_TEST
+extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
+static int e100_ethtool_test(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
+static char *test_strings[] = {
+ "E100_EEPROM_TEST_FAIL",
+ "E100_CHIP_TIMEOUT",
+ "E100_ROM_TEST_FAIL",
+ "E100_REG_TEST_FAIL",
+ "E100_MAC_TEST_FAIL",
+ "E100_LPBK_MAC_FAIL",
+ "E100_LPBK_PHY_FAIL"
+};
+
+#endif
#endif /*E100_ETHTOOL_IOCTL */
#ifdef SIOCGMIIPHY
@@ -165,7 +182,7 @@ static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-#define E100_VERSION "2.0.24-pre1"
+#define E100_VERSION "2.0.25-pre1"
#define E100_FULL_DRIVER_NAME "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
@@ -382,6 +399,7 @@ static void e100_set_multi_exec(struct net_device *dev);
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
E100_PARAM(TxDescriptors, "Number of transmit descriptors");
E100_PARAM(RxDescriptors, "Number of receive descriptors");
@@ -2715,8 +2733,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
ntcb_hdr->cb_lnk_ptr = 0;
wmb();
+ if (in_interrupt())
+ return e100_delayed_exec_non_cu_cmd(bdp, command);
- if (in_interrupt() || netif_running(bdp->device))
+ if (netif_running(bdp->device) && (!bdp->driver_isolated))
return e100_delayed_exec_non_cu_cmd(bdp, command);
spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -3302,6 +3322,16 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
rc = e100_ethtool_wol(dev, ifr);
break;
#endif
+#ifdef ETHTOOL_TEST
+ case ETHTOOL_TEST:
+ rc = e100_ethtool_test(dev, ifr);
+ break;
+#endif
+#ifdef ETHTOOL_GSTRINGS
+ case ETHTOOL_GSTRINGS:
+ rc = e100_ethtool_gstrings(dev,ifr);
+ break;
+#endif
default:
break;
} //switch
@@ -3464,6 +3494,36 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
}
#endif
+#ifdef ETHTOOL_TEST
+static int
+e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ethtool_test *info;
+ int rc = -EFAULT;
+
+ info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+ GFP_ATOMIC);
+
+ if (!info)
+ return -EFAULT;
+
+ memset((void *) info, 0, sizeof(*info) +
+ E100_MAX_TEST_RES * sizeof(u64));
+
+ if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
+ goto exit;
+
+ info->flags = e100_run_diag(dev, info->data, info->flags);
+
+ if (!copy_to_user(ifr->ifr_data, info,
+ sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+ rc = 0;
+exit:
+ kfree(info);
+ return rc;
+}
+#endif
+
#ifdef ETHTOOL_NWAY_RST
static int
e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
@@ -3505,7 +3565,9 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
#ifdef ETHTOOL_GEEPROM
info.eedump_len = (bdp->eeprom_size << 1);
#endif
-
+#ifdef ETHTOOL_TEST
+ info.testinfo_len = E100_MAX_TEST_RES;
+#endif
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
@@ -3738,6 +3800,51 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
}
#endif
+
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ethtool_gstrings info;
+ char *strings = NULL;
+ char *usr_strings;
+ int i;
+
+ memset((void *) &info, 0, sizeof(info));
+
+ usr_strings = (u8 *) (ifr->ifr_data +
+ offsetof(struct ethtool_gstrings, data));
+
+ if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
+ return -EFAULT;
+
+ switch (info.string_set) {
+ case ETH_SS_TEST:
+ if (info.len > E100_MAX_TEST_RES)
+ info.len = E100_MAX_TEST_RES;
+ strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
+ if (!strings)
+ return -EFAULT;
+ memset(strings, 0, info.len * ETH_GSTRING_LEN);
+
+ for (i = 0; i < info.len; i++) {
+ sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+ test_strings[i]);
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+ return -EFAULT;
+
+ if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+ return -EFAULT;
+
+ kfree(strings);
+ return 0;
+}
+#endif
#endif /*E100_ETHTOOL_IOCTL */
#ifdef E100_MII_IOCTL
diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
new file mode 100644
index 000000000000..77918c9f8f9c
--- /dev/null
+++ b/drivers/net/e100/e100_test.c
@@ -0,0 +1,467 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two
+licenses. You may choose to be licensed under either the GNU General Public
+License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+or the Intel BSD + Patent License, the text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which
+are necessarily infringed by the use of sale of the Software alone or when
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to
+any operating system available under the GNU General Public License 2.0 or
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or
+without modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code of the Software may retain the above
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above
+copyright notice, this list of conditions and the following disclaimer in
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors
+shall be used to endorse or promote products derived from this Software
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer
+to sell, import and otherwise transfer the Software, if any, in source code
+and object code form. This license shall include changes to the Software
+that are error corrections or other minor changes to the Software that do
+not add functionality or features when the Software is incorporated in any
+version of an operating system that has been distributed under the GNU
+General Public License 2.0 or later. This patent license shall apply to the
+combination of the Software and any operating system licensed under the GNU
+General Public License 2.0 or later if, at the time Intel provides the
+Software to Recipient, such addition of the Software to the then publicly
+available versions of such operating systems available under the GNU General
+Public License 2.0 or later (whether in gold, beta or alpha form) causes
+such combination to be covered by the Licensed Patents. The patent license
+shall not apply to any other combinations which include the Software. NO
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#include "e100.h"
+#include "e100_config.h"
+#ifdef ETHTOOL_TEST
+
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
+extern void e100_phy_reset(struct e100_private *bdp);
+
+static u8 e100_diag_selftest(struct net_device *);
+static u8 e100_diag_eeprom(struct net_device *);
+static u8 e100_diag_loopback(struct net_device *);
+
+static u8 e100_diag_one_loopback (struct net_device *, u8);
+static u8 e100_diag_rcv_loopback_pkt(struct e100_private *);
+static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *);
+static u8 e100_diag_loopback_alloc(struct e100_private *);
+static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
+static u8 e100_diag_check_pkt(u8 *);
+static void e100_diag_loopback_free(struct e100_private *);
+
+#define LB_PACKET_SIZE 1500
+
+/**
+ * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines
+ * @dev: atapter's net device data struct
+ * @test_info: array with test request mask also used to store test results
+ *
+ * RETURNS: updated flags field of struct ethtool_test
+ */
+u32
+e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
+{
+ struct e100_private* bdp = dev->priv;
+ u8 test_result = true;
+
+ e100_isolate_driver(bdp);
+
+ if (flags & ETH_TEST_FL_OFFLINE) {
+ u8 fail_mask;
+
+ fail_mask = e100_diag_selftest(dev);
+ if (fail_mask) {
+ test_result = false;
+ if (fail_mask & REGISTER_TEST_FAIL)
+ test_info [E100_REG_TEST_FAIL] = true;
+ if (fail_mask & ROM_TEST_FAIL)
+ test_info [E100_ROM_TEST_FAIL] = true;
+ if (fail_mask & SELF_TEST_FAIL)
+ test_info [E100_MAC_TEST_FAIL] = true;
+ if (fail_mask & TEST_TIMEOUT)
+ test_info [E100_CHIP_TIMEOUT] = true;
+ }
+
+ fail_mask = e100_diag_loopback(dev);
+ if (fail_mask) {
+ test_result = false;
+ if (fail_mask & PHY_LOOPBACK)
+ test_info [E100_LPBK_PHY_FAIL] = true;
+ if (fail_mask & MAC_LOOPBACK)
+ test_info [E100_LPBK_MAC_FAIL] = true;
+ }
+ }
+
+ if (!e100_diag_eeprom(dev)) {
+ test_result = false;
+ test_info [E100_EEPROM_TEST_FAIL] = true;
+ }
+
+ /* fully recover only if the device is open*/
+ if (netif_running(dev)) {
+ e100_deisolate_driver(bdp, true, false);
+ } else {
+ e100_deisolate_driver(bdp, false, false);
+ }
+ /*Let card recover from the test*/
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ * 2);
+
+ return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+}
+
+/**
+ * e100_diag_selftest - run hardware selftest
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_selftest(struct net_device *dev)
+{
+ struct e100_private *bdp = dev->priv;
+ u32 st_timeout, st_result;
+ u8 retval = 0;
+
+ if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+ if (!st_timeout) {
+ if (st_result & CB_SELFTEST_REGISTER_BIT)
+ retval |= REGISTER_TEST_FAIL;
+ if (st_result & CB_SELFTEST_DIAG_BIT)
+ retval |= SELF_TEST_FAIL;
+ if (st_result & CB_SELFTEST_ROM_BIT)
+ retval |= ROM_TEST_FAIL;
+ } else {
+ retval = TEST_TIMEOUT;
+ }
+ }
+
+ e100_hw_reset_recover(bdp,PORT_SOFTWARE_RESET);
+
+ return retval;
+}
+
+/**
+ * e100_diag_eeprom - validate eeprom checksum correctness
+ * @dev: atapter's net device data struct
+ *
+ */
+static u8
+e100_diag_eeprom (struct net_device *dev)
+{
+ struct e100_private *bdp = dev->priv;
+ u16 i, eeprom_sum, eeprom_actual_csm;
+
+ for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) {
+ eeprom_sum += e100_eeprom_read(bdp, i);
+ }
+
+ eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1);
+
+ if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_loopback (struct net_device *dev)
+{
+ u8 rc = 0;
+
+ if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
+ rc |= PHY_LOOPBACK;
+ }
+
+ if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
+ rc |= MAC_LOOPBACK;
+ }
+
+ return rc;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test
+ * @dev: atapter's net device data struct
+ * @mode: lopback test type
+ */
+static u8
+e100_diag_one_loopback (struct net_device *dev, u8 mode)
+{
+ struct e100_private *bdp = dev->priv;
+ u8 res = false;
+ u8 saved_dynamic_tbd = false;
+ u8 saved_extended_tcb = false;
+
+ if (!e100_diag_loopback_alloc(bdp))
+ return false;
+
+ /* change the config block to standard tcb and the correct loopback */
+ e100_diag_config_loopback(bdp, true, mode,
+ &saved_extended_tcb, &saved_dynamic_tbd);
+
+ e100_diag_loopback_cu_ru_exec(bdp);
+
+ if (e100_diag_rcv_loopback_pkt(bdp)) {
+ res = true;
+ }
+
+ e100_diag_loopback_free(bdp);
+
+ /* change the config block to previous tcb mode and the no loopback */
+ e100_diag_config_loopback(bdp, false, mode,
+ &saved_extended_tcb, &saved_dynamic_tbd);
+ return res;
+}
+
+/**
+ * e100_diag_config_loopback - setup/clear loopback before/after lpbk test
+ * @bdp: atapter's private data struct
+ * @set_loopback: true if the function is called to set lb
+ * @loopback_mode: the loopback mode(MAC or PHY)
+ * @tcb_extended: true if need to set extended tcb mode after clean loopback
+ * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback
+ *
+ */
+void
+e100_diag_config_loopback(struct e100_private* bdp,
+ u8 set_loopback,
+ u8 loopback_mode,
+ u8* tcb_extended,
+ u8* dynamic_tbd)
+{
+ /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd.
+ * the previous values are saved in the params tcb_extended/dynamic_tbd
+ * if set_loopback == false - we want to restore previous value.
+ */
+ if (set_loopback || (*tcb_extended))
+ *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended);
+
+ if (set_loopback || (*dynamic_tbd))
+ *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
+
+ if (set_loopback) {
+ e100_config_loopback_mode(bdp,loopback_mode);
+ } else {
+ e100_config_loopback_mode(bdp,NO_LOOPBACK);
+ }
+
+ e100_config(bdp);
+
+ if (loopback_mode == PHY_LOOPBACK) {
+ unsigned long expires = jiffies + HZ * 5;
+
+ if (set_loopback)
+ e100_phy_reset(bdp);
+
+ /* wait up to 5 secs for PHY loopback ON/OFF to take effect */
+ while ((e100_get_link_state(bdp) != set_loopback) &&
+ time_before(jiffies, expires)) {
+ yield();
+ }
+ } else { /* For MAC loopback wait 500 msec to take effect */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 2);
+ }
+}
+
+/**
+ * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback
+ * @bdp: atapter's private data struct
+ *
+ */
+static u8
+e100_diag_loopback_alloc(struct e100_private *bdp)
+{
+ dma_addr_t dma_handle;
+ tcb_t *tcb;
+ rfd_t *rfd;
+ tbd_t *tbd;
+
+ tcb = pci_alloc_consistent(bdp->pdev,
+ (sizeof (tcb_t) + sizeof (tbd_t) +
+ LB_PACKET_SIZE),
+ &dma_handle);
+ if (tcb == NULL)
+ return false;
+
+ memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE);
+ tcb->tcb_phys = dma_handle;
+ tcb->tcb_hdr.cb_status = 0;
+ tcb->tcb_hdr.cb_cmd =
+ cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
+ tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys);
+ tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff);
+ tcb->tcb_cnt = 0;
+ tcb->tcb_thrshld = bdp->tx_thld;
+ tcb->tcb_tbd_num = 1;
+ tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
+ tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+ tbd->tbd_buf_addr =
+ cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
+ tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
+ memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024);
+ memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
+ wmb();
+ rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
+
+ if (rfd == NULL) {
+ pci_free_consistent(bdp->pdev,
+ sizeof (tcb_t) + sizeof (tbd_t) +
+ LB_PACKET_SIZE, tcb, tcb->tcb_phys);
+ return false;
+ }
+
+ memset(rfd, 0x00, sizeof (rfd_t));
+
+ /* init all fields in rfd */
+ rfd->rfd_header.cb_status = 0;
+ rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
+ rfd->rfd_act_cnt = 0;
+ rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+ bdp->loopback.dma_handle = dma_handle;
+ bdp->loopback.tcb = tcb;
+ bdp->loopback.rfd = rfd;
+ wmb();
+ return true;
+}
+
+/**
+ * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
+{
+ /*load CU & RU base */
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+ printk("@@@ SCB_CUC_LOAD_BASE failed\n");
+ if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+ printk("@@@ SCB_RUC_LOAD_BASE failed!\n");
+ if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START))
+ printk("@@@ SCB_RUC_START failed!\n");
+
+ bdp->next_cu_cmd = START_WAIT;
+ e100_start_cu(bdp, bdp->loopback.tcb);
+ bdp->last_tcb = NULL;
+ rmb();
+}
+/**
+ * e100_diag_check_pkt - checks if a given packet is a loopback packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_check_pkt(u8 *datap)
+{
+ if( (*datap)==0xFF) {
+ if(*(datap + 600) == 0xBA) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_rcv_loopback_pkt(struct e100_private* bdp)
+{
+ rfd_t *rfdp;
+ u16 rfd_status;
+ unsigned long expires = jiffies + HZ * 2;
+
+ rfdp =bdp->loopback.rfd;
+
+ rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+
+ while (!(rfd_status & RFD_STATUS_COMPLETE)) {
+ if (time_before(jiffies, expires)) {
+ yield();
+ rmb();
+ rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+ } else {
+ break;
+ }
+ }
+
+ if (rfd_status & RFD_STATUS_COMPLETE)
+ return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
+ else
+ return false;
+}
+
+/**
+ * e100_diag_loopback_free - free data allocated for loopback pkt send/receive
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_free (struct e100_private *bdp)
+{
+ pci_free_consistent(bdp->pdev,
+ sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE,
+ bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys);
+
+ pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd,
+ bdp->loopback.dma_handle);
+}
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE
index 8dbf9d9ee04c..ab83d56a3471 100644
--- a/drivers/net/e1000/LICENSE
+++ b/drivers/net/e1000/LICENSE
@@ -1,8 +1,7 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
-License (GPL) Version 2, June 1991, available at
-http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
-text of which follows:
+License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -16,7 +15,7 @@ combined with the operating system referred to below.
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
-any operating system available under the GNU Public License version 2.0 or
+any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -49,10 +48,10 @@ not add functionality or features when the Software is incorporated in any
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
-Public License version 2.0 or later if, at the time Intel provides the
+General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
-available versions of such operating systems available under the GNU Public
-License version 2.0 or later (whether in gold, beta or alpha form) causes
+available versions of such operating systems available under the GNU General
+Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index 6fc1468d012b..0e99ae2369e0 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -9,8 +9,7 @@
O_TARGET := e1000.o
-obj-y := e1000_main.o e1000_mac.o e1000_phy.o \
- e1000_ethtool.o e1000_param.o e1000_proc.o
+obj-y := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o e1000_proc.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 9a09b351e549..5424cca61c84 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -109,11 +108,14 @@
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <asm/uaccess.h>
+#include <linux/ethtool.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
struct e1000_adapter;
-#include "e1000_mac.h"
-#include "e1000_phy.h"
+#include "e1000_hw.h"
#define BAR_0 0
@@ -138,7 +140,9 @@ struct e1000_adapter;
#define E1000_RXBUFFER_16384 16384
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define E1000_TX_QUEUE_WAKE 16
+#define E1000_TX_QUEUE_WAKE 16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE 16
#define E1000_JUMBO_PBA 0x00000028
#define E1000_DEFAULT_PBA 0x00000030
@@ -163,10 +167,6 @@ struct e1000_desc_ring {
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
- /* (atomic) number of desc with no buffer */
- atomic_t unused;
- /* number of desc with no buffer */
- unsigned int unused_count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
@@ -175,14 +175,13 @@ struct e1000_desc_ring {
struct e1000_buffer *buffer_info;
};
-#define E1000_RX_DESC(ring, i) \
- (&(((struct e1000_rx_desc *)((ring).desc))[i]))
-
-#define E1000_TX_DESC(ring, i) \
- (&(((struct e1000_tx_desc *)((ring).desc))[i]))
+#define E1000_DESC_UNUSED(R) \
+((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
-#define E1000_CONTEXT_DESC(ring, i) \
- (&(((struct e1000_context_desc *)((ring).desc))[i]))
+#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
@@ -192,6 +191,9 @@ struct e1000_adapter {
#ifdef CONFIG_PROC_FS
struct list_head proc_list_head;
#endif
+#ifdef NETIF_F_HW_VLAN_TX
+ struct vlan_group *vlgrp;
+#endif
char *id_string;
uint32_t bd_number;
uint32_t rx_buffer_len;
@@ -201,28 +203,29 @@ struct e1000_adapter {
uint16_t link_duplex;
spinlock_t stats_lock;
atomic_t irq_sem;
- boolean_t rx_csum;
/* TX */
struct e1000_desc_ring tx_ring;
unsigned long trans_finish;
- uint32_t tx_int_delay;
+ spinlock_t tx_lock;
uint32_t txd_cmd;
+ int max_data_per_txd;
/* RX */
struct e1000_desc_ring rx_ring;
uint64_t hw_csum_err;
uint64_t hw_csum_good;
uint32_t rx_int_delay;
+ boolean_t rx_csum;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
- /* structs defined in e1000_mac.h or e1000_phy.h */
- struct e1000_shared_adapter shared;
- struct e1000_shared_stats stats;
+ /* structs defined in e1000_hw.h */
+ struct e1000_hw hw;
+ struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
};
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 2d609aed890f..7ed6f8ebe931 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -89,9 +88,9 @@ extern void e1000_enable_WOL(struct e1000_adapter *adapter);
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->media_type == e1000_media_type_copper) {
+ if(hw->media_type == e1000_media_type_copper) {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
@@ -103,18 +102,18 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
ecmd->advertising = ADVERTISED_TP;
- if(shared->autoneg == 1) {
+ if(hw->autoneg == 1) {
ecmd->advertising |= ADVERTISED_Autoneg;
/* the e1000 autoneg seems to match ethtool nicely */
- ecmd->advertising |= shared->autoneg_advertised;
+ ecmd->advertising |= hw->autoneg_advertised;
}
ecmd->port = PORT_TP;
- ecmd->phy_address = shared->phy_addr;
+ ecmd->phy_address = hw->phy_addr;
- if(shared->mac_type == e1000_82543)
+ if(hw->mac_type == e1000_82543)
ecmd->transceiver = XCVR_EXTERNAL;
else
ecmd->transceiver = XCVR_INTERNAL;
@@ -129,13 +128,12 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
SUPPORTED_Autoneg);
ecmd->port = PORT_FIBRE;
-
ecmd->transceiver = XCVR_EXTERNAL;
}
if(netif_carrier_ok(adapter->netdev)) {
- e1000_get_speed_and_duplex(shared, &adapter->link_speed,
+ e1000_get_speed_and_duplex(hw, &adapter->link_speed,
&adapter->link_duplex);
ecmd->speed = adapter->link_speed;
@@ -151,37 +149,35 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
ecmd->duplex = -1;
}
- ecmd->autoneg = (shared->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
-
- return;
+ ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
}
static int
e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
if(ecmd->autoneg == AUTONEG_ENABLE) {
- shared->autoneg = 1;
- shared->autoneg_advertised = (ecmd->advertising & 0x002F);
+ hw->autoneg = 1;
+ hw->autoneg_advertised = (ecmd->advertising & 0x002F);
} else {
- shared->autoneg = 0;
+ hw->autoneg = 0;
switch(ecmd->speed + ecmd->duplex) {
case SPEED_10 + DUPLEX_HALF:
- shared->forced_speed_duplex = e1000_10_half;
+ hw->forced_speed_duplex = e1000_10_half;
break;
case SPEED_10 + DUPLEX_FULL:
- shared->forced_speed_duplex = e1000_10_full;
+ hw->forced_speed_duplex = e1000_10_full;
break;
case SPEED_100 + DUPLEX_HALF:
- shared->forced_speed_duplex = e1000_100_half;
+ hw->forced_speed_duplex = e1000_100_half;
break;
case SPEED_100 + DUPLEX_FULL:
- shared->forced_speed_duplex = e1000_100_full;
+ hw->forced_speed_duplex = e1000_100_full;
break;
case SPEED_1000 + DUPLEX_FULL:
- shared->autoneg = 1;
- shared->autoneg_advertised = ADVERTISE_1000_FULL;
+ hw->autoneg = 1;
+ hw->autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
@@ -198,9 +194,13 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
}
static inline int
-e1000_eeprom_size(struct e1000_shared_adapter *shared)
+e1000_eeprom_size(struct e1000_hw *hw)
{
- return 128;
+ if((hw->mac_type > e1000_82544) &&
+ (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
+ return 512;
+ else
+ return 128;
}
static void
@@ -211,36 +211,33 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
- drvinfo->eedump_len = e1000_eeprom_size(&adapter->shared);
- return;
+ drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
}
static void
e1000_ethtool_geeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
int i, max_len;
- eeprom->magic = shared->vendor_id | (shared->device_id << 16);
+ eeprom->magic = hw->vendor_id | (hw->device_id << 16);
- max_len = e1000_eeprom_size(shared);
+ max_len = e1000_eeprom_size(hw);
if ((eeprom->offset + eeprom->len) > max_len)
eeprom->len = (max_len - eeprom->offset);
for(i = 0; i < max_len; i++)
- eeprom_buff[i] = e1000_read_eeprom(&adapter->shared, i);
-
- return;
+ e1000_read_eeprom(&adapter->hw, i, &eeprom_buff[i]);
}
static void
e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->mac_type < e1000_82544) {
+ if(hw->mac_type < e1000_82544) {
wol->supported = 0;
wol->wolopts = 0;
return;
@@ -260,17 +257,15 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
wol->wolopts |= WAKE_BCAST;
if(adapter->wol & E1000_WUFC_MAG)
wol->wolopts |= WAKE_MAGIC;
-
- return;
}
static int
e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->mac_type < e1000_82544)
- return wol->wolopts == 0 ? 0 : -EOPNOTSUPP;
+ if(hw->mac_type < e1000_82544)
+ return wol->wolopts ? -EOPNOTSUPP : 0;
adapter->wol = 0;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
new file mode 100644
index 000000000000..0be1c6145771
--- /dev/null
+++ b/drivers/net/e1000/e1000_hw.c
@@ -0,0 +1,3228 @@
+/*******************************************************************************
+
+ This software program is available to you under a choice of one of two
+ licenses. You may choose to be licensed under either the GNU General Public
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
+
+ Recipient has requested a license and Intel Corporation ("Intel") is willing
+ to grant a license for the software entitled Linux Base Driver for the
+ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
+ by Intel Corporation. The following definitions apply to this license:
+
+ "Licensed Patents" means patent claims licensable by Intel Corporation which
+ are necessarily infringed by the use of sale of the Software alone or when
+ combined with the operating system referred to below.
+
+ "Recipient" means the party to whom Intel delivers this Software.
+
+ "Licensee" means Recipient and those third parties that receive a license to
+ any operating system available under the GNU General Public License 2.0 or
+ later.
+
+ Copyright (c) 1999 - 2002 Intel Corporation.
+ All rights reserved.
+
+ The license is provided to Recipient and Recipient's Licensees under the
+ following terms.
+
+ Redistribution and use in source and binary forms of the Software, with or
+ without modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code of the Software may retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form of the Software may reproduce the above
+ copyright notice, this list of conditions and the following disclaimer in
+ the documentation and/or materials provided with the distribution.
+
+ Neither the name of Intel Corporation nor the names of its contributors
+ shall be used to endorse or promote products derived from this Software
+ without specific prior written permission.
+
+ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
+ royalty-free patent license under Licensed Patents to make, use, sell, offer
+ to sell, import and otherwise transfer the Software, if any, in source code
+ and object code form. This license shall include changes to the Software
+ that are error corrections or other minor changes to the Software that do
+ not add functionality or features when the Software is incorporated in any
+ version of an operating system that has been distributed under the GNU
+ General Public License 2.0 or later. This patent license shall apply to the
+ combination of the Software and any operating system licensed under the GNU
+ General Public License 2.0 or later if, at the time Intel provides the
+ Software to Recipient, such addition of the Software to the then publicly
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
+ such combination to be covered by the Licensed Patents. The patent license
+ shall not apply to any other combinations which include the Software. NO
+ hardware per se is licensed hereunder.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/* e1000_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include "e1000_hw.h"
+
+static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
+static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
+static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
+static void e1000_setup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+ uint32_t icr;
+ uint32_t manc;
+ uint16_t pci_cmd_word;
+
+ DEBUGFUNC("e1000_reset_hw");
+
+ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+ }
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC with
+ * the global reset.
+ */
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+
+ /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+ hw->tbi_compatibility_on = FALSE;
+
+ /* Delay to allow any outstanding PCI transactions to complete before
+ * resetting the device
+ */
+ msec_delay(10);
+
+ /* Issue a global reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA, and link units. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+ /* Force a reload from the EEPROM if necessary */
+ if(hw->mac_type < e1000_82540) {
+ /* Wait for reset to complete */
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ /* Wait for EEPROM reload */
+ msec_delay(2);
+ } else {
+ /* Wait for EEPROM reload (it happens automatically) */
+ msec_delay(4);
+ /* Dissable HW ARPs on ASF enabled adapters */
+ manc = E1000_READ_REG(hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(hw, MANC, manc);
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Clear any pending interrupt events. */
+ icr = E1000_READ_REG(hw, ICR);
+
+ /* If MWI was previously enabled, reenable it. */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+e1000_init_hw(struct e1000_hw *hw)
+{
+ uint32_t ctrl, status;
+ uint32_t i;
+ int32_t ret_val;
+ uint16_t pci_cmd_word;
+
+ DEBUGFUNC("e1000_init_hw");
+
+ /* Set the Media Type and exit with error if it is not valid. */
+ if(hw->mac_type != e1000_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = FALSE;
+ }
+
+ if(hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_TBIMODE) {
+ hw->media_type = e1000_media_type_fiber;
+ /* tbi_compatibility not valid on fiber */
+ hw->tbi_compatibility_en = FALSE;
+ } else {
+ hw->media_type = e1000_media_type_copper;
+ }
+ } else {
+ /* This is an 82542 (fiber only) */
+ hw->media_type = e1000_media_type_fiber;
+ }
+
+ /* Disabling VLAN filtering. */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ E1000_WRITE_REG(hw, VET, 0);
+
+ e1000_clear_vfta(hw);
+
+ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+ }
+ E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ msec_delay(5);
+ }
+
+ /* Setup the receive address. This involves initializing all of the Receive
+ * Address Registers (RARs 0 - 15).
+ */
+ e1000_init_rx_addrs(hw);
+
+ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ E1000_WRITE_REG(hw, RCTL, 0);
+ msec_delay(1);
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ }
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+ /* Set the PCI priority bit correctly in the CTRL register. This
+ * determines if the adapter gives priority to receives, or if it
+ * gives equal priority to transmits and receives.
+ */
+ if(hw->dma_fairness) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+ }
+
+ /* Call a subroutine to configure the link and setup flow control. */
+ ret_val = e1000_setup_link(hw);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs(hw);
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+e1000_setup_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl_ext;
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("e1000_setup_link");
+
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ if(hw->fc == e1000_fc_default) {
+ if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc = e1000_fc_none;
+ else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+ hw->fc = e1000_fc_tx_pause;
+ else
+ hw->fc = e1000_fc_full;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ if(hw->mac_type == e1000_82542_rev2_0)
+ hw->fc &= (~e1000_fc_tx_pause);
+
+ if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+ hw->fc &= (~e1000_fc_rx_pause);
+
+ hw->original_fc = hw->fc;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+ /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+ * polarity value for the SW controlled pins, and setup the
+ * Extended Device Control reg with that info.
+ * This is needed because one of the SW controlled pins is used for
+ * signal detection. So this should be done before e1000_setup_pcs_link()
+ * or e1000_phy_setup() is called.
+ */
+ if(hw->mac_type == e1000_82543) {
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ SWDPIO__EXT_SHIFT);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ /* Call the necessary subroutine to configure the link. */
+ ret_val = (hw->media_type == e1000_media_type_fiber) ?
+ e1000_setup_fiber_link(hw) :
+ e1000_setup_copper_link(hw);
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames in not enabled, then these
+ * registers will be set to 0.
+ */
+ if(!(hw->fc & e1000_fc_tx_pause)) {
+ E1000_WRITE_REG(hw, FCRTL, 0);
+ E1000_WRITE_REG(hw, FCRTH, 0);
+ } else {
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
+ if(hw->fc_send_xon) {
+ E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ } else {
+ E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ }
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ * ctrl - Current value of the device control register
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t
+e1000_setup_fiber_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t txcw = 0;
+ uint32_t i;
+ uint32_t signal;
+ int32_t ret_val;
+
+ DEBUGFUNC("e1000_setup_fiber_link");
+
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+ else signal = 0;
+
+ /* Take the link out of reset */
+ ctrl &= ~(E1000_CTRL_LRST);
+
+ e1000_config_collision_dist(hw);
+
+ /* Check for a software override of the flow control settings, and setup
+ * the device accordingly. If auto-negotiation is enabled, then software
+ * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+ * Config Word Register (TXCW) and re-start auto-negotiation. However, if
+ * auto-negotiation is disabled, then software will have to manually
+ * configure the two flow control enable bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do
+ * not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none:
+ /* Flow control is completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled by a
+ * software over-ride. Since there really isn't a way to advertise
+ * that we are capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later, we will
+ * disable the adapter's ability to send PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled, by a
+ * software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the link
+ * will be in reset, because we previously reset the chip). This will
+ * restart auto-negotiation. If auto-neogtiation is successful then the
+ * link-up status bit will be set and the flow control enable bits (RFCE
+ * and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled\n");
+
+ E1000_WRITE_REG(hw, TXCW, txcw);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ hw->txcw = txcw;
+ msec_delay(1);
+
+ /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+ * indication in the Device Status Register. Time-out if a link isn't
+ * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+ * less than 500 milliseconds even if the other end is doing it in SW).
+ */
+ if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+ DEBUGOUT("Looking for Link\n");
+ for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+ msec_delay(10);
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_LU) break;
+ }
+ if(i == (LINK_UP_TIMEOUT / 10)) {
+ /* AutoNeg failed to achieve a link, so we'll call
+ * e1000_check_for_link. This routine will force the link up if we
+ * detect a signal. This will allow us to communicate with
+ * non-autonegotiating link partners.
+ */
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ hw->autoneg_failed = 1;
+ ret_val = e1000_check_for_link(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error while checking for link\n");
+ return ret_val;
+ }
+ hw->autoneg_failed = 0;
+ } else {
+ hw->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+ } else {
+ DEBUGOUT("No Signal Detected\n");
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - current value of the device control register
+******************************************************************************/
+static int32_t
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_setup_copper_link");
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* With 82543, we need to force speed and duplex on the MAC equal to what
+ * the PHY speed and duplex configuration is. In addition, we need to
+ * perform a hardware reset on the PHY to take it out of reset.
+ */
+ if(hw->mac_type > e1000_82543) {
+ ctrl |= E1000_CTRL_SLU;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ e1000_phy_hw_reset(hw);
+ }
+
+ /* Make sure we have a valid PHY */
+ ret_val = e1000_detect_gig_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error, did not detect valid phy.\n");
+ return ret_val;
+ }
+ DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if(hw->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Options:
+ * autoneg = 1 (default)
+ * PHY will advertise value(s) parsed from
+ * autoneg_advertised and fc
+ * autoneg = 0
+ * PHY will be set to 10H, 10F, 100H, or 100F
+ * depending on value parsed from forced_speed_duplex.
+ */
+
+ /* Is autoneg enabled? This is enabled by default or by software override.
+ * If so, call e1000_phy_setup_autoneg routine to parse the
+ * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+ * user should have provided a speed/duplex override. If so, then call
+ * e1000_phy_force_speed_duplex to parse and set this up.
+ */
+ if(hw->autoneg) {
+ /* Perform some bounds checking on the hw->autoneg_advertised
+ * parameter. If this variable is zero, then set it to the default.
+ */
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if(hw->autoneg_advertised == 0)
+ hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if(hw->wait_autoneg_complete) {
+ ret_val = e1000_wait_autoneg(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error while waiting for autoneg to complete\n");
+ return ret_val;
+ }
+ }
+ } else {
+ DEBUGOUT("Forcing speed and duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ for(i = 0; i < 10; i++) {
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & MII_SR_LINK_STATUS) {
+ /* We have link, so we need to finish the config process:
+ * 1) Set up the MAC to the current PHY speed/duplex
+ * if we are on 82543. If we
+ * are on newer silicon, we only need to configure
+ * collision distance in the Transmit Control Register.
+ * 2) Set up flow control on the MAC to that established with
+ * the link partner.
+ */
+ if(hw->mac_type >= e1000_82544) {
+ e1000_config_collision_dist(hw);
+ } else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Configuring Flow Control\n");
+ return ret_val;
+ }
+ DEBUGOUT("Valid link established!!!\n");
+ return 0;
+ }
+ usec_delay(10);
+ }
+
+ DEBUGOUT("Unable to establish link!!!\n");
+ return 0;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ uint16_t mii_autoneg_adv_reg;
+ uint16_t mii_1000t_ctrl_reg;
+
+ DEBUGFUNC("e1000_phy_setup_autoneg");
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+ DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+ }
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none: /* 0 */
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause: /* 1 */
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in e1000_config_fc_after_link_up) we will disable the
+ *hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause: /* 2 */
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full: /* 3 */
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if(e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t mii_ctrl_reg;
+ uint16_t mii_status_reg;
+ uint16_t phy_data;
+ uint16_t i;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+ /* Turn off Flow control if we are forcing speed and duplex. */
+ hw->fc = e1000_fc_none;
+
+ DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+ /* Read the Device Control Register. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(DEVICE_SPEED_MASK);
+
+ /* Clear the Auto Speed Detect Enable bit. */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Read the MII Control Register. */
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* We need to disable autoneg in order to force link and duplex. */
+
+ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Are we forcing Full or Half Duplex? */
+ if(hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_10_full) {
+ /* We want to force full duplex so we SET the full duplex bits in the
+ * Device and MII Control Registers.
+ */
+ ctrl |= E1000_CTRL_FD;
+ mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+ /* We want to force half duplex so we CLEAR the full duplex bits in
+ * the Device and MII Control Registers.
+ */
+ ctrl &= ~E1000_CTRL_FD;
+ mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ }
+
+ /* Are we forcing 100Mbps??? */
+ if(hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_100_half) {
+ /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+ ctrl |= E1000_CTRL_SPD_100;
+ mii_ctrl_reg |= MII_CR_SPEED_100;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ DEBUGOUT("Forcing 100mb ");
+ } else {
+ /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ mii_ctrl_reg |= MII_CR_SPEED_10;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ DEBUGOUT("Forcing 10mb ");
+ }
+
+ e1000_config_collision_dist(hw);
+
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Write the MII Control Register with the new PHY configuration. */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed are duplex are forced.
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+ /* Need to reset the PHY or these changes will be ignored */
+ mii_ctrl_reg |= MII_CR_RESET;
+ if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ usec_delay(1);
+
+ /* The wait_autoneg_complete flag may be a little misleading here.
+ * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+ * But we do want to delay for a period while forcing only so we
+ * don't generate false No Link messages. So we will wait here
+ * only if the user has set wait_autoneg_complete to 1, which is
+ * the default.
+ */
+ if(hw->wait_autoneg_complete) {
+ /* We will wait for autoneg to complete. */
+ DEBUGOUT("Waiting for forced speed/duplex link.\n");
+ mii_status_reg = 0;
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ }
+ if(i == 0) { /* We didn't get link */
+ /* Reset the DSP and wait again for link. */
+
+ ret_val = e1000_phy_reset_dsp(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Resetting PHY DSP\n");
+ return ret_val;
+ }
+ }
+ /* This loop will early-out if the link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ }
+ }
+
+ /* Because we reset the PHY above, we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock. This value
+ * defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* In addition, because of the s/w reset above, we need to enable CRS on
+ * TX. This must be set for both full and half duplex operation.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+ uint32_t tctl;
+
+ tctl = E1000_READ_REG(hw, TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, TCTL, tctl);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_config_mac_to_phy");
+
+ /* Read the Device Control Register and set the bits to Force Speed
+ * and Duplex.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+ else ctrl &= ~E1000_CTRL_FD;
+
+ e1000_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int32_t
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("e1000_force_mac_fc");
+
+ /* Get the current configuration of the Device Control Register */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+
+ switch (hw->fc) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Disable TX Flow Control for 82542 (rev 2.0) */
+ if(hw->mac_type == e1000_82542_rev2_0)
+ ctrl &= (~E1000_CTRL_TFCE);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t mii_nway_adv_reg;
+ uint16_t mii_nway_lp_ability_reg;
+ uint16_t speed;
+ uint16_t duplex;
+
+ DEBUGFUNC("e1000_config_fc_after_link_up");
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+ ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+ ret_val = e1000_force_mac_fc(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+
+ if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement Register
+ * (Address 4) and the Auto_Negotiation Base Page Ability
+ * Register (Address 5) to determine how flow control was
+ * negotiated.
+ */
+ if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | e1000_fc_full
+ *
+ */
+ if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if(hw->original_fc == e1000_fc_full) {
+ hw->fc = e1000_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ *
+ */
+ else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = e1000_fc_tx_pause;
+ DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if(hw->original_fc == e1000_fc_none ||
+ hw->original_fc == e1000_fc_tx_pause) {
+ hw->fc = e1000_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+ if(duplex == HALF_DUPLEX)
+ hw->fc = e1000_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ } else {
+ DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+e1000_check_for_link(struct e1000_hw *hw)
+{
+ uint32_t rxcw;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t rctl;
+ uint32_t signal;
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint16_t lp_capability;
+
+ DEBUGFUNC("e1000_check_for_link");
+
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+ else signal = 0;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ status = E1000_READ_REG(hw, STATUS);
+ rxcw = E1000_READ_REG(hw, RXCW);
+
+ /* If we have a copper PHY then we only want to go out to the PHY
+ * registers to see if Auto-Neg has completed and/or if our link
+ * status has changed. The get_link_status flag will be set if we
+ * receive a Link Status Change interrupt or we have Rx Sequence
+ * Errors.
+ */
+ if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ * Read the register twice since the link bit is sticky.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ if(phy_data & MII_SR_LINK_STATUS) {
+ hw->get_link_status = FALSE;
+ } else {
+ /* No link detected */
+ return 0;
+ }
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
+ * have Si on board that is 82544 or newer, Auto
+ * Speed Detection takes care of MAC speed/duplex
+ * configuration. So we only need to configure Collision
+ * Distance in the MAC. Otherwise, we need to force
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
+ if(hw->mac_type >= e1000_82544)
+ e1000_config_collision_dist(hw);
+ else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Configure Flow Control now that Auto-Neg has completed. First, we
+ * need to restore the desired flow control settings because we may
+ * have had to re-autoneg with a different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+
+ /* At this point we know that we are on copper and we have
+ * auto-negotiated link. These are conditions for checking the link
+ * parter capability register. We use the link partner capability to
+ * determine if TBI Compatibility needs to be turned on or off. If
+ * the link partner advertises any speed in addition to Gigabit, then
+ * we assume that they are GMII-based, and TBI compatibility is not
+ * needed. If no other speeds are advertised, we assume the link
+ * partner is TBI-based, and we turn on TBI Compatibility.
+ */
+ if(hw->tbi_compatibility_en) {
+ if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+ NWAY_LPAR_10T_FD_CAPS |
+ NWAY_LPAR_100TX_HD_CAPS |
+ NWAY_LPAR_100TX_FD_CAPS |
+ NWAY_LPAR_100T4_CAPS)) {
+ /* If our link partner advertises anything in addition to
+ * gigabit, we do not need to enable TBI compatibility.
+ */
+ if(hw->tbi_compatibility_on) {
+ /* If we previously were in the mode, turn it off. */
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl &= ~E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ hw->tbi_compatibility_on = FALSE;
+ }
+ } else {
+ /* If TBI compatibility is was previously off, turn it on. For
+ * compatibility with a TBI link partner, we will store bad
+ * packets. Some frames have an additional byte on the end and
+ * will look like CRC errors to to the hardware.
+ */
+ if(!hw->tbi_compatibility_on) {
+ hw->tbi_compatibility_on = TRUE;
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl |= E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ }
+ }
+ }
+ }
+ /* If we don't have link (auto-negotiation failed or link partner cannot
+ * auto-negotiate), the cable is plugged in (we have signal), and our
+ * link partner is not trying to auto-negotiate with us (we are receiving
+ * idles or data), we need to force link up. We also need to give
+ * auto-negotiation time to complete, in case the cable was just plugged
+ * in. The autoneg_failed flag does this.
+ */
+ else if((hw->media_type == e1000_media_type_fiber) &&
+ (!(status & E1000_STATUS_LU)) &&
+ ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if(hw->autoneg_failed == 0) {
+ hw->autoneg_failed = 1;
+ return 0;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+ }
+ /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable forced link in the
+ * Device Control register in an attempt to auto-negotiate with our link
+ * partner.
+ */
+ else if((hw->media_type == e1000_media_type_fiber) &&
+ (ctrl & E1000_CTRL_SLU) &&
+ (rxcw & E1000_RXCW_C)) {
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+ E1000_WRITE_REG(hw, TXCW, hw->txcw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+ uint16_t *speed,
+ uint16_t *duplex)
+{
+ uint32_t status;
+
+ DEBUGFUNC("e1000_get_speed_and_duplex");
+
+ if(hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if(status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if(status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\r\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT(" Half Duplex\r\n");
+ }
+ } else {
+ DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+ }
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_wait_autoneg");
+ DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+ return 0;
+ }
+ msec_delay(100);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Raise the clock input to the Management Data Clock (by setting the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+ usec_delay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Lower the clock input to the Management Data Clock (by clearing the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+ usec_delay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw,
+ uint32_t data,
+ uint16_t count)
+{
+ uint32_t ctrl;
+ uint32_t mask;
+
+ /* We need to shift "count" number of bits out to the PHY. So, the value
+ * in the "data" parameter will be shifted out to the PHY one bit at a
+ * time. In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01;
+ mask <<= (count - 1);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+ while(mask) {
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+ * then raising and lowering the Management Data Clock. A "0" is
+ * shifted out to the PHY by setting the MDIO bit to "0" and then
+ * raising and lowering the clock.
+ */
+ if(data & mask) ctrl |= E1000_CTRL_MDIO;
+ else ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ usec_delay(2);
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ mask = mask >> 1;
+ }
+
+ /* Clear the data bit just before leaving this routine. */
+ ctrl &= ~E1000_CTRL_MDIO;
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t data = 0;
+ uint8_t i;
+
+ /* In order to read a register from the PHY, we need to shift in a total
+ * of 18 bits from the PHY. The first two bit (turnaround) times are used
+ * to avoid contention on the MDIO pin when a read operation is performed.
+ * These two bits are ignored by us and thrown away. Bits are "shifted in"
+ * by raising the input to the Management Data Clock (setting the MDC bit),
+ * and then reading the value of the MDIO bit.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+ ctrl &= ~E1000_CTRL_MDIO_DIR;
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Raise and Lower the clock before reading in the data. This accounts for
+ * the turnaround bits. The first clock occurred when we clocked out the
+ * last bit of the Register Address.
+ */
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ for(data = 0, i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_mdi_clk(hw, &ctrl);
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Check to see if we shifted in a "1". */
+ if(ctrl & E1000_CTRL_MDIO) data |= 1;
+ e1000_lower_mdi_clk(hw, &ctrl);
+ }
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ /* Clear the MDIO bit just before leaving this routine. */
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+e1000_read_phy_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t *phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("e1000_read_phy_reg");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, and register address in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 64; i++) {
+ usec_delay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if(mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (uint16_t) mdic;
+ } else {
+ /* We must first send a preamble through the MDIO pin to signal the
+ * beginning of an MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the next few fields that are required for a read
+ * operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine five different times. The format of
+ * a MII read instruction consists of a shift out of 14 bits and is
+ * defined as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+ * followed by a shift in of 18 bits. This first two bits shifted in
+ * are TurnAround bits used to avoid contention on the MDIO pin when a
+ * READ operation is performed. These two bits are thrown away
+ * followed by a shift in of 16 bits which contains the desired data.
+ */
+ mdic = ((reg_addr) | (phy_addr << 5) |
+ (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+ e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+ /* Now that we've shifted out the read command to the MII, we need to
+ * "shift in" the 16-bit value (18 total bits) of the requested PHY
+ * register address.
+ */
+ *phy_data = e1000_shift_in_mdi_bits(hw);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+e1000_write_phy_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("e1000_write_phy_reg");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, register address, and data intended
+ * for the PHY register in the MDI Control register. The MAC will take
+ * care of interfacing with the PHY to send the desired data.
+ */
+ mdic = (((uint32_t) phy_data) |
+ (reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 64; i++) {
+ usec_delay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ } else {
+ /* We'll need to use the SW defined pins to shift the write command
+ * out to the PHY. We first send a preamble to the PHY to signal the
+ * beginning of the MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the remaining required fields that will indicate a
+ * write operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine for each field in the command. The
+ * format of a MII write instruction is as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+ */
+ mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+ (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+ mdic <<= 16;
+ mdic |= (uint32_t) phy_data;
+
+ e1000_shift_out_mdi_bits(hw, mdic, 32);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+
+ DEBUGFUNC("e1000_phy_hw_reset");
+
+ DEBUGOUT("Resetting Phy...\n");
+
+ if(hw->mac_type > e1000_82543) {
+ /* Read the device control register and assert the E1000_CTRL_PHY_RST
+ * bit. Then, take it out of reset.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+ msec_delay(10);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+ * bit to put the PHY into reset. Then, take it out of reset.
+ */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ msec_delay(10);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+ usec_delay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_phy_reset");
+
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= MII_CR_RESET;
+ if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ usec_delay(1);
+ return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+ uint16_t phy_id_high, phy_id_low;
+ boolean_t match = FALSE;
+
+ DEBUGFUNC("e1000_detect_gig_phy");
+
+ /* Read the PHY ID Registers to identify which PHY is onboard. */
+ if(e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->phy_id = (uint32_t) (phy_id_high << 16);
+ usec_delay(2);
+ if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+
+ switch(hw->mac_type) {
+ case e1000_82543:
+ if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+ break;
+ case e1000_82544:
+ if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_82540:
+ if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+ break;
+ default:
+ DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+ return -E1000_ERR_CONFIG;
+ }
+ if(match) {
+ DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+ return 0;
+ }
+ DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+ return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_reset_dsp(struct e1000_hw *hw)
+{
+ int32_t ret_val = -E1000_ERR_PHY;
+ DEBUGFUNC("e1000_phy_reset_dsp");
+
+ do {
+ if(e1000_write_phy_reg(hw, 29, 0x1d) < 0) break;
+ if(e1000_write_phy_reg(hw, 30, 0xc1) < 0) break;
+ if(e1000_write_phy_reg(hw, 30, 0x00) < 0) break;
+ ret_val = 0;
+ } while(0);
+
+ if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
+ return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+ struct e1000_phy_info *phy_info)
+{
+ int32_t ret_val = -E1000_ERR_PHY;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_phy_get_info");
+
+ phy_info->cable_length = e1000_cable_length_undefined;
+ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+ phy_info->cable_polarity = e1000_rev_polarity_undefined;
+ phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+ phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+ phy_info->local_rx = e1000_1000t_rx_status_undefined;
+ phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+ if(hw->media_type != e1000_media_type_copper) {
+ DEBUGOUT("PHY info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ do {
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+ if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+ DEBUGOUT("PHY info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+ break;
+ phy_info->extended_10bt_distance =
+ (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+ phy_info->polarity_correction =
+ (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+ break;
+ phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+ M88E1000_PSSR_REV_POLARITY_SHIFT;
+ phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+ M88E1000_PSSR_MDIX_SHIFT;
+ if(phy_data & M88E1000_PSSR_1000MBS) {
+ /* Cable Length Estimation and Local/Remote Receiver Informatoion
+ * are only valid at 1000 Mbps
+ */
+ phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+ break;
+ phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT;
+ phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ }
+ ret_val = 0;
+ } while(0);
+
+ if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
+ return ret_val;
+}
+
+int32_t
+e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_validate_mdi_settings");
+
+ if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->mdix = 1;
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ usec_delay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ usec_delay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+ uint16_t data,
+ uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t mask;
+
+ /* We need to shift "count" bits out to the EEPROM. So, value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01 << (count - 1);
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ do {
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+ * and then raising and then lowering the clock (the SK bit controls
+ * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
+ * by setting "DI" to "0" and then raising and then lowering the clock.
+ */
+ eecd &= ~E1000_EECD_DI;
+
+ if(data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ usec_delay(50);
+
+ e1000_raise_ee_clk(hw, &eecd);
+ e1000_lower_ee_clk(hw, &eecd);
+
+ mask = mask >> 1;
+
+ } while(mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+ uint32_t i;
+ uint16_t data;
+
+ /* In order to read a register from the EEPROM, we need to shift 16 bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the "DO"
+ * bit. During this "shifting in" process the "DI" bit should always be
+ * clear..
+ */
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for(i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+ if(eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_ee_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Deselct EEPROM */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+}
+
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t *data)
+{
+ uint32_t eecd;
+ uint32_t i = 0;
+ boolean_t large_eeprom = FALSE;
+
+ DEBUGFUNC("e1000_read_eeprom");
+
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+ i++;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+
+ /* Prepare the EEPROM for reading */
+ e1000_setup_eeprom(hw);
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+ if(large_eeprom) {
+ /* If we have a 256 word EEPROM, there are 8 address bits */
+ e1000_shift_out_ee_bits(hw, offset, 8);
+ } else {
+ /* If we have a 64 word EEPROM, there are 6 address bits */
+ e1000_shift_out_ee_bits(hw, offset, 6);
+ }
+
+ /* Read the data */
+ *data = e1000_shift_in_ee_bits(hw);
+
+ /* End this read operation */
+ e1000_standby_eeprom(hw);
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > e1000_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+
+ if(checksum == (uint16_t) EEPROM_SUM) {
+ return 0;
+ } else {
+ DEBUGOUT("EEPROM Checksum Invalid\n");
+ return -E1000_ERR_EEPROM;
+ }
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+e1000_read_part_num(struct e1000_hw *hw,
+ uint32_t *part_num)
+{
+ uint16_t offset = EEPROM_PBA_BYTE_1;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("e1000_read_part_num");
+
+ /* Get word 0 from EEPROM */
+ if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 0 in upper half of part_num */
+ *part_num = (uint32_t) (eeprom_data << 16);
+
+ /* Get word 1 from EEPROM */
+ if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 1 in lower half of part_num */
+ *part_num |= eeprom_data;
+
+ return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_read_mac_addr(struct e1000_hw * hw)
+{
+ uint16_t offset;
+ uint16_t eeprom_data, i;
+
+ DEBUGFUNC("e1000_read_mac_addr");
+
+ for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+ if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+ hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+ }
+ for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+ uint32_t i;
+ uint32_t addr_low;
+ uint32_t addr_high;
+
+ DEBUGFUNC("e1000_init_rx_addrs");
+
+ /* Setup the receive address. */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+ addr_low = (hw->mac_addr[0] |
+ (hw->mac_addr[1] << 8) |
+ (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+ addr_high = (hw->mac_addr[4] |
+ (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+ for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the
+ * multicast table.
+ *****************************************************************************/
+void
+e1000_mc_addr_list_update(struct e1000_hw *hw,
+ uint8_t *mc_addr_list,
+ uint32_t mc_addr_count,
+ uint32_t pad)
+{
+ uint32_t hash_value;
+ uint32_t i;
+ uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
+
+ DEBUGFUNC("e1000_mc_addr_list_update");
+
+ /* Set the new number of MC addresses that we are being requested to use. */
+ hw->num_mc_addrs = mc_addr_count;
+
+ /* Clear RAR[1-15] */
+ DEBUGOUT(" Clearing RAR[1-15]\n");
+ for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+
+ /* Clear the MTA */
+ DEBUGOUT(" Clearing MTA\n");
+ for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ }
+
+ /* Add the new addresses */
+ for(i = 0; i < mc_addr_count; i++) {
+ DEBUGOUT(" Adding the multicast addresses:\n");
+ DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+ hash_value = e1000_hash_mc_addr(hw,
+ mc_addr_list +
+ (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+ DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+ /* Place this multicast address in the RAR if there is room, *
+ * else put it in the MTA
+ */
+ if(rar_used_count < E1000_RAR_ENTRIES) {
+ e1000_rar_set(hw,
+ mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+ rar_used_count);
+ rar_used_count++;
+ } else {
+ e1000_mta_set(hw, hash_value);
+ }
+ }
+ DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *****************************************************************************/
+uint32_t
+e1000_hash_mc_addr(struct e1000_hw *hw,
+ uint8_t *mc_addr)
+{
+ uint32_t hash_value = 0;
+
+ /* The portion of the address that is used for the hash table is
+ * determined by the mc_filter_type setting.
+ */
+ switch (hw->mc_filter_type) {
+ /* [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ */
+ case 0:
+ /* [47:36] i.e. 0x563 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ break;
+ case 1:
+ /* [46:35] i.e. 0xAC6 for above example address */
+ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ break;
+ case 2:
+ /* [45:34] i.e. 0x5D8 for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ break;
+ case 3:
+ /* [43:32] i.e. 0x634 for above example address */
+ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ break;
+ }
+
+ hash_value &= 0xFFF;
+ return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+e1000_mta_set(struct e1000_hw *hw,
+ uint32_t hash_value)
+{
+ uint32_t hash_bit, hash_reg;
+ uint32_t mta;
+ uint32_t temp;
+
+ /* The MTA is a register array of 128 32-bit registers.
+ * It is treated like an array of 4096 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 5) & 0x7F;
+ hash_bit = hash_value & 0x1F;
+
+ mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+ mta |= (1 << hash_bit);
+
+ /* If we are on an 82544 and we are trying to write an odd offset
+ * in the MTA, save off the previous entry before writing and
+ * restore the old value after writing.
+ */
+ if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+e1000_rar_set(struct e1000_hw *hw,
+ uint8_t *addr,
+ uint32_t index)
+{
+ uint32_t rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((uint32_t) addr[0] |
+ ((uint32_t) addr[1] << 8) |
+ ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+ rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+e1000_write_vfta(struct e1000_hw *hw,
+ uint32_t offset,
+ uint32_t value)
+{
+ uint32_t temp;
+
+ if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+ uint32_t offset;
+
+ for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_setup_led(struct e1000_hw *hw)
+{
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_setup_led");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ /* No setup necessary */
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Save current LEDCTL settings */
+ hw->ledctl = ledctl;
+ /* Turn off LED2 and LED3 */
+ ledctl &= ~(E1000_LEDCTL_LED2_IVRT |
+ E1000_LEDCTL_LED2_BLINK |
+ E1000_LEDCTL_LED2_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED2_MODE_SHIFT);
+ ledctl &= ~(E1000_LEDCTL_LED3_IVRT |
+ E1000_LEDCTL_LED3_BLINK |
+ E1000_LEDCTL_LED3_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_cleanup_led(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ /* No cleanup necessary */
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ /* Restore LEDCTL settings */
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_on(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_led_on");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Set SW Defineable Pin 0 to turn on the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Clear SW Defineable Pin 0 to turn on the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Set LED 3 mode to on */
+ ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+ ledctl |= (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_off(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_led_off");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Clear SW Defineable Pin 0 to turn off the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Set SW Defineable Pin 0 to turn off the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Set LED 3 mode to off */
+ ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_hw_cntrs(struct e1000_hw *hw)
+{
+ volatile uint32_t temp;
+
+ temp = E1000_READ_REG(hw, CRCERRS);
+ temp = E1000_READ_REG(hw, SYMERRS);
+ temp = E1000_READ_REG(hw, MPC);
+ temp = E1000_READ_REG(hw, SCC);
+ temp = E1000_READ_REG(hw, ECOL);
+ temp = E1000_READ_REG(hw, MCC);
+ temp = E1000_READ_REG(hw, LATECOL);
+ temp = E1000_READ_REG(hw, COLC);
+ temp = E1000_READ_REG(hw, DC);
+ temp = E1000_READ_REG(hw, SEC);
+ temp = E1000_READ_REG(hw, RLEC);
+ temp = E1000_READ_REG(hw, XONRXC);
+ temp = E1000_READ_REG(hw, XONTXC);
+ temp = E1000_READ_REG(hw, XOFFRXC);
+ temp = E1000_READ_REG(hw, XOFFTXC);
+ temp = E1000_READ_REG(hw, FCRUC);
+ temp = E1000_READ_REG(hw, PRC64);
+ temp = E1000_READ_REG(hw, PRC127);
+ temp = E1000_READ_REG(hw, PRC255);
+ temp = E1000_READ_REG(hw, PRC511);
+ temp = E1000_READ_REG(hw, PRC1023);
+ temp = E1000_READ_REG(hw, PRC1522);
+ temp = E1000_READ_REG(hw, GPRC);
+ temp = E1000_READ_REG(hw, BPRC);
+ temp = E1000_READ_REG(hw, MPRC);
+ temp = E1000_READ_REG(hw, GPTC);
+ temp = E1000_READ_REG(hw, GORCL);
+ temp = E1000_READ_REG(hw, GORCH);
+ temp = E1000_READ_REG(hw, GOTCL);
+ temp = E1000_READ_REG(hw, GOTCH);
+ temp = E1000_READ_REG(hw, RNBC);
+ temp = E1000_READ_REG(hw, RUC);
+ temp = E1000_READ_REG(hw, RFC);
+ temp = E1000_READ_REG(hw, ROC);
+ temp = E1000_READ_REG(hw, RJC);
+ temp = E1000_READ_REG(hw, TORL);
+ temp = E1000_READ_REG(hw, TORH);
+ temp = E1000_READ_REG(hw, TOTL);
+ temp = E1000_READ_REG(hw, TOTH);
+ temp = E1000_READ_REG(hw, TPR);
+ temp = E1000_READ_REG(hw, TPT);
+ temp = E1000_READ_REG(hw, PTC64);
+ temp = E1000_READ_REG(hw, PTC127);
+ temp = E1000_READ_REG(hw, PTC255);
+ temp = E1000_READ_REG(hw, PTC511);
+ temp = E1000_READ_REG(hw, PTC1023);
+ temp = E1000_READ_REG(hw, PTC1522);
+ temp = E1000_READ_REG(hw, MPTC);
+ temp = E1000_READ_REG(hw, BPTC);
+
+ if(hw->mac_type < e1000_82543) return;
+
+ temp = E1000_READ_REG(hw, ALGNERRC);
+ temp = E1000_READ_REG(hw, RXERRC);
+ temp = E1000_READ_REG(hw, TNCRS);
+ temp = E1000_READ_REG(hw, CEXTERR);
+ temp = E1000_READ_REG(hw, TSCTC);
+ temp = E1000_READ_REG(hw, TSCTFC);
+
+ if(hw->mac_type <= e1000_82544) return;
+
+ temp = E1000_READ_REG(hw, MGTPRC);
+ temp = E1000_READ_REG(hw, MGTPDC);
+ temp = E1000_READ_REG(hw, MGTPTC);
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after e1000_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+e1000_reset_adaptive(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_reset_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if(!hw->ifs_params_forced) {
+ hw->current_ifs_val = 0;
+ hw->ifs_min_val = IFS_MIN;
+ hw->ifs_max_val = IFS_MAX;
+ hw->ifs_step_size = IFS_STEP;
+ hw->ifs_ratio = IFS_RATIO;
+ }
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+e1000_update_adaptive(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_update_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if((hw->collision_delta * hw->ifs_ratio) >
+ hw->tx_packet_delta) {
+ if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+ hw->in_ifs_mode = TRUE;
+ if(hw->current_ifs_val < hw->ifs_max_val) {
+ if(hw->current_ifs_val == 0)
+ hw->current_ifs_val = hw->ifs_min_val;
+ else
+ hw->current_ifs_val += hw->ifs_step_size;
+ E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+ }
+ }
+ } else {
+ if((hw->in_ifs_mode == TRUE) &&
+ (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+ hw->current_ifs_val = 0;
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ }
+ }
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ *
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+e1000_tbi_adjust_stats(struct e1000_hw *hw,
+ struct e1000_hw_stats *stats,
+ uint32_t frame_len,
+ uint8_t *mac_addr)
+{
+ uint64_t carry_bit;
+
+ /* First adjust the frame length. */
+ frame_len--;
+ /* We need to adjust the statistics counters, since the hardware
+ * counters overcount this packet as a CRC error and undercount
+ * the packet as a good packet
+ */
+ /* This packet should not be counted as a CRC error. */
+ stats->crcerrs--;
+ /* This packet does count as a Good Packet Received. */
+ stats->gprc++;
+
+ /* Adjust the Good Octets received counters */
+ carry_bit = 0x80000000 & stats->gorcl;
+ stats->gorcl += frame_len;
+ /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+ * Received Count) was one before the addition,
+ * AND it is zero after, then we lost the carry out,
+ * need to add one to Gorch (Good Octets Received Count High).
+ * This could be simplified if all environments supported
+ * 64-bit integers.
+ */
+ if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+ stats->gorch++;
+ /* Is this a broadcast or multicast? Check broadcast first,
+ * since the test for a multicast frame will test positive on
+ * a broadcast frame.
+ */
+ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+ /* Broadcast packet */
+ stats->bprc++;
+ else if(*mac_addr & 0x01)
+ /* Multicast packet */
+ stats->mprc++;
+
+ if(frame_len == hw->max_frame_size) {
+ /* In this case, the hardware has overcounted the number of
+ * oversize frames.
+ */
+ if(stats->roc > 0)
+ stats->roc--;
+ }
+
+ /* Adjust the bin counters when the extra byte put the frame in the
+ * wrong bin. Remember that the frame_len was adjusted above.
+ */
+ if(frame_len == 64) {
+ stats->prc64++;
+ stats->prc127--;
+ } else if(frame_len == 127) {
+ stats->prc127++;
+ stats->prc255--;
+ } else if(frame_len == 255) {
+ stats->prc255++;
+ stats->prc511--;
+ } else if(frame_len == 511) {
+ stats->prc511++;
+ stats->prc1023--;
+ } else if(frame_len == 1023) {
+ stats->prc1023++;
+ stats->prc1522--;
+ } else if(frame_len == 1522) {
+ stats->prc1522++;
+ }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_get_bus_info(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ if(hw->mac_type < e1000_82543) {
+ hw->bus_type = e1000_bus_type_unknown;
+ hw->bus_speed = e1000_bus_speed_unknown;
+ hw->bus_width = e1000_bus_width_unknown;
+ return;
+ }
+
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ e1000_bus_type_pcix : e1000_bus_type_pci;
+ if(hw->bus_type == e1000_bus_type_pci) {
+ hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+ e1000_bus_speed_66 : e1000_bus_speed_33;
+ } else {
+ switch (status & E1000_STATUS_PCIX_SPEED) {
+ case E1000_STATUS_PCIX_SPEED_66:
+ hw->bus_speed = e1000_bus_speed_66;
+ break;
+ case E1000_STATUS_PCIX_SPEED_100:
+ hw->bus_speed = e1000_bus_speed_100;
+ break;
+ case E1000_STATUS_PCIX_SPEED_133:
+ hw->bus_speed = e1000_bus_speed_133;
+ break;
+ default:
+ hw->bus_speed = e1000_bus_speed_reserved;
+ break;
+ }
+ }
+ hw->bus_width = (status & E1000_STATUS_BUS64) ?
+ e1000_bus_width_64 : e1000_bus_width_32;
+}
+
diff --git a/drivers/net/e1000/e1000_mac.h b/drivers/net/e1000/e1000_hw.h
index 928c277ac28d..7031ebde588a 100644
--- a/drivers/net/e1000/e1000_mac.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -72,18 +71,18 @@
*******************************************************************************/
-/* e1000_mac.h
+/* e1000_hw.h
* Structures, enums, and macros for the MAC
*/
-#ifndef _E1000_MAC_H_
-#define _E1000_MAC_H_
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
#include "e1000_osdep.h"
/* Forward declarations of structures used by the shared code */
-struct e1000_shared_adapter;
-struct e1000_shared_stats;
+struct e1000_hw;
+struct e1000_hw_stats;
/* Enumerated types specific to the e1000 hardware */
/* Media Access Controlers */
@@ -92,6 +91,7 @@ typedef enum {
e1000_82542_rev2_1,
e1000_82543,
e1000_82544,
+ e1000_82540,
e1000_num_macs
} e1000_mac_type;
@@ -142,40 +142,125 @@ typedef enum {
e1000_bus_width_64
} e1000_bus_width;
+/* PHY status info structure and supporting enums */
+typedef enum {
+ e1000_cable_length_50 = 0,
+ e1000_cable_length_50_80,
+ e1000_cable_length_80_110,
+ e1000_cable_length_110_140,
+ e1000_cable_length_140,
+ e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+typedef enum {
+ e1000_10bt_ext_dist_enable_normal = 0,
+ e1000_10bt_ext_dist_enable_lower,
+ e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
-/* Function prototypes */
-/* Setup */
-void e1000_adapter_stop(struct e1000_shared_adapter *shared);
-boolean_t e1000_init_hw(struct e1000_shared_adapter *shared);
-void e1000_init_rx_addrs(struct e1000_shared_adapter *shared);
+typedef enum {
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
-/* Filters (multicast, vlan, receive) */
-void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
-uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr);
-void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value);
-void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index);
-void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value);
-void e1000_clear_vfta(struct e1000_shared_adapter *shared);
-
-/* Link layer setup functions */
-boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared);
-boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg);
-void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared);
-void e1000_check_for_link(struct e1000_shared_adapter *shared);
-void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex);
+typedef enum {
+ e1000_polarity_reversal_enabled = 0,
+ e1000_polarity_reversal_disabled,
+ e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+ e1000_auto_x_mode_manual_mdi = 0,
+ e1000_auto_x_mode_manual_mdix,
+ e1000_auto_x_mode_auto1,
+ e1000_auto_x_mode_auto2,
+ e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+ e1000_cable_length cable_length;
+ e1000_10bt_ext_dist_enable extended_10bt_distance;
+ e1000_rev_polarity cable_polarity;
+ e1000_polarity_reversal polarity_correction;
+ e1000_auto_x_mode mdix_mode;
+ e1000_1000t_rx_status local_rx;
+ e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+ uint32_t idle_errors;
+ uint32_t receive_errors;
+};
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+
+/* Function prototypes */
+/* Initialization */
+void e1000_reset_hw(struct e1000_hw *hw);
+int32_t e1000_init_hw(struct e1000_hw *hw);
+
+/* Link Configuration */
+int32_t e1000_setup_link(struct e1000_hw *hw);
+int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+int32_t e1000_check_for_link(struct e1000_hw *hw);
+void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* PHY */
+int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+void e1000_phy_hw_reset(struct e1000_hw *hw);
+int32_t e1000_phy_reset(struct e1000_hw *hw);
+int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
/* EEPROM Functions */
-uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg);
-boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared);
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+/* Filters (multicast, vlan, receive) */
+void e1000_init_rx_addrs(struct e1000_hw *hw);
+void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
+uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
+void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
+void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+void e1000_clear_vfta(struct e1000_hw *hw);
+
+/* LED functions */
+int32_t e1000_setup_led(struct e1000_hw *hw);
+int32_t e1000_cleanup_led(struct e1000_hw *hw);
+int32_t e1000_led_on(struct e1000_hw *hw);
+int32_t e1000_led_off(struct e1000_hw *hw);
+
+/* Adaptive IFS Functions */
/* Everything else */
-void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared);
-boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num);
-void e1000_read_mac_addr(struct e1000_shared_adapter * shared);
-void e1000_get_bus_info(struct e1000_shared_adapter *shared);
-uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
-void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value);
+void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@@ -185,7 +270,9 @@ void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint
#define E1000_DEV_ID_82544EI_FIBER 0x1009
#define E1000_DEV_ID_82544GC_COPPER 0x100C
#define E1000_DEV_ID_82544GC_LOM 0x100D
-#define NUM_DEV_IDS 7
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define NUM_DEV_IDS 9
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -204,9 +291,14 @@ void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint
/* The sizes (in bytes) of a ethernet packet */
#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */
-#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */
-#define CRC_LENGTH 4
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+ (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH ETHERNET_FCS_SIZE
#define MAX_JUMBO_FRAME_SIZE 0x3F00
@@ -481,6 +573,7 @@ struct e1000_ffvt_entry {
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
@@ -623,6 +716,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_TDT 0x00438
#define E1000_82542_TIDV 0x00440
#define E1000_82542_TBT E1000_TBT
+#define E1000_82542_AIT E1000_AIT
#define E1000_82542_VFTA 0x00600
#define E1000_82542_LEDCTL E1000_LEDCTL
#define E1000_82542_PBA E1000_PBA
@@ -706,7 +800,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_FFVT E1000_FFVT
/* Statistics counters collected by the MAC */
-struct e1000_shared_stats {
+struct e1000_hw_stats {
uint64_t crcerrs;
uint64_t algnerrc;
uint64_t symerrs;
@@ -767,10 +861,8 @@ struct e1000_shared_stats {
uint64_t tsctfc;
};
-/* Structure containing variables used by the shared code (e1000_mac.c and
- * e1000_phy.c)
- */
-struct e1000_shared_adapter {
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
uint8_t *hw_addr;
e1000_mac_type mac_type;
e1000_media_type media_type;
@@ -782,29 +874,30 @@ struct e1000_shared_adapter {
uint32_t phy_id;
uint32_t phy_addr;
uint32_t original_fc;
- uint32_t txcw_reg;
+ uint32_t txcw;
uint32_t autoneg_failed;
uint32_t max_frame_size;
uint32_t min_frame_size;
uint32_t mc_filter_type;
uint32_t num_mc_addrs;
+ uint32_t collision_delta;
+ uint32_t tx_packet_delta;
+ uint32_t ledctl;
uint16_t autoneg_advertised;
uint16_t pci_cmd_word;
uint16_t fc_high_water;
uint16_t fc_low_water;
uint16_t fc_pause_time;
+ uint16_t current_ifs_val;
+ uint16_t ifs_min_val;
+ uint16_t ifs_max_val;
+ uint16_t ifs_step_size;
+ uint16_t ifs_ratio;
uint16_t device_id;
uint16_t vendor_id;
uint16_t subsystem_id;
uint16_t subsystem_vendor_id;
uint8_t revision_id;
- boolean_t disable_polarity_correction;
- boolean_t get_link_status;
- boolean_t tbi_compatibility_en;
- boolean_t tbi_compatibility_on;
- boolean_t adapter_stopped;
- boolean_t fc_send_xon;
- boolean_t report_tx_early;
uint8_t autoneg;
uint8_t mdix;
uint8_t forced_speed_duplex;
@@ -812,6 +905,15 @@ struct e1000_shared_adapter {
uint8_t dma_fairness;
uint8_t mac_addr[NODE_ADDRESS_SIZE];
uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+ boolean_t disable_polarity_correction;
+ boolean_t get_link_status;
+ boolean_t tbi_compatibility_en;
+ boolean_t tbi_compatibility_on;
+ boolean_t fc_send_xon;
+ boolean_t report_tx_early;
+ boolean_t adaptive_ifs;
+ boolean_t ifs_params_forced;
+ boolean_t in_ifs_mode;
};
@@ -1254,8 +1356,9 @@ struct e1000_shared_adapter {
/* Collision related configuration parameters */
#define E1000_COLLISION_THRESHOLD 16
#define E1000_CT_SHIFT 4
-#define E1000_FDX_COLLISION_DISTANCE 64
-#define E1000_HDX_COLLISION_DISTANCE 64
+#define E1000_COLLISION_DISTANCE 64
+#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_GB_HDX_COLLISION_DISTANCE 512
#define E1000_COLD_SHIFT 12
@@ -1282,6 +1385,19 @@ struct e1000_shared_adapter {
#define E1000_TXDMAC_DPP 0x00000001
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START 8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP 190
+#define TX_THRESHOLD_DISABLE 0
+#define TX_THRESHOLD_TIMER_MS 10000
+#define MIN_NUM_XMITS 1000
+#define IFS_MAX 80
+#define IFS_STEP 10
+#define IFS_MIN 40
+#define IFS_RATIO 4
+
/* PBA constants */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
#define E1000_PBA_24K 0x0018
@@ -1337,17 +1453,9 @@ struct e1000_shared_adapter {
/* TBI_ACCEPT macro definition:
*
- * If Tbi Compatibility mode is turned-on, then we should accept frames with
- * receive errors if and only if:
- * 1) errors is equal to the CRC error bit.
- * 2) The last byte is a Carrier extension (0x0F).
- * 3) The frame length (as reported by Hardware) is greater than 64 (60
- * if a VLAN tag was stripped from the frame.
- * 4) " " " " " " " <= max_frame_size+1.
- *
* This macro requires:
- * adapter = a pointer to struct e1000_shared_adapter
- * special = the 16 bit special field of the RX descriptor with EOP set
+ * adapter = a pointer to struct e1000_hw
+ * status = the 8 bit status field of the RX descriptor with EOP set
* error = the 8 bit error field of the RX descriptor with EOP set
* length = the sum of all the length fields of the RX descriptors that
* make up the current frame
@@ -1370,14 +1478,290 @@ struct e1000_shared_adapter {
* ...
*/
-#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
((adapter)->tbi_compatibility_on && \
(((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
((last_byte) == CARRIER_EXTENSION) && \
- ((length) <= ((adapter)->max_frame_size + 1)) && \
- ((length) > ((special == 0x0000) ? \
- ((adapter)->min_frame_size) : \
- ((adapter)->min_frame_size - VLAN_TAG_SIZE))))
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= ((adapter)->max_frame_size + 1))) : \
+ (((length) > (adapter)->min_frame_size) && \
+ ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
-#endif /* _E1000_MAC_H_ */
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
+ * 0=CLK125 toggling
+ */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT 6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE 0xFFFFFFFF
+#define PHY_SOF 0x01
+#define PHY_OP_READ 0x02
+#define PHY_OP_WRITE 0x01
+#define PHY_TURNAROUND 0x02
+#define PHY_PREAMBLE_SIZE 32
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+#define E1000_PHY_ADDRESS 0x01
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK 0x01E0
+#define REG9_SPEED_MASK 0x0300
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+
+#endif /* _E1000_HW_H_ */
diff --git a/drivers/net/e1000/e1000_mac.c b/drivers/net/e1000/e1000_mac.c
deleted file mode 100644
index fcbba64b1cb3..000000000000
--- a/drivers/net/e1000/e1000_mac.c
+++ /dev/null
@@ -1,1821 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_mac.c
- * Shared functions for accessing and configuring the MAC
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
- * Raises the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_raise_clock(struct e1000_shared_adapter *shared,
- uint32_t *eecd_reg)
-{
- /* Raise the clock input to the EEPROM (by setting the SK bit), and then
- * wait 50 microseconds.
- */
- *eecd_reg = *eecd_reg | E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, *eecd_reg);
- usec_delay(50);
- return;
-}
-
-/******************************************************************************
- * Lowers the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_lower_clock(struct e1000_shared_adapter *shared,
- uint32_t *eecd_reg)
-{
- /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
- * wait 50 microseconds.
- */
- *eecd_reg = *eecd_reg & ~E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, *eecd_reg);
- usec_delay(50);
- return;
-}
-
-/******************************************************************************
- * Shift data bits out to the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * data - data to send to the EEPROM
- * count - number of bits to shift out
- *****************************************************************************/
-static void
-e1000_shift_out_bits(struct e1000_shared_adapter *shared,
- uint16_t data,
- uint16_t count)
-{
- uint32_t eecd_reg;
- uint32_t mask;
-
- /* We need to shift "count" bits out to the EEPROM. So, value in the
- * "data" parameter will be shifted out to the EEPROM one bit at a time.
- * In order to do this, "data" must be broken down into bits.
- */
- mask = 0x01 << (count - 1);
- eecd_reg = E1000_READ_REG(shared, EECD);
- eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
- do {
- /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
- * and then raising and then lowering the clock (the SK bit controls
- * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
- * by setting "DI" to "0" and then raising and then lowering the clock.
- */
- eecd_reg &= ~E1000_EECD_DI;
-
- if(data & mask)
- eecd_reg |= E1000_EECD_DI;
-
- E1000_WRITE_REG(shared, EECD, eecd_reg);
-
- usec_delay(50);
-
- e1000_raise_clock(shared, &eecd_reg);
- e1000_lower_clock(shared, &eecd_reg);
-
- mask = mask >> 1;
-
- } while(mask);
-
- /* We leave the "DI" bit set to "0" when we leave this routine. */
- eecd_reg &= ~E1000_EECD_DI;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- return;
-}
-
-/******************************************************************************
- * Shift data bits in from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static uint16_t
-e1000_shift_in_bits(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
- uint32_t i;
- uint16_t data;
-
- /* In order to read a register from the EEPROM, we need to shift 16 bits
- * in from the EEPROM. Bits are "shifted in" by raising the clock input to
- * the EEPROM (setting the SK bit), and then reading the value of the "DO"
- * bit. During this "shifting in" process the "DI" bit should always be
- * clear..
- */
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
- data = 0;
-
- for(i = 0; i < 16; i++) {
- data = data << 1;
- e1000_raise_clock(shared, &eecd_reg);
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- eecd_reg &= ~(E1000_EECD_DI);
- if(eecd_reg & E1000_EECD_DO)
- data |= 1;
-
- e1000_lower_clock(shared, &eecd_reg);
- }
-
- return data;
-}
-
-/******************************************************************************
- * Prepares EEPROM for access
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
- *****************************************************************************/
-static void
-e1000_setup_eeprom(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- /* Clear SK and DI */
- eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI);
- E1000_WRITE_REG(shared, EECD, eecd_reg);
-
- /* Set CS */
- eecd_reg |= E1000_EECD_CS;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- return;
-}
-
-/******************************************************************************
- * Returns EEPROM to a "standby" state
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- /* Deselct EEPROM */
- eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Clock high */
- eecd_reg |= E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Select EEPROM */
- eecd_reg |= E1000_EECD_CS;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Clock low */
- eecd_reg &= ~E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
- return;
-}
-
-
-/******************************************************************************
- * Forces the MAC's flow control settings.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Sets the TFCE and RFCE bits in the device control register to reflect
- * the adapter settings. TFCE and RFCE need to be explicitly set by
- * software when a Copper PHY is used because autonegotiation is managed
- * by the PHY rather than the MAC. Software must also configure these
- * bits when link is forced on a fiber connection.
- *****************************************************************************/
-static void
-e1000_force_mac_fc(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
-
- DEBUGFUNC("e1000_force_mac_fc");
-
- /* Get the current configuration of the Device Control Register */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Because we didn't get link via the internal auto-negotiation
- * mechanism (we either forced link or we got link via PHY
- * auto-neg), we have to manually enable/disable transmit an
- * receive flow control.
- *
- * The "Case" statement below enables/disable flow control
- * according to the "shared->fc" parameter.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause
- * frames but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * frames but we do not receive pause frames).
- * 3: Both Rx and TX flow control (symmetric) is enabled.
- * other: No other values should be possible at this point.
- */
-
- switch (shared->fc) {
- case e1000_fc_none:
- ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
- break;
- case e1000_fc_rx_pause:
- ctrl_reg &= (~E1000_CTRL_TFCE);
- ctrl_reg |= E1000_CTRL_RFCE;
- break;
- case e1000_fc_tx_pause:
- ctrl_reg &= (~E1000_CTRL_RFCE);
- ctrl_reg |= E1000_CTRL_TFCE;
- break;
- case e1000_fc_full:
- ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
- break;
- default:
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Disable TX Flow Control for 82542 (rev 2.0) */
- if(shared->mac_type == e1000_82542_rev2_0)
- ctrl_reg &= (~E1000_CTRL_TFCE);
-
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
- return;
-}
-
-/******************************************************************************
- * Reset the transmit and receive units; mask and clear all interrupts.
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_adapter_stop(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t ctrl_ext_reg;
- uint32_t icr_reg;
- uint16_t pci_cmd_word;
-
- DEBUGFUNC("e1000_shared_adapter_stop");
-
- /* If we are stopped or resetting exit gracefully and wait to be
- * started again before accessing the hardware.
- */
- if(shared->adapter_stopped) {
- DEBUGOUT("Exiting because the adapter is already stopped!!!\n");
- return;
- }
-
- /* Set the Adapter Stopped flag so other driver functions stop
- * touching the Hardware.
- */
- shared->adapter_stopped = TRUE;
-
- /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-
- pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-
- e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
- }
-
- /* Clear interrupt mask to stop board from generating interrupts */
- DEBUGOUT("Masking off all interrupts\n");
- E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
- /* Disable the Transmit and Receive units. Then delay to allow
- * any pending transactions to complete before we hit the MAC with
- * the global reset.
- */
- E1000_WRITE_REG(shared, RCTL, 0);
- E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
- /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
- shared->tbi_compatibility_on = FALSE;
-
- msec_delay(10);
-
- /* Issue a global reset to the MAC. This will reset the chip's
- * transmit, receive, DMA, and link units. It will not effect
- * the current PCI configuration. The global reset bit is self-
- * clearing, and should clear within a microsecond.
- */
- DEBUGOUT("Issuing a global reset to MAC\n");
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- E1000_WRITE_REG(shared, CTRL, (ctrl_reg | E1000_CTRL_RST));
-
- /* Delay a few ms just to allow the reset to complete */
- msec_delay(10);
-
-#if DBG
- /* Make sure the self-clearing global reset bit did self clear */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ASSERT(!(ctrl_reg & E1000_CTRL_RST));
-#endif
-
- /* Force a reload from the EEPROM */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
- ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST;
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
- msec_delay(2);
-
- /* Clear interrupt mask to stop board from generating interrupts */
- DEBUGOUT("Masking off all interrupts\n");
- E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
- /* Clear any pending interrupt events. */
- icr_reg = E1000_READ_REG(shared, ICR);
-
- /* If MWI was previously enabled, reenable it. */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- e1000_write_pci_cfg(shared,
- PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
- }
- }
- return;
-}
-
-/******************************************************************************
- * Performs basic configuration of the adapter.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Assumes that the controller has previously been reset and is in a
- * post-reset uninitialized state. Initializes the receive address registers,
- * multicast table, and VLAN filter table. Calls routines to setup link
- * configuration and flow control settings. Clears all on-chip counters. Leaves
- * the transmit and receive units disabled and uninitialized.
- *****************************************************************************/
-boolean_t
-e1000_init_hw(struct e1000_shared_adapter *shared)
-{
- uint32_t status_reg;
- uint32_t i;
- uint16_t pci_cmd_word;
- boolean_t status;
-
- DEBUGFUNC("e1000_init_hw");
-
- /* Set the Media Type and exit with error if it is not valid. */
- if(shared->mac_type != e1000_82543) {
- /* tbi_compatibility is only valid on 82543 */
- shared->tbi_compatibility_en = FALSE;
- }
-
- if(shared->mac_type >= e1000_82543) {
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_TBIMODE) {
- shared->media_type = e1000_media_type_fiber;
- /* tbi_compatibility not valid on fiber */
- shared->tbi_compatibility_en = FALSE;
- } else {
- shared->media_type = e1000_media_type_copper;
- }
- } else {
- /* This is an 82542 (fiber only) */
- shared->media_type = e1000_media_type_fiber;
- }
-
- /* Disabling VLAN filtering. */
- DEBUGOUT("Initializing the IEEE VLAN\n");
- E1000_WRITE_REG(shared, VET, 0);
-
- e1000_clear_vfta(shared);
-
- /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
- pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
- e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
- E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST);
-
- msec_delay(5);
- }
-
- /* Setup the receive address. This involves initializing all of the Receive
- * Address Registers (RARs 0 - 15).
- */
- e1000_init_rx_addrs(shared);
-
- /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
- if(shared->mac_type == e1000_82542_rev2_0) {
- E1000_WRITE_REG(shared, RCTL, 0);
-
- msec_delay(1);
-
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- e1000_write_pci_cfg(shared,
- PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
- }
- }
-
- /* Zero out the Multicast HASH table */
- DEBUGOUT("Zeroing the MTA\n");
- for(i = 0; i < E1000_MC_TBL_SIZE; i++)
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
-
- /* Call a subroutine to configure the link and setup flow control. */
- status = e1000_setup_fc_and_link(shared);
-
- /* Clear all of the statistics registers (clear on read). It is
- * important that we do this after we have tried to establish link
- * because the symbol error count will increment wildly if there
- * is no link.
- */
- e1000_clear_hw_cntrs(shared);
-
- return (status);
-}
-
-/******************************************************************************
- * Initializes receive address filters.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Places the MAC address in receive address register 0 and clears the rest
- * of the receive addresss registers. Clears the multicast table. Assumes
- * the receiver is in reset when the routine is called.
- *****************************************************************************/
-void
-e1000_init_rx_addrs(struct e1000_shared_adapter *shared)
-{
- uint32_t i;
- uint32_t addr_low;
- uint32_t addr_high;
-
- DEBUGFUNC("e1000_init_rx_addrs");
-
- /* Setup the receive address. */
- DEBUGOUT("Programming MAC Address into RAR[0]\n");
- addr_low = (shared->mac_addr[0] |
- (shared->mac_addr[1] << 8) |
- (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24));
-
- addr_high = (shared->mac_addr[4] |
- (shared->mac_addr[5] << 8) | E1000_RAH_AV);
-
- E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low);
- E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high);
-
- /* Zero out the other 15 receive addresses. */
- DEBUGOUT("Clearing RAR[1-15]\n");
- for(i = 1; i < E1000_RAR_ENTRIES; i++) {
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
- E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
- }
-
- return;
-}
-
-/******************************************************************************
- * Updates the MAC's list of multicast addresses.
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr_list - the list of new multicast addresses
- * mc_addr_count - number of addresses
- * pad - number of bytes between addresses in the list
- *
- * The given list replaces any existing list. Clears the last 15 receive
- * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the
- * multicast table.
- *****************************************************************************/
-void
-e1000_mc_addr_list_update(struct e1000_shared_adapter *shared,
- uint8_t *mc_addr_list,
- uint32_t mc_addr_count,
- uint32_t pad)
-{
- uint32_t hash_value;
- uint32_t i;
- uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
-
- DEBUGFUNC("e1000_mc_addr_list_update");
-
- /* Set the new number of MC addresses that we are being requested to use. */
- shared->num_mc_addrs = mc_addr_count;
-
- /* Clear RAR[1-15] */
- DEBUGOUT(" Clearing RAR[1-15]\n");
- for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
- E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
- }
-
- /* Clear the MTA */
- DEBUGOUT(" Clearing MTA\n");
- for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
- }
-
- /* Add the new addresses */
- for(i = 0; i < mc_addr_count; i++) {
- DEBUGOUT(" Adding the multicast addresses:\n");
- DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
-
- hash_value = e1000_hash_mc_addr(shared,
- mc_addr_list +
- (i * (ETH_LENGTH_OF_ADDRESS + pad)));
-
- DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
-
- /* Place this multicast address in the RAR if there is room, *
- * else put it in the MTA
- */
- if(rar_used_count < E1000_RAR_ENTRIES) {
- e1000_rar_set(shared,
- mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
- rar_used_count);
- rar_used_count++;
- } else {
- e1000_mta_set(shared, hash_value);
- }
- }
-
- DEBUGOUT("MC Update Complete\n");
- return;
-}
-
-/******************************************************************************
- * Hashes an address to determine its location in the multicast table
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr - the multicast address to hash
- *****************************************************************************/
-uint32_t
-e1000_hash_mc_addr(struct e1000_shared_adapter *shared,
- uint8_t *mc_addr)
-{
- uint32_t hash_value = 0;
-
- /* The portion of the address that is used for the hash table is
- * determined by the mc_filter_type setting.
- */
- switch (shared->mc_filter_type) {
- /* [0] [1] [2] [3] [4] [5]
- * 01 AA 00 12 34 56
- * LSB MSB - According to H/W docs */
- case 0:
- /* [47:36] i.e. 0x563 for above example address */
- hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
- break;
- case 1: /* [46:35] i.e. 0xAC6 for above example address */
- hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
- break;
- case 2: /* [45:34] i.e. 0x5D8 for above example address */
- hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
- break;
- case 3: /* [43:32] i.e. 0x634 for above example address */
- hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
- break;
- }
-
- hash_value &= 0xFFF;
- return (hash_value);
-}
-
-/******************************************************************************
- * Sets the bit in the multicast table corresponding to the hash value.
- *
- * shared - Struct containing variables accessed by shared code
- * hash_value - Multicast address hash value
- *****************************************************************************/
-void
-e1000_mta_set(struct e1000_shared_adapter *shared,
- uint32_t hash_value)
-{
- uint32_t hash_bit, hash_reg;
- uint32_t mta_reg;
- uint32_t temp;
-
- /* The MTA is a register array of 128 32-bit registers.
- * It is treated like an array of 4096 bits. We want to set
- * bit BitArray[hash_value]. So we figure out what register
- * the bit is in, read it, OR in the new bit, then write
- * back the new value. The register is determined by the
- * upper 7 bits of the hash value and the bit within that
- * register are determined by the lower 5 bits of the value.
- */
- hash_reg = (hash_value >> 5) & 0x7F;
- hash_bit = hash_value & 0x1F;
-
- mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg);
-
- mta_reg |= (1 << hash_bit);
-
- /* If we are on an 82544 and we are trying to write an odd offset
- * in the MTA, save off the previous entry before writing and
- * restore the old value after writing.
- */
- if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
- temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1));
- E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
- E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp);
- } else {
- E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
- }
- return;
-}
-
-/******************************************************************************
- * Puts an ethernet address into a receive address register.
- *
- * shared - Struct containing variables accessed by shared code
- * addr - Address to put into receive address register
- * index - Receive address register to write
- *****************************************************************************/
-void
-e1000_rar_set(struct e1000_shared_adapter *shared,
- uint8_t *addr,
- uint32_t index)
-{
- uint32_t rar_low, rar_high;
-
- /* HW expects these in little endian so we reverse the byte order
- * from network order (big endian) to little endian
- */
- rar_low = ((uint32_t) addr[0] |
- ((uint32_t) addr[1] << 8) |
- ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
-
- rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
-
- E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low);
- E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high);
- return;
-}
-
-/******************************************************************************
- * Writes a value to the specified offset in the VLAN filter table.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - Offset in VLAN filer table to write
- * value - Value to write into VLAN filter table
- *****************************************************************************/
-void
-e1000_write_vfta(struct e1000_shared_adapter *shared,
- uint32_t offset,
- uint32_t value)
-{
- uint32_t temp;
-
- if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
- temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1));
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
- E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp);
- } else {
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
- }
- return;
-}
-
-/******************************************************************************
- * Clears the VLAN filer table
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_vfta(struct e1000_shared_adapter *shared)
-{
- uint32_t offset;
-
- for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0);
- return;
-}
-
-/******************************************************************************
- * Configures flow control and link settings.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Determines which flow control settings to use. Calls the apropriate media-
- * specific link configuration function. Configures the flow control settings.
- * Assuming the adapter has a valid link partner, a valid link should be
- * established. Assumes the hardware has previously been reset and the
- * transmitter and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_fc_and_link(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t eecd_reg;
- uint32_t ctrl_ext_reg;
- boolean_t status = TRUE;
-
- DEBUGFUNC("e1000_setup_fc_and_link");
-
- /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the
- * EEPROM. Store these bits in a variable that we will later write
- * to the Device Control Register (CTRL).
- */
- eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG);
-
- ctrl_reg =
- (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) |
- ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT));
-
- /* Set the PCI priority bit correctly in the CTRL register. This
- * determines if the adapter gives priority to receives, or if it
- * gives equal priority to transmits and receives.
- */
- if(shared->dma_fairness)
- ctrl_reg |= E1000_CTRL_PRIOR;
-
- /* Read and store word 0x0F of the EEPROM. This word contains bits
- * that determine the hardware's default PAUSE (flow control) mode,
- * a bit that determines whether the HW defaults to enabling or
- * disabling auto-negotiation, and the direction of the
- * SW defined pins. If there is no SW over-ride of the flow
- * control setting, then the variable shared->fc will
- * be initialized based on a value in the EEPROM.
- */
- eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG);
-
- if(shared->fc > e1000_fc_full) {
- if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0)
- shared->fc = e1000_fc_none;
- else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
- shared->fc = e1000_fc_tx_pause;
- else
- shared->fc = e1000_fc_full;
- }
-
- /* We want to save off the original Flow Control configuration just
- * in case we get disconnected and then reconnected into a different
- * hub or switch with different Flow Control capabilities.
- */
- shared->original_fc = shared->fc;
-
- if(shared->mac_type == e1000_82542_rev2_0)
- shared->fc &= (~e1000_fc_tx_pause);
-
- if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1))
- shared->fc &= (~e1000_fc_rx_pause);
-
- DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc);
-
- /* Take the 4 bits from EEPROM word 0x0F that determine the initial
- * polarity value for the SW controlled pins, and setup the
- * Extended Device Control reg with that info.
- * This is needed because one of the SW controlled pins is used for
- * signal detection. So this should be done before e1000_setup_pcs_link()
- * or e1000_phy_setup() is called.
- */
- if(shared->mac_type == e1000_82543) {
- ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT)
- << SWDPIO__EXT_SHIFT);
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
- }
-
- /* Call the necessary subroutine to configure the link. */
- if(shared->media_type == e1000_media_type_fiber)
- status = e1000_setup_pcs_link(shared, ctrl_reg);
- else
- status = e1000_phy_setup(shared, ctrl_reg);
-
- /* Initialize the flow control address, type, and PAUSE timer
- * registers to their default values. This is done even if flow
- * control is disabled, because it does not hurt anything to
- * initialize these registers.
- */
- DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
-
- E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW);
- E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
- E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE);
- E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time);
-
- /* Set the flow control receive threshold registers. Normally,
- * these registers will be set to a default threshold that may be
- * adjusted later by the driver's runtime code. However, if the
- * ability to transmit pause frames in not enabled, then these
- * registers will be set to 0.
- */
- if(!(shared->fc & e1000_fc_tx_pause)) {
- E1000_WRITE_REG(shared, FCRTL, 0);
- E1000_WRITE_REG(shared, FCRTH, 0);
- } else {
- /* We need to set up the Receive Threshold high and low water marks
- * as well as (optionally) enabling the transmission of XON frames.
- */
- if(shared->fc_send_xon) {
- E1000_WRITE_REG(shared, FCRTL,
- (shared->fc_low_water | E1000_FCRTL_XONE));
- E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
- } else {
- E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water);
- E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
- }
- }
- return (status);
-}
-
-/******************************************************************************
- * Sets up link for a fiber based adapter
- *
- * shared - Struct containing variables accessed by shared code
- * ctrl_reg - Current value of the device control register
- *
- * Manipulates Physical Coding Sublayer functions in order to configure
- * link. Assumes the hardware has been previously reset and the transmitter
- * and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_pcs_link(struct e1000_shared_adapter *shared,
- uint32_t ctrl_reg)
-{
- uint32_t status_reg;
- uint32_t tctl_reg;
- uint32_t txcw_reg = 0;
- uint32_t i;
-
- DEBUGFUNC("e1000_setup_pcs_link");
-
- /* Setup the collsion distance. Since this is configuring the
- * TBI it is assumed that we are in Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- i = E1000_FDX_COLLISION_DISTANCE;
- i <<= E1000_COLD_SHIFT;
- tctl_reg |= i;
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Check for a software override of the flow control settings, and
- * setup the device accordingly. If auto-negotiation is enabled,
- * then software will have to set the "PAUSE" bits to the correct
- * value in the Tranmsit Config Word Register (TXCW) and re-start
- * auto-negotiation. However, if auto-negotiation is disabled,
- * then software will have to manually configure the two flow
- * control enable bits in the CTRL register.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames
- * but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * but we do not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
- * other: No software override. The flow control configuration
- * in the EEPROM is used.
- */
- switch (shared->fc) {
- case e1000_fc_none: /* 0 */
- /* Flow control (RX & TX) is completely disabled by a
- * software over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD);
- break;
- case e1000_fc_rx_pause: /* 1 */
- /* RX Flow control is enabled, and TX Flow control is
- * disabled, by a software over-ride.
- */
- /* Since there really isn't a way to advertise that we are
- * capable of RX Pause ONLY, we will advertise that we
- * support both symmetric and asymmetric RX PAUSE. Later
- * we will disable the adapter's ability to send PAUSE
- * frames.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- case e1000_fc_tx_pause: /* 2 */
- /* TX Flow control is enabled, and RX Flow control is
- * disabled, by a software over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
- break;
- case e1000_fc_full: /* 3 */
- /* Flow control (both RX and TX) is enabled by a software
- * over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- default:
- /* We should never get here. The value should be 0-3. */
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Since auto-negotiation is enabled, take the link out of reset.
- * (the link will be in reset, because we previously reset the
- * chip). This will restart auto-negotiation. If auto-neogtiation
- * is successful then the link-up status bit will be set and the
- * flow control enable bits (RFCE and TFCE) will be set according
- * to their negotiated value.
- */
- DEBUGOUT("Auto-negotiation enabled\n");
-
- E1000_WRITE_REG(shared, TXCW, txcw_reg);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- shared->txcw_reg = txcw_reg;
- msec_delay(1);
-
- /* If we have a signal then poll for a "Link-Up" indication in the
- * Device Status Register. Time-out if a link isn't seen in 500
- * milliseconds seconds (Auto-negotiation should complete in less
- * than 500 milliseconds even if the other end is doing it in SW).
- */
- if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) {
-
- DEBUGOUT("Looking for Link\n");
- for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
- msec_delay(10);
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_LU)
- break;
- }
-
- if(i == (LINK_UP_TIMEOUT / 10)) {
- /* AutoNeg failed to achieve a link, so we'll call the
- * "CheckForLink" routine. This routine will force the link
- * up if we have "signal-detect". This will allow us to
- * communicate with non-autonegotiating link partners.
- */
- DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-
- shared->autoneg_failed = 1;
- e1000_check_for_link(shared);
- shared->autoneg_failed = 0;
- } else {
- shared->autoneg_failed = 0;
- DEBUGOUT("Valid Link Found\n");
- }
- } else {
- DEBUGOUT("No Signal Detected\n");
- }
-
- return (TRUE);
-}
-
-/******************************************************************************
- * Configures flow control settings after link is established
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Should be called immediately after a valid link has been established.
- * Forces MAC flow control settings if link was forced. When in MII/GMII mode
- * and autonegotiation is enabled, the MAC flow control settings will be set
- * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
- * and RFCE bits will be automaticaly set to the negotiated flow control mode.
- *****************************************************************************/
-void
-e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared)
-{
- uint16_t mii_status_reg;
- uint16_t mii_nway_adv_reg;
- uint16_t mii_nway_lp_ability_reg;
- uint16_t speed;
- uint16_t duplex;
-
- DEBUGFUNC("e1000_config_fc_after_link_up");
-
- /* Check for the case where we have fiber media and auto-neg failed
- * so we had to force link. In this case, we need to force the
- * configuration of the MAC to match the "fc" parameter.
- */
- if(((shared->media_type == e1000_media_type_fiber)
- && (shared->autoneg_failed))
- || ((shared->media_type == e1000_media_type_copper)
- && (!shared->autoneg))) {
- e1000_force_mac_fc(shared);
- }
-
- /* Check for the case where we have copper media and auto-neg is
- * enabled. In this case, we need to check and see if Auto-Neg
- * has completed, and if so, how the PHY and link partner has
- * flow control configured.
- */
- if((shared->media_type == e1000_media_type_copper) && shared->autoneg) {
- /* Read the MII Status Register and check to see if AutoNeg
- * has completed. We read this twice because this reg has
- * some "sticky" (latched) bits.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
- /* The AutoNeg process has completed, so we now need to
- * read both the Auto Negotiation Advertisement Register
- * (Address 4) and the Auto_Negotiation Base Page Ability
- * Register (Address 5) to determine how flow control was
- * negotiated.
- */
- mii_nway_adv_reg = e1000_read_phy_reg(shared,
- PHY_AUTONEG_ADV);
- mii_nway_lp_ability_reg = e1000_read_phy_reg(shared,
- PHY_LP_ABILITY);
-
- /* Two bits in the Auto Negotiation Advertisement Register
- * (Address 4) and two bits in the Auto Negotiation Base
- * Page Ability Register (Address 5) determine flow control
- * for both the PHY and the link partner. The following
- * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
- * 1999, describes these PAUSE resolution bits and how flow
- * control is determined based upon these settings.
- * NOTE: DC = Don't Care
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
- *-------|---------|-------|---------|--------------------
- * 0 | 0 | DC | DC | e1000_fc_none
- * 0 | 1 | 0 | DC | e1000_fc_none
- * 0 | 1 | 1 | 0 | e1000_fc_none
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
- * 1 | 0 | 0 | DC | e1000_fc_none
- * 1 | DC | 1 | DC | e1000_fc_full
- * 1 | 1 | 0 | 0 | e1000_fc_none
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
- *
- */
- /* Are both PAUSE bits set to 1? If so, this implies
- * Symmetric Flow Control is enabled at both ends. The
- * ASM_DIR bits are irrelevant per the spec.
- *
- * For Symmetric Flow Control:
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | DC | 1 | DC | e1000_fc_full
- *
- */
- if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
- /* Now we need to check if the user selected RX ONLY
- * of pause frames. In this case, we had to advertise
- * FULL flow control because we could not advertise RX
- * ONLY. Hence, we must now check to see if we need to
- * turn OFF the TRANSMISSION of PAUSE frames.
- */
- if(shared->original_fc == e1000_fc_full) {
- shared->fc = e1000_fc_full;
- DEBUGOUT("Flow Control = FULL.\r\n");
- } else {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
- }
- /* For receiving PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
- *
- */
- else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- shared->fc = e1000_fc_tx_pause;
- DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
- }
- /* For transmitting PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
- *
- */
- else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
- /* Per the IEEE spec, at this point flow control should be
- * disabled. However, we want to consider that we could
- * be connected to a legacy switch that doesn't advertise
- * desired flow control, but can be forced on the link
- * partner. So if we advertised no flow control, that is
- * what we will resolve to. If we advertised some kind of
- * receive capability (Rx Pause Only or Full Flow Control)
- * and the link partner advertised none, we will configure
- * ourselves to enable Rx Flow Control only. We can do
- * this safely for two reasons: If the link partner really
- * didn't want flow control enabled, and we enable Rx, no
- * harm done since we won't be receiving any PAUSE frames
- * anyway. If the intent on the link partner was to have
- * flow control enabled, then by us enabling RX only, we
- * can at least receive pause frames and process them.
- * This is a good idea because in most cases, since we are
- * predominantly a server NIC, more times than not we will
- * be asked to delay transmission of packets than asking
- * our link partner to pause transmission of frames.
- */
- else if(shared->original_fc == e1000_fc_none ||
- shared->original_fc == e1000_fc_tx_pause) {
- shared->fc = e1000_fc_none;
- DEBUGOUT("Flow Control = NONE.\r\n");
- } else {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
-
- /* Now we need to do one last check... If we auto-
- * negotiated to HALF DUPLEX, flow control should not be
- * enabled per IEEE 802.3 spec.
- */
- e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
- if(duplex == HALF_DUPLEX)
- shared->fc = e1000_fc_none;
-
- /* Now we call a subroutine to actually force the MAC
- * controller to use the correct flow control settings.
- */
- e1000_force_mac_fc(shared);
- } else {
- DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
- }
- }
- return;
-}
-
-/******************************************************************************
- * Checks to see if the link status of the hardware has changed.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Called by any function that needs to check the link status of the adapter.
- *****************************************************************************/
-void
-e1000_check_for_link(struct e1000_shared_adapter *shared)
-{
- uint32_t rxcw_reg;
- uint32_t ctrl_reg;
- uint32_t status_reg;
- uint32_t rctl_reg;
- uint16_t phy_data;
- uint16_t lp_capability;
-
- DEBUGFUNC("e1000_check_for_link");
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- status_reg = E1000_READ_REG(shared, STATUS);
- rxcw_reg = E1000_READ_REG(shared, RXCW);
-
- /* If we have a copper PHY then we only want to go out to the PHY
- * registers to see if Auto-Neg has completed and/or if our link
- * status has changed. The get_link_status flag will be set if we
- * receive a Link Status Change interrupt or we have Rx Sequence
- * Errors.
- */
- if(shared->media_type == e1000_media_type_copper
- && shared->get_link_status) {
- /* First we want to see if the MII Status Register reports
- * link. If so, then we want to get the current speed/duplex
- * of the PHY.
- * Read the register twice since the link bit is sticky.
- */
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(phy_data & MII_SR_LINK_STATUS) {
- shared->get_link_status = FALSE;
- } else {
- DEBUGOUT("**** CFL - No link detected. ****\r\n");
- return;
- }
-
- /* If we are forcing speed/duplex, then we simply return since
- * we have already determined whether we have link or not.
- */
- if(!shared->autoneg) {
- return;
- }
-
- switch (shared->phy_id) {
- case M88E1000_12_PHY_ID:
- case M88E1000_14_PHY_ID:
- case M88E1000_I_PHY_ID:
- /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
- * have Si on board that is 82544 or newer, Auto
- * Speed Detection takes care of MAC speed/duplex
- * configuration. So we only need to configure Collision
- * Distance in the MAC. Otherwise, we need to force
- * speed/duplex on the MAC to the current PHY speed/duplex
- * settings.
- */
- if(shared->mac_type >= e1000_82544) {
- DEBUGOUT("CFL - Auto-Neg complete.");
- DEBUGOUT("Configuring Collision Distance.");
- e1000_config_collision_dist(shared);
- } else {
- /* Read the Phy Specific Status register to get the
- * resolved speed/duplex settings. Then call
- * e1000_config_mac_to_phy which will retrieve
- * PHY register information and configure the MAC to
- * equal the negotiated speed/duplex.
- */
- phy_data = e1000_read_phy_reg(shared,
- M88E1000_PHY_SPEC_STATUS);
-
- DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n",
- phy_data);
- e1000_config_mac_to_phy(shared, phy_data);
- }
-
- /* Configure Flow Control now that Auto-Neg has completed.
- * We need to first restore the users desired Flow
- * Control setting since we may have had to re-autoneg
- * with a different link partner.
- */
- e1000_config_fc_after_link_up(shared);
- break;
-
- default:
- DEBUGOUT("CFL - Invalid PHY detected.\r\n");
-
- } /* end switch statement */
-
- /* At this point we know that we are on copper, link is up,
- * and we are auto-neg'd. These are pre-conditions for checking
- * the link parter capabilities register. We use the link partner
- * capabilities to determine if TBI Compatibility needs to be turned on
- * or turned off. If the link partner advertises any speed in addition
- * to Gigabit, then we assume that they are GMII-based and TBI
- * compatibility is not needed.
- * If no other speeds are advertised, then we assume the link partner
- * is TBI-based and we turn on TBI Compatibility.
- */
- if(shared->tbi_compatibility_en) {
- lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY);
- if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
- NWAY_LPAR_10T_FD_CAPS |
- NWAY_LPAR_100TX_HD_CAPS |
- NWAY_LPAR_100TX_FD_CAPS |
- NWAY_LPAR_100T4_CAPS)) {
- /* If our link partner advertises below Gig, then they do not
- * need the special Tbi Compatibility mode.
- */
- if(shared->tbi_compatibility_on) {
- /* If we previously were in the mode, turn it off, now. */
- rctl_reg = E1000_READ_REG(shared, RCTL);
- rctl_reg &= ~E1000_RCTL_SBP;
- E1000_WRITE_REG(shared, RCTL, rctl_reg);
- shared->tbi_compatibility_on = FALSE;
- }
- } else {
- /* If the mode is was previously off, turn it on.
- * For compatibility with a suspected Tbi link partners,
- * we will store bad packets.
- * (Certain frames have an additional byte on the end and will
- * look like CRC errors to to the hardware).
- */
- if(!shared->tbi_compatibility_on) {
- shared->tbi_compatibility_on = TRUE;
- rctl_reg = E1000_READ_REG(shared, RCTL);
- rctl_reg |= E1000_RCTL_SBP;
- E1000_WRITE_REG(shared, RCTL, rctl_reg);
- }
- }
- }
- } /* end if e1000_media_type_copper statement */
- /* If we don't have link (auto-negotiation failed or link partner
- * cannot auto-negotiate) and the cable is plugged in since we don't
- * have Loss-Of-Signal (we HAVE a signal) and our link partner is
- * not trying to AutoNeg with us (we are receiving idles/data
- * then we need to force our link to connect to a non
- * auto-negotiating link partner. We also need to give
- * auto-negotiation time to complete in case the cable was just
- * plugged in. The autoneg_failed flag does this.
- */
- else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */
- (!(status_reg & E1000_STATUS_LU)) && /* no link and */
- (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */
- (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */
- if(shared->autoneg_failed == 0) { /* given AutoNeg time */
- shared->autoneg_failed = 1;
- return;
- }
-
- DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
-
- /* Disable auto-negotiation in the TXCW register */
- E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE));
-
- /* Force link-up and also force full-duplex. */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Configure Flow Control after forcing link up. */
- e1000_config_fc_after_link_up(shared);
-
- } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */
- (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */
- (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */
- /* If we are forcing link and we are receiving /C/ ordered sets,
- * then re-enable auto-negotiation in the RXCW register and
- * disable forced link in the Device Control register in an attempt
- * to AutoNeg with our link partner.
- */
- DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
-
- /* Enable auto-negotiation in the TXCW register and stop
- * forcing link.
- */
- E1000_WRITE_REG(shared, TXCW, shared->txcw_reg);
-
- E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU));
- }
-
- return;
-}
-
-/******************************************************************************
- * Clears all hardware statistics counters.
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared)
-{
- volatile uint32_t temp_reg;
-
- DEBUGFUNC("e1000_clear_hw_cntrs");
-
- /* if we are stopped or resetting exit gracefully */
- if(shared->adapter_stopped) {
- DEBUGOUT("Exiting because the adapter is stopped!!!\n");
- return;
- }
-
- temp_reg = E1000_READ_REG(shared, CRCERRS);
- temp_reg = E1000_READ_REG(shared, SYMERRS);
- temp_reg = E1000_READ_REG(shared, MPC);
- temp_reg = E1000_READ_REG(shared, SCC);
- temp_reg = E1000_READ_REG(shared, ECOL);
- temp_reg = E1000_READ_REG(shared, MCC);
- temp_reg = E1000_READ_REG(shared, LATECOL);
- temp_reg = E1000_READ_REG(shared, COLC);
- temp_reg = E1000_READ_REG(shared, DC);
- temp_reg = E1000_READ_REG(shared, SEC);
- temp_reg = E1000_READ_REG(shared, RLEC);
- temp_reg = E1000_READ_REG(shared, XONRXC);
- temp_reg = E1000_READ_REG(shared, XONTXC);
- temp_reg = E1000_READ_REG(shared, XOFFRXC);
- temp_reg = E1000_READ_REG(shared, XOFFTXC);
- temp_reg = E1000_READ_REG(shared, FCRUC);
- temp_reg = E1000_READ_REG(shared, PRC64);
- temp_reg = E1000_READ_REG(shared, PRC127);
- temp_reg = E1000_READ_REG(shared, PRC255);
- temp_reg = E1000_READ_REG(shared, PRC511);
- temp_reg = E1000_READ_REG(shared, PRC1023);
- temp_reg = E1000_READ_REG(shared, PRC1522);
- temp_reg = E1000_READ_REG(shared, GPRC);
- temp_reg = E1000_READ_REG(shared, BPRC);
- temp_reg = E1000_READ_REG(shared, MPRC);
- temp_reg = E1000_READ_REG(shared, GPTC);
- temp_reg = E1000_READ_REG(shared, GORCL);
- temp_reg = E1000_READ_REG(shared, GORCH);
- temp_reg = E1000_READ_REG(shared, GOTCL);
- temp_reg = E1000_READ_REG(shared, GOTCH);
- temp_reg = E1000_READ_REG(shared, RNBC);
- temp_reg = E1000_READ_REG(shared, RUC);
- temp_reg = E1000_READ_REG(shared, RFC);
- temp_reg = E1000_READ_REG(shared, ROC);
- temp_reg = E1000_READ_REG(shared, RJC);
- temp_reg = E1000_READ_REG(shared, TORL);
- temp_reg = E1000_READ_REG(shared, TORH);
- temp_reg = E1000_READ_REG(shared, TOTL);
- temp_reg = E1000_READ_REG(shared, TOTH);
- temp_reg = E1000_READ_REG(shared, TPR);
- temp_reg = E1000_READ_REG(shared, TPT);
- temp_reg = E1000_READ_REG(shared, PTC64);
- temp_reg = E1000_READ_REG(shared, PTC127);
- temp_reg = E1000_READ_REG(shared, PTC255);
- temp_reg = E1000_READ_REG(shared, PTC511);
- temp_reg = E1000_READ_REG(shared, PTC1023);
- temp_reg = E1000_READ_REG(shared, PTC1522);
- temp_reg = E1000_READ_REG(shared, MPTC);
- temp_reg = E1000_READ_REG(shared, BPTC);
-
- if(shared->mac_type < e1000_82543)
- return;
-
- temp_reg = E1000_READ_REG(shared, ALGNERRC);
- temp_reg = E1000_READ_REG(shared, RXERRC);
- temp_reg = E1000_READ_REG(shared, TNCRS);
- temp_reg = E1000_READ_REG(shared, CEXTERR);
- temp_reg = E1000_READ_REG(shared, TSCTC);
- temp_reg = E1000_READ_REG(shared, TSCTFC);
- return;
-}
-
-/******************************************************************************
- * Detects the current speed and duplex settings of the hardware.
- *
- * shared - Struct containing variables accessed by shared code
- * speed - Speed of the connection
- * duplex - Duplex setting of the connection
- *****************************************************************************/
-void
-e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared,
- uint16_t *speed,
- uint16_t *duplex)
-{
- uint32_t status_reg;
-#if DBG
- uint16_t phy_data;
-#endif
-
- DEBUGFUNC("e1000_get_speed_and_duplex");
-
- /* If the adapter is stopped we don't have a speed or duplex */
- if(shared->adapter_stopped) {
- *speed = 0;
- *duplex = 0;
- return;
- }
-
- if(shared->mac_type >= e1000_82543) {
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_SPEED_1000) {
- *speed = SPEED_1000;
- DEBUGOUT("1000 Mbs, ");
- } else if(status_reg & E1000_STATUS_SPEED_100) {
- *speed = SPEED_100;
- DEBUGOUT("100 Mbs, ");
- } else {
- *speed = SPEED_10;
- DEBUGOUT("10 Mbs, ");
- }
-
- if(status_reg & E1000_STATUS_FD) {
- *duplex = FULL_DUPLEX;
- DEBUGOUT("Full Duplex\r\n");
- } else {
- *duplex = HALF_DUPLEX;
- DEBUGOUT(" Half Duplex\r\n");
- }
- } else {
- DEBUGOUT("1000 Mbs, Full Duplex\r\n");
- *speed = SPEED_1000;
- *duplex = FULL_DUPLEX;
- }
-
-#if DBG
- if(shared->phy_id == M88E1000_12_PHY_ID ||
- shared->phy_id == M88E1000_14_PHY_ID ||
- shared->phy_id == M88E1000_I_PHY_ID) {
- /* read the phy specific status register */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data);
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
- DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data);
- DEBUGOUT1("Device Status Reg contents = %x\n",
- E1000_READ_REG(shared, STATUS));
- }
-#endif
- return;
-}
-
-/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - offset of 16 bit word in the EEPROM to read
- *****************************************************************************/
-uint16_t
-e1000_read_eeprom(struct e1000_shared_adapter *shared,
- uint16_t offset)
-{
- uint16_t data;
-
- /* Prepare the EEPROM for reading */
- e1000_setup_eeprom(shared);
-
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3);
- e1000_shift_out_bits(shared, offset, 6);
-
- /* Read the data */
- data = e1000_shift_in_bits(shared);
-
- /* End this read operation */
- e1000_standby_eeprom(shared);
-
- return (data);
-}
-
-/******************************************************************************
- * Verifies that the EEPROM has a valid checksum
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
- * valid.
- *****************************************************************************/
-boolean_t
-e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared)
-{
- uint16_t checksum = 0;
- uint16_t i;
-
- for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++)
- checksum += e1000_read_eeprom(shared, i);
-
- if(checksum == (uint16_t) EEPROM_SUM)
- return (TRUE);
- else
- return (FALSE);
-}
-/******************************************************************************
- * Reads the adapter's part number from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- * part_num - Adapter's part number
- *****************************************************************************/
-boolean_t
-e1000_read_part_num(struct e1000_shared_adapter *shared,
- uint32_t *part_num)
-{
- uint16_t eeprom_word;
-
- DEBUGFUNC("e1000_read_part_num");
-
- /* Don't read the EEPROM if we are stopped */
- if(shared->adapter_stopped) {
- *part_num = 0;
- return (FALSE);
- }
-
- /* Get word 0 from EEPROM */
- eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1));
-
- DEBUGOUT("Read first part number word\n");
-
- /* Save word 0 in upper half is PartNumber */
- *part_num = (uint32_t) eeprom_word;
- *part_num = *part_num << 16;
-
- /* Get word 1 from EEPROM */
- eeprom_word =
- e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1));
-
- DEBUGOUT("Read second part number word\n");
-
- /* Save word 1 in lower half of PartNumber */
- *part_num |= eeprom_word;
-
- /* read a valid part number */
- return (TRUE);
-}
-
-void
-e1000_read_mac_addr(struct e1000_shared_adapter * shared)
-{
- uint16_t temp, x;
-
- for(x = 0; x < NODE_ADDRESS_SIZE; x += 2) {
- temp = e1000_read_eeprom(shared, (uint16_t)
- (EEPROM_NODE_ADDRESS_BYTE_0 + (x/2)));
- shared->perm_mac_addr[x] = (uint8_t) (temp & 0x00FF);
- shared->perm_mac_addr[x+1] = (uint8_t) (temp >> 8);
- }
-
- for(x = 0; x < NODE_ADDRESS_SIZE; x++)
- shared->mac_addr[x] = shared->perm_mac_addr[x];
-}
-
-/******************************************************************************
- * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- *
- * shared - Struct containing variables accessed by shared code
- * frame_len - The length of the frame in question
- * mac_addr - The Ethernet destination address of the frame in question
- *****************************************************************************/
-uint32_t
-e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared,
- struct e1000_shared_stats *stats,
- uint32_t frame_len,
- uint8_t *mac_addr)
-{
- uint64_t carry_bit;
-
- /* First adjust the frame length. */
- frame_len--;
- /* We need to adjust the statistics counters, since the hardware
- * counters overcount this packet as a CRC error and undercount
- * the packet as a good packet
- */
- /* This packet should not be counted as a CRC error. */
- stats->crcerrs--;
- /* This packet does count as a Good Packet Received. */
- stats->gprc++;
-
- /* Adjust the Good Octets received counters */
- carry_bit = 0x80000000 & stats->gorcl;
- stats->gorcl += frame_len;
- /* If the high bit of Gorcl (the low 32 bits of the Good Octets
- * Received Count) was one before the addition,
- * AND it is zero after, then we lost the carry out,
- * need to add one to Gorch (Good Octets Received Count High).
- * This could be simplified if all environments supported
- * 64-bit integers.
- */
- if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
- stats->gorch++;
- /* Is this a broadcast or multicast? Check broadcast first,
- * since the test for a multicast frame will test positive on
- * a broadcast frame.
- */
- if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
- /* Broadcast packet */
- stats->bprc++;
- else if(*mac_addr & 0x01)
- /* Multicast packet */
- stats->mprc++;
-
- if(frame_len == shared->max_frame_size) {
- /* In this case, the hardware has overcounted the number of
- * oversize frames.
- */
- if(stats->roc > 0)
- stats->roc--;
- }
-
- /* Adjust the bin counters when the extra byte put the frame in the
- * wrong bin. Remember that the frame_len was adjusted above.
- */
- if(frame_len == 64) {
- stats->prc64++;
- stats->prc127--;
- } else if(frame_len == 127) {
- stats->prc127++;
- stats->prc255--;
- } else if(frame_len == 255) {
- stats->prc255++;
- stats->prc511--;
- } else if(frame_len == 511) {
- stats->prc511++;
- stats->prc1023--;
- } else if(frame_len == 1023) {
- stats->prc1023++;
- stats->prc1522--;
- } else if(frame_len == 1522) {
- stats->prc1522++;
- }
- return frame_len;
-}
-
-/******************************************************************************
- * Gets the current PCI bus type, speed, and width of the hardware
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_get_bus_info(struct e1000_shared_adapter *shared)
-{
- uint32_t status_reg;
-
- if(shared->mac_type < e1000_82543) {
- shared->bus_type = e1000_bus_type_unknown;
- shared->bus_speed = e1000_bus_speed_unknown;
- shared->bus_width = e1000_bus_width_unknown;
- return;
- }
-
- status_reg = E1000_READ_REG(shared, STATUS);
-
- shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ?
- e1000_bus_type_pcix : e1000_bus_type_pci;
-
- if(shared->bus_type == e1000_bus_type_pci) {
- shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ?
- e1000_bus_speed_66 : e1000_bus_speed_33;
- } else {
- switch (status_reg & E1000_STATUS_PCIX_SPEED) {
- case E1000_STATUS_PCIX_SPEED_66:
- shared->bus_speed = e1000_bus_speed_66;
- break;
- case E1000_STATUS_PCIX_SPEED_100:
- shared->bus_speed = e1000_bus_speed_100;
- break;
- case E1000_STATUS_PCIX_SPEED_133:
- shared->bus_speed = e1000_bus_speed_133;
- break;
- default:
- shared->bus_speed = e1000_bus_speed_reserved;
- break;
- }
- }
-
- shared->bus_width = (status_reg & E1000_STATUS_BUS64) ?
- e1000_bus_width_64 : e1000_bus_width_32;
-
- return;
-}
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 1192f7cf424a..cede9df83e7d 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -76,11 +75,8 @@
#include "e1000.h"
char e1000_driver_name[] = "e1000";
-
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-
-char e1000_driver_version[] = "4.2.4-k2";
-
+char e1000_driver_version[] = "4.2.8";
char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
@@ -100,6 +96,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
{0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
{0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
+ {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
/* Compaq Gigabit Ethernet Server Adapter */
{0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
{0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
@@ -116,6 +113,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
{0,}
};
@@ -132,6 +130,8 @@ static char *e1000_strings[] = {
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+
static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -164,13 +164,17 @@ static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
-static void e1000_reset(struct e1000_adapter *adapter);
static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
struct e1000_rx_desc *rx_desc,
struct sk_buff *skb);
void e1000_enable_WOL(struct e1000_adapter *adapter);
+#ifdef NETIF_F_HW_VLAN_TX
+static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+#endif
/* Exported from other modules */
@@ -192,6 +196,7 @@ static struct pci_driver e1000_driver = {
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
/**
* e1000_init_module - Driver Registration Routine
@@ -224,8 +229,6 @@ static void __exit
e1000_exit_module(void)
{
pci_unregister_driver(&e1000_driver);
-
- return;
}
module_exit(e1000_exit_module);
@@ -249,8 +252,6 @@ e1000_up(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
- e1000_clear_hw_cntrs(&adapter->shared);
-
mod_timer(&adapter->watchdog_timer, jiffies);
e1000_irq_enable(adapter);
@@ -260,74 +261,41 @@ e1000_up(struct e1000_adapter *adapter)
void
e1000_down(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
struct net_device *netdev = adapter->netdev;
e1000_irq_disable(adapter);
free_irq(netdev->irq, netdev);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- /* disable the transmit and receive units */
-
- E1000_WRITE_REG(shared, RCTL, 0);
- E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
- /* delay to allow PCI transactions to complete */
-
- msec_delay(10);
-
+ e1000_reset(adapter);
e1000_clean_tx_ring(adapter);
e1000_clean_rx_ring(adapter);
-
- e1000_reset(adapter);
}
-static void
+void
e1000_reset(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
- uint32_t ctrl_ext;
-
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
*/
if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
- E1000_WRITE_REG(shared, PBA, E1000_JUMBO_PBA);
+ E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
else
- E1000_WRITE_REG(shared, PBA, E1000_DEFAULT_PBA);
-
- /* 82542 2.0 needs MWI disabled while issuing a reset */
-
- if(shared->mac_type == e1000_82542_rev2_0)
- e1000_enter_82542_rst(adapter);
-
- /* global reset */
-
- E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST);
- msec_delay(10);
-
- /* EEPROM reload */
-
- ctrl_ext = E1000_READ_REG(shared, CTRL_EXT);
- ctrl_ext |= E1000_CTRL_EXT_EE_RST;
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext);
- msec_delay(5);
-
- if(shared->mac_type == e1000_82542_rev2_0)
- e1000_leave_82542_rst(adapter);
+ E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
- shared->tbi_compatibility_on = FALSE;
- shared->fc = shared->original_fc;
-
- e1000_init_hw(shared);
+ adapter->hw.fc = adapter->hw.original_fc;
+ e1000_reset_hw(&adapter->hw);
+ e1000_init_hw(&adapter->hw);
+ e1000_reset_adaptive(&adapter->hw);
+ e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
e1000_enable_WOL(adapter);
-
- return;
}
/**
@@ -382,13 +350,13 @@ e1000_probe(struct pci_dev *pdev,
adapter = netdev->priv;
adapter->netdev = netdev;
adapter->pdev = pdev;
- adapter->shared.back = adapter;
+ adapter->hw.back = adapter;
mmio_start = pci_resource_start(pdev, BAR_0);
mmio_len = pci_resource_len(pdev, BAR_0);
- adapter->shared.hw_addr = ioremap(mmio_start, mmio_len);
- if(!adapter->shared.hw_addr)
+ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+ if(!adapter->hw.hw_addr)
goto err_ioremap;
netdev->open = &e1000_open;
@@ -401,6 +369,11 @@ e1000_probe(struct pci_dev *pdev,
netdev->do_ioctl = &e1000_ioctl;
netdev->tx_timeout = &e1000_tx_timeout;
netdev->watchdog_timeo = HZ;
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->vlan_rx_register = e1000_vlan_rx_register;
+ netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#endif
netdev->irq = pdev->irq;
netdev->base_addr = mmio_start;
@@ -412,8 +385,16 @@ e1000_probe(struct pci_dev *pdev,
e1000_sw_init(adapter);
- if(adapter->shared.mac_type >= e1000_82543) {
+ if(adapter->hw.mac_type >= e1000_82543) {
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+#else
netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
} else {
netdev->features = NETIF_F_SG;
}
@@ -423,19 +404,28 @@ e1000_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
- if(!e1000_validate_eeprom_checksum(&adapter->shared))
+ if(e1000_validate_eeprom_checksum(&adapter->hw) < 0)
goto err_eeprom;
/* copy the MAC address out of the EEPROM */
- e1000_read_mac_addr(&adapter->shared);
- memcpy(netdev->dev_addr, adapter->shared.mac_addr, netdev->addr_len);
+ e1000_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
if(!is_valid_ether_addr(netdev->dev_addr))
goto err_eeprom;
- e1000_read_part_num(&adapter->shared, &(adapter->part_num));
- e1000_get_bus_info(&adapter->shared);
+ e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+
+ e1000_get_bus_info(&adapter->hw);
+
+ if((adapter->hw.mac_type == e1000_82544) &&
+ (adapter->hw.bus_type == e1000_bus_type_pcix))
+
+ adapter->max_data_per_txd = 4096;
+ else
+ adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
+
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &e1000_watchdog;
@@ -464,7 +454,7 @@ e1000_probe(struct pci_dev *pdev,
return 0;
err_eeprom:
- iounmap(adapter->shared.hw_addr);
+ iounmap(adapter->hw.hw_addr);
err_ioremap:
pci_release_regions(pdev);
kfree(netdev);
@@ -480,10 +470,6 @@ err_alloc_etherdev:
* that it should release a PCI device. The could be caused by a
* Hot-Plug event, or because the driver is going to be removed from
* memory.
- *
- * This routine is also called to clean up from a failure in
- * e1000_probe. The Adapter struct and netdev will always exist,
- * all other pointers must be checked for NULL before freeing.
**/
static void __devexit
@@ -494,15 +480,14 @@ e1000_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- e1000_phy_hw_reset(&adapter->shared);
+ e1000_phy_hw_reset(&adapter->hw);
e1000_proc_dev_free(adapter);
- iounmap(adapter->shared.hw_addr);
+ iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
kfree(netdev);
- return;
}
/**
@@ -517,17 +502,17 @@ e1000_remove(struct pci_dev *pdev)
static void __devinit
e1000_sw_init(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
/* PCI config space info */
- uint16_t *vendor = &shared->vendor_id;
- uint16_t *device = &shared->device_id;
- uint16_t *subvendor = &shared->subsystem_vendor_id;
- uint16_t *subsystem = &shared->subsystem_id;
- uint8_t *revision = &shared->revision_id;
+ uint16_t *vendor = &hw->vendor_id;
+ uint16_t *device = &hw->device_id;
+ uint16_t *subvendor = &hw->subsystem_vendor_id;
+ uint16_t *subsystem = &hw->subsystem_id;
+ uint8_t *revision = &hw->revision_id;
pci_read_config_word(pdev, PCI_VENDOR_ID, vendor);
pci_read_config_word(pdev, PCI_DEVICE_ID, device);
@@ -535,11 +520,12 @@ e1000_sw_init(struct e1000_adapter *adapter)
pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, subvendor);
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, subsystem);
- pci_read_config_word(pdev, PCI_COMMAND, &shared->pci_cmd_word);
+ pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- shared->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH;
- shared->min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH;
+ hw->max_frame_size = netdev->mtu +
+ ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
/* identify the MAC */
@@ -547,25 +533,28 @@ e1000_sw_init(struct e1000_adapter *adapter)
case E1000_DEV_ID_82542:
switch (*revision) {
case E1000_82542_2_0_REV_ID:
- shared->mac_type = e1000_82542_rev2_0;
+ hw->mac_type = e1000_82542_rev2_0;
break;
case E1000_82542_2_1_REV_ID:
- shared->mac_type = e1000_82542_rev2_1;
+ hw->mac_type = e1000_82542_rev2_1;
break;
default:
- shared->mac_type = e1000_82542_rev2_0;
+ hw->mac_type = e1000_82542_rev2_0;
E1000_ERR("Could not identify 82542 revision\n");
}
break;
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82543GC_COPPER:
- shared->mac_type = e1000_82543;
+ hw->mac_type = e1000_82543;
break;
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544EI_FIBER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
- shared->mac_type = e1000_82544;
+ hw->mac_type = e1000_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ hw->mac_type = e1000_82540;
break;
default:
/* should never have loaded on this device */
@@ -574,33 +563,35 @@ e1000_sw_init(struct e1000_adapter *adapter)
/* flow control settings */
- shared->fc_high_water = FC_DEFAULT_HI_THRESH;
- shared->fc_low_water = FC_DEFAULT_LO_THRESH;
- shared->fc_pause_time = FC_DEFAULT_TX_TIMER;
- shared->fc_send_xon = 1;
+ hw->fc_high_water = FC_DEFAULT_HI_THRESH;
+ hw->fc_low_water = FC_DEFAULT_LO_THRESH;
+ hw->fc_pause_time = FC_DEFAULT_TX_TIMER;
+ hw->fc_send_xon = 1;
/* Media type - copper or fiber */
- if(shared->mac_type >= e1000_82543) {
- uint32_t status = E1000_READ_REG(shared, STATUS);
+ if(hw->mac_type >= e1000_82543) {
+ uint32_t status = E1000_READ_REG(hw, STATUS);
if(status & E1000_STATUS_TBIMODE)
- shared->media_type = e1000_media_type_fiber;
+ hw->media_type = e1000_media_type_fiber;
else
- shared->media_type = e1000_media_type_copper;
+ hw->media_type = e1000_media_type_copper;
} else {
- shared->media_type = e1000_media_type_fiber;
+ hw->media_type = e1000_media_type_fiber;
}
- if(shared->mac_type < e1000_82543)
- shared->report_tx_early = 0;
+ if(hw->mac_type < e1000_82543)
+ hw->report_tx_early = 0;
else
- shared->report_tx_early = 1;
+ hw->report_tx_early = 1;
- shared->wait_autoneg_complete = FALSE;
- shared->tbi_compatibility_en = TRUE;
+ hw->wait_autoneg_complete = FALSE;
+ hw->tbi_compatibility_en = TRUE;
+ hw->adaptive_ifs = TRUE;
atomic_set(&adapter->irq_sem, 1);
+ spin_lock_init(&adapter->tx_lock);
spin_lock_init(&adapter->stats_lock);
}
@@ -677,9 +668,6 @@ e1000_close(struct net_device *netdev)
* @adapter: board private structure
*
* Return 0 on success, negative on failure
- *
- * e1000_setup_tx_resources allocates all software transmit resources
- * and enabled the Tx unit of the MAC.
**/
static int
@@ -708,7 +696,6 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter)
}
memset(txdr->desc, 0, txdr->size);
- atomic_set(&txdr->unused, txdr->count);
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
@@ -729,19 +716,19 @@ e1000_configure_tx(struct e1000_adapter *adapter)
uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
uint32_t tctl, tipg;
- E1000_WRITE_REG(&adapter->shared, TDBAL, (tdba & 0x00000000FFFFFFFF));
- E1000_WRITE_REG(&adapter->shared, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
- E1000_WRITE_REG(&adapter->shared, TDLEN, tdlen);
+ E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
/* Setup the HW Tx Head and Tail descriptor pointers */
- E1000_WRITE_REG(&adapter->shared, TDH, 0);
- E1000_WRITE_REG(&adapter->shared, TDT, 0);
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
/* Set the default values for the Tx Inter Packet Gap timer */
- switch (adapter->shared.mac_type) {
+ switch (adapter->hw.mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
tipg = DEFAULT_82542_TIPG_IPGT;
@@ -749,53 +736,45 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
break;
default:
- if(adapter->shared.media_type == e1000_media_type_fiber)
+ if(adapter->hw.media_type == e1000_media_type_fiber)
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
else
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
}
- E1000_WRITE_REG(&adapter->shared, TIPG, tipg);
+ E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
/* Set the Tx Interrupt Delay register */
- E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay);
+ E1000_WRITE_REG(&adapter->hw, TIDV, 64);
/* Program the Transmit Control Register */
- tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
+ tctl = E1000_READ_REG(&adapter->hw, TCTL);
+
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- if(adapter->link_duplex == FULL_DUPLEX) {
- tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
- } else {
- tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
- }
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
- E1000_WRITE_REG(&adapter->shared, TCTL, tctl);
+ e1000_config_collision_dist(&adapter->hw);
/* Setup Transmit Descriptor Settings for this adapter */
- adapter->txd_cmd = E1000_TXD_CMD_IFCS;
+ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
- if(adapter->tx_int_delay > 0)
- adapter->txd_cmd |= E1000_TXD_CMD_IDE;
- if(adapter->shared.report_tx_early == 1)
+ if(adapter->hw.report_tx_early == 1)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
else
adapter->txd_cmd |= E1000_TXD_CMD_RPS;
-
- return;
}
/**
- * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs)
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
* @adapter: board private structure
*
* Returns 0 on success, negative on failure
- *
- * e1000_setup_rx_resources allocates all software receive resources
- * and network buffers, and enables the Rx unit of the MAC.
**/
static int
@@ -826,7 +805,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter)
memset(rxdr->desc, 0, rxdr->size);
rxdr->next_to_clean = 0;
- rxdr->unused_count = rxdr->count;
rxdr->next_to_use = 0;
return 0;
@@ -842,18 +820,25 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
{
uint32_t rctl;
- /* Setup the Receive Control Register */
- rctl = E1000_RCTL_EN | E1000_RCTL_BAM |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
- (adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
- if(adapter->shared.tbi_compatibility_on == 1)
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+ if(adapter->hw.tbi_compatibility_on == 1)
rctl |= E1000_RCTL_SBP;
+ else
+ rctl &= ~E1000_RCTL_SBP;
+ rctl &= ~(E1000_RCTL_SZ_4096);
switch (adapter->rx_buffer_len) {
case E1000_RXBUFFER_2048:
default:
rctl |= E1000_RCTL_SZ_2048;
+ rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
break;
case E1000_RXBUFFER_4096:
rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
@@ -866,7 +851,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
break;
}
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
}
/**
@@ -886,38 +871,47 @@ e1000_configure_rx(struct e1000_adapter *adapter)
/* make sure receives are disabled while setting up the descriptors */
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
/* set the Receive Delay Timer Register */
- E1000_WRITE_REG(&adapter->shared, RDTR,
- adapter->rx_int_delay | E1000_RDT_FPDB);
+ if(adapter->hw.mac_type == e1000_82540) {
+ E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay);
+ E1000_WRITE_REG(&adapter->hw, RDTR, 64);
+
+ /* Set the interrupt throttling rate. Value is calculated
+ * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+ E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+
+ } else {
+ E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+ }
/* Setup the Base and Length of the Rx Descriptor Ring */
- E1000_WRITE_REG(&adapter->shared, RDBAL, (rdba & 0x00000000FFFFFFFF));
- E1000_WRITE_REG(&adapter->shared, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
- E1000_WRITE_REG(&adapter->shared, RDLEN, rdlen);
+ E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
/* Setup the HW Rx Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(&adapter->shared, RDH, 0);
- E1000_WRITE_REG(&adapter->shared, RDT, 0);
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
- if((adapter->shared.mac_type >= e1000_82543) &&
+ if((adapter->hw.mac_type >= e1000_82543) &&
(adapter->rx_csum == TRUE)) {
- rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM);
+ rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
rxcsum |= E1000_RXCSUM_TUOFL;
- E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum);
+ E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
}
/* Enable Receives */
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
}
/**
@@ -941,8 +935,6 @@ e1000_free_tx_resources(struct e1000_adapter *adapter)
adapter->tx_ring.desc, adapter->tx_ring.dma);
adapter->tx_ring.desc = NULL;
-
- return;
}
/**
@@ -980,14 +972,11 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter)
memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
- atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count);
adapter->tx_ring.next_to_use = 0;
adapter->tx_ring.next_to_clean = 0;
- E1000_WRITE_REG(&adapter->shared, TDH, 0);
- E1000_WRITE_REG(&adapter->shared, TDT, 0);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
}
/**
@@ -1011,8 +1000,6 @@ e1000_free_rx_resources(struct e1000_adapter *adapter)
adapter->rx_ring.desc, adapter->rx_ring.dma);
adapter->rx_ring.desc = NULL;
-
- return;
}
/**
@@ -1050,14 +1037,11 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
- adapter->rx_ring.unused_count = adapter->rx_ring.count;
adapter->rx_ring.next_to_clean = 0;
adapter->rx_ring.next_to_use = 0;
- E1000_WRITE_REG(&adapter->shared, RDH, 0);
- E1000_WRITE_REG(&adapter->shared, RDT, 0);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
}
/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
@@ -1068,7 +1052,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+ uint16_t pci_command_word = adapter->hw.pci_cmd_word;
uint32_t rctl;
if(pci_command_word & PCI_COMMAND_INVALIDATE) {
@@ -1076,14 +1060,13 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
pci_write_config_word(pdev, PCI_COMMAND, pci_command_word);
}
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
msec_delay(5);
if(netif_running(netdev))
e1000_clean_rx_ring(adapter);
- return;
}
static void
@@ -1091,12 +1074,12 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+ uint16_t pci_command_word = adapter->hw.pci_cmd_word;
uint32_t rctl;
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
msec_delay(5);
if(pci_command_word & PCI_COMMAND_INVALIDATE)
@@ -1106,7 +1089,6 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
}
- return;
}
/**
@@ -1125,15 +1107,15 @@ e1000_set_mac(struct net_device *netdev, void *p)
/* 82542 2.0 needs to be in reset to write receive address registers */
- if(adapter->shared.mac_type == e1000_82542_rev2_0)
+ if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_enter_82542_rst(adapter);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
- e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0);
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
- if(adapter->shared.mac_type == e1000_82542_rev2_0)
+ if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
return 0;
@@ -1153,7 +1135,7 @@ static void
e1000_set_multi(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
uint32_t rctl;
uint32_t hash_value;
@@ -1161,7 +1143,7 @@ e1000_set_multi(struct net_device *netdev)
/* Check for Promiscuous and All Multicast modes */
- rctl = E1000_READ_REG(shared, RCTL);
+ rctl = E1000_READ_REG(hw, RCTL);
if(netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
@@ -1172,11 +1154,11 @@ e1000_set_multi(struct net_device *netdev)
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
}
- E1000_WRITE_REG(shared, RCTL, rctl);
+ E1000_WRITE_REG(hw, RCTL, rctl);
/* 82542 2.0 needs to be in reset to write receive address registers */
- if(shared->mac_type == e1000_82542_rev2_0)
+ if(hw->mac_type == e1000_82542_rev2_0)
e1000_enter_82542_rst(adapter);
/* load the first 15 multicast address into the exact filters 1-15
@@ -1187,29 +1169,28 @@ e1000_set_multi(struct net_device *netdev)
for(i = 1; i < E1000_RAR_ENTRIES; i++) {
if(mc_ptr) {
- e1000_rar_set(shared, mc_ptr->dmi_addr, i);
+ e1000_rar_set(hw, mc_ptr->dmi_addr, i);
mc_ptr = mc_ptr->next;
} else {
- E1000_WRITE_REG_ARRAY(shared, RA, i << 1, 0);
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1) + 1, 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
}
}
/* clear the old settings from the multicast hash table */
for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
/* load any remaining addresses into the hash table */
for(; mc_ptr; mc_ptr = mc_ptr->next) {
- hash_value = e1000_hash_mc_addr(shared, mc_ptr->dmi_addr);
- e1000_mta_set(shared, hash_value);
+ hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ e1000_mta_set(hw, hash_value);
}
- if(shared->mac_type == e1000_82542_rev2_0)
+ if(hw->mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
- return;
}
@@ -1219,8 +1200,7 @@ static void
e1000_update_phy_info(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
- e1000_phy_get_info(&adapter->shared, &adapter->phy_info);
- return;
+ e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
}
/**
@@ -1234,11 +1214,11 @@ e1000_watchdog(unsigned long data)
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
struct net_device *netdev = adapter->netdev;
- e1000_check_for_link(&adapter->shared);
+ e1000_check_for_link(&adapter->hw);
- if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) {
+ if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
if(!netif_carrier_ok(netdev)) {
- e1000_get_speed_and_duplex(&adapter->shared,
+ e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -1262,171 +1242,203 @@ e1000_watchdog(unsigned long data)
netdev->name);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
+ mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
}
}
e1000_update_stats(adapter);
+ e1000_update_adaptive(&adapter->hw);
/* Reset the timer */
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
-
- return;
}
-/**
- * e1000_xmit_frame - Transmit entry point
- * @skb: buffer with frame data to transmit
- * @netdev: network interface device structure
- *
- * Returns 0 on success, 1 on error
- *
- * e1000_xmit_frame is called by the stack to initiate a transmit.
- * The out of resource condition is checked after each successful Tx
- * so that the stack can be notified, preventing the driver from
- * ever needing to drop a frame. The atomic operations on
- * tx_ring.unused are used to syncronize with the transmit
- * interrupt processing code without the need for a spinlock.
- **/
+#define E1000_TX_FLAGS_CSUM 0x00000001
+#define E1000_TX_FLAGS_VLAN 0x00000002
+#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT 16
-#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0))
+static inline boolean_t
+e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+ struct e1000_context_desc *context_desc;
+ int i;
+ uint8_t css, cso;
-#define SETUP_TXD_PAGE(L, P, O) do { \
- tx_ring->buffer_info[i].length = (L); \
- tx_ring->buffer_info[i].dma = \
- pci_map_page(pdev, (P), (O), (L), PCI_DMA_TODEVICE); \
- tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); \
- tx_desc->lower.data = cpu_to_le32(txd_lower | (L)); \
- tx_desc->upper.data = cpu_to_le32(txd_upper); \
-} while (0)
+ if(skb->ip_summed == CHECKSUM_HW) {
+ css = skb->h.raw - skb->data;
+ cso = (skb->h.raw + skb->csum) - skb->data;
-#define SETUP_TXD_PTR(L, P) \
- SETUP_TXD_PAGE((L), virt_to_page(P), (unsigned long)(P) & ~PAGE_MASK)
+ i = adapter->tx_ring.next_to_use;
+ context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
-#define QUEUE_TXD() do { i = (i + 1) % tx_ring->count; \
- atomic_dec(&tx_ring->unused); } while (0)
+ context_desc->upper_setup.tcp_fields.tucss = css;
+ context_desc->upper_setup.tcp_fields.tucso = cso;
+ context_desc->upper_setup.tcp_fields.tucse = 0;
+ context_desc->tcp_seg_setup.data = 0;
+ context_desc->cmd_and_length =
+ cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+ i = (i + 1) % adapter->tx_ring.count;
+ adapter->tx_ring.next_to_use = i;
-static int
-e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static inline int
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
{
- struct e1000_adapter *adapter = netdev->priv;
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
- struct pci_dev *pdev = adapter->pdev;
- struct e1000_tx_desc *tx_desc;
- int f, len, offset, txd_needed;
- skb_frag_t *frag;
+ int len, offset, size, count, i;
- int i = tx_ring->next_to_use;
- uint32_t txd_upper = 0;
- uint32_t txd_lower = adapter->txd_cmd;
+ int f;
+ len = skb->len - skb->data_len;
+ i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
+ count = 0;
- /* If controller appears hung, force transmit timeout */
+ offset = 0;
- if (time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
- /* If transmitting XOFFs, we're not really hung */
- !(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF)) {
- adapter->trans_finish = jiffies;
- netif_stop_queue(netdev);
- return 1;
+ while(len) {
+ i = (i + 1) % tx_ring->count;
+ size = min(len, adapter->max_data_per_txd);
+ tx_ring->buffer_info[i].length = size;
+ tx_ring->buffer_info[i].dma =
+ pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size,
+ PCI_DMA_TODEVICE);
+
+ len -= size;
+ offset += size;
+ count++;
}
- txd_needed = TXD_USE_COUNT(skb->len - skb->data_len);
-
for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- frag = &skb_shinfo(skb)->frags[f];
- txd_needed += TXD_USE_COUNT(frag->size);
- }
+ struct skb_frag_struct *frag;
- if(skb->ip_summed == CHECKSUM_HW)
- txd_needed += 1;
-
- /* make sure there are enough Tx descriptors available in the ring */
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = 0;
- if(atomic_read(&tx_ring->unused) <= (txd_needed + 1)) {
- adapter->net_stats.tx_dropped++;
- netif_stop_queue(netdev);
- return 1;
+ while(len) {
+ i = (i + 1) % tx_ring->count;
+ size = min(len, adapter->max_data_per_txd);
+ tx_ring->buffer_info[i].length = size;
+ tx_ring->buffer_info[i].dma =
+ pci_map_page(adapter->pdev,
+ frag->page,
+ frag->page_offset + offset,
+ size,
+ PCI_DMA_TODEVICE);
+
+ len -= size;
+ offset += size;
+ count++;
+ }
}
+ tx_ring->buffer_info[i].skb = skb;
- if(skb->ip_summed == CHECKSUM_HW) {
- struct e1000_context_desc *context_desc;
- uint8_t css = skb->h.raw - skb->data;
- uint8_t cso = (skb->h.raw + skb->csum) - skb->data;
-
- context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ return count;
+}
- context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso = cso;
- context_desc->upper_setup.tcp_fields.tucse = 0;
- context_desc->tcp_seg_setup.data = 0;
- context_desc->cmd_and_length =
- cpu_to_le32(txd_lower | E1000_TXD_CMD_DEXT);
+static inline void
+e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+{
+ struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc = NULL;
+ uint32_t txd_upper, txd_lower;
+ int i;
- QUEUE_TXD();
+ txd_upper = 0;
+ txd_lower = adapter->txd_cmd;
- txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ if(tx_flags & E1000_TX_FLAGS_CSUM) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
}
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len = skb->len - skb->data_len;
- offset = 0;
+ if(tx_flags & E1000_TX_FLAGS_VLAN) {
+ txd_lower |= E1000_TXD_CMD_VLE;
+ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+ }
- while(len > 4096) {
- SETUP_TXD_PTR(4096, skb->data + offset);
- QUEUE_TXD();
+ i = tx_ring->next_to_use;
+ while(count--) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
- len -= 4096;
- offset += 4096;
+ tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+ tx_desc->lower.data =
+ cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
+ tx_desc->upper.data = cpu_to_le32(txd_upper);
+ i = (i + 1) % tx_ring->count;
}
- SETUP_TXD_PTR(len, skb->data + offset);
+ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
- for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- frag = &skb_shinfo(skb)->frags[f];
+ tx_ring->next_to_use = i;
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
+}
- QUEUE_TXD();
+#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len = frag->size;
- offset = 0;
+static int
+e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ unsigned long flags;
+ int tx_flags = 0, count;
- while(len > 4096) {
- SETUP_TXD_PAGE(4096, frag->page,
- frag->page_offset + offset);
- QUEUE_TXD();
+ int f;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len -= 4096;
- offset += 4096;
- }
- SETUP_TXD_PAGE(len, frag->page, frag->page_offset + offset);
- }
- /* EOP and SKB pointer go with the last fragment */
+ if(time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
+ !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) {
- tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
- tx_ring->buffer_info[i].skb = skb;
+ adapter->trans_finish = jiffies;
+ netif_stop_queue(netdev);
+ return 1;
+ }
- QUEUE_TXD();
+ count = TXD_USE_COUNT(skb->len - skb->data_len,
+ adapter->max_data_per_txd);
+ for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ adapter->max_data_per_txd);
+ if(skb->ip_summed == CHECKSUM_HW)
+ count++;
- tx_ring->next_to_use = i;
+ spin_lock_irqsave(&adapter->tx_lock, flags);
+ e1000_clean_tx_irq(adapter);
+ if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+
+ if(e1000_tx_csum(adapter, skb))
+ tx_flags |= E1000_TX_FLAGS_CSUM;
- /* Move the HW Tx Tail Pointer */
+#ifdef NETIF_F_HW_VLAN_TX
+ if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= E1000_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ }
+#endif
+
+ count = e1000_tx_map(adapter, skb);
- E1000_WRITE_REG(&adapter->shared, TDT, i);
+ e1000_tx_queue(adapter, count, tx_flags);
netdev->trans_start = jiffies;
return 0;
}
-#undef TXD_USE_COUNT
-#undef SETUP_TXD
-#undef QUEUE_TXD
-
/**
* e1000_tx_timeout - Respond to a Tx Hang
* @netdev: network interface device structure
@@ -1470,24 +1482,21 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
struct e1000_adapter *adapter = netdev->priv;
int old_mtu = adapter->rx_buffer_len;
- int max_frame = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
- if((max_frame < MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) ||
- (max_frame > MAX_JUMBO_FRAME_SIZE + CRC_LENGTH)) {
+ if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
E1000_ERR("Invalid MTU setting\n");
return -EINVAL;
}
- if(max_frame <= MAXIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) {
+ if(max_frame <= E1000_RXBUFFER_2048) {
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- } else if(adapter->shared.mac_type < e1000_82543) {
+ } else if(adapter->hw.mac_type < e1000_82543) {
E1000_ERR("Jumbo Frames not supported on 82542\n");
return -EINVAL;
- } else if(max_frame <= E1000_RXBUFFER_2048) {
- adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-
} else if(max_frame <= E1000_RXBUFFER_4096) {
adapter->rx_buffer_len = E1000_RXBUFFER_4096;
@@ -1501,13 +1510,11 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
e1000_down(adapter);
- e1000_clean_rx_ring(adapter);
- e1000_clean_tx_ring(adapter);
e1000_up(adapter);
}
netdev->mtu = new_mtu;
- adapter->shared.max_frame_size = max_frame;
+ adapter->hw.max_frame_size = max_frame;
return 0;
}
@@ -1520,8 +1527,9 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
static void
e1000_update_stats(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
unsigned long flags;
+ uint16_t phy_tmp;
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
@@ -1532,68 +1540,73 @@ e1000_update_stats(struct e1000_adapter *adapter)
* be written while holding adapter->stats_lock
*/
- adapter->stats.crcerrs += E1000_READ_REG(shared, CRCERRS);
- adapter->stats.gprc += E1000_READ_REG(shared, GPRC);
- adapter->stats.gorcl += E1000_READ_REG(shared, GORCL);
- adapter->stats.gorch += E1000_READ_REG(shared, GORCH);
- adapter->stats.bprc += E1000_READ_REG(shared, BPRC);
- adapter->stats.mprc += E1000_READ_REG(shared, MPRC);
- adapter->stats.roc += E1000_READ_REG(shared, ROC);
- adapter->stats.prc64 += E1000_READ_REG(shared, PRC64);
- adapter->stats.prc127 += E1000_READ_REG(shared, PRC127);
- adapter->stats.prc255 += E1000_READ_REG(shared, PRC255);
- adapter->stats.prc511 += E1000_READ_REG(shared, PRC511);
- adapter->stats.prc1023 += E1000_READ_REG(shared, PRC1023);
- adapter->stats.prc1522 += E1000_READ_REG(shared, PRC1522);
+ adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
+ adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
+ adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+ adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
+ adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
+ adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
+ adapter->stats.roc += E1000_READ_REG(hw, ROC);
+ adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
+ adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
+ adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
+ adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
+ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
+ adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
spin_unlock_irqrestore(&adapter->stats_lock, flags);
/* the rest of the counters are only modified here */
- adapter->stats.symerrs += E1000_READ_REG(shared, SYMERRS);
- adapter->stats.mpc += E1000_READ_REG(shared, MPC);
- adapter->stats.scc += E1000_READ_REG(shared, SCC);
- adapter->stats.ecol += E1000_READ_REG(shared, ECOL);
- adapter->stats.mcc += E1000_READ_REG(shared, MCC);
- adapter->stats.latecol += E1000_READ_REG(shared, LATECOL);
- adapter->stats.colc += E1000_READ_REG(shared, COLC);
- adapter->stats.dc += E1000_READ_REG(shared, DC);
- adapter->stats.sec += E1000_READ_REG(shared, SEC);
- adapter->stats.rlec += E1000_READ_REG(shared, RLEC);
- adapter->stats.xonrxc += E1000_READ_REG(shared, XONRXC);
- adapter->stats.xontxc += E1000_READ_REG(shared, XONTXC);
- adapter->stats.xoffrxc += E1000_READ_REG(shared, XOFFRXC);
- adapter->stats.xofftxc += E1000_READ_REG(shared, XOFFTXC);
- adapter->stats.fcruc += E1000_READ_REG(shared, FCRUC);
- adapter->stats.gptc += E1000_READ_REG(shared, GPTC);
- adapter->stats.gotcl += E1000_READ_REG(shared, GOTCL);
- adapter->stats.gotch += E1000_READ_REG(shared, GOTCH);
- adapter->stats.rnbc += E1000_READ_REG(shared, RNBC);
- adapter->stats.ruc += E1000_READ_REG(shared, RUC);
- adapter->stats.rfc += E1000_READ_REG(shared, RFC);
- adapter->stats.rjc += E1000_READ_REG(shared, RJC);
- adapter->stats.torl += E1000_READ_REG(shared, TORL);
- adapter->stats.torh += E1000_READ_REG(shared, TORH);
- adapter->stats.totl += E1000_READ_REG(shared, TOTL);
- adapter->stats.toth += E1000_READ_REG(shared, TOTH);
- adapter->stats.tpr += E1000_READ_REG(shared, TPR);
- adapter->stats.tpt += E1000_READ_REG(shared, TPT);
- adapter->stats.ptc64 += E1000_READ_REG(shared, PTC64);
- adapter->stats.ptc127 += E1000_READ_REG(shared, PTC127);
- adapter->stats.ptc255 += E1000_READ_REG(shared, PTC255);
- adapter->stats.ptc511 += E1000_READ_REG(shared, PTC511);
- adapter->stats.ptc1023 += E1000_READ_REG(shared, PTC1023);
- adapter->stats.ptc1522 += E1000_READ_REG(shared, PTC1522);
- adapter->stats.mptc += E1000_READ_REG(shared, MPTC);
- adapter->stats.bptc += E1000_READ_REG(shared, BPTC);
-
- if(adapter->shared.mac_type >= e1000_82543) {
- adapter->stats.algnerrc += E1000_READ_REG(shared, ALGNERRC);
- adapter->stats.rxerrc += E1000_READ_REG(shared, RXERRC);
- adapter->stats.tncrs += E1000_READ_REG(shared, TNCRS);
- adapter->stats.cexterr += E1000_READ_REG(shared, CEXTERR);
- adapter->stats.tsctc += E1000_READ_REG(shared, TSCTC);
- adapter->stats.tsctfc += E1000_READ_REG(shared, TSCTFC);
+ adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
+ adapter->stats.mpc += E1000_READ_REG(hw, MPC);
+ adapter->stats.scc += E1000_READ_REG(hw, SCC);
+ adapter->stats.ecol += E1000_READ_REG(hw, ECOL);
+ adapter->stats.mcc += E1000_READ_REG(hw, MCC);
+ adapter->stats.latecol += E1000_READ_REG(hw, LATECOL);
+ adapter->stats.dc += E1000_READ_REG(hw, DC);
+ adapter->stats.sec += E1000_READ_REG(hw, SEC);
+ adapter->stats.rlec += E1000_READ_REG(hw, RLEC);
+ adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC);
+ adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC);
+ adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC);
+ adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
+ adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
+ adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
+ adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+ adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
+ adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
+ adapter->stats.ruc += E1000_READ_REG(hw, RUC);
+ adapter->stats.rfc += E1000_READ_REG(hw, RFC);
+ adapter->stats.rjc += E1000_READ_REG(hw, RJC);
+ adapter->stats.torl += E1000_READ_REG(hw, TORL);
+ adapter->stats.torh += E1000_READ_REG(hw, TORH);
+ adapter->stats.totl += E1000_READ_REG(hw, TOTL);
+ adapter->stats.toth += E1000_READ_REG(hw, TOTH);
+ adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+ adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
+ adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
+ adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
+ adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
+ adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
+ adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+ adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
+ adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
+
+ /* used for adaptive IFS */
+
+ hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
+ adapter->stats.tpt += hw->tx_packet_delta;
+ hw->collision_delta = E1000_READ_REG(hw, COLC);
+ adapter->stats.colc += hw->collision_delta;
+
+ if(hw->mac_type >= e1000_82543) {
+ adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC);
+ adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC);
+ adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS);
+ adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR);
+ adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
+ adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
}
/* Fill out the OS statistics structure */
@@ -1627,14 +1640,18 @@ e1000_update_stats(struct e1000_adapter *adapter)
/* Tx Dropped needs to be maintained elsewhere */
- if(adapter->shared.media_type == e1000_media_type_copper) {
- adapter->phy_stats.idle_errors +=
- (e1000_read_phy_reg(shared, PHY_1000T_STATUS)
- & PHY_IDLE_ERROR_COUNT_MASK);
- adapter->phy_stats.receive_errors +=
- e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR);
+ /* Phy Stats */
+
+ if(hw->media_type == e1000_media_type_copper) {
+ if((adapter->link_speed == SPEED_1000) &&
+ (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
+ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+ adapter->phy_stats.idle_errors += phy_tmp;
+ }
+
+ if(!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+ adapter->phy_stats.receive_errors += phy_tmp;
}
- return;
}
/**
@@ -1646,9 +1663,8 @@ static inline void
e1000_irq_disable(struct e1000_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(&adapter->shared, IMC, ~0);
+ E1000_WRITE_REG(&adapter->hw, IMC, ~0);
synchronize_irq();
- return;
}
/**
@@ -1660,8 +1676,7 @@ static inline void
e1000_irq_enable(struct e1000_adapter *adapter)
{
if(atomic_dec_and_test(&adapter->irq_sem))
- E1000_WRITE_REG(&adapter->shared, IMS, IMS_ENABLE_MASK);
- return;
+ E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
}
/**
@@ -1679,20 +1694,23 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
uint32_t icr;
int i = E1000_MAX_INTR;
- while(i && (icr = E1000_READ_REG(&adapter->shared, ICR))) {
+ while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- /* run the watchdog ASAP */
- adapter->shared.get_link_status = 1;
+ adapter->hw.get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
}
e1000_clean_rx_irq(adapter);
- e1000_clean_tx_irq(adapter);
+
+ if((icr & E1000_ICR_TXDW) && spin_trylock(&adapter->tx_lock)) {
+ e1000_clean_tx_irq(adapter);
+ spin_unlock(&adapter->tx_lock);
+ }
+
i--;
- }
- return;
+ }
}
/**
@@ -1726,7 +1744,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
if(tx_ring->buffer_info[i].skb) {
- dev_kfree_skb_irq(tx_ring->buffer_info[i].skb);
+ dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
tx_ring->buffer_info[i].skb = NULL;
}
@@ -1734,7 +1752,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
memset(tx_desc, 0, sizeof(struct e1000_tx_desc));
mb();
- atomic_inc(&tx_ring->unused);
i = (i + 1) % tx_ring->count;
tx_desc = E1000_TX_DESC(*tx_ring, i);
@@ -1744,11 +1761,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->next_to_clean = i;
if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
- (atomic_read(&tx_ring->unused) > E1000_TX_QUEUE_WAKE)) {
+ (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
netif_wake_queue(netdev);
}
- return;
}
/**
@@ -1789,12 +1805,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
E1000_DBG("Receive packet consumed multiple buffers\n");
dev_kfree_skb_irq(skb);
- memset(rx_desc, 0, 16);
+ memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
-
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1805,12 +1819,12 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
last_byte = *(skb->data + length - 1);
- if(TBI_ACCEPT(&adapter->shared, rx_desc->special,
+ if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
rx_desc->errors, length, last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
- e1000_tbi_adjust_stats(&adapter->shared,
+ e1000_tbi_adjust_stats(&adapter->hw,
&adapter->stats,
length, skb->data);
@@ -1820,11 +1834,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
} else {
dev_kfree_skb_irq(skb);
- memset(rx_desc, 0, 16);
+ memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1833,20 +1846,28 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
}
/* Good Receive */
- skb_put(skb, length - CRC_LENGTH);
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
/* Receive Checksum Offload */
e1000_rx_checksum(adapter, rx_desc, skb);
skb->protocol = eth_type_trans(skb, netdev);
+#ifdef NETIF_F_HW_VLAN_TX
+ if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+ vlan_hwaccel_rx(skb, adapter->vlgrp,
+ (rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+ } else {
+ netif_rx(skb);
+ }
+#else
netif_rx(skb);
+#endif
+ netdev->last_rx = jiffies;
memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
-
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1855,8 +1876,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_ring->next_to_clean = i;
e1000_alloc_rx_buffers(adapter);
-
- return;
}
/**
@@ -1911,16 +1930,13 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
- /* move tail */
- E1000_WRITE_REG(&adapter->shared, RDT, i);
-
- atomic_dec(&rx_ring->unused);
+ if(!(i % E1000_RX_BUFFER_WRITE))
+ E1000_WRITE_REG(&adapter->hw, RDT, i);
i = (i + 1) % rx_ring->count;
}
rx_ring->next_to_use = i;
- return;
}
/**
@@ -1954,7 +1970,7 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
struct sk_buff *skb)
{
/* 82543 or newer only */
- if((adapter->shared.mac_type < e1000_82543) ||
+ if((adapter->hw.mac_type < e1000_82543) ||
/* Ignore Checksum bit is set */
(rx_desc->status & E1000_RXD_STAT_IXSM) ||
/* TCP Checksum has not been calculated */
@@ -1974,10 +1990,8 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
skb->ip_summed = CHECKSUM_UNNECESSARY;
adapter->hw_csum_good++;
}
- return;
}
-
/**
* e1000_enable_WOL - Wake On Lan Support (Magic Pkt)
* @adapter: Adapter structure
@@ -1988,29 +2002,104 @@ e1000_enable_WOL(struct e1000_adapter *adapter)
{
uint32_t wuc;
- if(adapter->shared.mac_type < e1000_82544)
+ if(adapter->hw.mac_type < e1000_82544)
return;
if(adapter->wol) {
wuc = E1000_WUC_APME | E1000_WUC_PME_EN |
E1000_WUC_PME_STATUS | E1000_WUC_APMPME;
- E1000_WRITE_REG(&adapter->shared, WUC, wuc);
+ E1000_WRITE_REG(&adapter->hw, WUC, wuc);
- E1000_WRITE_REG(&adapter->shared, WUFC, adapter->wol);
+ E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
}
-
- return;
}
void
-e1000_write_pci_cfg(struct e1000_shared_adapter *shared,
+e1000_write_pci_cfg(struct e1000_hw *hw,
uint32_t reg, uint16_t *value)
{
- struct e1000_adapter *adapter = shared->back;
+ struct e1000_adapter *adapter = hw->back;
pci_write_config_word(adapter->pdev, reg, *value);
- return;
}
+#ifdef NETIF_F_HW_VLAN_TX
+static void
+e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t ctrl, rctl;
+
+ e1000_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if(grp) {
+ /* enable VLAN tag insert/strip */
+
+ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ /* enable VLAN receive filtering */
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl |= E1000_RCTL_VFE;
+ rctl &= ~E1000_RCTL_CFIEN;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ } else {
+ /* disable VLAN tag insert/strip */
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ /* disable VLAN filtering */
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl &= ~E1000_RCTL_VFE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ }
+
+ e1000_irq_enable(adapter);
+}
+
+static void
+e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t vfta, index;
+
+ /* add VID to filter table */
+
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+ vfta |= (1 << (vid & 0x1F));
+ e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t vfta, index;
+
+ e1000_irq_disable(adapter);
+
+ if(adapter->vlgrp)
+ adapter->vlgrp->vlan_devices[vid] = NULL;
+
+ e1000_irq_enable(adapter);
+
+ /* remove VID from filter table*/
+
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+ vfta &= ~(1 << (vid & 0x1F));
+ e1000_write_vfta(&adapter->hw, index, vfta);
+}
+#endif
+
/* e1000_main.c */
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index a7a1be20bc7c..3990e01eb1dc 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index b93595df24f2..618515ae94f2 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -153,7 +152,7 @@ E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
- * Valid Range: 0x00-0x0F, 0x20-0x2F
+ * Valid Range: 0x01-0x0F, 0x20-0x2F
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
@@ -193,20 +192,11 @@ E1000_PARAM(FlowControl, "Flow Control setting");
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
-/* Transmit Interrupt Delay in units of 1.024 microseconds
- *
- * Valid Range: 0-65535
- *
- * Default Value: 64
- */
-
-E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
-
/* Receive Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*
- * Default Value: 64
+ * Default Value: 64/128
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
@@ -252,13 +242,10 @@ E1000_PARAM(DisablePolarityCorrection,
#define MIN_RXD 80
#define MAX_82544_RXD 4096
-#define DEFAULT_TIDV 64
-#define MAX_TIDV 0xFFFF
-#define MIN_TIDV 0
-
-#define DEFAULT_RIDV 64
-#define MAX_RIDV 0xFFFF
-#define MIN_RIDV 0
+#define DEFAULT_RDTR 64
+#define DEFAULT_RADV 128
+#define MAX_RXDELAY 0xFFFF
+#define MIN_RXDELAY 0
#define DEFAULT_MDIX 0
#define MAX_MDIX 3
@@ -332,8 +319,6 @@ e1000_validate_option(int *value, struct e1000_option *opt)
return -1;
}
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
@@ -367,7 +352,7 @@ e1000_check_options(struct e1000_adapter *adapter)
arg: { r: { min: MIN_TXD }}
};
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
- e1000_mac_type mac_type = adapter->shared.mac_type;
+ e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD;
tx_ring->count = TxDescriptors[bd];
@@ -383,7 +368,7 @@ e1000_check_options(struct e1000_adapter *adapter)
arg: { r: { min: MIN_RXD }}
};
struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
- e1000_mac_type mac_type = adapter->shared.mac_type;
+ e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD;
rx_ring->count = RxDescriptors[bd];
@@ -416,39 +401,30 @@ e1000_check_options(struct e1000_adapter *adapter)
name: "Flow Control",
err: "reading default settings from EEPROM",
def: e1000_fc_default,
- arg: { l: { nr: LIST_LEN(fc_list), p: fc_list }}
+ arg: { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
};
int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt);
- adapter->shared.fc = adapter->shared.original_fc = fc;
- }
- { /* Transmit Interrupt Delay */
- struct e1000_option opt = {
- type: range_option,
- name: "Transmit Interrupt Delay",
- err: "using default of " __MODULE_STRING(DEFAULT_TIDV),
- def: DEFAULT_TIDV,
- arg: { r: { min: MIN_TIDV, max: MAX_TIDV }}
- };
-
- adapter->tx_int_delay = TxIntDelay[bd];
- e1000_validate_option(&adapter->tx_int_delay, &opt);
+ adapter->hw.fc = adapter->hw.original_fc = fc;
}
{ /* Receive Interrupt Delay */
+ char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
+ char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
struct e1000_option opt = {
type: range_option,
name: "Receive Interrupt Delay",
- err: "using default of " __MODULE_STRING(DEFAULT_RIDV),
- def: DEFAULT_RIDV,
- arg: { r: { min: MIN_RIDV, max: MAX_RIDV }}
+ arg: { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
};
+ e1000_mac_type mac_type = adapter->hw.mac_type;
+ opt.def = mac_type < e1000_82540 ? DEFAULT_RDTR : DEFAULT_RADV;
+ opt.err = mac_type < e1000_82540 ? rdtr : radv;
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt);
}
- switch(adapter->shared.media_type) {
+ switch(adapter->hw.media_type) {
case e1000_media_type_fiber:
e1000_check_fiber_options(adapter);
break;
@@ -511,7 +487,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
name: "Speed",
err: "parameter ignored",
def: 0,
- arg: { l: { nr: LIST_LEN(speed_list), p: speed_list }}
+ arg: { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
};
speed = Speed[bd];
@@ -526,7 +502,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
name: "Duplex",
err: "parameter ignored",
def: 0,
- arg: { l: { nr: LIST_LEN(dplx_list), p: dplx_list }}
+ arg: { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
};
dplx = Duplex[bd];
@@ -537,10 +513,10 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
printk(KERN_INFO
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
- adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+ adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
struct e1000_opt_list an_list[] =
- #define AA "Autoneg advertising "
+ #define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
@@ -575,20 +551,20 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
struct e1000_option opt = {
type: list_option,
- name: "Autoneg",
+ name: "AutoNeg",
err: "parameter ignored",
def: AUTONEG_ADV_DEFAULT,
- arg: { l: { nr: LIST_LEN(an_list), p: an_list }}
+ arg: { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
};
int an = AutoNeg[bd];
e1000_validate_option(&an, &opt);
- adapter->shared.autoneg_advertised = an;
+ adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
- adapter->shared.autoneg = 1;
+ adapter->hw.autoneg = 1;
if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
printk(KERN_INFO
"Speed and duplex autonegotiation enabled\n");
@@ -596,75 +572,75 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
case HALF_DUPLEX:
printk(KERN_INFO "Half Duplex specified without Speed\n");
printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_100_HALF;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+ ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
printk(KERN_INFO "Full Duplex specified without Speed\n");
printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_FULL |
- ADVERTISE_100_FULL |
- ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
+ ADVERTISE_100_FULL |
+ ADVERTISE_1000_FULL;
break;
case SPEED_10:
printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_10_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+ ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_10_half;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_10_half;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_10_full;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_10_full;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_100_HALF |
- ADVERTISE_100_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
+ ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_100_half;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_100_half;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_100_full;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_100_full;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + HALF_DUPLEX:
printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + FULL_DUPLEX:
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
@@ -683,7 +659,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
int mdix = MdiX[bd];
e1000_validate_option(&mdix, &opt);
- adapter->shared.mdix = mdix;
+ adapter->hw.mdix = mdix;
}
{ /* Automatic Correction for Reverse Cable Polarity */
/* option is actually to disable polarity correction,
@@ -697,11 +673,11 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
int dpc = DisablePolarityCorrection[bd];
e1000_validate_option(&dpc, &opt);
- adapter->shared.disable_polarity_correction = dpc;
+ adapter->hw.disable_polarity_correction = dpc;
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
- if (!e1000_validate_mdi_setting(&(adapter->shared))) {
+ if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
diff --git a/drivers/net/e1000/e1000_phy.c b/drivers/net/e1000/e1000_phy.c
deleted file mode 100644
index a1e61ccfa84a..000000000000
--- a/drivers/net/e1000/e1000_phy.c
+++ /dev/null
@@ -1,1485 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_phy.c
- * Shared functions for accessing and configuring the PHY
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
-* Raises the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_raise_mdc(struct e1000_shared_adapter *shared,
- uint32_t *ctrl_reg)
-{
- /* Raise the clock input to the Management Data Clock (by setting
- * the MDC bit), and then delay 2 microseconds.
- */
- E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC));
- usec_delay(2);
- return;
-}
-
-/******************************************************************************
-* Lowers the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_lower_mdc(struct e1000_shared_adapter *shared,
- uint32_t *ctrl_reg)
-{
- /* Lower the clock input to the Management Data Clock (by clearing
- * the MDC bit), and then delay 2 microseconds.
- */
- E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC));
- usec_delay(2);
- return;
-}
-
-/******************************************************************************
-* Shifts data bits out to the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* data - Data to send out to the PHY
-* count - Number of bits to shift out
-*
-* Bits are shifted out in MSB to LSB order.
-******************************************************************************/
-static void
-e1000_phy_shift_out(struct e1000_shared_adapter *shared,
- uint32_t data,
- uint16_t count)
-{
- uint32_t ctrl_reg;
- uint32_t mask;
-
- ASSERT(count <= 32);
-
- /* We need to shift "count" number of bits out to the PHY. So, the
- * value in the "Data" parameter will be shifted out to the PHY
- * one bit at a time. In order to do this, "Data" must be broken
- * down into bits, which is what the "while" logic does below.
- */
- mask = 0x01;
- mask <<= (count - 1);
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to
- * be used as output pins.
- */
- ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
-
- while(mask) {
- /* A "1" is shifted out to the PHY by setting the MDIO bit to
- * "1" and then raising and lowering the Management Data Clock
- * (MDC). A "0" is shifted out to the PHY by setting the MDIO
- * bit to "0" and then raising and lowering the clock.
- */
- if(data & mask)
- ctrl_reg |= E1000_CTRL_MDIO;
- else
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- usec_delay(2);
-
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- mask = mask >> 1;
- }
-
- /* Clear the data bit just before leaving this routine. */
- ctrl_reg &= ~E1000_CTRL_MDIO;
- return;
-}
-
-/******************************************************************************
-* Shifts data bits in from the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Bits are shifted in in MSB to LSB order.
-******************************************************************************/
-static uint16_t
-e1000_phy_shift_in(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint16_t data = 0;
- uint8_t i;
-
- /* In order to read a register from the PHY, we need to shift in a
- * total of 18 bits from the PHY. The first two bit (TurnAround)
- * times are used to avoid contention on the MDIO pin when a read
- * operation is performed. These two bits are ignored by us and
- * thrown away. Bits are "shifted in" by raising the clock input
- * to the Management Data Clock (setting the MDC bit), and then
- * reading the value of the MDIO bit.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
- * input.
- */
- ctrl_reg &= ~E1000_CTRL_MDIO_DIR;
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Raise and Lower the clock before reading in the data. This
- * accounts for the TurnAround bits. The first clock occurred
- * when we clocked out the last bit of the Register Address.
- */
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- for(data = 0, i = 0; i < 16; i++) {
- data = data << 1;
- e1000_raise_mdc(shared, &ctrl_reg);
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Check to see if we shifted in a "1". */
- if(ctrl_reg & E1000_CTRL_MDIO)
- data |= 1;
-
- e1000_lower_mdc(shared, &ctrl_reg);
- }
-
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- /* Clear the MDIO bit just before leaving this routine. */
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- return (data);
-}
-
-/******************************************************************************
-* Force PHY speed and duplex settings to shared->forced_speed_duplex
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-static void
-e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared)
-{
- uint32_t tctl_reg;
- uint32_t ctrl_reg;
- uint32_t shift;
- uint16_t mii_ctrl_reg;
- uint16_t mii_status_reg;
- uint16_t phy_data;
- uint16_t i;
-
- DEBUGFUNC("e1000_phy_force_speed_duplex");
-
- /* Turn off Flow control if we are forcing speed and duplex. */
- shared->fc = e1000_fc_none;
-
- DEBUGOUT1("shared->fc = %d\n", shared->fc);
-
- /* Read the Device Control Register. */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
- ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
- /* Clear the Auto Speed Detect Enable bit. */
- ctrl_reg &= ~E1000_CTRL_ASDE;
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- /* We need to disable autoneg in order to force link and duplex. */
-
- mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
-
- /* Are we forcing Full or Half Duplex? */
- if(shared->forced_speed_duplex == e1000_100_full ||
- shared->forced_speed_duplex == e1000_10_full) {
-
- /* We want to force full duplex so we SET the full duplex bits
- * in the Device and MII Control Registers.
- */
- ctrl_reg |= E1000_CTRL_FD;
- mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
-
- DEBUGOUT("Full Duplex\n");
- } else {
-
- /* We want to force half duplex so we CLEAR the full duplex
- * bits in the Device and MII Control Registers.
- */
- ctrl_reg &= ~E1000_CTRL_FD;
- mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */
-
- DEBUGOUT("Half Duplex\n");
- }
-
- /* Are we forcing 100Mbps??? */
- if(shared->forced_speed_duplex == e1000_100_full ||
- shared->forced_speed_duplex == e1000_100_half) {
-
- /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
- ctrl_reg |= E1000_CTRL_SPD_100;
- mii_ctrl_reg |= MII_CR_SPEED_100;
- mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-
- DEBUGOUT("Forcing 100mb ");
- } else { /* Force 10MB Full or Half */
-
- /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
- ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
- mii_ctrl_reg |= MII_CR_SPEED_10;
- mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-
- DEBUGOUT("Forcing 10mb ");
- }
-
- /* Now we need to configure the Collision Distance. We need to read
- * the Transmit Control Register to do this.
- * Note: This must be done for both Half or Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) {
-
- /* We are in Half Duplex mode so we need to set up our collision
- * distance for 10/100.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- /* We are in Full Duplex mode. We have the same collision
- * distance regardless of speed.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Write the configured values back to the Device Control Reg. */
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Write the MII Control Register with the new PHY configuration. */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- /* Clear Auto-Crossover to force MDI manually.
- * M88E1000 requires MDI forced whenever speed/duplex is forced
- */
- phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
-
- DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-
- /* Need to reset the PHY or these bits will get ignored. */
- mii_ctrl_reg |= MII_CR_RESET;
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- /* The wait_autoneg_complete flag may be a little misleading here.
- * Since we are forcing speed and duplex, Auto-Neg is not enabled.
- * But we do want to delay for a period while forcing only so we
- * don't generate false No Link messages. So we will wait here
- * only if the user has set wait_autoneg_complete to 1, which is
- * the default.
- */
- if(shared->wait_autoneg_complete) {
- /* We will wait for autoneg to complete. */
- DEBUGOUT("Waiting for forced speed/duplex link.\n");
- mii_status_reg = 0;
-
- /* We will wait for autoneg to complete or 4.5 seconds to expire. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
-
- msec_delay(100);
- } /* end for loop */
-
- if(i == 0) { /* We didn't get link */
-
- /* Reset the DSP and wait again for link. */
- e1000_phy_reset_dsp(shared);
- }
-
- /* This loop will early-out if the link condition has been met. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
-
- msec_delay(100);
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- } /* end for loop */
- } /* end if wait_autoneg_complete */
- /*
- * Because we reset the PHY above, we need to re-force TX_CLK in the
- * Extended PHY Specific Control Register to 25MHz clock. This
- * value defaults back to a 2.5MHz clock when the PHY is reset.
- */
- phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
- phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
- e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-
- /* In addition, because of the s/w reset above, we need to enable
- * CRS on TX. This must be set for both full and half duplex
- * operation.
- */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
- DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data);
-
- return;
-}
-
-/*****************************************************************************
-* Reads the value from a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to read
-******************************************************************************/
-uint16_t
-e1000_read_phy_reg(struct e1000_shared_adapter *shared,
- uint32_t reg_addr)
-{
- uint32_t i;
- uint32_t data = 0;
- uint32_t command = 0;
-
- ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
- if(shared->mac_type > e1000_82543) {
- /* Set up Op-code, Phy Address, and
- * register address in the MDI Control register. The MAC will
- * take care of interfacing with the PHY to retrieve the
- * desired data.
- */
- command = ((reg_addr << E1000_MDIC_REG_SHIFT) |
- (shared->phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_READ));
-
- E1000_WRITE_REG(shared, MDIC, command);
-
- /* Check every 10 usec to see if the read completed. The read
- * may take as long as 64 usecs (we'll wait 100 usecs max)
- * from the CPU Write to the Ready bit assertion.
- */
- for(i = 0; i < 64; i++) {
- usec_delay(10);
-
- data = E1000_READ_REG(shared, MDIC);
-
- if(data & E1000_MDIC_READY)
- break;
- }
- } else {
- /* We must first send a preamble through the MDIO pin to signal the
- * beginning of an MII instruction. This is done by sending 32
- * consecutive "1" bits.
- */
- e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
- /* Now combine the next few fields that are required for a read
- * operation. We use this method instead of calling the
- * e1000_phy_shift_out routine five different times. The format of
- * a MII read instruction consists of a shift out of 14 bits and is
- * defined as follows:
- * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
- * followed by a shift in of 18 bits. This first two bits shifted
- * in are TurnAround bits used to avoid contention on the MDIO pin
- * when a READ operation is performed. These two bits are thrown
- * away followed by a shift in of 16 bits which contains the
- * desired data.
- */
- command = ((reg_addr) |
- (shared->phy_addr << 5) |
- (PHY_OP_READ << 10) | (PHY_SOF << 12));
-
- e1000_phy_shift_out(shared, command, 14);
-
- /* Now that we've shifted out the read command to the MII, we need
- * to "shift in" the 16-bit value (18 total bits) of the requested
- * PHY register address.
- */
- data = (uint32_t) e1000_phy_shift_in(shared);
- }
-
- ASSERT(!(data & E1000_MDIC_ERROR));
-
- return ((uint16_t) data);
-}
-
-/******************************************************************************
-* Writes a value to a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to write
-* data - data to write to the PHY
-******************************************************************************/
-void
-e1000_write_phy_reg(struct e1000_shared_adapter *shared,
- uint32_t reg_addr,
- uint16_t data)
-{
- uint32_t i;
- uint32_t command = 0;
- uint32_t mdic_reg;
-
- ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
- if(shared->mac_type > e1000_82543) {
- /* Set up Op-code, Phy Address, register
- * address, and data intended for the PHY register in the MDI
- * Control register. The MAC will take care of interfacing
- * with the PHY to send the desired data.
- */
- command = (((uint32_t) data) |
- (reg_addr << E1000_MDIC_REG_SHIFT) |
- (shared->phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_WRITE));
-
- E1000_WRITE_REG(shared, MDIC, command);
-
- /* Check every 10 usec to see if the read completed. The read
- * may take as long as 64 usecs (we'll wait 100 usecs max)
- * from the CPU Write to the Ready bit assertion.
- */
- for(i = 0; i < 10; i++) {
- usec_delay(10);
-
- mdic_reg = E1000_READ_REG(shared, MDIC);
-
- if(mdic_reg & E1000_MDIC_READY)
- break;
- }
- } else {
- /* We'll need to use the SW defined pins to shift the write command
- * out to the PHY. We first send a preamble to the PHY to signal the
- * beginning of the MII instruction. This is done by sending 32
- * consecutive "1" bits.
- */
- e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
- /* Now combine the remaining required fields that will indicate
- * a write operation. We use this method instead of calling the
- * e1000_phy_shift_out routine for each field in the command. The
- * format of a MII write instruction is as follows:
- * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
- */
- command = ((PHY_TURNAROUND) |
- (reg_addr << 2) |
- (shared->phy_addr << 7) |
- (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
- command <<= 16;
- command |= ((uint32_t) data);
-
- e1000_phy_shift_out(shared, command, 32);
- }
- return;
-}
-
-/******************************************************************************
-* Returns the PHY to the power-on reset state
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_hw_reset(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t ctrl_ext_reg;
-
- DEBUGFUNC("e1000_phy_hw_reset");
-
- DEBUGOUT("Resetting Phy...\n");
-
- if(shared->mac_type > e1000_82543) {
- /* Read the device control register and assert the
- * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out
- * of reset.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ctrl_reg |= E1000_CTRL_PHY_RST;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- msec_delay(20);
-
- ctrl_reg &= ~E1000_CTRL_PHY_RST;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- msec_delay(20);
- } else {
- /* Read the Extended Device Control Register, assert the
- * PHY_RESET_DIR bit. Then clock it out to the PHY.
- */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
-
- /* Set the reset bit in the device control register and clock
- * it out to the PHY.
- */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
-
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg |= E1000_CTRL_PHY_RESET4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
- }
- return;
-}
-
-/******************************************************************************
-* Resets the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Sets bit 15 of the MII Control regiser
-******************************************************************************/
-boolean_t
-e1000_phy_reset(struct e1000_shared_adapter *shared)
-{
- uint16_t reg_data;
- uint16_t i;
-
- DEBUGFUNC("e1000_phy_reset");
-
- /* Read the MII control register, set the reset bit and write the
- * value back by clocking it out to the PHY.
- */
- reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
-
- reg_data |= MII_CR_RESET;
-
- e1000_write_phy_reg(shared, PHY_CTRL, reg_data);
-
- /* Wait for bit 15 of the MII Control Register to be cleared
- * indicating the PHY has been reset.
- */
- i = 0;
- while((reg_data & MII_CR_RESET) && i++ < 500) {
- reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
- usec_delay(1);
- }
-
- if(i >= 500) {
- DEBUGOUT("Timeout waiting for PHY to reset.\n");
- return FALSE;
- }
- return TRUE;
-}
-
-/******************************************************************************
-* Detects which PHY is present and the speed and duplex
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - current value of the device control register
-******************************************************************************/
-boolean_t
-e1000_phy_setup(struct e1000_shared_adapter *shared,
- uint32_t ctrl_reg)
-{
- uint16_t mii_ctrl_reg;
- uint16_t mii_status_reg;
- uint16_t phy_specific_ctrl_reg;
- uint16_t mii_autoneg_adv_reg;
- uint16_t mii_1000t_ctrl_reg;
- uint16_t i;
- uint16_t data;
- uint16_t autoneg_hw_setting;
- uint16_t autoneg_fc_setting;
- boolean_t restart_autoneg = FALSE;
- boolean_t force_autoneg_restart = FALSE;
-
- DEBUGFUNC("e1000_phy_setup");
-
- /* We want to enable the Auto-Speed Detection bit in the Device
- * Control Register. When set to 1, the MAC automatically detects
- * the resolved speed of the link and self-configures appropriately.
- * The Set Link Up bit must also be set for this behavior work
- * properly.
- */
- /* Nothing but 82543 and newer */
- ASSERT(shared->mac_type >= e1000_82543);
-
- /* With 82543, we need to force speed/duplex
- * on the MAC equal to what the PHY speed/duplex configuration is.
- * In addition, on 82543, we need to perform a hardware reset
- * on the PHY to take it out of reset.
- */
- if(shared->mac_type >= e1000_82544) {
- ctrl_reg |= E1000_CTRL_SLU;
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
- } else {
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- if(shared->mac_type == e1000_82543)
- e1000_phy_hw_reset(shared);
- }
-
- if(!e1000_detect_gig_phy(shared)) {
- /* No PHY detected, return FALSE */
- DEBUGOUT("PhySetup failure, did not detect valid phy.\n");
- return (FALSE);
- }
-
- DEBUGOUT1("Phy ID = %x \n", shared->phy_id);
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg);
-
- /* Check to see if the Auto Neg Enable bit is set in the MII Control
- * Register. If not, we could be in a situation where a driver was
- * loaded previously and was forcing speed and duplex. Then the
- * driver was unloaded but a e1000_phy_hw_reset was not performed, so
- * link was still being forced and link was still achieved. Then
- * the driver was reloaded with the intention to auto-negotiate, but
- * since link is already established we end up not restarting
- * auto-neg. So if the auto-neg bit is not enabled and the driver
- * is being loaded with the desire to auto-neg, we set this flag to
- * to ensure the restart of the auto-neg engine later in the logic.
- */
- if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN))
- force_autoneg_restart = TRUE;
-
- /* Clear the isolate bit for normal operation and write it back to
- * the MII Control Reg. Although the spec says this doesn't need
- * to be done when the PHY address is not equal to zero, we do it
- * anyway just to be safe.
- */
- mii_ctrl_reg &= ~(MII_CR_ISOLATE);
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- /* Enable CRS on TX. This must be set for half-duplex operation. */
- data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
- DEBUGOUT1("M88E1000 PSCR: %x \n", data);
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data);
-
- data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
- /* Force TX_CLK in the Extended PHY Specific Control Register
- * to 25MHz clock.
- */
- data |= M88E1000_EPSCR_TX_CLK_25;
-
- e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data);
-
- /* Certain PHYs will set the default of MII register 4 differently.
- * We need to check this against our fc value. If it is
- * different, we need to setup up register 4 correctly and restart
- * autonegotiation.
- */
- /* Read the MII Auto-Neg Advertisement Register (Address 4). */
- mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
- /* Shift right to put 10T-Half bit in bit 0
- * Isolate the four bits for 100/10 Full/Half.
- */
- autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF;
-
- /* Get the 1000T settings. */
- mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
- /* Isolate and OR in the 1000T settings. */
- autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4);
-
- /* mask all bits in the MII Auto-Neg Advertisement Register
- * except for ASM_DIR and PAUSE and shift. This value
- * will be used later to see if we need to restart Auto-Negotiation.
- */
- autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10);
-
- /* Perform some bounds checking on the shared->autoneg_advertised
- * parameter. If this variable is zero, then set it to the default.
- */
- shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
- /* If autoneg_advertised is zero, we assume it was not defaulted
- * by the calling code so we set to advertise full capability.
- */
- if(shared->autoneg_advertised == 0)
- shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
- /* We could be in the situation where Auto-Neg has already completed
- * and the user has not indicated any overrides. In this case we
- * simply need to call e1000_get_speed_and_duplex to obtain the Auto-
- * Negotiated speed and duplex, then return.
- */
- if(!force_autoneg_restart && shared->autoneg &&
- (shared->autoneg_advertised == autoneg_hw_setting) &&
- (shared->fc == autoneg_fc_setting)) {
-
- DEBUGOUT("No overrides - Reading MII Status Reg..\n");
-
- /* Read the MII Status Register. We read this twice because
- * certain bits are "sticky" and need to be read twice.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg);
-
- /* Do we have link now? (if so, auto-neg has completed) */
- if(mii_status_reg & MII_SR_LINK_STATUS) {
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
- /* We have link, so we need to finish the config process:
- * 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
- * 2) Set up flow control on the MAC to that established
- * with the link partner.
- */
- if(shared->mac_type >= e1000_82544)
- e1000_config_collision_dist(shared);
- else
- e1000_config_mac_to_phy(shared, data);
-
- e1000_config_fc_after_link_up(shared);
-
- return (TRUE);
- }
- }
-
- /* Options:
- * MDI/MDI-X = 0 (default)
- * 0 - Auto for all speeds
- * 1 - MDI mode
- * 2 - MDI-X mode
- * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
- */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
-
- switch (shared->mdix) {
- case 1:
- phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE;
- break;
- case 2:
- phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE;
- break;
- case 3:
- phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T;
- break;
- case 0:
- default:
- phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE;
- break;
- }
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
- /* Options:
- * disable_polarity_correction = 0 (default)
- * Automatic Correction for Reversed Cable Polarity
- * 0 - Disabled
- * 1 - Enabled
- */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-
- if(shared->disable_polarity_correction == 1)
- phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
- /* Options:
- * autoneg = 1 (default)
- * PHY will advertise value(s) parsed from
- * autoneg_advertised and fc
- * autoneg = 0
- * PHY will be set to 10H, 10F, 100H, or 100F
- * depending on value parsed from forced_speed_duplex.
- */
-
- /* Is autoneg enabled? This is enabled by default or by software override.
- * If so, call e1000_phy_setup_autoneg routine to parse the
- * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
- * user should have provided a speed/duplex override. If so, then call
- * e1000_phy_force_speed_duplex to parse and set this up. Otherwise,
- * we are in an error situation and need to bail.
- */
- if(shared->autoneg) {
- DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
- restart_autoneg = e1000_phy_setup_autoneg(shared);
- } else {
- DEBUGOUT("Forcing speed and duplex\n");
- e1000_phy_force_speed_duplex(shared);
- }
-
- /* Based on information parsed above, check the flag to indicate
- * whether we need to restart Auto-Neg.
- */
- if(restart_autoneg) {
- DEBUGOUT("Restarting Auto-Neg\n");
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- /* Restart auto-negotiation by setting the Auto Neg Enable bit and
- * the Auto Neg Restart bit.
- */
- mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- /* Does the user want to wait for Auto-Neg to complete here, or
- * check at a later time (for example, callback routine).
- */
- if(shared->wait_autoneg_complete)
- e1000_wait_autoneg(shared);
- } /* end if restart_autoneg */
-
- /* Read the MII Status Register. */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n",
- mii_status_reg);
-
- /* Check link status. Wait up to 100 microseconds for link to
- * become valid.
- */
- for(i = 0; i < 10; i++) {
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
- usec_delay(10);
- DEBUGOUT(". ");
-
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- }
-
- if(mii_status_reg & MII_SR_LINK_STATUS) {
- /* Yes, so configure MAC to PHY settings as well as flow control
- * registers.
- */
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
- /* We have link, so we need to finish the config process:
- * 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
- * 2) Set up flow control on the MAC to that established with
- * the link partner.
- */
- if(shared->mac_type >= e1000_82544)
- e1000_config_collision_dist(shared);
- else
- e1000_config_mac_to_phy(shared, data);
-
- e1000_config_fc_after_link_up(shared);
-
- DEBUGOUT("Valid link established!!!\n");
- } else {
- DEBUGOUT("Unable to establish link!!!\n");
- }
-
- return (TRUE);
-}
-
-/******************************************************************************
-* Configures PHY autoneg and flow control advertisement settings
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared)
-{
- uint16_t mii_autoneg_adv_reg;
- uint16_t mii_1000t_ctrl_reg;
-
- DEBUGFUNC("e1000_phy_setup_autoneg");
-
- /* Read the MII Auto-Neg Advertisement Register (Address 4). */
- mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
- /* Read the MII 1000Base-T Control Register (Address 9). */
- mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
- /* Need to parse both autoneg_advertised and fc and set up
- * the appropriate PHY registers. First we will parse for
- * autoneg_advertised software override. Since we can advertise
- * a plethora of combinations, we need to check each bit
- * individually.
- */
-
- /* First we clear all the 10/100 mb speed bits in the Auto-Neg
- * Advertisement Register (Address 4) and the 1000 mb speed bits in
- * the 1000Base-T Control Register (Address 9).
- */
- mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
- mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
-
- DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised);
-
- /* Do we want to advertise 10 Mb Half Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_10_HALF) {
- DEBUGOUT("Advertise 10mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
- }
-
- /* Do we want to advertise 10 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_10_FULL) {
- DEBUGOUT("Advertise 10mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
- }
-
- /* Do we want to advertise 100 Mb Half Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_100_HALF) {
- DEBUGOUT("Advertise 100mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
- }
-
- /* Do we want to advertise 100 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_100_FULL) {
- DEBUGOUT("Advertise 100mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
- }
-
- /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
- if(shared->autoneg_advertised & ADVERTISE_1000_HALF) {
- DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
- }
-
- /* Do we want to advertise 1000 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_1000_FULL) {
- DEBUGOUT("Advertise 1000mb Full duplex\n");
- mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
- }
-
- /* Check for a software override of the flow control settings, and
- * setup the PHY advertisement registers accordingly. If
- * auto-negotiation is enabled, then software will have to set the
- * "PAUSE" bits to the correct value in the Auto-Negotiation
- * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames
- * but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * but we do not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
- * other: No software override. The flow control configuration
- * in the EEPROM is used.
- */
- switch (shared->fc) {
- case e1000_fc_none: /* 0 */
- /* Flow control (RX & TX) is completely disabled by a
- * software over-ride.
- */
- mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- case e1000_fc_rx_pause: /* 1 */
- /* RX Flow control is enabled, and TX Flow control is
- * disabled, by a software over-ride.
- */
-
- /* Since there really isn't a way to advertise that we are
- * capable of RX Pause ONLY, we will advertise that we
- * support both symmetric and asymmetric RX PAUSE. Later
- * (in e1000_config_fc_after_link_up) we will disable the
- *shared's ability to send PAUSE frames.
- */
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- case e1000_fc_tx_pause: /* 2 */
- /* TX Flow control is enabled, and RX Flow control is
- * disabled, by a software over-ride.
- */
- mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
- mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
- break;
- case e1000_fc_full: /* 3 */
- /* Flow control (both RX and TX) is enabled by a software
- * over-ride.
- */
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- default:
- /* We should never get here. The value should be 0-3. */
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Write the MII Auto-Neg Advertisement Register (Address 4). */
- e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-
- DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
- /* Write the MII 1000Base-T Control Register (Address 9). */
- e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- return (TRUE);
-}
-
-/******************************************************************************
-* Sets MAC speed and duplex settings to reflect the those in the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* mii_reg - data to write to the MII control register
-*
-* The contents of the PHY register containing the needed information need to
-* be passed in.
-******************************************************************************/
-void
-e1000_config_mac_to_phy(struct e1000_shared_adapter *shared,
- uint16_t mii_reg)
-{
- uint32_t ctrl_reg;
- uint32_t tctl_reg;
- uint32_t shift;
-
- DEBUGFUNC("e1000_config_mac_to_phy");
-
- /* We need to read the Transmit Control register to configure the
- * collision distance.
- * Note: This must be done for both Half or Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- /* Read the Device Control Register and set the bits to Force Speed
- * and Duplex.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
- ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
- DEBUGOUT1("MII Register Data = %x\r\n", mii_reg);
-
- /* Clear the ILOS bit. */
- ctrl_reg &= ~E1000_CTRL_ILOS;
-
- /* Set up duplex in the Device Control and Transmit Control
- * registers depending on negotiated values.
- */
- if(mii_reg & M88E1000_PSSR_DPLX) {
- ctrl_reg |= E1000_CTRL_FD;
-
- /* We are in Full Duplex mode. We have the same collision
- * distance regardless of speed.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- ctrl_reg &= ~E1000_CTRL_FD;
-
- /* We are in Half Duplex mode. Our Half Duplex collision
- * distance is different for Gigabit than for 10/100 so we will
- * set accordingly.
- */
- if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
- /* 1000Mbs HDX */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_GB_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
- } else {
- /* 10/100Mbs HDX */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
- }
-
- /* Set up speed in the Device Control register depending on
- * negotiated values.
- */
- if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
- ctrl_reg |= E1000_CTRL_SPD_1000;
- else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
- ctrl_reg |= E1000_CTRL_SPD_100;
- else
- ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Write the configured values back to the Device Control Reg. */
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- return;
-}
-
-/******************************************************************************
-* Sets the collision distance in the Transmit Control register
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Link should have been established previously. Reads the speed and duplex
-* information from the Device Status register.
-******************************************************************************/
-void
-e1000_config_collision_dist(struct e1000_shared_adapter *shared)
-{
- uint32_t tctl_reg;
- uint16_t speed;
- uint16_t duplex;
- uint32_t shift;
-
- DEBUGFUNC("e1000_config_collision_dist");
-
- /* Get our current speed and duplex from the Device Status Register. */
- e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
- /* We need to configure the Collision Distance for both Full or
- * Half Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- /* mask the Collision Distance bits in the Transmit Control Reg. */
- tctl_reg &= ~E1000_TCTL_COLD;
-
- if(duplex == FULL_DUPLEX) {
- /* We are in Full Duplex mode. Therefore, the collision distance
- * is the same regardless of speed.
- */
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- /* We are in Half Duplex mode. Half Duplex collision distance is
- * different for Gigabit vs. 10/100, so we will set accordingly.
- */
- if(speed == SPEED_1000) { /* 1000Mbs HDX */
- shift = E1000_GB_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
- } else { /* 10/100Mbs HDX */
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
- }
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- return;
-}
-
-/******************************************************************************
-* Probes the expected PHY address for known PHY IDs
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_detect_gig_phy(struct e1000_shared_adapter *shared)
-{
- uint32_t phy_id_high;
- uint16_t phy_id_low;
-
- DEBUGFUNC("e1000_detect_gig_phy");
-
- /* Read the PHY ID Registers to identify which PHY is onboard. */
- shared->phy_addr = 1;
-
- phy_id_high = e1000_read_phy_reg(shared, PHY_ID1);
-
- usec_delay(2);
-
- phy_id_low = e1000_read_phy_reg(shared, PHY_ID2);
-
- shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK;
-
- if(shared->phy_id == M88E1000_12_PHY_ID ||
- shared->phy_id == M88E1000_14_PHY_ID ||
- shared->phy_id == M88E1000_I_PHY_ID) {
-
- DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n",
- shared->phy_id, shared->phy_addr);
- return (TRUE);
- } else {
- DEBUGOUT("Could not auto-detect Phy!\n");
- return (FALSE);
- }
-}
-
-/******************************************************************************
-* Resets the PHY's DSP
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_reset_dsp(struct e1000_shared_adapter *shared)
-{
- e1000_write_phy_reg(shared, 29, 0x1d);
- e1000_write_phy_reg(shared, 30, 0xc1);
- e1000_write_phy_reg(shared, 30, 0x00);
- return;
-}
-
-/******************************************************************************
-* Blocks until autoneg completes or times out (~4.5 seconds)
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_wait_autoneg(struct e1000_shared_adapter *shared)
-{
- uint16_t i;
- uint16_t mii_status_reg;
- boolean_t autoneg_complete = FALSE;
-
- DEBUGFUNC("e1000_wait_autoneg");
-
- /* We will wait for autoneg to complete. */
- DEBUGOUT("Waiting for Auto-Neg to complete.\n");
- mii_status_reg = 0;
-
- /* We will wait for autoneg to complete or 4.5 seconds to expire. */
-
- for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
- autoneg_complete = TRUE;
- break;
- }
-
- msec_delay(100);
- }
-
- return (autoneg_complete);
-}
-
-/******************************************************************************
-* Get PHY information from various PHY registers
-*
-* shared - Struct containing variables accessed by shared code
-* phy_status_info - PHY information structure
-******************************************************************************/
-boolean_t
-e1000_phy_get_info(struct e1000_shared_adapter *shared,
- struct e1000_phy_info *phy_status_info)
-{
- uint16_t phy_mii_status_reg;
- uint16_t phy_specific_ctrl_reg;
- uint16_t phy_specific_status_reg;
- uint16_t phy_specific_ext_ctrl_reg;
- uint16_t phy_1000t_stat_reg;
-
- phy_status_info->cable_length = e1000_cable_length_undefined;
- phy_status_info->extended_10bt_distance =
- e1000_10bt_ext_dist_enable_undefined;
- phy_status_info->cable_polarity = e1000_rev_polarity_undefined;
- phy_status_info->polarity_correction = e1000_polarity_reversal_undefined;
- phy_status_info->link_reset = e1000_down_no_idle_undefined;
- phy_status_info->mdix_mode = e1000_auto_x_mode_undefined;
- phy_status_info->local_rx = e1000_1000t_rx_status_undefined;
- phy_status_info->remote_rx = e1000_1000t_rx_status_undefined;
-
- /* PHY info only valid for copper media. */
- if(shared == NULL || shared->media_type != e1000_media_type_copper)
- return FALSE;
-
- /* PHY info only valid for LINK UP. Read MII status reg
- * back-to-back to get link status.
- */
- phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
- return FALSE;
-
- /* Read various PHY registers to get the PHY info. */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
- phy_specific_status_reg =
- e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- phy_specific_ext_ctrl_reg =
- e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
- phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS);
-
- phy_status_info->cable_length =
- ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT);
-
- phy_status_info->extended_10bt_distance =
- (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
- M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
-
- phy_status_info->cable_polarity =
- (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >>
- M88E1000_PSSR_REV_POLARITY_SHIFT;
-
- phy_status_info->polarity_correction =
- (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >>
- M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
-
- phy_status_info->link_reset =
- (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >>
- M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT;
-
- phy_status_info->mdix_mode =
- (phy_specific_status_reg & M88E1000_PSSR_MDIX) >>
- M88E1000_PSSR_MDIX_SHIFT;
-
- phy_status_info->local_rx =
- (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT;
-
- phy_status_info->remote_rx =
- (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT;
-
- return TRUE;
-}
-
-boolean_t
-e1000_validate_mdi_setting(struct e1000_shared_adapter *shared)
-{
- if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) {
- shared->mdix = 1;
- return FALSE;
- }
- return TRUE;
-}
diff --git a/drivers/net/e1000/e1000_phy.h b/drivers/net/e1000/e1000_phy.h
deleted file mode 100644
index 2232583cec04..000000000000
--- a/drivers/net/e1000/e1000_phy.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_phy.h
- * Structures, enums, and macros for the PHY
- */
-
-#ifndef _E1000_PHY_H_
-#define _E1000_PHY_H_
-
-#include "e1000_osdep.h"
-
-/* PHY status info structure and supporting enums */
-typedef enum {
- e1000_cable_length_50 = 0,
- e1000_cable_length_50_80,
- e1000_cable_length_80_110,
- e1000_cable_length_110_140,
- e1000_cable_length_140,
- e1000_cable_length_undefined = 0xFF
-} e1000_cable_length;
-
-typedef enum {
- e1000_10bt_ext_dist_enable_normal = 0,
- e1000_10bt_ext_dist_enable_lower,
- e1000_10bt_ext_dist_enable_undefined = 0xFF
-} e1000_10bt_ext_dist_enable;
-
-typedef enum {
- e1000_rev_polarity_normal = 0,
- e1000_rev_polarity_reversed,
- e1000_rev_polarity_undefined = 0xFF
-} e1000_rev_polarity;
-
-typedef enum {
- e1000_polarity_reversal_enabled = 0,
- e1000_polarity_reversal_disabled,
- e1000_polarity_reversal_undefined = 0xFF
-} e1000_polarity_reversal;
-
-typedef enum {
- e1000_down_no_idle_no_detect = 0,
- e1000_down_no_idle_detect,
- e1000_down_no_idle_undefined = 0xFF
-} e1000_down_no_idle;
-
-typedef enum {
- e1000_auto_x_mode_manual_mdi = 0,
- e1000_auto_x_mode_manual_mdix,
- e1000_auto_x_mode_auto1,
- e1000_auto_x_mode_auto2,
- e1000_auto_x_mode_undefined = 0xFF
-} e1000_auto_x_mode;
-
-typedef enum {
- e1000_1000t_rx_status_not_ok = 0,
- e1000_1000t_rx_status_ok,
- e1000_1000t_rx_status_undefined = 0xFF
-} e1000_1000t_rx_status;
-
-struct e1000_phy_info {
- e1000_cable_length cable_length;
- e1000_10bt_ext_dist_enable extended_10bt_distance;
- e1000_rev_polarity cable_polarity;
- e1000_polarity_reversal polarity_correction;
- e1000_down_no_idle link_reset;
- e1000_auto_x_mode mdix_mode;
- e1000_1000t_rx_status local_rx;
- e1000_1000t_rx_status remote_rx;
-};
-
-struct e1000_phy_stats {
- uint32_t idle_errors;
- uint32_t receive_errors;
-};
-
-/* Function Prototypes */
-uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr);
-void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data);
-void e1000_phy_hw_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg);
-boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared);
-void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg);
-void e1000_config_collision_dist(struct e1000_shared_adapter *shared);
-boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared);
-void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared);
-boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info);
-boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared);
-
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CTRL 0x00 /* Control Register */
-#define PHY_STATUS 0x01 /* Status Regiser */
-#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
-
-#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
-#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
-#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN 0x0800 /* Power down */
-#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
-#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
-#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
-#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */
-
-/* Next Page TX Register */
-#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
- * of different NP
- */
-#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
- * 0 = cannot comply with msg
- */
-#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
-#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
- * 0 = sending last NP
- */
-
-/* Link Partner Next Page Register */
-#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
- * of different NP
- */
-#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
- * 0 = cannot comply with msg
- */
-#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
-#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
-#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
- * 0 = sending last NP
- */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
-#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
- /* 0=DTE device */
-#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
- /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
- /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
-#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
-#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
-
-/* Extended Status Register */
-#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
-#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
-#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
-#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
-
-#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
-#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
-
-#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
- /* (0=enable, 1=disable) */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
-#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
-#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
- * 0=CLK125 toggling
- */
-#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
- /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
-#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
- * 100BASE-TX/10BASE-T:
- * MDI Mode
- */
-#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
- * all speeds.
- */
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
- /* 1=Enable Extended 10BASE-T distance
- * (Lower 10BASE-T RX Threshold)
- * 0=Normal 10BASE-T RX Threshold */
-#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
- /* 1=5-Bit interface in 100BASE-TX
- * 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
-
-#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
-#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
-#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
- * 3=110-140M;4=>140M */
-#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
-#define M88E1000_PSSR_MDIX_SHIFT 6
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
- * Will assert lost lock and bring
- * link down if idle not seen
- * within 1ms in 1000BASE-T
- */
-#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
-
-#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15
-
-/* Bit definitions for valid PHY IDs. */
-#define M88E1000_12_PHY_ID 0x01410C50
-#define M88E1000_14_PHY_ID 0x01410C40
-#define M88E1000_I_PHY_ID 0x01410C30
-
-/* Miscellaneous PHY bit definitions. */
-#define PHY_PREAMBLE 0xFFFFFFFF
-#define PHY_SOF 0x01
-#define PHY_OP_READ 0x02
-#define PHY_OP_WRITE 0x01
-#define PHY_TURNAROUND 0x02
-#define PHY_PREAMBLE_SIZE 32
-#define MII_CR_SPEED_1000 0x0040
-#define MII_CR_SPEED_100 0x2000
-#define MII_CR_SPEED_10 0x0000
-#define E1000_PHY_ADDRESS 0x01
-#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
-#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
-#define PHY_REVISION_MASK 0xFFFFFFF0
-#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
-#define REG4_SPEED_MASK 0x01E0
-#define REG9_SPEED_MASK 0x0300
-#define ADVERTISE_10_HALF 0x0001
-#define ADVERTISE_10_FULL 0x0002
-#define ADVERTISE_100_HALF 0x0004
-#define ADVERTISE_100_FULL 0x0008
-#define ADVERTISE_1000_HALF 0x0010
-#define ADVERTISE_1000_FULL 0x0020
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
-
-#endif /* _E1000_PHY_H_ */
diff --git a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c
index f497f0de1b6a..620638eb47c7 100644
--- a/drivers/net/e1000/e1000_proc.c
+++ b/drivers/net/e1000/e1000_proc.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -96,7 +95,9 @@
#include <linux/proc_fs.h>
#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
-#define TAG_MAX_LENGTH 36
+#define TAG_MAX_LENGTH 32
+#define LINE_MAX_LENGTH 80
+#define FIELD_MAX_LENGTH LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
extern char e1000_driver_name[];
extern char e1000_driver_version[];
@@ -110,7 +111,7 @@ extern char e1000_driver_version[];
struct proc_list {
struct list_head list; /* link list */
- char tag[TAG_MAX_LENGTH]; /* attribute name */
+ char tag[TAG_MAX_LENGTH + 1]; /* attribute name */
void *data; /* attribute data */
size_t len; /* sizeof data */
char *(*func)(void *, size_t, char *); /* format data func */
@@ -142,15 +143,20 @@ e1000_proc_info_read(char *page, char **start, off_t off,
struct list_head *proc_list_head = data, *curr;
struct proc_list *elem;
char *p = page;
- char buf[64];
+ char buf[FIELD_MAX_LENGTH + 1];
list_for_each(curr, proc_list_head) {
elem = list_entry(curr, struct proc_list, list);
- if(strlen(elem->tag) == 0)
+ if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
+ break;
+
+ if(!strlen(elem->tag))
p += sprintf(p, "\n");
else
- p += sprintf(p, "%-32s %s\n", elem->tag,
+ p += sprintf(p, "%-*.*s %.*s\n",
+ TAG_MAX_LENGTH, TAG_MAX_LENGTH,
+ elem->tag, FIELD_MAX_LENGTH,
elem->func(elem->data, elem->len, buf));
}
@@ -165,7 +171,8 @@ e1000_proc_single_read(char *page, char **start, off_t off,
{
struct proc_list *elem = data;
- sprintf(page, "%s", elem->func(elem->data, elem->len, page));
+ sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data,
+ elem->len, page));
return e1000_proc_read(page, start, off, count, eof);
}
@@ -179,8 +186,7 @@ e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
- (memcmp(intel_proc_dir->name,
- ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+ !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
@@ -224,8 +230,6 @@ e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
if(!proc_dir)
remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-
- return;
}
@@ -241,7 +245,7 @@ e1000_proc_singles_create(struct proc_dir_entry *parent,
elem = list_entry(curr, struct proc_list, list);
- if(strlen(elem->tag) == 0)
+ if(!strlen(elem->tag))
continue;
if(!(proc_entry =
@@ -256,8 +260,9 @@ e1000_proc_singles_create(struct proc_dir_entry *parent,
return 1;
}
-static int __devinit
-e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
+static void __devinit
+e1000_proc_dirs_create(void *data, char *name,
+ struct list_head *proc_list_head)
{
struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
char info_name[strlen(name) + strlen(".info")];
@@ -265,8 +270,7 @@ e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
- (memcmp(intel_proc_dir->name,
- ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+ !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
@@ -274,28 +278,26 @@ e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
if(!(intel_proc_dir =
create_proc_entry(ADAPTERS_PROC_DIR,
S_IFDIR, proc_net)))
- return 0;
+ return;
if(!(proc_dir =
create_proc_entry(name, S_IFDIR, intel_proc_dir)))
- return 0;
+ return;
SET_MODULE_OWNER(proc_dir);
if(!e1000_proc_singles_create(proc_dir, proc_list_head))
- return 0;
+ return;
strcpy(info_name, name);
strcat(info_name, ".info");
if(!(info_entry =
create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
- return 0;
+ return;
SET_MODULE_OWNER(info_entry);
info_entry->read_proc = e1000_proc_info_read;
info_entry->data = proc_list_head;
-
- return 1;
}
static void __devinit
@@ -315,8 +317,6 @@ e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
new->func = func;
list_add_tail(&new->list, proc_list_head);
-
- return;
}
static void __devexit
@@ -329,8 +329,6 @@ e1000_proc_list_free(struct list_head *proc_list_head)
list_del(&elem->list);
kfree(elem);
}
-
- return;
}
/*
@@ -491,7 +489,7 @@ e1000_proc_media_type(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf,
- adapter->shared.media_type == e1000_media_type_copper ?
+ adapter->hw.media_type == e1000_media_type_copper ?
"Copper" : "Fiber");
return buf;
}
@@ -547,18 +545,6 @@ e1000_proc_polarity_correction(void *data, size_t len, char *buf)
sprintf(buf,
correction == e1000_polarity_reversal_enabled ? "Disabled" :
correction == e1000_polarity_reversal_disabled ? "Enabled" :
- "Undefined");
- return buf;
-}
-
-static char *
-e1000_proc_link_reset_enabled(void *data, size_t len, char *buf)
-{
- struct e1000_adapter *adapter = data;
- e1000_down_no_idle link_reset = adapter->phy_info.link_reset;
- sprintf(buf,
- link_reset == e1000_down_no_idle_no_detect ? "Disabled" :
- link_reset == e1000_down_no_idle_detect ? "Enabled" :
"Unknown");
return buf;
}
@@ -568,7 +554,10 @@ e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
- sprintf(buf, mdix_mode == 0 ? "MDI" : "MDI-X");
+ sprintf(buf,
+ mdix_mode == e1000_auto_x_mode_manual_mdi ? "MDI" :
+ mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
+ "Unknown");
return buf;
}
@@ -601,7 +590,7 @@ e1000_proc_rx_status(void *data, size_t len, char *buf)
static void __devinit
e1000_proc_list_setup(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct list_head *proc_list_head = &adapter->proc_list_head;
INIT_LIST_HEAD(proc_list_head);
@@ -610,21 +599,21 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
LIST_ADD_S("Driver_Name", e1000_driver_name);
LIST_ADD_S("Driver_Version", e1000_driver_version);
- LIST_ADD_H("PCI_Vendor", &shared->vendor_id);
- LIST_ADD_H("PCI_Device_ID", &shared->device_id);
- LIST_ADD_H("PCI_Subsystem_Vendor", &shared->subsystem_vendor_id);
- LIST_ADD_H("PCI_Subsystem_ID", &shared->subsystem_id);
- LIST_ADD_H("PCI_Revision_ID", &shared->revision_id);
+ LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
+ LIST_ADD_H("PCI_Device_ID", &hw->device_id);
+ LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
+ LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
+ LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
- if(adapter->shared.mac_type >= e1000_82543) {
+ if(adapter->hw.mac_type >= e1000_82543) {
LIST_ADD_F("PCI_Bus_Type",
- &shared->bus_type, e1000_proc_bus_type);
+ &hw->bus_type, e1000_proc_bus_type);
LIST_ADD_F("PCI_Bus_Speed",
- &shared->bus_speed, e1000_proc_bus_speed);
+ &hw->bus_speed, e1000_proc_bus_speed);
LIST_ADD_F("PCI_Bus_Width",
- &shared->bus_width, e1000_proc_bus_width);
+ &hw->bus_width, e1000_proc_bus_width);
}
LIST_ADD_U("IRQ", &adapter->pdev->irq);
@@ -632,7 +621,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_F("Current_HWaddr",
adapter->netdev->dev_addr, e1000_proc_hwaddr);
LIST_ADD_F("Permanent_HWaddr",
- adapter->shared.perm_mac_addr, e1000_proc_hwaddr);
+ adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
LIST_ADD_BLANK();
@@ -679,7 +668,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
/* The 82542 does not have an alignment error count register */
- if(adapter->shared.mac_type >= e1000_82543)
+ if(adapter->hw.mac_type >= e1000_82543)
LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
@@ -693,7 +682,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
/* Cable diags */
LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
- if(adapter->shared.media_type == e1000_media_type_copper) {
+ if(adapter->hw.media_type == e1000_media_type_copper) {
LIST_ADD_F("PHY_Cable_Length",
adapter, e1000_proc_cable_length);
LIST_ADD_F("PHY_Extended_10Base_T_Distance",
@@ -704,8 +693,6 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
adapter, e1000_proc_polarity_correction);
LIST_ADD_U("PHY_Idle_Errors",
&adapter->phy_stats.idle_errors);
- LIST_ADD_F("PHY_Link_Reset_Enabled",
- adapter, e1000_proc_link_reset_enabled);
LIST_ADD_U("PHY_Receive_Errors",
&adapter->phy_stats.receive_errors);
LIST_ADD_F("PHY_MDI_X_Enabled",
@@ -718,7 +705,6 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
e1000_proc_rx_status);
}
- return;
}
/*
@@ -731,9 +717,9 @@ e1000_proc_dev_setup(struct e1000_adapter *adapter)
{
e1000_proc_list_setup(adapter);
- e1000_proc_dirs_create(adapter->netdev->name,&adapter->proc_list_head);
-
- return;
+ e1000_proc_dirs_create(adapter,
+ adapter->netdev->name,
+ &adapter->proc_list_head);
}
/*
@@ -747,8 +733,6 @@ e1000_proc_dev_free(struct e1000_adapter *adapter)
e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head);
e1000_proc_list_free(&adapter->proc_list_head);
-
- return;
}
#else /* CONFIG_PROC_FS */
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index bfed15fec876..31493d863982 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -72,7 +72,7 @@ static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
#define E21_SAPROM 0x10 /* Offset to station address data. */
#define E21_IO_EXTENT 0x20
-extern inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, volatile char *mem_base,
unsigned char start_page )
{
/* This is a little weird: set the shared memory window by doing a
@@ -82,7 +82,7 @@ extern inline void mem_on(short port, volatile char *mem_base,
outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
}
-extern inline void mem_off(short port)
+static inline void mem_off(short port)
{
inb(port + E21_MEM_ENABLE);
outb(0x00, port + E21_MEM_ENABLE);
@@ -234,8 +234,8 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr)
#ifdef notdef
/* These values are unused. The E2100 has a 2K window into the packet
buffer. The window can be set to start on any page boundary. */
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
#endif
printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index bc61bd97f6de..e455ac71d802 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1795,6 +1795,7 @@ speedo_rx(struct net_device *dev)
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
+ dev->last_rx = jiffies;
sp->stats.rx_packets++;
sp->stats.rx_bytes += pkt_len;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4f9ad8cf8879..fe20646ddb5e 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -60,11 +60,14 @@
LK1.1.12:
* fix power-up sequence
+ LK1.1.13:
+ * revert version 1.1.12, power-up sequence "fix"
+
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.12"
-#define DRV_RELDATE "Jan 18, 2002"
+#define DRV_VERSION "1.11+LK1.1.13"
+#define DRV_RELDATE "Mar 20, 2002"
/* The user-configurable values.
@@ -678,8 +681,9 @@ static int epic_open(struct net_device *dev)
required by the details of which bits are reset and the transceiver
wiring on the Ositech CardBus card.
*/
-
- outl(0x12, ioaddr + MIICfg);
+#if 0
+ outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+#endif
if (ep->chip_flags & MII_PWRDWN)
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 07ac2b091ee7..fa9ddc648790 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -233,9 +233,9 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
printk(" assigning ");
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (ES_STOP_PG - ES_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
@@ -335,12 +335,12 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
{
unsigned long xfer_start = dev->mem_start + ring_offset - (ES_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index beafabd51e36..26f08dce4b20 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -256,7 +256,7 @@ static void sp_bump(struct sixpack *sp, char cmd)
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
- dev->last_rx = jiffies;
+ sp->dev->last_rx = jiffies;
sp->stats.rx_packets++;
}
@@ -701,7 +701,6 @@ static struct tty_ldisc sp_ldisc = {
/* Initialize 6pack control device -- register 6pack line discipline */
static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
-static char msg_invparm[] __initdata = KERN_ERR "6pack: sixpack_maxdev parameter too large.\n";
static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n";
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index e20dc463f6ab..30598d841821 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -302,7 +302,7 @@ static const unsigned short crc_ccitt_table[] = {
/*---------------------------------------------------------------------------*/
#if 0
-extern inline void append_crc_ccitt(unsigned char *buffer, int len)
+static inline void append_crc_ccitt(unsigned char *buffer, int len)
{
unsigned int crc = 0xffff;
@@ -316,7 +316,7 @@ extern inline void append_crc_ccitt(unsigned char *buffer, int len)
/*---------------------------------------------------------------------------*/
-extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
{
unsigned int crc = 0xffff;
@@ -327,7 +327,7 @@ extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
/*---------------------------------------------------------------------------*/
-extern inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
{
unsigned int crc = 0xffff;
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index c1c3fc6ca023..7fd2a1dc4e59 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -201,12 +201,12 @@ static inline void ser12_set_divisor(struct net_device *dev,
/* --------------------------------------------------------------------- */
#if 0
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -214,7 +214,7 @@ extern inline unsigned int hweight16(unsigned int w)
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 2fcf1ff4af27..9f237af5479b 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1121,6 +1121,7 @@ static void rx_bh(void *arg) {
skb->protocol = ntohs(ETH_P_AX25);
skb->mac.raw = skb->data;
netif_rx(skb);
+ priv->dev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes += cb;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d2e593db080f..4f32863e7da8 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -345,7 +345,7 @@ static void ax_bump(struct ax_disp *ax)
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
- dev->last_rx = jiffies;
+ tmp_ax->dev->last_rx = jiffies;
tmp_ax->rx_packets++;
}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 99c110a6561e..fe404f366022 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1661,7 +1661,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
skb->pkt_type = PACKET_HOST;
netif_rx(skb);
- dev->last_rx = jiffies;
+ scc->dev->last_rx = jiffies;
return;
}
diff --git a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h
index 367b045b8086..25c47f948ba7 100644
--- a/drivers/net/hamradio/soundmodem/sm.h
+++ b/drivers/net/hamradio/soundmodem/sm.h
@@ -158,7 +158,7 @@ extern const char sm_drvinfo[];
* ===================== diagnostics stuff ===============================
*/
-extern inline void diag_trigger(struct sm_state *sm)
+static inline void diag_trigger(struct sm_state *sm)
{
if (sm->diag.ptr < 0)
if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd)
@@ -170,7 +170,7 @@ extern inline void diag_trigger(struct sm_state *sm)
#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1))
#define SHRT_MIN (-SHRT_MAX-1)
-extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
+static inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
{
int val;
@@ -189,7 +189,7 @@ extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
/* --------------------------------------------------------------------- */
-extern inline void diag_add_one(struct sm_state *sm, int val)
+static inline void diag_add_one(struct sm_state *sm, int val)
{
if ((sm->diag.mode != SM_DIAGMODE_INPUT &&
sm->diag.mode != SM_DIAGMODE_DEMOD) ||
@@ -229,14 +229,14 @@ static inline void diag_add_constellation(struct sm_state *sm, int vali, int val
*/
#if 0
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
__attribute__ ((unused));
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
{
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -245,7 +245,7 @@ extern inline unsigned int hweight32(unsigned int w)
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -253,7 +253,7 @@ extern inline unsigned int hweight16(unsigned short w)
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
@@ -262,12 +262,12 @@ extern inline unsigned int hweight8(unsigned char w)
#endif
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
__attribute__ ((unused));
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
__attribute__ ((unused));
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
{
for (;;) {
if (!x)
@@ -281,7 +281,7 @@ extern inline unsigned int gcd(unsigned int x, unsigned int y)
}
}
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
{
return x * y / gcd(x, y);
}
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk1200.c b/drivers/net/hamradio/soundmodem/sm_afsk1200.c
index 64b20a57c591..1463d7fdd577 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk1200.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk1200.c
@@ -94,7 +94,7 @@ static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -111,7 +111,7 @@ extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff,
return sum * sum;
}
-extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -128,7 +128,7 @@ extern __inline__ int convolution8_s16(const short *st, const int *coeff, int cs
return sum * sum;
}
-extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
+static __inline__ int do_filter_1200_u8(const unsigned char *buf)
{
int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
@@ -137,7 +137,7 @@ extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_1200_s16(const short *buf)
+static __inline__ int do_filter_1200_s16(const short *buf)
{
int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
index d217936abdbd..5d9f9ee9971a 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
@@ -104,7 +104,7 @@ static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -127,7 +127,7 @@ extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff
return sum * sum;
}
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -150,7 +150,7 @@ extern __inline__ int convolution14_s16(const short *st, const int *coeff, int c
return sum * sum;
}
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@ extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
index 23d2337464b3..435afee2ecef 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
@@ -104,7 +104,7 @@ static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -127,7 +127,7 @@ extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff
return sum * sum;
}
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -150,7 +150,7 @@ extern __inline__ int convolution14_s16(const short *st, const int *coeff, int c
return sum * sum;
}
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@ extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2666.c b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
index 2aa2972e47d8..81d1fe27921e 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2666.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
@@ -114,7 +114,7 @@ static void modulator_2666_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -134,7 +134,7 @@ extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff
return sum;
}
-extern __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
diff --git a/drivers/net/hamradio/soundmodem/sm_sbc.c b/drivers/net/hamradio/soundmodem/sm_sbc.c
index 85ae47588ef4..a73c74056f51 100644
--- a/drivers/net/hamradio/soundmodem/sm_sbc.c
+++ b/drivers/net/hamradio/soundmodem/sm_sbc.c
@@ -59,7 +59,7 @@
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_READ, from, n);
if (i)
@@ -68,7 +68,7 @@ extern inline int copy_from_user(void *to, const void *from, unsigned long n)
return 0;
}
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_WRITE, to, n);
if (i)
diff --git a/drivers/net/hamradio/soundmodem/sm_wss.c b/drivers/net/hamradio/soundmodem/sm_wss.c
index 6d94d6da4a46..2fba58589f8d 100644
--- a/drivers/net/hamradio/soundmodem/sm_wss.c
+++ b/drivers/net/hamradio/soundmodem/sm_wss.c
@@ -58,7 +58,7 @@
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_READ, from, n);
if (i)
@@ -67,7 +67,7 @@ extern inline int copy_from_user(void *to, const void *from, unsigned long n)
return 0;
}
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_WRITE, to, n);
if (i)
diff --git a/drivers/net/hamradio/soundmodem/smdma.h b/drivers/net/hamradio/soundmodem/smdma.h
index 44e457a7a170..9e48713116ae 100644
--- a/drivers/net/hamradio/soundmodem/smdma.h
+++ b/drivers/net/hamradio/soundmodem/smdma.h
@@ -52,7 +52,7 @@
/*
* returns the number of samples per fragment
*/
-extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
+static __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
{
if (send) {
disable_dma(dmanr);
@@ -79,7 +79,7 @@ extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned
/* --------------------------------------------------------------------- */
-extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
+static __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
unsigned int *curfrag)
{
unsigned int dmaptr, sz, frg, offs;
@@ -120,7 +120,7 @@ extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned i
/* --------------------------------------------------------------------- */
-extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
+static __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
{
unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
@@ -137,7 +137,7 @@ extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag
return 0;
}
-extern __inline__ void dma_transmit(struct sm_state *sm)
+static __inline__ void dma_transmit(struct sm_state *sm)
{
void *p;
@@ -155,13 +155,13 @@ extern __inline__ void dma_transmit(struct sm_state *sm)
}
}
-extern __inline__ void dma_init_transmit(struct sm_state *sm)
+static __inline__ void dma_init_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
sm->dma.ptt_cnt = 0;
}
-extern __inline__ void dma_start_transmit(struct sm_state *sm)
+static __inline__ void dma_start_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
if (sm->dma.o16bit) {
@@ -174,7 +174,7 @@ extern __inline__ void dma_start_transmit(struct sm_state *sm)
sm->dma.ptt_cnt = 1;
}
-extern __inline__ void dma_clear_transmit(struct sm_state *sm)
+static __inline__ void dma_clear_transmit(struct sm_state *sm)
{
sm->dma.ptt_cnt = 0;
memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
@@ -182,7 +182,7 @@ extern __inline__ void dma_clear_transmit(struct sm_state *sm)
/* --------------------------------------------------------------------- */
-extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
+static __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
{
void *p;
@@ -205,7 +205,7 @@ extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
}
}
-extern __inline__ void dma_init_receive(struct sm_state *sm)
+static __inline__ void dma_init_receive(struct sm_state *sm)
{
sm->dma.ifragptr = 0;
}
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 7e175b3a5138..d74a43f3ce20 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -308,7 +308,8 @@ static const unsigned char chktabh[256] =
static void delay(int ms)
{
unsigned long timeout = jiffies + ((ms * HZ) / 1000);
- while (jiffies < timeout);
+ while (time_before(jiffies, timeout))
+ cpu_relax();
}
/*
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 330407a31839..0e05ee7803a4 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -230,8 +230,8 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
ei_status.block_output = &hpp_mem_block_output;
ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
dev->mem_start = mem_start;
- dev->rmem_start = dev->mem_start + TX_2X_PAGES*256;
- dev->mem_end = dev->rmem_end
+ ei_status.rmem_start = dev->mem_start + TX_2X_PAGES*256;
+ dev->mem_end = ei_status.rmem_end
= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
}
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 6a06d6a7195b..1c6a1de329a4 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -598,6 +598,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
sa1100_irda_rx_alloc(si);
netif_rx(skb);
+ dev->last_rx = jiffies;
} else {
/*
* Remap the buffer.
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 771ab0c30533..03e504fa4b5b 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -383,7 +383,7 @@ int __init lance_probe(struct net_device *dev)
return 0;
}
}
- release_resource(r);
+ release_region(ioaddr, LANCE_TOTAL_SIZE);
}
}
return -ENODEV;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 0866d905c37b..c18997bbfcc7 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -247,9 +247,9 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
LNE390_STOP_PG/4, dev->mem_start);
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (LNE390_STOP_PG - LNE390_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* The 8390 offset is zero for the LNE390 */
dev->base_addr = ioaddr;
@@ -334,12 +334,12 @@ static void lne390_block_input(struct net_device *dev, int count, struct sk_buff
{
unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_memcpy_fromio(skb->data, xfer_start, count);
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 426530bbed93..818527d9b3e7 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -234,9 +234,9 @@ static int __init ne3210_probe1(struct net_device *dev, int ioaddr)
NE3210_STOP_PG/4, dev->mem_start);
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (NE3210_STOP_PG - NE3210_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* The 8390 offset is zero for the NE3210 */
dev->base_addr = ioaddr;
@@ -323,12 +323,12 @@ static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff
{
unsigned long xfer_start = dev->mem_start + ring_offset - (NE3210_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_memcpy_fromio(skb->data, xfer_start, count);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index d880da73b616..e3378847e0a8 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -797,23 +797,6 @@ static void ns83820_cleanup_rx(struct ns83820 *dev)
}
}
-/* I hate the network stack sometimes */
-#ifdef __i386__
-#define skb_mangle_for_davem(skb,len) (skb)
-#else
-static inline struct sk_buff *skb_mangle_for_davem(struct sk_buff *skb, int len)
-{
- tmp = __dev_alloc_skb(len+2, GFP_ATOMIC);
- if (!tmp)
- goto done;
- tmp->dev = &dev->net_dev;
- skb_reserve(tmp, 2);
- memcpy(skb_put(tmp, len), skb->data, len);
- kfree_skb(skb);
- return tmp;
-}
-#endif
-
static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev));
static void ns83820_rx_kick(struct ns83820 *dev)
{
@@ -883,7 +866,6 @@ static void rx_irq(struct ns83820 *dev)
if (likely(CMDSTS_OK & cmdsts)) {
int len = cmdsts & 0xffff;
skb_put(skb, len);
- skb = skb_mangle_for_davem(skb, len);
if (unlikely(!skb))
goto netdev_mangle_me_harder_failed;
if (cmdsts & CMDSTS_DEST_MULTI)
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index ecf6ec9b94a4..66b5455f29c9 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -511,7 +511,6 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
struct pci_dev *pdev)
{
struct pcnet32_private *lp;
- struct resource *res;
dma_addr_t lp_dma_addr;
int i, media;
int fdx, mii, fset, dxsuflo, ltint;
@@ -689,13 +688,12 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
}
dev->base_addr = ioaddr;
- res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
- if (!res)
+ if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL)
return -EBUSY;
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENOMEM;
}
@@ -727,7 +725,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
if (!a) {
printk(KERN_ERR PFX "No access methods\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENODEV;
}
lp->a = *a;
@@ -775,7 +773,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
else {
printk(", failed to detect IRQ line.\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENODEV;
}
}
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 55dd5e283548..184b2a4c2aae 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -196,7 +196,7 @@ sb1000_probe(struct net_device *dev)
/* check I/O base and IRQ */
if (dev->base_addr != 0 && dev->base_addr != ioaddr[0])
continue;
- if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1])
+ if (dev->mem_start != 0 && dev->mem_start != ioaddr[1])
continue;
if (dev->irq != 0 && dev->irq != irq)
continue;
@@ -212,14 +212,14 @@ sb1000_probe(struct net_device *dev)
}
dev->base_addr = ioaddr[0];
- /* rmem_end holds the second I/O address - fv */
- dev->rmem_end = ioaddr[1];
+ /* mem_start holds the second I/O address */
+ dev->mem_start = ioaddr[1];
dev->irq = irq;
if (sb1000_debug > 0)
printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
- dev->rmem_end, serial_number, dev->irq);
+ dev->mem_start, serial_number, dev->irq);
dev = init_etherdev(dev, 0);
if (!dev)
@@ -405,7 +405,7 @@ sb1000_wait_for_ready(const int ioaddr[], const char* name)
}
timeout = jiffies + Sb1000TimeOutJiffies;
while (!(inb(ioaddr[1] + 6) & 0x40)) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
name);
return -ETIME;
@@ -423,7 +423,7 @@ sb1000_wait_for_ready_clear(const int ioaddr[], const char* name)
timeout = jiffies + Sb1000TimeOutJiffies;
while (inb(ioaddr[1] + 6) & 0x80) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
name);
return -ETIME;
@@ -431,7 +431,7 @@ sb1000_wait_for_ready_clear(const int ioaddr[], const char* name)
}
timeout = jiffies + Sb1000TimeOutJiffies;
while (inb(ioaddr[1] + 6) & 0x40) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
name);
return -ETIME;
@@ -935,8 +935,8 @@ sb1000_error_dpc(struct net_device *dev)
const int ErrorDpcCounterInitialize = 200;
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
sb1000_wait_for_ready_clear(ioaddr, name);
@@ -961,8 +961,8 @@ sb1000_open(struct net_device *dev)
const unsigned short FirmwareVersion[] = {0x01, 0x01};
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
/* initialize sb1000 */
@@ -1029,8 +1029,8 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -ENODEV;
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
switch (cmd) {
@@ -1130,8 +1130,8 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
/* is it a good interrupt? */
@@ -1189,8 +1189,8 @@ static int sb1000_close(struct net_device *dev)
netif_stop_queue(dev);
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
free_irq(dev->irq, dev);
/* If we don't do this, we can't re-insmod it later. */
@@ -1234,8 +1234,8 @@ init_module(void)
}
dev_sb1000.init = sb1000_probe;
dev_sb1000.base_addr = io[0];
- /* rmem_end holds the second I/O address - fv */
- dev_sb1000.rmem_end = io[1];
+ /* mem_start holds the second I/O address */
+ dev_sb1000.mem_start = io[1];
dev_sb1000.irq = irq;
if (register_netdev(&dev_sb1000) != 0) {
printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x "
@@ -1249,7 +1249,7 @@ void cleanup_module(void)
{
unregister_netdev(&dev_sb1000);
release_region(dev_sb1000.base_addr, 16);
- release_region(dev_sb1000.rmem_end, 16);
+ release_region(dev_sb1000.mem_start, 16);
kfree(dev_sb1000.priv);
dev_sb1000.priv = NULL;
}
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
new file mode 100644
index 000000000000..e0f35309bd79
--- /dev/null
+++ b/drivers/net/sb1250-mac.c
@@ -0,0 +1,2673 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ This driver is designed for the Broadcom BCM12500 SOC chip's built-in
+ Ethernet controllers.
+
+ The author may be reached as mpl@broadcom.com
+*/
+
+
+/* A few user-configurable values.
+ These may be modified when a driver module is loaded. */
+
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+/* Used to pass the media type, etc.
+ Both 'options[]' and 'full_duplex[]' should exist for driver
+ interoperability.
+ The media type is usually passed in 'options[]'.
+*/
+
+#define MAX_UNITS 3 /* More are supported, limit only on options */
+#ifdef MODULE
+static int options[MAX_UNITS] = {-1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1};
+#endif
+
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/64bit.h>
+
+/* This is only here until the firmware is ready. In that case,
+ the firmware leaves the ethernet address in the register for us. */
+#ifdef CONFIG_SWARM_STANDALONE
+#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
+#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
+#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
+#endif
+
+
+/* These identify the driver base version and may not be removed. */
+#if 0
+static char version1[] __devinitdata =
+"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n";
+#endif
+
+
+
+MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)");
+MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+
+#include <asm/sibyte/sb1250_defs.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_mac.h>
+#include <asm/sibyte/sb1250_dma.h>
+#include <asm/sibyte/sb1250_int.h>
+
+
+/**********************************************************************
+ * Simple types
+ ********************************************************************* */
+
+
+typedef unsigned long sbmac_port_t;
+typedef uint64_t sbmac_physaddr_t;
+typedef uint64_t sbmac_enetaddr_t;
+
+typedef enum { sbmac_speed_auto, sbmac_speed_10,
+ sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
+
+typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
+ sbmac_duplex_full } sbmac_duplex_t;
+
+typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
+ sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
+
+typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
+ sbmac_state_broken } sbmac_state_t;
+
+
+/**********************************************************************
+ * Macros
+ ********************************************************************* */
+
+
+#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \
+ (d)->sbdma_dscrtable : (d)->f+1)
+
+
+#define CACHELINESIZE 32
+#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE)
+#define KMALLOC(x) kmalloc((x),GFP_KERNEL)
+#define KFREE(x) kfree(x)
+#define KVTOPHYS(x) virt_to_bus((void *)(x))
+
+
+#define SBMAC_READCSR(t) (in64((unsigned long)(t)))
+#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t)))
+
+#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
+
+#define SBMAC_MAX_TXDESCR 32
+#define SBMAC_MAX_RXDESCR 32
+
+#define ETHER_ALIGN 2
+#define ETHER_ADDR_LEN 6
+#define ENET_PACKET_SIZE 1518
+
+/**********************************************************************
+ * DMA Descriptor structure
+ ********************************************************************* */
+
+typedef struct sbdmadscr_s {
+ uint64_t dscr_a;
+ uint64_t dscr_b;
+} sbdmadscr_t;
+
+typedef unsigned long paddr_t;
+typedef unsigned long vaddr_t;
+
+/**********************************************************************
+ * DMA Controller structure
+ ********************************************************************* */
+
+typedef struct sbmacdma_s {
+
+ /*
+ * This stuff is used to identify the channel and the registers
+ * associated with it.
+ */
+
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
+ int sbdma_channel; /* channel number */
+ int sbdma_txdir; /* direction (1=transmit) */
+ int sbdma_maxdescr; /* total # of descriptors in ring */
+ sbmac_port_t sbdma_config0; /* DMA config register 0 */
+ sbmac_port_t sbdma_config1; /* DMA config register 1 */
+ sbmac_port_t sbdma_dscrbase; /* Descriptor base address */
+ sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */
+ sbmac_port_t sbdma_curdscr; /* current descriptor address */
+
+ /*
+ * This stuff is for maintenance of the ring
+ */
+
+ sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
+ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
+
+ struct sk_buff **sbdma_ctxtable; /* context table, one per descr */
+
+ paddr_t sbdma_dscrtable_phys; /* and also the phys addr */
+ sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */
+ sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */
+
+} sbmacdma_t;
+
+
+/**********************************************************************
+ * Ethernet softc structure
+ ********************************************************************* */
+
+struct sbmac_softc {
+
+ /*
+ * Linux-specific things
+ */
+
+ struct net_device *sbm_dev; /* pointer to linux device */
+ spinlock_t sbm_lock; /* spin lock */
+ struct timer_list sbm_timer; /* for monitoring MII */
+ struct net_device_stats sbm_stats;
+ int sbm_devflags; /* current device flags */
+
+ int sbm_phy_oldbmsr;
+ int sbm_phy_oldanlpar;
+ int sbm_phy_oldk1stsr;
+ int sbm_phy_oldlinkstat;
+ int sbm_buffersize;
+
+ unsigned char sbm_phys[2];
+
+ /*
+ * Controller-specific things
+ */
+
+ sbmac_port_t sbm_base; /* MAC's base address */
+ sbmac_state_t sbm_state; /* current state */
+
+ sbmac_port_t sbm_macenable; /* MAC Enable Register */
+ sbmac_port_t sbm_maccfg; /* MAC Configuration Register */
+ sbmac_port_t sbm_fifocfg; /* FIFO configuration register */
+ sbmac_port_t sbm_framecfg; /* Frame configuration register */
+ sbmac_port_t sbm_rxfilter; /* receive filter register */
+ sbmac_port_t sbm_isr; /* Interrupt status register */
+ sbmac_port_t sbm_imr; /* Interrupt mask register */
+ sbmac_port_t sbm_mdio; /* MDIO register */
+
+ sbmac_speed_t sbm_speed; /* current speed */
+ sbmac_duplex_t sbm_duplex; /* current duplex */
+ sbmac_fc_t sbm_fc; /* current flow control setting */
+
+ u_char sbm_hwaddr[ETHER_ADDR_LEN];
+
+ sbmacdma_t sbm_txdma; /* for now, only use channel 0 */
+ sbmacdma_t sbm_rxdma;
+
+};
+
+
+/**********************************************************************
+ * Externs
+ ********************************************************************* */
+
+/**********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+ struct sbmac_softc *s,
+ int chan,
+ int txrx,
+ int maxdescr);
+static void sbdma_channel_start(sbmacdma_t *d);
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
+static void sbdma_emptyring(sbmacdma_t *d);
+static void sbdma_fillring(sbmacdma_t *d);
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbmac_initctx(struct sbmac_softc *s);
+static void sbmac_channel_start(struct sbmac_softc *s);
+static void sbmac_channel_stop(struct sbmac_softc *s);
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/
+static uint64_t sbmac_addr2reg(unsigned char *ptr);
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void sbmac_setmulti(struct sbmac_softc *sc);
+static int sbmac_init(struct net_device *dev);
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+
+static int sbmac_open(struct net_device *dev);
+static void sbmac_timer(unsigned long data);
+static void sbmac_tx_timeout (struct net_device *dev);
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
+static void sbmac_set_rx_mode(struct net_device *dev);
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int sbmac_close(struct net_device *dev);
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+
+static void sbmac_mii_sync(struct sbmac_softc *s);
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+ unsigned int regval);
+
+
+/**********************************************************************
+ * Globals
+ ********************************************************************* */
+
+
+/**********************************************************************
+ * MDIO constants
+ ********************************************************************* */
+
+#define MII_COMMAND_START 0x01
+#define MII_COMMAND_READ 0x02
+#define MII_COMMAND_WRITE 0x01
+#define MII_COMMAND_ACK 0x02
+
+#define BMCR_RESET 0x8000
+#define BMCR_LOOPBACK 0x4000
+#define BMCR_SPEED0 0x2000
+#define BMCR_ANENABLE 0x1000
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE 0x0400
+#define BMCR_RESTARTAN 0x0200
+#define BMCR_DUPLEX 0x0100
+#define BMCR_COLTEST 0x0080
+#define BMCR_SPEED1 0x0040
+#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0)
+#define BMCR_SPEED100 (BMCR_SPEED0)
+#define BMCR_SPEED10 0
+
+#define BMSR_100BT4 0x8000
+#define BMSR_100BT_FDX 0x4000
+#define BMSR_100BT_HDX 0x2000
+#define BMSR_10BT_FDX 0x1000
+#define BMSR_10BT_HDX 0x0800
+#define BMSR_100BT2_FDX 0x0400
+#define BMSR_100BT2_HDX 0x0200
+#define BMSR_1000BT_XSR 0x0100
+#define BMSR_PRESUP 0x0040
+#define BMSR_ANCOMPLT 0x0020
+#define BMSR_REMFAULT 0x0010
+#define BMSR_AUTONEG 0x0008
+#define BMSR_LINKSTAT 0x0004
+#define BMSR_JABDETECT 0x0002
+#define BMSR_EXTCAPAB 0x0001
+
+#define PHYIDR1 0x2000
+#define PHYIDR2 0x5C60
+
+#define ANAR_NP 0x8000
+#define ANAR_RF 0x2000
+#define ANAR_ASYPAUSE 0x0800
+#define ANAR_PAUSE 0x0400
+#define ANAR_T4 0x0200
+#define ANAR_TXFD 0x0100
+#define ANAR_TXHD 0x0080
+#define ANAR_10FD 0x0040
+#define ANAR_10HD 0x0020
+#define ANAR_PSB 0x0001
+
+#define ANLPAR_NP 0x8000
+#define ANLPAR_ACK 0x4000
+#define ANLPAR_RF 0x2000
+#define ANLPAR_ASYPAUSE 0x0800
+#define ANLPAR_PAUSE 0x0400
+#define ANLPAR_T4 0x0200
+#define ANLPAR_TXFD 0x0100
+#define ANLPAR_TXHD 0x0080
+#define ANLPAR_10FD 0x0040
+#define ANLPAR_10HD 0x0020
+#define ANLPAR_PSB 0x0001 /* 802.3 */
+
+#define ANER_PDF 0x0010
+#define ANER_LPNPABLE 0x0008
+#define ANER_NPABLE 0x0004
+#define ANER_PAGERX 0x0002
+#define ANER_LPANABLE 0x0001
+
+#define ANNPTR_NP 0x8000
+#define ANNPTR_MP 0x2000
+#define ANNPTR_ACK2 0x1000
+#define ANNPTR_TOGTX 0x0800
+#define ANNPTR_CODE 0x0008
+
+#define ANNPRR_NP 0x8000
+#define ANNPRR_MP 0x2000
+#define ANNPRR_ACK3 0x1000
+#define ANNPRR_TOGTX 0x0800
+#define ANNPRR_CODE 0x0008
+
+#define K1TCR_TESTMODE 0x0000
+#define K1TCR_MSMCE 0x1000
+#define K1TCR_MSCV 0x0800
+#define K1TCR_RPTR 0x0400
+#define K1TCR_1000BT_FDX 0x200
+#define K1TCR_1000BT_HDX 0x100
+
+#define K1STSR_MSMCFLT 0x8000
+#define K1STSR_MSCFGRES 0x4000
+#define K1STSR_LRSTAT 0x2000
+#define K1STSR_RRSTAT 0x1000
+#define K1STSR_LP1KFD 0x0800
+#define K1STSR_LP1KHD 0x0400
+#define K1STSR_LPASMDIR 0x0200
+
+#define K1SCR_1KX_FDX 0x8000
+#define K1SCR_1KX_HDX 0x4000
+#define K1SCR_1KT_FDX 0x2000
+#define K1SCR_1KT_HDX 0x1000
+
+#define STRAP_PHY1 0x0800
+#define STRAP_NCMODE 0x0400
+#define STRAP_MANMSCFG 0x0200
+#define STRAP_ANENABLE 0x0100
+#define STRAP_MSVAL 0x0080
+#define STRAP_1KHDXADV 0x0010
+#define STRAP_1KFDXADV 0x0008
+#define STRAP_100ADV 0x0004
+#define STRAP_SPEEDSEL 0x0000
+#define STRAP_SPEED100 0x0001
+
+#define PHYSUP_SPEED1000 0x10
+#define PHYSUP_SPEED100 0x08
+#define PHYSUP_SPEED10 0x00
+#define PHYSUP_LINKUP 0x04
+#define PHYSUP_FDX 0x02
+
+#define MII_BMCR 0x00 /* Basic mode control register (rw) */
+#define MII_BMSR 0x01 /* Basic mode status register (ro) */
+#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
+#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
+
+
+#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
+
+
+/**********************************************************************
+ * SBMAC_MII_SYNC(s)
+ *
+ * Synchronize with the MII - send a pattern of bits to the MII
+ * that will guarantee that it is ready to accept a command.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_mii_sync(struct sbmac_softc *s)
+{
+ int cnt;
+ uint64_t bits;
+
+ bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
+
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+
+ for (cnt = 0; cnt < 32; cnt++) {
+ SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ }
+}
+
+/**********************************************************************
+ * SBMAC_MII_SENDDATA(s,data,bitcnt)
+ *
+ * Send some bits to the MII. The bits to be sent are right-
+ * justified in the 'data' parameter.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * data - data to send
+ * bitcnt - number of bits to send
+ ********************************************************************* */
+
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+{
+ int i;
+ uint64_t bits;
+ unsigned int curmask;
+
+ bits = M_MAC_MDIO_DIR_OUTPUT;
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+
+ curmask = 1 << (bitcnt - 1);
+
+ for (i = 0; i < bitcnt; i++) {
+ if (data & curmask) bits |= M_MAC_MDIO_OUT;
+ else bits &= ~M_MAC_MDIO_OUT;
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ curmask >>= 1;
+ }
+}
+
+
+
+/**********************************************************************
+ * SBMAC_MII_READ(s,phyaddr,regidx)
+ *
+ * Read a PHY register.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * phyaddr - PHY's address
+ * regidx = index of register to read
+ *
+ * Return value:
+ * value read, or 0 if an error occured.
+ ********************************************************************* */
+
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+{
+ int idx;
+ int error;
+ int regval;
+
+ /*
+ * Synchronize ourselves so that the PHY knows the next
+ * thing coming down is a command
+ */
+
+ sbmac_mii_sync(s);
+
+ /*
+ * Send the data to the PHY. The sequence is
+ * a "start" command (2 bits)
+ * a "read" command (2 bits)
+ * the PHY addr (5 bits)
+ * the register index (5 bits)
+ */
+
+ sbmac_mii_senddata(s,MII_COMMAND_START, 2);
+ sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
+ sbmac_mii_senddata(s,phyaddr, 5);
+ sbmac_mii_senddata(s,regidx, 5);
+
+ /*
+ * Switch the port around without a clock transition.
+ */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ /*
+ * Send out a clock pulse to signal we want the status
+ */
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ /*
+ * If an error occured, the PHY will signal '1' back
+ */
+ error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN;
+
+ /*
+ * Issue an 'idle' clock pulse, but keep the direction
+ * the same.
+ */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ regval = 0;
+
+ for (idx = 0; idx < 16; idx++) {
+ regval <<= 1;
+
+ if (error == 0) {
+ if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1;
+ }
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+ }
+
+ /* Switch back to output */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+
+ if (error == 0) return regval;
+ return 0;
+}
+
+
+/**********************************************************************
+ * SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ *
+ * Write a value to a PHY register.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * phyaddr - PHY to use
+ * regidx - register within the PHY
+ * regval - data to write to register
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+ unsigned int regval)
+{
+
+ sbmac_mii_sync(s);
+
+ sbmac_mii_senddata(s,MII_COMMAND_START,2);
+ sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
+ sbmac_mii_senddata(s,phyaddr, 5);
+ sbmac_mii_senddata(s,regidx, 5);
+ sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
+ sbmac_mii_senddata(s,regval,16);
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+}
+
+
+
+/**********************************************************************
+ * SBDMA_INITCTX(d,s,chan,txrx,maxdescr)
+ *
+ * Initialize a DMA channel context. Since there are potentially
+ * eight DMA channels per MAC, it's nice to do this in a standard
+ * way.
+ *
+ * Input parameters:
+ * d - sbmacdma_t structure (DMA channel context)
+ * s - sbmac_softc structure (pointer to a MAC)
+ * chan - channel number (0..1 right now)
+ * txrx - Identifies DMA_TX or DMA_RX for channel direction
+ * maxdescr - number of descriptors
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+ struct sbmac_softc *s,
+ int chan,
+ int txrx,
+ int maxdescr)
+{
+ /*
+ * Save away interesting stuff in the structure
+ */
+
+ d->sbdma_eth = s;
+ d->sbdma_channel = chan;
+ d->sbdma_txdir = txrx;
+
+ /*
+ * initialize register pointers
+ */
+
+ d->sbdma_config0 =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+ d->sbdma_config1 =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+ d->sbdma_dscrbase =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));
+ d->sbdma_dscrcnt =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT));
+ d->sbdma_curdscr =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR));
+
+ /*
+ * Allocate memory for the ring
+ */
+
+ d->sbdma_maxdescr = maxdescr;
+
+ d->sbdma_dscrtable = (sbdmadscr_t *)
+ KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+
+ memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+
+ d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
+
+ d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable);
+
+ /*
+ * And context table
+ */
+
+ d->sbdma_ctxtable = (struct sk_buff **)
+ KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *));
+
+ memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+
+}
+
+/**********************************************************************
+ * SBDMA_CHANNEL_START(d)
+ *
+ * Initialize the hardware registers for a DMA channel.
+ *
+ * Input parameters:
+ * d - DMA channel to init (context must be previously init'd
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_channel_start(sbmacdma_t *d)
+{
+ /*
+ * Turn on the DMA channel
+ */
+
+ SBMAC_WRITECSR(d->sbdma_config1,0);
+
+ SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+
+ SBMAC_WRITECSR(d->sbdma_config0,
+ V_DMA_RINGSZ(d->sbdma_maxdescr) |
+ 0);
+
+ /*
+ * Initialize ring pointers
+ */
+
+ d->sbdma_addptr = d->sbdma_dscrtable;
+ d->sbdma_remptr = d->sbdma_dscrtable;
+}
+
+
+static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
+{
+ unsigned long addr;
+ unsigned long newaddr;
+
+ addr = (unsigned long) skb->data;
+
+ newaddr = (addr + power2 - 1) & ~(power2 - 1);
+
+ skb_reserve(skb,newaddr-addr+offset);
+}
+
+
+/**********************************************************************
+ * SBDMA_ADD_RCVBUFFER(d,sb)
+ *
+ * Add a buffer to the specified DMA channel. For receive channels,
+ * this queues a buffer for inbound packets.
+ *
+ * Input parameters:
+ * d - DMA channel descriptor
+ * sb - sk_buff to add, or NULL if we should allocate one
+ *
+ * Return value:
+ * 0 if buffer could not be added (ring is full)
+ * 1 if buffer added successfully
+ ********************************************************************* */
+
+
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+ sbdmadscr_t *dsc;
+ sbdmadscr_t *nextdsc;
+ struct sk_buff *sb_new = NULL;
+ int pktsize = ENET_PACKET_SIZE;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->sbdma_addptr;
+ nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+
+ if (nextdsc == d->sbdma_remptr) {
+ return -ENOSPC;
+ }
+
+ /*
+ * Allocate a sk_buff if we don't already have one.
+ * If we do have an sk_buff, reset it so that it's empty.
+ *
+ * Note: sk_buffs don't seem to be guaranteed to have any sort
+ * of alignment when they are allocated. Therefore, allocate enough
+ * extra space to make sure that:
+ *
+ * 1. the data does not start in the middle of a cache line.
+ * 2. The data does not end in the middle of a cache line
+ * 3. The buffer can be aligned such that the IP addresses are
+ * naturally aligned.
+ *
+ * Remember, the SB1250's MAC writes whole cache lines at a time,
+ * without reading the old contents first. So, if the sk_buff's
+ * data portion starts in the middle of a cache line, the SB1250
+ * DMA will trash the beginning (and ending) portions.
+ */
+
+ if (sb == NULL) {
+ sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN);
+ if (sb_new == NULL) {
+ printk(KERN_INFO "%s: sk_buff allocation failed\n",
+ d->sbdma_eth->sbm_dev->name);
+ return -ENOBUFS;
+ }
+
+ sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN);
+
+ /* mark skbuff owned by our device */
+ sb_new->dev = d->sbdma_eth->sbm_dev;
+ }
+ else {
+ sb_new = sb;
+ /*
+ * nothing special to reinit buffer, it's already aligned
+ * and sb->tail already points to a good place.
+ */
+ }
+
+ /*
+ * fill in the descriptor
+ */
+
+ dsc->dscr_a = KVTOPHYS(sb_new->tail) |
+ V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+ M_DMA_DSCRA_INTERRUPT;
+
+ /* receiving: no options */
+ dsc->dscr_b = 0;
+
+ /*
+ * fill in the context
+ */
+
+ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new;
+
+ /*
+ * point at next packet
+ */
+
+ d->sbdma_addptr = nextdsc;
+
+ /*
+ * Give the buffer to the DMA engine.
+ */
+
+ SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+
+ return 0; /* we did it */
+}
+
+/**********************************************************************
+ * SBDMA_ADD_TXBUFFER(d,sb)
+ *
+ * Add a transmit buffer to the specified DMA channel, causing a
+ * transmit to start.
+ *
+ * Input parameters:
+ * d - DMA channel descriptor
+ * sb - sk_buff to add
+ *
+ * Return value:
+ * 0 transmit queued successfully
+ * otherwise error code
+ ********************************************************************* */
+
+
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+ sbdmadscr_t *dsc;
+ sbdmadscr_t *nextdsc;
+ uint64_t phys;
+ uint64_t ncb;
+ int length;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->sbdma_addptr;
+ nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+
+ if (nextdsc == d->sbdma_remptr) {
+ return -ENOSPC;
+ }
+
+ /*
+ * Under Linux, it's not necessary to copy/coalesce buffers
+ * like it is on NetBSD. We think they're all contiguous,
+ * but that may not be true for GBE.
+ */
+
+ length = sb->len;
+
+ /*
+ * fill in the descriptor. Note that the number of cache
+ * blocks in the descriptor is the number of blocks
+ * *spanned*, so we need to add in the offset (if any)
+ * while doing the calculation.
+ */
+
+ phys = KVTOPHYS(sb->data);
+ ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1)));
+
+ dsc->dscr_a = phys |
+ V_DMA_DSCRA_A_SIZE(ncb) |
+ M_DMA_DSCRA_INTERRUPT |
+ M_DMA_ETHTX_SOP;
+
+ /* transmitting: set outbound options and length */
+
+ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
+ V_DMA_DSCRB_PKT_SIZE(length);
+
+ /*
+ * fill in the context
+ */
+
+ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb;
+
+ /*
+ * point at next packet
+ */
+
+ d->sbdma_addptr = nextdsc;
+
+ /*
+ * Give the buffer to the DMA engine.
+ */
+
+ SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+
+ return 0; /* we did it */
+}
+
+
+
+
+/**********************************************************************
+ * SBDMA_EMPTYRING(d)
+ *
+ * Free all allocated sk_buffs on the specified DMA channel;
+ *
+ * Input parameters:
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_emptyring(sbmacdma_t *d)
+{
+ int idx;
+ struct sk_buff *sb;
+
+ for (idx = 0; idx < d->sbdma_maxdescr; idx++) {
+ sb = d->sbdma_ctxtable[idx];
+ if (sb) {
+ dev_kfree_skb(sb);
+ d->sbdma_ctxtable[idx] = NULL;
+ }
+ }
+}
+
+
+/**********************************************************************
+ * SBDMA_FILLRING(d)
+ *
+ * Fill the specified DMA channel (must be receive channel)
+ * with sk_buffs
+ *
+ * Input parameters:
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_fillring(sbmacdma_t *d)
+{
+ int idx;
+
+ for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
+ if (sbdma_add_rcvbuffer(d,NULL) != 0) break;
+ }
+}
+
+
+/**********************************************************************
+ * SBDMA_RX_PROCESS(sc,d)
+ *
+ * Process "completed" receive buffers on the specified DMA channel.
+ * Note that this isn't really ideal for priority channels, since
+ * it processes all of the packets on a given channel before
+ * returning.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ int len;
+
+ for (;;) {
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual address
+ * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+ */
+
+ curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one that
+ * the hardware is working on right now.
+ */
+
+ if (curidx == hwidx) break;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+
+ dsc = &(d->sbdma_dscrtable[curidx]);
+ sb = d->sbdma_ctxtable[curidx];
+ d->sbdma_ctxtable[curidx] = NULL;
+
+ len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
+
+ /*
+ * Check packet status. If good, process it.
+ * If not, silently drop it and put it back on the
+ * receive ring.
+ */
+
+ if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+
+ /*
+ * Set length into the packet
+ */
+ skb_put(sb,len);
+
+ /*
+ * Add a new buffer to replace the old one. If we fail
+ * to allocate a buffer, we're going to drop this
+ * packet and put it right back on the receive ring.
+ */
+
+ if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
+ sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+ }
+ else {
+ /*
+ * Buffer has been replaced on the receive ring.
+ * Pass the buffer to the kernel
+ */
+ sc->sbm_stats.rx_bytes += len;
+ sc->sbm_stats.rx_packets++;
+ sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+ netif_rx(sb);
+ }
+ }
+ else {
+ /*
+ * Packet was mangled somehow. Just drop it and
+ * put it back on the receive ring.
+ */
+ sbdma_add_rcvbuffer(d,sb);
+ }
+
+
+ /*
+ * .. and advance to the next buffer.
+ */
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+
+ }
+}
+
+
+
+/**********************************************************************
+ * SBDMA_TX_PROCESS(sc,d)
+ *
+ * Process "completed" transmit buffers on the specified DMA channel.
+ * This is normally called within the interrupt service routine.
+ * Note that this isn't really ideal for priority channels, since
+ * it processes all of the packets on a given channel before
+ * returning.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(sc->sbm_lock), flags);
+
+ for (;;) {
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual address
+ * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+ */
+
+ curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ {
+ /* XXX This is gross, ugly, and only here because justin hacked it
+ in to fix a problem without really understanding it.
+
+ It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts.
+ So then the Read below returns zero, making hwidx a negative number, and anti-hilarity
+ ensues.
+
+ I'm guessing there's a proper fix involving clearing out interrupt state from old packets
+ before enabling interrupts, but I'm not sure.
+
+ Anyways, this hack seems to work, and is Good Enough for 11 PM. :)
+
+ -Justin
+ */
+
+ uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr);
+ if (!tmp) {
+ break;
+ }
+ hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ }
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one that
+ * the hardware is working on right now.
+ */
+
+ if (curidx == hwidx) break;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+
+ dsc = &(d->sbdma_dscrtable[curidx]);
+ sb = d->sbdma_ctxtable[curidx];
+ d->sbdma_ctxtable[curidx] = NULL;
+
+ /*
+ * Stats
+ */
+
+ sc->sbm_stats.tx_bytes += sb->len;
+ sc->sbm_stats.tx_packets++;
+
+ /*
+ * for transmits, we just free buffers.
+ */
+
+ dev_kfree_skb_irq(sb);
+
+ /*
+ * .. and advance to the next buffer.
+ */
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+
+ }
+
+ /*
+ * Decide if we should wake up the protocol or not.
+ * Other drivers seem to do this when we reach a low
+ * watermark on the transmit queue.
+ */
+
+ netif_wake_queue(d->sbdma_eth->sbm_dev);
+
+ spin_unlock_irqrestore(&(sc->sbm_lock), flags);
+
+}
+
+
+
+/**********************************************************************
+ * SBMAC_INITCTX(s)
+ *
+ * Initialize an Ethernet context structure - this is called
+ * once per MAC on the 1250. Memory is allocated here, so don't
+ * call it again from inside the ioctl routines that bring the
+ * interface up/down
+ *
+ * Input parameters:
+ * s - sbmac context structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int sbmac_initctx(struct sbmac_softc *s)
+{
+
+ /*
+ * figure out the addresses of some ports
+ */
+
+ s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE);
+ s->sbm_maccfg = PKSEG1(s->sbm_base + R_MAC_CFG);
+ s->sbm_fifocfg = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG);
+ s->sbm_framecfg = PKSEG1(s->sbm_base + R_MAC_FRAMECFG);
+ s->sbm_rxfilter = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG);
+ s->sbm_isr = PKSEG1(s->sbm_base + R_MAC_STATUS);
+ s->sbm_imr = PKSEG1(s->sbm_base + R_MAC_INT_MASK);
+ s->sbm_mdio = PKSEG1(s->sbm_base + R_MAC_MDIO);
+
+ s->sbm_phys[0] = 1;
+ s->sbm_phys[1] = 0;
+
+ s->sbm_phy_oldbmsr = 0;
+ s->sbm_phy_oldanlpar = 0;
+ s->sbm_phy_oldk1stsr = 0;
+ s->sbm_phy_oldlinkstat = 0;
+
+ /*
+ * Initialize the DMA channels. Right now, only one per MAC is used
+ * Note: Only do this _once_, as it allocates memory from the kernel!
+ */
+
+ sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
+ sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
+
+ /*
+ * initial state is OFF
+ */
+
+ s->sbm_state = sbmac_state_off;
+
+ /*
+ * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
+ */
+
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+
+ return 0;
+}
+
+
+static void sbdma_uninitctx(struct sbmacdma_s *d)
+{
+ if (d->sbdma_dscrtable) {
+ KFREE(d->sbdma_dscrtable);
+ d->sbdma_dscrtable = NULL;
+ }
+
+ if (d->sbdma_ctxtable) {
+ KFREE(d->sbdma_ctxtable);
+ d->sbdma_ctxtable = NULL;
+ }
+}
+
+
+static void sbmac_uninitctx(struct sbmac_softc *sc)
+{
+ sbdma_uninitctx(&(sc->sbm_txdma));
+ sbdma_uninitctx(&(sc->sbm_rxdma));
+}
+
+
+/**********************************************************************
+ * SBMAC_CHANNEL_START(s)
+ *
+ * Start packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_channel_start(struct sbmac_softc *s)
+{
+ uint64_t reg;
+ sbmac_port_t port;
+ uint64_t cfg,fifo,framecfg;
+ int idx;
+
+ /*
+ * Don't do this if running
+ */
+
+ if (s->sbm_state == sbmac_state_on) return;
+
+ /*
+ * Bring the controller out of reset, but leave it off.
+ */
+
+ SBMAC_WRITECSR(s->sbm_macenable,0);
+
+ /*
+ * Ignore all received packets
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+
+ /*
+ * Calculate values for various control registers.
+ */
+
+ cfg = M_MAC_RETRY_EN |
+ M_MAC_TX_HOLD_SOP_EN |
+ V_MAC_TX_PAUSE_CNT_16K |
+ M_MAC_AP_STAT_EN |
+ M_MAC_FAST_SYNC |
+ M_MAC_SS_EN |
+ 0;
+
+ fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */
+ V_MAC_TX_RD_THRSH(4) |
+ V_MAC_TX_RL_THRSH(4) |
+ V_MAC_RX_PL_THRSH(4) |
+ V_MAC_RX_RD_THRSH(4) | /* Must be '4' */
+ V_MAC_RX_PL_THRSH(4) |
+ V_MAC_RX_RL_THRSH(8) |
+ 0;
+
+ framecfg = V_MAC_MIN_FRAMESZ_DEFAULT |
+ V_MAC_MAX_FRAMESZ_DEFAULT |
+ V_MAC_BACKOFF_SEL(1);
+
+
+ /*
+ * Clear out the hash address map
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE);
+ for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Clear out the exact-match table
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+ for (idx = 0; idx < MAC_ADDR_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Clear out the DMA Channel mapping table registers
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE);
+ for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+
+ port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE);
+ for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Program the hardware address. It goes into the hardware-address
+ * register as well as the first filter register.
+ */
+
+ reg = sbmac_addr2reg(s->sbm_hwaddr);
+
+ port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+ SBMAC_WRITECSR(port,reg);
+ port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR);
+
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
+ /*
+ * Pass1 SB1250s do not receive packets addressed to the
+ * destination address in the R_MAC_ETHERNET_ADDR register.
+ * Set the value to zero.
+ */
+ SBMAC_WRITECSR(port,0);
+#else
+ SBMAC_WRITECSR(port,reg);
+#endif
+
+ /*
+ * Set the receive filter for no packets, and write values
+ * to the various config registers
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+ SBMAC_WRITECSR(s->sbm_imr,0);
+ SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+ SBMAC_WRITECSR(s->sbm_fifocfg,fifo);
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ /*
+ * Initialize DMA channels (rings should be ok now)
+ */
+
+ sbdma_channel_start(&(s->sbm_rxdma));
+ sbdma_channel_start(&(s->sbm_txdma));
+
+ /*
+ * Configure the speed, duplex, and flow control
+ */
+
+ sbmac_set_speed(s,s->sbm_speed);
+ sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc);
+
+ /*
+ * Fill the receive ring
+ */
+
+ sbdma_fillring(&(s->sbm_rxdma));
+
+ /*
+ * Turn on the rest of the bits in the enable register
+ */
+
+ SBMAC_WRITECSR(s->sbm_macenable,
+ M_MAC_RXDMA_EN0 |
+ M_MAC_TXDMA_EN0 |
+ M_MAC_RX_ENABLE |
+ M_MAC_TX_ENABLE);
+
+
+
+ /*
+ * Accept any kind of interrupt on TX and RX DMA channel 0
+ */
+ SBMAC_WRITECSR(s->sbm_imr,
+ (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0));
+
+ /*
+ * Enable receiving unicasts and broadcasts
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN);
+
+ /*
+ * we're running now.
+ */
+
+ s->sbm_state = sbmac_state_on;
+
+ /*
+ * Program multicast addresses
+ */
+
+ sbmac_setmulti(s);
+
+ /*
+ * If channel was in promiscuous mode before, turn that on
+ */
+
+ if (s->sbm_devflags & IFF_PROMISC) {
+ sbmac_promiscuous_mode(s,1);
+ }
+
+}
+
+
+/**********************************************************************
+ * SBMAC_CHANNEL_STOP(s)
+ *
+ * Stop packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_channel_stop(struct sbmac_softc *s)
+{
+ uint64_t ctl;
+
+ /* don't do this if already stopped */
+
+ if (s->sbm_state == sbmac_state_off) return;
+
+ /* don't accept any packets, disable all interrupts */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+ SBMAC_WRITECSR(s->sbm_imr,0);
+
+ /* Turn off ticker */
+
+ /* XXX */
+
+ /* turn off receiver and transmitter */
+
+ ctl = SBMAC_READCSR(s->sbm_macenable);
+ ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0);
+ SBMAC_WRITECSR(s->sbm_macenable,ctl);
+
+ /* We're stopped now. */
+
+ s->sbm_state = sbmac_state_off;
+
+
+ /* Empty the receive and transmit rings */
+
+ sbdma_emptyring(&(s->sbm_rxdma));
+ sbdma_emptyring(&(s->sbm_txdma));
+
+}
+
+/**********************************************************************
+ * SBMAC_SET_CHANNEL_STATE(state)
+ *
+ * Set the channel's state ON or OFF
+ *
+ * Input parameters:
+ * state - new state
+ *
+ * Return value:
+ * old state
+ ********************************************************************* */
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
+ sbmac_state_t state)
+{
+ sbmac_state_t oldstate = sc->sbm_state;
+
+ /*
+ * If same as previous state, return
+ */
+
+ if (state == oldstate) {
+ return oldstate;
+ }
+
+ /*
+ * If new state is ON, turn channel on
+ */
+
+ if (state == sbmac_state_on) {
+ sbmac_channel_start(sc);
+ }
+ else {
+ sbmac_channel_stop(sc);
+ }
+
+ /*
+ * Return previous state
+ */
+
+ return oldstate;
+}
+
+
+/**********************************************************************
+ * SBMAC_PROMISCUOUS_MODE(sc,onoff)
+ *
+ * Turn on or off promiscuous mode
+ *
+ * Input parameters:
+ * sc - softc
+ * onoff - 1 to turn on, 0 to turn off
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
+{
+ uint64_t reg;
+
+ if (sc->sbm_state != sbmac_state_on) return;
+
+ if (onoff) {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= M_MAC_ALLPKT_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+ else {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg &= ~M_MAC_ALLPKT_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+}
+
+
+
+#if 0
+/**********************************************************************
+ * SBMAC_INIT_AND_START(sc)
+ *
+ * Stop the channel and restart it. This is generally used
+ * when we have to do something to the channel that requires
+ * a swift kick.
+ *
+ * Input parameters:
+ * sc - softc
+ ********************************************************************* */
+
+static void sbmac_init_and_start(struct sbmac_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&(sc->sbm_lock),flags);
+
+ sbmac_set_channel_state(sc,sbmac_state_on);
+
+ spin_unlock_irqrestore(&(sc->sbm_lock),flags);
+}
+#endif
+
+
+/**********************************************************************
+ * SBMAC_ADDR2REG(ptr)
+ *
+ * Convert six bytes into the 64-bit register value that
+ * we typically write into the SBMAC's address/mcast registers
+ *
+ * Input parameters:
+ * ptr - pointer to 6 bytes
+ *
+ * Return value:
+ * register value
+ ********************************************************************* */
+
+static uint64_t sbmac_addr2reg(unsigned char *ptr)
+{
+ uint64_t reg = 0;
+
+ ptr += 6;
+
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+
+ return reg;
+}
+
+
+/**********************************************************************
+ * SBMAC_SET_SPEED(s,speed)
+ *
+ * Configure LAN speed for the specified MAC.
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * speed - speed to set MAC to (see sbmac_speed_t enum)
+ *
+ * Return value:
+ * 1 if successful
+ * 0 indicates invalid parameters
+ ********************************************************************* */
+
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+{
+ uint64_t cfg;
+ uint64_t framecfg;
+
+ /*
+ * Save new current values
+ */
+
+ s->sbm_speed = speed;
+
+ if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+
+ cfg = SBMAC_READCSR(s->sbm_maccfg);
+ framecfg = SBMAC_READCSR(s->sbm_framecfg);
+
+ /*
+ * Mask out the stuff we want to change
+ */
+
+ cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL);
+ framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH |
+ M_MAC_SLOT_SIZE);
+
+ /*
+ * Now add in the new bits
+ */
+
+ switch (speed) {
+ case sbmac_speed_10:
+ framecfg |= V_MAC_IFG_RX_10 |
+ V_MAC_IFG_TX_10 |
+ K_MAC_IFG_THRSH_10 |
+ V_MAC_SLOT_SIZE_10;
+ cfg |= V_MAC_SPEED_SEL_10MBPS;
+ break;
+
+ case sbmac_speed_100:
+ framecfg |= V_MAC_IFG_RX_100 |
+ V_MAC_IFG_TX_100 |
+ V_MAC_IFG_THRSH_100 |
+ V_MAC_SLOT_SIZE_100;
+ cfg |= V_MAC_SPEED_SEL_100MBPS ;
+ break;
+
+ case sbmac_speed_1000:
+ framecfg |= V_MAC_IFG_RX_1000 |
+ V_MAC_IFG_TX_1000 |
+ V_MAC_IFG_THRSH_1000 |
+ V_MAC_SLOT_SIZE_1000;
+ cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
+ break;
+
+ case sbmac_speed_auto: /* XXX not implemented */
+ /* fall through */
+ default:
+ return 0;
+ }
+
+ /*
+ * Send the bits back to the hardware
+ */
+
+ SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ return 1;
+
+}
+
+/**********************************************************************
+ * SBMAC_SET_DUPLEX(s,duplex,fc)
+ *
+ * Set Ethernet duplex and flow control options for this MAC
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * duplex - duplex setting (see sbmac_duplex_t)
+ * fc - flow control setting (see sbmac_fc_t)
+ *
+ * Return value:
+ * 1 if ok
+ * 0 if an invalid parameter combination was specified
+ ********************************************************************* */
+
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+{
+ uint64_t cfg;
+
+ /*
+ * Save new current values
+ */
+
+ s->sbm_duplex = duplex;
+ s->sbm_fc = fc;
+
+ if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+
+ cfg = SBMAC_READCSR(s->sbm_maccfg);
+
+ /*
+ * Mask off the stuff we're about to change
+ */
+
+ cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN);
+
+
+ switch (duplex) {
+ case sbmac_duplex_half:
+ switch (fc) {
+ case sbmac_fc_disabled:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED;
+ break;
+
+ case sbmac_fc_collision:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED;
+ break;
+
+ case sbmac_fc_carrier:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
+ break;
+
+ case sbmac_fc_auto: /* XXX not implemented */
+ /* fall through */
+ case sbmac_fc_frame: /* not valid in half duplex */
+ default: /* invalid selection */
+ return 0;
+ }
+ break;
+
+ case sbmac_duplex_full:
+ switch (fc) {
+ case sbmac_fc_disabled:
+ cfg |= V_MAC_FC_CMD_DISABLED;
+ break;
+
+ case sbmac_fc_frame:
+ cfg |= V_MAC_FC_CMD_ENABLED;
+ break;
+
+ case sbmac_fc_collision: /* not valid in full duplex */
+ case sbmac_fc_carrier: /* not valid in full duplex */
+ case sbmac_fc_auto: /* XXX not implemented */
+ /* fall through */
+ default:
+ return 0;
+ }
+ break;
+ case sbmac_duplex_auto:
+ /* XXX not implemented */
+ break;
+ }
+
+ /*
+ * Send the bits back to the hardware
+ */
+
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ return 1;
+}
+
+
+
+
+/**********************************************************************
+ * SBMAC_INTR()
+ *
+ * Interrupt handler for MAC interrupts
+ *
+ * Input parameters:
+ * MAC structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
+ uint64_t isr;
+
+ for (;;) {
+
+ /*
+ * Read the ISR (this clears the bits in the real register)
+ */
+
+ isr = SBMAC_READCSR(sc->sbm_isr);
+
+ if (isr == 0) break;
+
+ /*
+ * Transmits on channel 0
+ */
+
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ sbdma_tx_process(sc,&(sc->sbm_txdma));
+ }
+
+ /*
+ * Receives on channel 0
+ */
+
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+ sbdma_rx_process(sc,&(sc->sbm_rxdma));
+ }
+ }
+
+}
+
+
+/**********************************************************************
+ * SBMAC_START_TX(skb,dev)
+ *
+ * Start output on the specified interface. Basically, we
+ * queue as many buffers as we can until the ring fills up, or
+ * we run off the end of the queue, whichever comes first.
+ *
+ * Input parameters:
+ *
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ /* lock eth irq */
+ spin_lock_irq (&sc->sbm_lock);
+
+ /*
+ * Put the buffer on the transmit ring. If we
+ * don't have room, stop the queue.
+ */
+
+ if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
+ /* XXX save skb that we could not send */
+ netif_stop_queue(dev);
+ }
+
+ dev->trans_start = jiffies;
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ return 0;
+}
+
+/**********************************************************************
+ * SBMAC_SETMULTI(sc)
+ *
+ * Reprogram the multicast table into the hardware, given
+ * the list of multicasts associated with the interface
+ * structure.
+ *
+ * Input parameters:
+ * sc - softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_setmulti(struct sbmac_softc *sc)
+{
+ uint64_t reg;
+ sbmac_port_t port;
+ int idx;
+ struct dev_mc_list *mclist;
+ struct net_device *dev = sc->sbm_dev;
+
+ /*
+ * Clear out entire multicast table. We do this by nuking
+ * the entire hash table and all the direct matches except
+ * the first one, which is used for our station address
+ */
+
+ for (idx = 1; idx < MAC_ADDR_COUNT; idx++) {
+ port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,0);
+ }
+
+ for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+ port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,0);
+ }
+
+ /*
+ * Clear the filter to say we don't want any multicasts.
+ */
+
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /*
+ * Enable ALL multicasts. Do this by inverting the
+ * multicast enable bit.
+ */
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ return;
+ }
+
+
+ /*
+ * Progam new multicast entries. For now, only use the
+ * perfect filter. In the future we'll need to use the
+ * hash filter if the perfect filter overflows
+ */
+
+ /* XXX only using perfect filter for now, need to use hash
+ * XXX if the table overflows */
+
+ idx = 1; /* skip station address */
+ mclist = dev->mc_list;
+ while (mclist && (idx < MAC_ADDR_COUNT)) {
+ reg = sbmac_addr2reg(mclist->dmi_addr);
+ port = PKSEG1(sc->sbm_base +
+ R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,reg);
+ idx++;
+ mclist = mclist->next;
+ }
+
+ /*
+ * Enable the "accept multicast bits" if we programmed at least one
+ * multicast.
+ */
+
+ if (idx > 1) {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= M_MAC_MCAST_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+/**********************************************************************
+ * SBMAC_PARSE_XDIGIT(str)
+ *
+ * Parse a hex digit, returning its value
+ *
+ * Input parameters:
+ * str - character
+ *
+ * Return value:
+ * hex value, or -1 if invalid
+ ********************************************************************* */
+
+static int sbmac_parse_xdigit(char str)
+{
+ int digit;
+
+ if ((str >= '0') && (str <= '9')) digit = str - '0';
+ else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10;
+ else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10;
+ else return -1;
+
+ return digit;
+}
+
+/**********************************************************************
+ * SBMAC_PARSE_HWADDR(str,hwaddr)
+ *
+ * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ * Ethernet address.
+ *
+ * Input parameters:
+ * str - string
+ * hwaddr - pointer to hardware address
+ *
+ * Return value:
+ * 0 if ok, else -1
+ ********************************************************************* */
+
+static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
+{
+ int digit1,digit2;
+ int idx = 6;
+
+ while (*str && (idx > 0)) {
+ digit1 = sbmac_parse_xdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = sbmac_parse_xdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if (*str == '-') str++;
+ if (*str == ':') str++;
+ }
+ return 0;
+}
+#endif
+
+/**********************************************************************
+ * SBMAC_INIT(dev)
+ *
+ * Attach routine - init hardware and hook ourselves into linux
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+static int sbmac_init(struct net_device *dev)
+{
+ struct sbmac_softc *sc;
+ u_char *eaddr;
+ uint64_t ea_reg;
+ int idx;
+
+ sc = (struct sbmac_softc *)dev->priv;
+
+ /* Determine controller base address */
+
+ sc->sbm_base = (sbmac_port_t) dev->base_addr;
+ sc->sbm_dev = dev;
+
+ eaddr = sc->sbm_hwaddr;
+
+ /*
+ * Read the ethernet address. The firwmare left this programmed
+ * for us in the ethernet address register for each mac.
+ */
+
+ ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR));
+ SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0);
+ for (idx = 0; idx < 6; idx++) {
+ eaddr[idx] = (uint8_t) (ea_reg & 0xFF);
+ ea_reg >>= 8;
+ }
+
+
+ for (idx = 0; idx < 6; idx++) {
+ dev->dev_addr[idx] = eaddr[idx];
+ }
+
+
+ /*
+ * Init packet size
+ */
+
+ sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN;
+
+ /*
+ * Initialize context (get pointers to registers and stuff), then
+ * allocate the memory for the descriptor tables.
+ */
+
+ sbmac_initctx(sc);
+
+
+ /*
+ * Display Ethernet address (this is called during the config process
+ * so we need to finish off the config message that was being displayed)
+ */
+ printk(KERN_INFO
+ "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n",
+ dev->name,
+ (unsigned long) sc->sbm_base,
+ eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
+
+ /*
+ * Set up Linux device callins
+ */
+
+ spin_lock_init(&(sc->sbm_lock));
+
+ ether_setup(dev);
+ dev->open = sbmac_open;
+ dev->hard_start_xmit = sbmac_start_tx;
+ dev->stop = sbmac_close;
+ dev->get_stats = sbmac_get_stats;
+ dev->set_multicast_list = sbmac_set_rx_mode;
+ dev->do_ioctl = sbmac_mii_ioctl;
+ dev->tx_timeout = sbmac_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ return 0;
+
+}
+
+
+static int sbmac_open(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ MOD_INC_USE_COUNT;
+
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
+ }
+
+ /*
+ * map/route interrupt
+ */
+
+ if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ /*
+ * Configure default speed
+ */
+
+ sbmac_mii_poll(sc,1);
+
+ /*
+ * Turn on the channel
+ */
+
+ sbmac_set_channel_state(sc,sbmac_state_on);
+
+ /*
+ * XXX Station address is in dev->dev_addr
+ */
+
+ if (dev->if_port == 0)
+ dev->if_port = 0;
+
+ netif_start_queue(dev);
+
+ sbmac_set_rx_mode(dev);
+
+ /* Set the timer to check for link beat. */
+ init_timer(&sc->sbm_timer);
+ sc->sbm_timer.expires = jiffies + 2;
+ sc->sbm_timer.data = (unsigned long)dev;
+ sc->sbm_timer.function = &sbmac_timer;
+ add_timer(&sc->sbm_timer);
+
+ return 0;
+}
+
+
+
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
+{
+ int bmsr,bmcr,k1stsr,anlpar;
+ int chg;
+ char buffer[100];
+ char *p = buffer;
+
+ /* Read the mode status and mode control registers. */
+ bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
+ bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
+
+ /* get the link partner status */
+ anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
+
+ /* if supported, read the 1000baseT register */
+ if (bmsr & BMSR_1000BT_XSR) {
+ k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
+ }
+ else {
+ k1stsr = 0;
+ }
+
+ chg = 0;
+
+ if ((bmsr & BMSR_LINKSTAT) == 0) {
+ /*
+ * If link status is down, clear out old info so that when
+ * it comes back up it will force us to reconfigure speed
+ */
+ s->sbm_phy_oldbmsr = 0;
+ s->sbm_phy_oldanlpar = 0;
+ s->sbm_phy_oldk1stsr = 0;
+ return 0;
+ }
+
+ if ((s->sbm_phy_oldbmsr != bmsr) ||
+ (s->sbm_phy_oldanlpar != anlpar) ||
+ (s->sbm_phy_oldk1stsr != k1stsr)) {
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n",
+ s->sbm_dev->name,
+ s->sbm_phy_oldbmsr,bmsr,
+ s->sbm_phy_oldanlpar,anlpar,
+ s->sbm_phy_oldk1stsr,k1stsr);
+ }
+ s->sbm_phy_oldbmsr = bmsr;
+ s->sbm_phy_oldanlpar = anlpar;
+ s->sbm_phy_oldk1stsr = k1stsr;
+ chg = 1;
+ }
+
+ if (chg == 0) return 0;
+
+ p += sprintf(p,"Link speed: ");
+
+ if (k1stsr & K1STSR_LP1KFD) {
+ s->sbm_speed = sbmac_speed_1000;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = sbmac_fc_frame;
+ p += sprintf(p,"1000BaseT FDX");
+ }
+ else if (k1stsr & K1STSR_LP1KHD) {
+ s->sbm_speed = sbmac_speed_1000;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+ p += sprintf(p,"1000BaseT HDX");
+ }
+ else if (anlpar & ANLPAR_TXFD) {
+ s->sbm_speed = sbmac_speed_100;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
+ p += sprintf(p,"100BaseT FDX");
+ }
+ else if (anlpar & ANLPAR_TXHD) {
+ s->sbm_speed = sbmac_speed_100;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+ p += sprintf(p,"100BaseT HDX");
+ }
+ else if (anlpar & ANLPAR_10FD) {
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = sbmac_fc_frame;
+ p += sprintf(p,"10BaseT FDX");
+ }
+ else if (anlpar & ANLPAR_10HD) {
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_collision;
+ p += sprintf(p,"10BaseT HDX");
+ }
+ else {
+ p += sprintf(p,"Unknown");
+ }
+
+ if (noisy) {
+ printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
+ }
+
+ return 1;
+}
+
+
+
+
+static void sbmac_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ int next_tick = HZ;
+ int mii_status;
+
+ spin_lock_irq (&sc->sbm_lock);
+
+ /* make IFF_RUNNING follow the MII status bit "Link established" */
+ mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
+
+ if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
+ sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
+ if (mii_status & BMSR_LINKSTAT) {
+ netif_carrier_on(dev);
+ }
+ else {
+ netif_carrier_off(dev);
+ }
+ }
+
+ /*
+ * Poll the PHY to see what speed we should be running at
+ */
+
+ if (sbmac_mii_poll(sc,1)) {
+ if (sc->sbm_state != sbmac_state_off) {
+ /*
+ * something changed, restart the channel
+ */
+ if (debug > 1) {
+ printk("%s: restarting channel because speed changed\n",
+ sc->sbm_dev->name);
+ }
+ sbmac_channel_stop(sc);
+ sbmac_channel_start(sc);
+ }
+ }
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ sc->sbm_timer.expires = jiffies + next_tick;
+ add_timer(&sc->sbm_timer);
+}
+
+
+static void sbmac_tx_timeout (struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+
+ spin_lock_irq (&sc->sbm_lock);
+
+
+ dev->trans_start = jiffies;
+ sc->sbm_stats.tx_errors++;
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
+}
+
+
+
+
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+
+ /* XXX update other stats here */
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ return &sc->sbm_stats;
+}
+
+
+
+static void sbmac_set_rx_mode(struct net_device *dev)
+{
+ unsigned long flags;
+ int msg_flag = 0;
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+ if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) {
+ /*
+ * Promiscuous changed.
+ */
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ msg_flag = 1;
+ sbmac_promiscuous_mode(sc,1);
+ }
+ else {
+ msg_flag = 2;
+ sbmac_promiscuous_mode(sc,0);
+ }
+ }
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ if (msg_flag) {
+ printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis");
+ }
+
+ /*
+ * Program the multicasts. Do this every time.
+ */
+
+ sbmac_setmulti(sc);
+
+}
+
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ u16 *data = (u16 *)&rq->ifr_data;
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+ retval = 0;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = sc->sbm_phys[0] & 0x1f;
+ /* Fall Through */
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
+ break;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!capable(CAP_NET_ADMIN)) {
+ retval = -EPERM;
+ break;
+ }
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
+ data[0],data[1],data[2]);
+ }
+ sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ break;
+ default:
+ retval = -EOPNOTSUPP;
+ }
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+ return retval;
+}
+
+static int sbmac_close(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ unsigned long flags;
+
+ sbmac_set_channel_state(sc,sbmac_state_off);
+
+ del_timer_sync(&sc->sbm_timer);
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+
+ netif_stop_queue(dev);
+
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
+ }
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ /* Make sure there is no irq-handler running on a different CPU. */
+ synchronize_irq();
+
+ free_irq(dev->irq, dev);
+
+ sbdma_emptyring(&(sc->sbm_txdma));
+ sbdma_emptyring(&(sc->sbm_rxdma));
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+static void
+sbmac_setup_hwaddr(int chan,char *addr)
+{
+ uint8_t eaddr[6];
+ uint64_t val;
+ sbmac_port_t port;
+
+ port = A_MAC_CHANNEL_BASE(chan);
+ sbmac_parse_hwaddr(addr,eaddr);
+ val = sbmac_addr2reg(eaddr);
+ SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val);
+ val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+}
+#endif
+
+static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0};
+
+static int __init
+sbmac_init_module(void)
+{
+ int idx;
+ int macidx = 0;
+ struct net_device *dev;
+ sbmac_port_t port;
+
+ /*
+ * For bringup when not using the firmware, we can pre-fill
+ * the MAC addresses using the environment variables
+ * specified in this file (or maybe from the config file?)
+ */
+#ifdef SBMAC_ETH0_HWADDR
+ sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+#endif
+#ifdef SBMAC_ETH1_HWADDR
+ sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+#endif
+#ifdef SBMAC_ETH2_HWADDR
+ sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+#endif
+
+ /*
+ * Walk through the Ethernet controllers and find
+ * those who have their MAC addresses set.
+ */
+
+ for (idx = 0; idx < MAX_UNITS; idx++) {
+
+ /*
+ * This is the base address of the MAC.
+ */
+
+ port = A_MAC_CHANNEL_BASE(idx);
+
+ /*
+ * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+ * value for us by the firmware if we're going to use this MAC.
+ * If we find a zero, skip this MAC.
+ */
+
+ if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) {
+ continue;
+ }
+
+ /*
+ * Okay, cool. Initialize this MAC.
+ */
+
+ dev = init_etherdev(NULL,sizeof(struct sbmac_softc));
+ if (!dev) break; /* problems, get out now. */
+ dev->irq = K_INT_MAC_0 + idx;
+ dev->base_addr = port;
+ dev->mem_end = 0;
+ /*dev->init = sbmac_init;*/
+ sbmac_init(dev);
+
+ dev_sbmac[macidx] = dev;
+ macidx++;
+
+ }
+
+ /*
+ * Should we care, 'macidx' is the total number of enabled MACs.
+ */
+
+ return 0;
+}
+
+
+static void __exit
+sbmac_cleanup_module(void)
+{
+ int idx;
+ struct net_device *dev;
+ for (idx = 0; idx < MAX_UNITS; idx++) {
+ dev = dev_sbmac[idx];
+ if (dev == NULL) continue;
+ if (dev->priv != NULL) {
+ struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+
+ unregister_netdev(dev);
+
+ sbmac_uninitctx(sc);
+
+ KFREE(sc);
+ }
+ KFREE(dev);
+ dev_sbmac[idx] = NULL;
+ }
+}
+
+module_init(sbmac_init_module);
+module_exit(sbmac_cleanup_module);
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index e748b5c9aa4c..6b67bce267b8 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -520,8 +520,6 @@ static void init_dev(struct net_device *dev, u_long iobase)
{
/* Initialize new device structure */
- dev->rmem_end = 0; /* shared memory isn't used */
- dev->rmem_start = 0; /* shared memory isn't used */
dev->mem_end = 0; /* shared memory isn't used */
dev->mem_start = 0; /* shared memory isn't used */
dev->base_addr = iobase; /* save port (I/O) base address */
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 50baaf26db69..7d947eaa4095 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -299,8 +299,8 @@ int __init ultramca_probe(struct net_device *dev)
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = num_pages;
- dev->rmem_start = dev->mem_start + TX_PAGES * 256;
- dev->mem_end = dev->rmem_end =
+ ei_status.rmem_start = dev->mem_start + TX_PAGES * 256;
+ dev->mem_end = ei_status.rmem_end =
dev->mem_start + (ei_status.stop_page - START_PG) * 256;
printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.\n",
@@ -387,12 +387,12 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu
{
unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index c6ac05f774bb..5dcb815b767f 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -251,8 +251,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = num_pages;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end
= dev->mem_start + (ei_status.stop_page - START_PG)*256;
if (piomode) {
@@ -403,12 +403,12 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri
/* Enable shared memory. */
outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index b0c295b5593d..52861584519c 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -231,8 +231,8 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
/* All Ultra32 cards have 32KB memory with an 8KB window. */
ei_status.stop_page = 128;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start + 0x1fff;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + 0x1fff;
printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
dev->irq, dev->mem_start, dev->mem_end);
@@ -353,7 +353,7 @@ static void ultra32_block_input(struct net_device *dev,
} else {
/* Select first 8KB Window. */
outb(ei_status.reg0, RamReg);
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
}
} else {
/* Packet is in one chunk -- we can copy + cksum. */
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index 1ae2fb3fb71f..98577b85d138 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -2080,6 +2080,7 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header *header, __u16
#ifdef EXT_COUNTERS
strip_info->rx_bytes += packetlen;
#endif
+ skb->dev->last_rx = jiffies;
netif_rx(skb);
}
}
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
new file mode 100644
index 000000000000..0fad42a4021c
--- /dev/null
+++ b/drivers/net/sun3_82586.c
@@ -0,0 +1,1206 @@
+/*
+ * Sun3 i82586 Ethernet driver
+ *
+ * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
+ *
+ * Original copyright follows:
+ * --------------------------
+ *
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * --------------------------
+ *
+ * Consult ni52.c for further notes from the original driver.
+ *
+ * This incarnation currently supports the OBIO version of the i82586 chip
+ * used in certain sun3 models. It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+ */
+
+static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume = 0; /* experimental .. better should be zero */
+static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo=0x8; /* don't change */
+
+/* #define REALLY_SLOW_IO */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sun3_82586.h"
+
+#define DEBUG /* debug on */
+#define SYSBUSVAL 0 /* 16 Bit */
+
+#define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
+#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
+#define sun3_disint() {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
+#define sun3_enaint() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
+#define sun3_active() {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
+
+#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
+#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
+#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
+
+/******************* how to calculate the buffers *****************************
+
+ * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+ * --------------- in a different (more stable?) mode. Only in this mode it's
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+ * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1536 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1 /* config for 32K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
+#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+/* different DELAYs */
+#define DELAY(x) mdelay(32 * x);
+#define DELAY_16(); { udelay(16); }
+#define DELAY_18(); { udelay(4); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() \
+{ int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_cuc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_SCB_CMD_RUC() { int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_ruc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_STAT_COMPL(addr) { int i; \
+ for(i=0;i<32767;i++) { \
+ if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
+ DELAY_16(); DELAY_16(); } }
+
+static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
+static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
+static int sun3_82586_open(struct net_device *dev);
+static int sun3_82586_close(struct net_device *dev);
+static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void sun3_82586_timeout(struct net_device *dev);
+#if 0
+static void sun3_82586_dump(struct net_device *,void *);
+#endif
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev,char *where,unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void *alloc_rfa(struct net_device *dev,void *ptr);
+static void sun3_82586_rcv_int(struct net_device *dev);
+static void sun3_82586_xmt_int(struct net_device *dev);
+static void sun3_82586_rnr_int(struct net_device *dev);
+
+struct priv
+{
+ struct net_device_stats stats;
+ unsigned long base;
+ char *memtop;
+ long int lock;
+ int reseted;
+ volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first;
+ volatile struct scp_struct *scp; /* volatile is important */
+ volatile struct iscp_struct *iscp; /* volatile is important */
+ volatile struct scb_struct *scb; /* volatile is important */
+ volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
+ volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+ volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+ volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+ volatile int nop_point,num_recv_buffs;
+ volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
+ volatile int xmit_count,xmit_last;
+};
+
+/**********************************************
+ * close device
+ */
+static int sun3_82586_close(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+
+ sun3_reset586(); /* the hard way to stop the receiver */
+
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int sun3_82586_open(struct net_device *dev)
+{
+ int ret;
+
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+
+ ret = request_irq(dev->irq, &sun3_82586_interrupt,0,dev->name,dev);
+ if (ret)
+ {
+ sun3_reset586();
+ return ret;
+ }
+
+ netif_start_queue(dev);
+
+ return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev,char *where,unsigned size)
+{
+ struct priv pb;
+ struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+ char *iscp_addr;
+ int i;
+
+ p->base = (unsigned long) dvma_btov(0);
+ p->memtop = (char *)dvma_btov((unsigned long)where);
+ p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+ memset((char *)p->scp,0, sizeof(struct scp_struct));
+ for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+ if(((char *)p->scp)[i])
+ return 0;
+ p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
+ if(p->scp->sysbus != SYSBUSVAL)
+ return 0;
+
+ iscp_addr = (char *)dvma_btov((unsigned long)where);
+
+ p->iscp = (struct iscp_struct *) iscp_addr;
+ memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->iscp->busy = 1;
+
+ sun3_reset586();
+ sun3_attn586();
+ DELAY(1); /* wait a while... */
+
+ if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+ return 0;
+
+ return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by sun3_82586_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ sun3_reset586();
+ DELAY(1);
+
+ p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+ p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
+ p->scb = (struct scb_struct *) ((char *)p->iscp + sizeof(struct iscp_struct));
+
+ memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+ memset((char *) p->scp ,0,sizeof(struct scp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->scp->sysbus = SYSBUSVAL;
+ p->iscp->scb_offset = make16(p->scb);
+ p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
+
+ p->iscp->busy = 1;
+ sun3_reset586();
+ sun3_attn586();
+
+ DELAY(1);
+
+ if(p->iscp->busy)
+ printk("%s: Init-Problems (alloc).\n",dev->name);
+
+ p->reseted = 0;
+
+ memset((char *)p->scb,0,sizeof(struct scb_struct));
+}
+
+int __init sun3_82586_probe(struct net_device *dev)
+{
+ unsigned long ioaddr, iopte;
+ static int found = 0;
+
+ /* check that this machine has an onboard lance */
+ switch(idprom->id_machtype) {
+ case SM_SUN3|SM_3_160:
+ case SM_SUN3|SM_3_260:
+ /* these machines have lance */
+ break;
+
+ default:
+ return(-ENODEV);
+ }
+
+ if(found)
+ return -ENODEV;
+
+ for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
+ SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
+
+ iopte = sun3_get_pte(ioaddr);
+ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+ continue;
+
+ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+ IE_OBIO) {
+ found = 1;
+ break;
+ }
+ }
+
+ if(!found)
+ return 0;
+
+ SET_MODULE_OWNER(dev);
+
+ dev->irq = IE_IRQ;
+ dev->base_addr = ioaddr;
+ if(sun3_82586_probe1(dev, ioaddr) == 0)
+ return 0;
+
+ return -ENODEV;
+}
+
+static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
+{
+ int i, size, retval;
+
+// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name))
+// return -EBUSY;
+
+ /* copy in the ethernet address from the prom */
+ for(i = 0; i < 6 ; i++)
+ dev->dev_addr[i] = idprom->id_ethaddr[i];
+
+ printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
+
+ /*
+ * check (or search) IO-Memory, 32K
+ */
+ size = 0x8000;
+
+ dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
+ dev->mem_end = dev->mem_start + size;
+
+ if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
+ printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
+ retval = -ENODEV;
+ goto out;
+ }
+ if(!check586(dev,(char *) dev->mem_start,size)) {
+ printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
+ if(dev->priv == NULL) {
+ printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ /* warning: we don't free it on errors */
+ memset((char *) dev->priv,0,sizeof(struct priv));
+
+ ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start);
+ ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0);
+ alloc586(dev);
+
+ /* set number of receive-buffs according to memsize */
+ if(size == 0x2000)
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+ else if(size == 0x4000)
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+ else
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
+
+ printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+
+ dev->open = sun3_82586_open;
+ dev->stop = sun3_82586_close;
+ dev->get_stats = sun3_82586_get_stats;
+ dev->tx_timeout = sun3_82586_timeout;
+ dev->watchdog_timeo = HZ/20;
+ dev->hard_start_xmit = sun3_82586_send_packet;
+ dev->set_multicast_list = set_multicast_list;
+
+ dev->if_port = 0;
+
+ ether_setup(dev);
+
+ return 0;
+out:
+ return retval;
+}
+
+
+static int init586(struct net_device *dev)
+{
+ void *ptr;
+ int i,result=0;
+ struct priv *p = (struct priv *) dev->priv;
+ volatile struct configure_cmd_struct *cfg_cmd;
+ volatile struct iasetup_cmd_struct *ias_cmd;
+ volatile struct tdr_cmd_struct *tdr_cmd;
+ volatile struct mcsetup_cmd_struct *mc_cmd;
+ struct dev_mc_list *dmi=dev->mc_list;
+ int num_addrs=dev->mc_count;
+
+ ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+ cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+ cfg_cmd->cmd_status = 0;
+ cfg_cmd->cmd_cmd = swab16(CMD_CONFIGURE | CMD_LAST);
+ cfg_cmd->cmd_link = 0xffff;
+
+ cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
+ cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */
+ cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
+ cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+ cfg_cmd->priority = 0x00;
+ cfg_cmd->ifs = 0x60;
+ cfg_cmd->time_low = 0x00;
+ cfg_cmd->time_high = 0xf2;
+ cfg_cmd->promisc = 0;
+ if(dev->flags & IFF_ALLMULTI) {
+ int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+ if(num_addrs > len) {
+ printk("%s: switching to promisc. mode\n",dev->name);
+ dev->flags|=IFF_PROMISC;
+ }
+ }
+ if(dev->flags&IFF_PROMISC)
+ {
+ cfg_cmd->promisc=1;
+ dev->flags|=IFF_PROMISC;
+ }
+ cfg_cmd->carr_coll = 0x00;
+
+ p->scb->cbl_offset = make16(cfg_cmd);
+ p->scb->cmd_ruc = 0;
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(cfg_cmd);
+
+ if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+ {
+ printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * individual address setup
+ */
+
+ ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+ ias_cmd->cmd_status = 0;
+ ias_cmd->cmd_cmd = swab16(CMD_IASETUP | CMD_LAST);
+ ias_cmd->cmd_link = 0xffff;
+
+ memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+ p->scb->cbl_offset = make16(ias_cmd);
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(ias_cmd);
+
+ if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+ printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+
+ tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+ tdr_cmd->cmd_status = 0;
+ tdr_cmd->cmd_cmd = swab16(CMD_TDR | CMD_LAST);
+ tdr_cmd->cmd_link = 0xffff;
+ tdr_cmd->status = 0;
+
+ p->scb->cbl_offset = make16(tdr_cmd);
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(tdr_cmd);
+
+ if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
+ {
+ printk("%s: Problems while running the TDR.\n",dev->name);
+ }
+ else
+ {
+ DELAY_16(); /* wait for result */
+ result = swab16(tdr_cmd->status);
+
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586(); /* ack the interrupts */
+
+ if(result & TDR_LNK_OK)
+ ;
+ else if(result & TDR_XCVR_PRB)
+ printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+ else if(result & TDR_ET_OPN)
+ printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ else if(result & TDR_ET_SRT)
+ {
+ if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+ printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ }
+ else
+ printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+ }
+
+ /*
+ * Multicast setup
+ */
+ if(num_addrs && !(dev->flags & IFF_PROMISC) )
+ {
+ mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+ mc_cmd->cmd_status = 0;
+ mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
+ mc_cmd->cmd_link = 0xffff;
+ mc_cmd->mc_cnt = swab16(num_addrs * 6);
+
+ for(i=0;i<num_addrs;i++,dmi=dmi->next)
+ memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+
+ p->scb->cbl_offset = make16(mc_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(mc_cmd);
+
+ if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't apply multicast-address-list.\n",dev->name);
+ }
+
+ /*
+ * alloc nop/xmit-cmds
+ */
+#if (NUM_XMIT_BUFFS == 1)
+ for(i=0;i<2;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#else
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#endif
+
+ ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+ /*
+ * alloc xmit-buffs / init xmit_cmds
+ */
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+ ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+ p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+ ptr = (char *) ptr + XMIT_BUFF_SIZE;
+ p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+ ptr = (char *) ptr + sizeof(struct tbd_struct);
+ if((void *)ptr > (void *)dev->mem_end)
+ {
+ printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+ return 1;
+ }
+ memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+ memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+ p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+ p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
+ p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
+ p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+ p->xmit_buffs[i]->next = 0xffff;
+ p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+ }
+
+ p->xmit_count = 0;
+ p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+ p->nop_point = 0;
+#endif
+
+ /*
+ * 'start transmitter'
+ */
+#ifndef NO_NOPCOMMANDS
+ p->scb->cbl_offset = make16(p->nop_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+#else
+ p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+ p->xmit_cmds[0]->cmd_cmd = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
+#endif
+
+ /*
+ * ack. interrupts
+ */
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586();
+ DELAY_16();
+
+ sun3_enaint();
+ sun3_active();
+
+ return 0;
+}
+
+/******************************************************
+ * This is a helper routine for sun3_82586_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev,void *ptr)
+{
+ volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+ volatile struct rbd_struct *rbd;
+ int i;
+ struct priv *p = (struct priv *) dev->priv;
+
+ memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+ p->rfd_first = rfd;
+
+ for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+ rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+ rfd[i].rbd_offset = 0xffff;
+ }
+ rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */
+
+ ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+ rbd = (struct rbd_struct *) ptr;
+ ptr = (void *) (rbd + p->num_recv_buffs);
+
+ /* clr descriptors */
+ memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+ for(i=0;i<p->num_recv_buffs;i++)
+ {
+ rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+ rbd[i].size = swab16(RECV_BUFF_SIZE);
+ rbd[i].buffer = make24(ptr);
+ ptr = (char *) ptr + RECV_BUFF_SIZE;
+ }
+
+ p->rfd_top = p->rfd_first;
+ p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->rfd_first->rbd_offset = make16(rbd);
+
+ return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
+{
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+ int cnt=0;
+ struct priv *p;
+
+ if (!dev) {
+ printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
+ return;
+ }
+ p = (struct priv *) dev->priv;
+
+ if(debuglevel > 1)
+ printk("I");
+
+ WAIT_4_SCB_CMD(); /* wait for last command */
+
+ while((stat=p->scb->cus & STAT_MASK))
+ {
+ p->scb->cmd_cuc = stat;
+ sun3_attn586();
+
+ if(stat & STAT_FR) /* received a frame */
+ sun3_82586_rcv_int(dev);
+
+ if(stat & STAT_RNR) /* RU went 'not ready' */
+ {
+ printk("(R)");
+ if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+ else
+ {
+ printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+ sun3_82586_rnr_int(dev);
+ }
+ }
+
+ if(stat & STAT_CX) /* command with I-bit set complete */
+ sun3_82586_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+ if(stat & STAT_CNA) /* CU went 'not ready' */
+ {
+ if(netif_running(dev))
+ printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+ }
+#endif
+
+ if(debuglevel > 1)
+ printk("%d",cnt++);
+
+ WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
+ if(p->scb->cmd_cuc) /* timed out? */
+ {
+ printk("%s: Acknowledge timed out.\n",dev->name);
+ sun3_disint();
+ break;
+ }
+ }
+
+ if(debuglevel > 1)
+ printk("i");
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void sun3_82586_rcv_int(struct net_device *dev)
+{
+ int status,cnt=0;
+ unsigned short totlen;
+ struct sk_buff *skb;
+ struct rbd_struct *rbd;
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(debuglevel > 0)
+ printk("R");
+
+ for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+ {
+ rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+ if(status & RFD_OK) /* frame received without error? */
+ {
+ if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
+ {
+ totlen &= RBD_MASK; /* length of this frame */
+ rbd->status = 0;
+ skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+ if(skb != NULL)
+ {
+ skb->dev = dev;
+ skb_reserve(skb,2);
+ skb_put(skb,totlen);
+ eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ p->stats.rx_packets++;
+ }
+ else
+ p->stats.rx_dropped++;
+ }
+ else
+ {
+ int rstat;
+ /* free all RBD's until RBD_LAST is set */
+ totlen = 0;
+ while(!((rstat=swab16(rbd->status)) & RBD_LAST))
+ {
+ totlen += rstat & RBD_MASK;
+ if(!rstat)
+ {
+ printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+ break;
+ }
+ rbd->status = 0;
+ rbd = (struct rbd_struct *) make32(rbd->next);
+ }
+ totlen += rstat & RBD_MASK;
+ rbd->status = 0;
+ printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+ p->stats.rx_dropped++;
+ }
+ }
+ else /* frame !(ok), only with 'save-bad-frames' */
+ {
+ printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+ p->stats.rx_errors++;
+ }
+ p->rfd_top->stat_high = 0;
+ p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+ p->rfd_top->rbd_offset = 0xffff;
+ p->rfd_last->last = 0; /* delete RFD_SUSP */
+ p->rfd_last = p->rfd_top;
+ p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+ p->scb->rfa_offset = make16(p->rfd_top);
+
+ if(debuglevel > 0)
+ printk("%d",cnt++);
+ }
+
+ if(automatic_resume)
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+
+#ifdef WAIT_4_BUSY
+ {
+ int i;
+ for(i=0;i<1024;i++)
+ {
+ if(p->rfd_top->status)
+ break;
+ DELAY_16();
+ if(i == 1023)
+ printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+ }
+ }
+#endif
+
+#if 0
+ if(!at_least_one)
+ {
+ int i;
+ volatile struct rfd_struct *rfds=p->rfd_top;
+ volatile struct rbd_struct *rbds;
+ printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+ for(i=0;i< (p->num_recv_buffs+4);i++)
+ {
+ rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+ printk("%04x:%04x ",rfds->status,rbds->status);
+ rfds = (struct rfd_struct *) make32(rfds->next);
+ }
+ printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+ printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+ }
+ old_at_least = at_least_one;
+#endif
+
+ if(debuglevel > 0)
+ printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void sun3_82586_rnr_int(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ p->stats.rx_errors++;
+
+ WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+ p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */
+
+ alloc_rfa(dev,(char *)p->rfd_first);
+/* maybe add a check here, before restarting the RU */
+ startrecv586(dev); /* restart RU */
+
+ printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void sun3_82586_xmt_int(struct net_device *dev)
+{
+ int status;
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(debuglevel > 0)
+ printk("X");
+
+ status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
+ if(!(status & STAT_COMPL))
+ printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+ if(status & STAT_OK)
+ {
+ p->stats.tx_packets++;
+ p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ }
+ else
+ {
+ p->stats.tx_errors++;
+ if(status & TCMD_LATECOLL) {
+ printk("%s: late collision detected.\n",dev->name);
+ p->stats.collisions++;
+ }
+ else if(status & TCMD_NOCARRIER) {
+ p->stats.tx_carrier_errors++;
+ printk("%s: no carrier detected.\n",dev->name);
+ }
+ else if(status & TCMD_LOSTCTS)
+ printk("%s: loss of CTS detected.\n",dev->name);
+ else if(status & TCMD_UNDERRUN) {
+ p->stats.tx_fifo_errors++;
+ printk("%s: DMA underrun detected.\n",dev->name);
+ }
+ else if(status & TCMD_MAXCOLL) {
+ printk("%s: Max. collisions exceeded.\n",dev->name);
+ p->stats.collisions += 16;
+ }
+ }
+
+#if (NUM_XMIT_BUFFS > 1)
+ if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+ p->xmit_last = 0;
+#endif
+ netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->scb->cmd_ruc = RUC_START;
+ sun3_attn586(); /* start cmd. */
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */
+}
+
+static void sun3_82586_timeout(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+#ifndef NO_NOPCOMMANDS
+ if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+ {
+ netif_wake_queue(dev);
+#ifdef DEBUG
+ printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+ printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
+#endif
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ dev->trans_start = jiffies;
+ return 0;
+ }
+#endif
+ {
+#ifdef DEBUG
+ printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+ printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
+ printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+ sun3_82586_close(dev);
+ sun3_82586_open(dev);
+ }
+ dev->trans_start = jiffies;
+}
+
+/******************************************************
+ * send frame
+ */
+
+static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ int len,i;
+#ifndef NO_NOPCOMMANDS
+ int next_nop;
+#endif
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(skb->len > XMIT_BUFF_SIZE)
+ {
+ printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+ return 0;
+ }
+
+ netif_stop_queue(dev);
+
+#if(NUM_XMIT_BUFFS > 1)
+ if(test_and_set_bit(0,(void *) &p->lock)) {
+ printk("%s: Queue was locked\n",dev->name);
+ return 1;
+ }
+ else
+#endif
+ {
+ memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+ len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+#if (NUM_XMIT_BUFFS == 1)
+# ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+ if(p->scb->cus & CU_ACTIVE)
+ {
+ printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+ printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
+ }
+#endif
+
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+ for(i=0;i<16;i++)
+ {
+ p->xmit_cmds[0]->cmd_status = 0;
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+ p->scb->cmd_cuc = CUC_RESUME;
+ else
+ {
+ p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ }
+
+ sun3_attn586();
+ dev->trans_start = jiffies;
+ if(!i)
+ dev_kfree_skb(skb);
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+ break;
+ if(p->xmit_cmds[0]->cmd_status)
+ break;
+ if(i==15)
+ printk("%s: Can't start transmit-command.\n",dev->name);
+ }
+# else
+ next_nop = (p->nop_point + 1) & 0x1;
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+
+ p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+ dev->trans_start = jiffies;
+ p->nop_point = next_nop;
+ dev_kfree_skb(skb);
+# endif
+#else
+ p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
+ if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+ next_nop = 0;
+
+ p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+ /* linkpointer of xmit-command already points to next nop cmd */
+ p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+ p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+ dev->trans_start = jiffies;
+ p->xmit_count = next_nop;
+
+ {
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if(p->xmit_count != p->xmit_last)
+ netif_wake_queue(dev);
+ p->lock = 0;
+ restore_flags(flags);
+ }
+ dev_kfree_skb(skb);
+#endif
+ }
+ return 0;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ unsigned short crc,aln,rsc,ovrn;
+
+ crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
+ p->scb->crc_errs = 0;
+ aln = swab16(p->scb->aln_errs);
+ p->scb->aln_errs = 0;
+ rsc = swab16(p->scb->rsc_errs);
+ p->scb->rsc_errs = 0;
+ ovrn = swab16(p->scb->ovrn_errs);
+ p->scb->ovrn_errs = 0;
+
+ p->stats.rx_crc_errors += crc;
+ p->stats.rx_fifo_errors += ovrn;
+ p->stats.rx_frame_errors += aln;
+ p->stats.rx_dropped += rsc;
+
+ return &p->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+ netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+#error This code is not currently supported as a module
+static struct net_device dev_sun3_82586;
+
+int init_module(void)
+{
+ dev_sun3_82586.init = sun3_82586_probe;
+ if (register_netdev(&dev_sun3_82586) != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&dev_sun3_82586);
+ kfree(dev_sun3_82586.priv);
+ dev_sun3_82586.priv = NULL;
+}
+#endif /* MODULE */
+
+#if 0
+/*
+ * DUMP .. we expect a not running CMD unit and enough space
+ */
+void sun3_82586_dump(struct net_device *dev,void *ptr)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+ int i;
+
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+
+ dump_cmd->cmd_status = 0;
+ dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+ dump_cmd->dump_offset = make16((dump_cmd + 1));
+ dump_cmd->cmd_link = 0xffff;
+
+ p->scb->cbl_offset = make16(dump_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_STAT_COMPL(dump_cmd);
+
+ if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't get dump information.\n",dev->name);
+
+ for(i=0;i<170;i++) {
+ printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+ if(i % 24 == 23)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
new file mode 100644
index 000000000000..81cfb098bcca
--- /dev/null
+++ b/drivers/net/sun3_82586.h
@@ -0,0 +1,318 @@
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ * crynwr-packet-driver by Russ Nelson
+ * Garret A. Wollman's i82586-driver for BSD
+ */
+
+/*
+ * Cloned from ni52.h, copyright as above.
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
+ */
+
+
+/* defines for the obio chip (not vme) */
+#define IEOB_NORSET 0x80 /* don't reset the board */
+#define IEOB_ONAIR 0x40 /* put us on the air */
+#define IEOB_ATTEN 0x20 /* attention! */
+#define IEOB_IENAB 0x10 /* interrupt enable */
+#define IEOB_XXXXX 0x08 /* free bit */
+#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02 /* bus error */
+#define IEOB_INT 0x01 /* interrupt */
+
+/* where the obio one lives */
+#define IE_OBIO 0xc0000
+#define IE_IRQ 3
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+ unsigned short zero_dum0; /* has to be zero */
+ unsigned char sysbus; /* 0=16Bit,1=8Bit */
+ unsigned char zero_dum1; /* has to be zero for 586 */
+ unsigned short zero_dum2;
+ unsigned short zero_dum3;
+ char *iscp; /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+ unsigned char busy; /* 586 clears after successful init */
+ unsigned char zero_dummy; /* has to be zero */
+ unsigned short scb_offset; /* pointeroffset to the scb_base */
+ char *scb_base; /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+ unsigned char rus;
+ unsigned char cus;
+ unsigned char cmd_ruc; /* command word: RU part */
+ unsigned char cmd_cuc; /* command word: CU part & ACK */
+ unsigned short cbl_offset; /* pointeroffset, command block list */
+ unsigned short rfa_offset; /* pointeroffset, receive frame area */
+ unsigned short crc_errs; /* CRC-Error counter */
+ unsigned short aln_errs; /* allignmenterror counter */
+ unsigned short rsc_errs; /* Resourceerror counter */
+ unsigned short ovrn_errs; /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK 0x0070 /* mask for RU commands */
+#define RUC_NOP 0x0000 /* NOP-command */
+#define RUC_START 0x0010 /* start RU */
+#define RUC_RESUME 0x0020 /* resume RU after suspend */
+#define RUC_SUSPEND 0x0030 /* suspend RU */
+#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
+
+#define CUC_MASK 0x07 /* mask for CU command */
+#define CUC_NOP 0x00 /* NOP-command */
+#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME 0x02 /* resume after suspend */
+#define CUC_SUSPEND 0x03 /* Suspend CU */
+#define CUC_ABORT 0x04 /* abort command operation immediately */
+
+#define ACK_MASK 0xf0 /* mask for ACK command */
+#define ACK_CX 0x80 /* acknowledges STAT_CX */
+#define ACK_FR 0x40 /* ack. STAT_FR */
+#define ACK_CNA 0x20 /* ack. STAT_CNA */
+#define ACK_RNR 0x10 /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK 0xf0 /* mask for cause of interrupt */
+#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
+#define STAT_FR 0x40 /* RU finished receiving a frame */
+#define STAT_CNA 0x20 /* CU left active state */
+#define STAT_RNR 0x10 /* RU left ready state */
+
+#define CU_STATUS 0x7 /* CU status, 0=idle */
+#define CU_SUSPEND 0x1 /* CU is suspended */
+#define CU_ACTIVE 0x2 /* CU is active */
+
+#define RU_STATUS 0x70 /* RU status, 0=idle */
+#define RU_SUSPEND 0x10 /* RU suspended */
+#define RU_NOSPACE 0x20 /* RU no resources */
+#define RU_READY 0x40 /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+ unsigned char stat_low; /* status word */
+ unsigned char stat_high; /* status word */
+ unsigned char rfd_sf; /* 82596 mode only */
+ unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */
+ unsigned short next; /* linkoffset to next RFD */
+ unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
+ unsigned char dest[6]; /* ethernet-address, destination */
+ unsigned char source[6]; /* ethernet-address, source */
+ unsigned short length; /* 802.3 frame-length */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RFD_LAST 0x80 /* last: last rfd in the list */
+#define RFD_SUSP 0x40 /* last: suspend RU after */
+#define RFD_COMPL 0x80
+#define RFD_OK 0x20
+#define RFD_BUSY 0x40
+#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC 0x08 /* CRC error */
+#define RFD_ERR_ALGN 0x04 /* Alignment error */
+#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
+#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
+
+#define RFD_ERR_FTS 0x0080 /* Frame to short */
+#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET 0x0001 /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+ char *buffer; /* receive buffer address pointer */
+ unsigned short size; /* size of this buffer */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RBD_LAST 0x8000 /* last buffer */
+#define RBD_USED 0x4000 /* this buffer has data */
+#define RBD_MASK 0x3fff /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL 0x8000 /* status: frame/command is complete */
+#define STAT_BUSY 0x4000 /* status: frame/command is busy */
+#define STAT_OK 0x2000 /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP 0x0000 /* NOP */
+#define CMD_IASETUP 0x0001 /* initial address setup command */
+#define CMD_CONFIGURE 0x0002 /* configure command */
+#define CMD_MCSETUP 0x0003 /* MC setup command */
+#define CMD_XMIT 0x0004 /* transmit command */
+#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
+#define CMD_DUMP 0x0006 /* dump command */
+#define CMD_DIAGNOSE 0x0007 /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST 0x8000 /* indicates last command in the CBL */
+#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
+#define CMD_INT 0x2000 /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+ unsigned short cmd_status; /* status of this command */
+ unsigned short cmd_cmd; /* the command itself (+bits) */
+ unsigned short cmd_link; /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char byte_cnt; /* size of the config-cmd */
+ unsigned char fifo; /* fifo/recv monitor */
+ unsigned char sav_bf; /* save bad frames (bit7=1)*/
+ unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+ unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+ unsigned char ifs; /* inter frame spacing */
+ unsigned char time_low; /* slot time low */
+ unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
+ unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
+ unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
+ unsigned char fram_len; /* minimal frame len */
+ unsigned char dummy; /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short mc_cnt; /* number of bytes in the MC-List */
+ unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short dump_offset; /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short tbd_offset; /* pointeroffset to TBD */
+ unsigned char dest[6]; /* destination address of the frame */
+ unsigned short length; /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK 0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL 0x0020
+#define TCMD_HEARTBEAT 0x0040
+#define TCMD_DEFERRED 0x0080
+#define TCMD_UNDERRUN 0x0100
+#define TCMD_LOSTCTS 0x0200
+#define TCMD_NOCARRIER 0x0400
+#define TCMD_LATECOLL 0x0800
+
+struct tdr_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short status;
+};
+
+#define TDR_LNK_OK 0x8000 /* No link problem identified */
+#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
+#define TDR_ET_OPN 0x2000 /* open, no correct termination */
+#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
+#define TDR_TIMEMASK 0x07ff /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+ unsigned short size; /* size + EOF-Flag(15) */
+ unsigned short next; /* pointeroffset to next TBD */
+ char *buffer; /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
+
+
+
+
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index bbdc8ca9ae6f..ff6f30e1404c 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1,7 +1,7 @@
/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
- * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
*
* Support for Apple GMAC and assorted PHYs by
* Benjamin Herrenscmidt (benh@kernel.crashing.org)
@@ -16,6 +16,8 @@
* I can at least detect gigabit with autoneg.
*/
+#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -35,9 +37,10 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -67,8 +70,8 @@
NETIF_MSG_LINK)
#define DRV_NAME "sungem"
-#define DRV_VERSION "0.96"
-#define DRV_RELDATE "11/17/01"
+#define DRV_VERSION "0.97"
+#define DRV_RELDATE "3/20/02"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
static char version[] __devinitdata =
@@ -293,19 +296,119 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
return 0;
}
+/* When we get a RX fifo overflow, the RX unit in GEM is probably hung
+ * so we do the following.
+ *
+ * If any part of the reset goes wrong, we return 1 and that causes the
+ * whole chip to be reset.
+ */
+static int gem_rxmac_reset(struct gem *gp)
+{
+ struct net_device *dev = gp->dev;
+ int limit, i;
+ u64 desc_dma;
+ u32 val;
+
+ /* First, reset MAC RX. */
+ writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB,
+ gp->regs + MAC_RXCFG);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ /* Second, disable RX DMA. */
+ writel(0, gp->regs + RXDMA_CFG);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + RXDMA_CFG) & RXDMA_CFG_ENABLE))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ udelay(5000);
+
+ /* Execute RX reset command. */
+ writel(gp->swrst_base | GREG_SWRST_RXRST,
+ gp->regs + GREG_SWRST);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + GREG_SWRST) & GREG_SWRST_RXRST))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX reset command will not execute, resetting "
+ "whole chip.\n", dev->name);
+ return 1;
+ }
+
+ /* Refresh the RX ring. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct gem_rxd *rxd = &gp->init_block->rxd[i];
+
+ if (gp->rx_skbs[i] == NULL) {
+ printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
+ "whole chip.\n", dev->name);
+ return 1;
+ }
+
+ rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
+ }
+ gp->rx_new = gp->rx_old = 0;
+
+ /* Now we must reprogram the rest of RX unit. */
+ desc_dma = (u64) gp->gblock_dvma;
+ desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
+ writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
+ writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
+ writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+ val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
+ ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+ writel(val, gp->regs + RXDMA_CFG);
+ if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((8 << 12) & RXDMA_BLANK_ITIME)),
+ gp->regs + RXDMA_BLANK);
+ else
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((4 << 12) & RXDMA_BLANK_ITIME)),
+ gp->regs + RXDMA_BLANK);
+ val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF);
+ val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON);
+ writel(val, gp->regs + RXDMA_PTHRESH);
+ val = readl(gp->regs + RXDMA_CFG);
+ writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+ writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+ val = readl(gp->regs + MAC_RXCFG);
+ writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+ return 0;
+}
+
static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
{
u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
+ int ret = 0;
if (netif_msg_intr(gp))
printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
gp->dev->name, rxmac_stat);
if (rxmac_stat & MAC_RXSTAT_OFLW) {
- printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
- dev->name);
gp->net_stats.rx_over_errors++;
gp->net_stats.rx_fifo_errors++;
+
+ ret = gem_rxmac_reset(gp);
}
if (rxmac_stat & MAC_RXSTAT_ACE)
@@ -320,7 +423,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
/* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE
* events.
*/
- return 0;
+ return ret;
}
static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
@@ -480,7 +583,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat
return 0;
do_reset:
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
return 1;
@@ -542,7 +645,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
gp->tx_old = entry;
if (netif_queue_stopped(dev) &&
- TX_BUFFS_AVAIL(gp) > 0)
+ TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev);
}
@@ -717,7 +820,7 @@ static void gem_tx_timeout(struct net_device *dev)
spin_lock_irq(&gp->lock);
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
spin_unlock_irq(&gp->lock);
@@ -752,9 +855,12 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&gp->lock);
+ /* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&gp->lock);
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+ dev->name);
return 1;
}
@@ -829,7 +935,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
gp->tx_new = entry;
- if (TX_BUFFS_AVAIL(gp) <= 0)
+ if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
if (netif_msg_tx_queued(gp))
@@ -844,19 +950,28 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Jumbo-grams don't seem to work :-( */
+#define GEM_MIN_MTU 68
#if 1
-#define MAX_MTU 1500
+#define GEM_MAX_MTU 1500
#else
-#define MAX_MTU 9000
+#define GEM_MAX_MTU 9000
#endif
static int gem_change_mtu(struct net_device *dev, int new_mtu)
{
struct gem *gp = dev->priv;
- if (new_mtu < 0 || new_mtu > MAX_MTU)
+ if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
return -EINVAL;
+ if (!netif_running(dev) || !netif_device_present(dev)) {
+ /* We'll just catch it later when the
+ * device is up'd or resumed.
+ */
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
spin_lock_irq(&gp->lock);
dev->mtu = new_mtu;
gp->reset_task_pending = 1;
@@ -870,6 +985,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
#define STOP_TRIES 32
+/* Must be invoked under gp->lock. */
static void gem_stop(struct gem *gp)
{
int limit;
@@ -879,7 +995,8 @@ static void gem_stop(struct gem *gp)
writel(0xffffffff, gp->regs + GREG_IMASK);
/* Reset the chip */
- writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
+ writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST,
+ gp->regs + GREG_SWRST);
limit = STOP_TRIES;
@@ -894,6 +1011,7 @@ static void gem_stop(struct gem *gp)
printk(KERN_ERR "gem: SW reset is ghetto.\n");
}
+/* Must be invoked under gp->lock. */
static void gem_start_dma(struct gem *gp)
{
unsigned long val;
@@ -929,6 +1047,7 @@ static int phy_BCM5400_link_table[8][3] = {
{ 1, 0, 1 }, /* 1000BT */
};
+/* Must be invoked under gp->lock. */
static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
{
u16 ctl;
@@ -954,11 +1073,8 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
}
start_aneg:
- spin_lock_irq(&gp->lock);
- if (!gp->hw_running) {
- spin_unlock_irq(&gp->lock);
+ if (!gp->hw_running)
return;
- }
/* Configure PHY & start aneg */
ctl = phy_read(gp, MII_BMCR);
@@ -973,11 +1089,10 @@ start_aneg:
phy_write(gp, MII_BMCR, ctl);
gp->timer_ticks = 0;
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
- spin_unlock_irq(&gp->lock);
+ mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
}
+/* Must be invoked under gp->lock. */
static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
{
u32 val;
@@ -1021,6 +1136,8 @@ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause
/* A link-up condition has occurred, initialize and enable the
* rest of the chip.
+ *
+ * Must be invoked under gp->lock.
*/
static void gem_set_link_modes(struct gem *gp)
{
@@ -1101,6 +1218,20 @@ static void gem_set_link_modes(struct gem *gp)
pause = 1;
}
+ if (netif_msg_link(gp)) {
+ if (pause) {
+ printk(KERN_INFO "%s: Pause is enabled "
+ "(rxfifo: %d off: %d on: %d)\n",
+ gp->dev->name,
+ gp->rx_fifo_sz,
+ gp->rx_pause_off,
+ gp->rx_pause_on);
+ } else {
+ printk(KERN_INFO "%s: Pause is disabled\n",
+ gp->dev->name);
+ }
+ }
+
if (!full_duplex)
writel(512, gp->regs + MAC_STIME);
else
@@ -1115,6 +1246,7 @@ static void gem_set_link_modes(struct gem *gp)
gem_start_dma(gp);
}
+/* Must be invoked under gp->lock. */
static int gem_mdio_link_not_up(struct gem *gp)
{
u16 val;
@@ -1158,7 +1290,7 @@ static int gem_mdio_link_not_up(struct gem *gp)
return 0;
}
-static void gem_init_rings(struct gem *, int);
+static void gem_init_rings(struct gem *);
static void gem_init_hw(struct gem *, int);
static void gem_reset_task(void *data)
@@ -1169,24 +1301,27 @@ static void gem_reset_task(void *data)
* DMA stopped. Todo: Use this function for reset
* on error as well.
*/
+
+ spin_lock_irq(&gp->lock);
+
if (gp->hw_running && gp->opened) {
/* Make sure we don't get interrupts or tx packets */
- spin_lock_irq(&gp->lock);
-
netif_stop_queue(gp->dev);
writel(0xffffffff, gp->regs + GREG_IMASK);
- spin_unlock_irq(&gp->lock);
-
/* Reset the chip & rings */
gem_stop(gp);
- gem_init_rings(gp, 0);
- gem_init_hw(gp, 0);
+ gem_init_rings(gp);
+
+ gem_init_hw(gp,
+ (gp->reset_task_pending == 2));
netif_wake_queue(gp->dev);
}
gp->reset_task_pending = 0;
+
+ spin_unlock_irq(&gp->lock);
}
static void gem_link_timer(unsigned long data)
@@ -1196,13 +1331,14 @@ static void gem_link_timer(unsigned long data)
if (!gp->hw_running)
return;
+ spin_lock_irq(&gp->lock);
+
/* If the link of task is still pending, we just
* reschedule the link timer
*/
if (gp->reset_task_pending)
goto restart;
- spin_lock_irq(&gp->lock);
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
u16 val = phy_read(gp, MII_BMSR);
@@ -1247,16 +1383,15 @@ static void gem_link_timer(unsigned long data)
if (netif_msg_link(gp))
printk(KERN_INFO "%s: Link down\n",
gp->dev->name);
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
restart = 1;
} else if (++gp->timer_ticks > 10)
restart = gem_mdio_link_not_up(gp);
if (restart) {
- spin_unlock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
- return;
+ goto out_unlock;
}
}
} else {
@@ -1273,11 +1408,12 @@ static void gem_link_timer(unsigned long data)
}
restart:
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
+ mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
+out_unlock:
spin_unlock_irq(&gp->lock);
}
+/* Must be invoked under gp->lock. */
static void gem_clean_rings(struct gem *gp)
{
struct gem_init_block *gb = gp->init_block;
@@ -1311,7 +1447,9 @@ static void gem_clean_rings(struct gem *gp)
gp->tx_skbs[i] = NULL;
for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
- txd = &gb->txd[i];
+ int ent = i & (TX_RING_SIZE - 1);
+
+ txd = &gb->txd[ent];
dma_addr = le64_to_cpu(txd->buffer);
pci_unmap_page(gp->pdev, dma_addr,
le64_to_cpu(txd->control_word) &
@@ -1325,16 +1463,14 @@ static void gem_clean_rings(struct gem *gp)
}
}
-static void gem_init_rings(struct gem *gp, int from_irq)
+/* Must be invoked under gp->lock. */
+static void gem_init_rings(struct gem *gp)
{
struct gem_init_block *gb = gp->init_block;
struct net_device *dev = gp->dev;
- int i, gfp_flags = GFP_KERNEL;
+ int i;
dma_addr_t dma_addr;
- if (from_irq)
- gfp_flags = GFP_ATOMIC;
-
gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0;
gem_clean_rings(gp);
@@ -1343,7 +1479,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
struct sk_buff *skb;
struct gem_rxd *rxd = &gb->rxd[i];
- skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags);
+ skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
if (!skb) {
rxd->buffer = 0;
rxd->status_word = 0;
@@ -1372,6 +1508,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
}
}
+/* Must be invoked under gp->lock. */
static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
{
u16 val;
@@ -1396,6 +1533,7 @@ static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
return (limit <= 0);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5201_phy(struct gem *gp)
{
u16 data;
@@ -1405,6 +1543,7 @@ static void gem_init_bcm5201_phy(struct gem *gp)
phy_write(gp, MII_BCM5201_MULTIPHY, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5400_phy(struct gem *gp)
{
u16 data;
@@ -1432,6 +1571,7 @@ static void gem_init_bcm5400_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_AUXCONTROL, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5401_phy(struct gem *gp)
{
u16 data;
@@ -1446,6 +1586,9 @@ static void gem_init_bcm5401_phy(struct gem *gp)
* WARNING ! OF and Darwin don't agree on the
* register addresses. OF seem to interpret the
* register numbers below as decimal
+ *
+ * Note: This should (and does) match tg3_init_5401phy_dsp
+ * in the tg3.c driver. -DaveM
*/
phy_write(gp, 0x18, 0x0c20);
phy_write(gp, 0x17, 0x0012);
@@ -1475,6 +1618,7 @@ static void gem_init_bcm5401_phy(struct gem *gp)
__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5411_phy(struct gem *gp)
{
u16 data;
@@ -1501,6 +1645,7 @@ static void gem_init_bcm5411_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_GB_CONTROL, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_phy(struct gem *gp)
{
u32 mifcfg;
@@ -1649,7 +1794,9 @@ static void gem_init_phy(struct gem *gp)
val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
writel(val, gp->regs + PCS_CFG);
- /* Advertise all capabilities. */
+ /* Advertise all capabilities except assymetric
+ * pause.
+ */
val = readl(gp->regs + PCS_MIIADV);
val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
PCS_MIIADV_SP | PCS_MIIADV_AP);
@@ -1684,9 +1831,9 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
gp->phy_mod != phymod_bcm5411)
gp->link_cntl &= ~BMCR_SPD2;
-
}
+/* Must be invoked under gp->lock. */
static void gem_init_dma(struct gem *gp)
{
u64 desc_dma = (u64) gp->gblock_dvma;
@@ -1702,7 +1849,7 @@ static void gem_init_dma(struct gem *gp)
writel(0, gp->regs + TXDMA_KICK);
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
- ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512);
+ ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
writel(val, gp->regs + RXDMA_CFG);
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
@@ -1724,6 +1871,7 @@ static void gem_init_dma(struct gem *gp)
gp->regs + RXDMA_BLANK);
}
+/* Must be invoked under gp->lock. */
static u32
gem_setup_multicast(struct gem *gp)
{
@@ -1766,10 +1914,10 @@ gem_setup_multicast(struct gem *gp)
return rxcfg;
}
+/* Must be invoked under gp->lock. */
static void gem_init_mac(struct gem *gp)
{
unsigned char *e = &gp->dev->dev_addr[0];
- u32 rxcfg;
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
gp->pdev->device == PCI_DEVICE_ID_SUN_GEM)
@@ -1780,7 +1928,10 @@ static void gem_init_mac(struct gem *gp)
writel(0x04, gp->regs + MAC_IPG2);
writel(0x40, gp->regs + MAC_STIME);
writel(0x40, gp->regs + MAC_MINFSZ);
- writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ);
+
+ /* Ethernet payload + header + FCS + optional VLAN tag. */
+ writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ);
+
writel(0x07, gp->regs + MAC_PASIZE);
writel(0x04, gp->regs + MAC_JAMSIZE);
writel(0x10, gp->regs + MAC_ATTLIM);
@@ -1806,7 +1957,7 @@ static void gem_init_mac(struct gem *gp)
writel(0, gp->regs + MAC_AF21MSK);
writel(0, gp->regs + MAC_AF0MSK);
- rxcfg = gem_setup_multicast(gp);
+ gp->mac_rx_cfg = gem_setup_multicast(gp);
writel(0, gp->regs + MAC_NCOLL);
writel(0, gp->regs + MAC_FASUCC);
@@ -1824,7 +1975,7 @@ static void gem_init_mac(struct gem *gp)
* them once a link is established.
*/
writel(0, gp->regs + MAC_TXCFG);
- writel(rxcfg, gp->regs + MAC_RXCFG);
+ writel(gp->mac_rx_cfg, gp->regs + MAC_RXCFG);
writel(0, gp->regs + MAC_MCCFG);
writel(0, gp->regs + MAC_XIFCFG);
@@ -1841,6 +1992,7 @@ static void gem_init_mac(struct gem *gp)
writel(0xffffffff, gp->regs + MAC_MCMASK);
}
+/* Must be invoked under gp->lock. */
static void gem_init_pause_thresholds(struct gem *gp)
{
/* Calculate pause thresholds. Setting the OFF threshold to the
@@ -1851,8 +2003,9 @@ static void gem_init_pause_thresholds(struct gem *gp)
if (gp->rx_fifo_sz <= (2 * 1024)) {
gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
} else {
- int off = (gp->rx_fifo_sz - (5 * 1024));
- int on = off - 1024;
+ int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
+ int off = (gp->rx_fifo_sz - (max_frame * 2));
+ int on = off - max_frame;
gp->rx_pause_off = off;
gp->rx_pause_on = on;
@@ -1861,7 +2014,10 @@ static void gem_init_pause_thresholds(struct gem *gp)
{
u32 cfg;
- cfg = GREG_CFG_IBURST;
+ cfg = 0;
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
+ cfg |= GREG_CFG_IBURST;
+#endif
cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
writel(cfg, gp->regs + GREG_CFG);
@@ -1881,6 +2037,7 @@ static int gem_check_invariants(struct gem *gp)
gp->phy_type = phy_mii_mdio0;
gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+ gp->swrst_base = 0;
return 0;
}
@@ -1943,6 +2100,7 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
+ gp->swrst_base = 0;
} else {
if (gp->tx_fifo_sz != (2 * 1024) ||
gp->rx_fifo_sz != (2 * 1024)) {
@@ -1950,12 +2108,14 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
+ gp->swrst_base = (64 / 4) << GREG_SWRST_CACHE_SHIFT;
}
}
return 0;
}
+/* Must be invoked under gp->lock. */
static void gem_init_hw(struct gem *gp, int restart_link)
{
/* On Apple's gmac, I initialize the PHY only after
@@ -1970,21 +2130,16 @@ static void gem_init_hw(struct gem *gp, int restart_link)
gem_init_mac(gp);
gem_init_pause_thresholds(gp);
- spin_lock_irq(&gp->lock);
if (restart_link) {
/* Default aneg parameters */
gp->timer_ticks = 0;
gp->lstate = link_down;
- spin_unlock_irq(&gp->lock);
-
/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
gem_begin_auto_negotiation(gp, NULL);
} else {
if (gp->lstate == link_up)
gem_set_link_modes(gp);
-
- spin_unlock_irq(&gp->lock);
}
}
@@ -2029,6 +2184,7 @@ static void gem_apple_powerdown(struct gem *gp)
#endif /* CONFIG_ALL_PPC */
+/* Must be invoked under gp->lock. */
static void gem_stop_phy(struct gem *gp)
{
u32 mifcfg;
@@ -2100,14 +2256,21 @@ static void gem_shutdown(struct gem *gp)
schedule();
/* Actually stop the chip */
+ spin_lock_irq(&gp->lock);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
gem_stop_phy(gp);
+
+ spin_unlock_irq(&gp->lock);
+
#ifdef CONFIG_ALL_PPC
/* Power down the chip */
gem_apple_powerdown(gp);
#endif /* CONFIG_ALL_PPC */
- } else
+ } else {
gem_stop(gp);
+
+ spin_unlock_irq(&gp->lock);
+ }
}
static void gem_pm_task(void *data)
@@ -2142,14 +2305,19 @@ static void gem_pm_timer(unsigned long data)
static int gem_open(struct net_device *dev)
{
struct gem *gp = dev->priv;
- int hw_was_up = gp->hw_running;
+ int hw_was_up;
down(&gp->pm_sem);
+ hw_was_up = gp->hw_running;
+
/* Stop the PM timer/task */
del_timer(&gp->pm_timer);
flush_scheduled_tasks();
+ /* The power-management semaphore protects the hw_running
+ * etc. state so it is safe to do this bit without gp->lock
+ */
if (!gp->hw_running) {
#ifdef CONFIG_ALL_PPC
/* First, we need to bring up the chip */
@@ -2158,18 +2326,26 @@ static int gem_open(struct net_device *dev)
gem_check_invariants(gp);
}
#endif /* CONFIG_ALL_PPC */
+
/* Reset the chip */
+ spin_lock_irq(&gp->lock);
gem_stop(gp);
+ spin_unlock_irq(&gp->lock);
gp->hw_running = 1;
}
+ spin_lock_irq(&gp->lock);
+
/* We can now request the interrupt as we know it's masked
* on the controller
*/
if (request_irq(gp->pdev->irq, gem_interrupt,
SA_SHIRQ, dev->name, (void *)dev)) {
+ spin_unlock_irq(&gp->lock);
+
printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
+
#ifdef CONFIG_ALL_PPC
if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerdown(gp);
@@ -2183,13 +2359,15 @@ static int gem_open(struct net_device *dev)
}
/* Allocate & setup ring buffers */
- gem_init_rings(gp, 0);
+ gem_init_rings(gp);
/* Init & setup chip hardware */
gem_init_hw(gp, !hw_was_up);
gp->opened = 1;
+ spin_unlock_irq(&gp->lock);
+
up(&gp->pm_sem);
return 0;
@@ -2209,8 +2387,6 @@ static int gem_close(struct net_device *dev)
writel(0xffffffff, gp->regs + GREG_IMASK);
netif_stop_queue(dev);
- spin_unlock_irq(&gp->lock);
-
/* Stop chip */
gem_stop(gp);
@@ -2220,6 +2396,8 @@ static int gem_close(struct net_device *dev)
/* Bye, the pm timer will finish the job */
free_irq(gp->pdev->irq, (void *) dev);
+ spin_unlock_irq(&gp->lock);
+
/* Fire the PM timer that will shut us down in about 10 seconds */
gp->pm_timer.expires = jiffies + 10*HZ;
add_timer(&gp->pm_timer);
@@ -2245,21 +2423,21 @@ static int gem_suspend(struct pci_dev *pdev, u32 state)
/* If the driver is opened, we stop the DMA */
if (gp->opened) {
+ spin_lock_irq(&gp->lock);
+
/* Stop traffic, mark us closed */
netif_device_detach(dev);
- spin_lock_irq(&gp->lock);
-
writel(0xffffffff, gp->regs + GREG_IMASK);
- spin_unlock_irq(&gp->lock);
-
/* Stop chip */
gem_stop(gp);
/* Get rid of ring buffers */
gem_clean_rings(gp);
+ spin_unlock_irq(&gp->lock);
+
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
disable_irq(gp->pdev->irq);
}
@@ -2290,10 +2468,15 @@ static int gem_resume(struct pci_dev *pdev)
gem_check_invariants(gp);
}
#endif /* CONFIG_ALL_PPC */
+ spin_lock_irq(&gp->lock);
+
gem_stop(gp);
gp->hw_running = 1;
- gem_init_rings(gp, 0);
+ gem_init_rings(gp);
gem_init_hw(gp, 1);
+
+ spin_unlock_irq(&gp->lock);
+
netif_device_attach(dev);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
enable_irq(gp->pdev->irq);
@@ -2309,6 +2492,8 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
struct gem *gp = dev->priv;
struct net_device_stats *stats = &gp->net_stats;
+ spin_lock_irq(&gp->lock);
+
if (gp->hw_running) {
stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
writel(0, gp->regs + MAC_FCSERR);
@@ -2326,6 +2511,9 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
writel(0, gp->regs + MAC_ECOLL);
writel(0, gp->regs + MAC_LCOLL);
}
+
+ spin_unlock_irq(&gp->lock);
+
return &gp->net_stats;
}
@@ -2338,10 +2526,12 @@ static void gem_set_multicast(struct net_device *dev)
if (!gp->hw_running)
return;
+ spin_lock_irq(&gp->lock);
+
netif_stop_queue(dev);
rxcfg = readl(gp->regs + MAC_RXCFG);
- rxcfg_new = gem_setup_multicast(gp);
+ gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp);
writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
@@ -2355,8 +2545,9 @@ static void gem_set_multicast(struct net_device *dev)
writel(rxcfg, gp->regs + MAC_RXCFG);
- /* Hrm... we may walk on the reset task here... */
netif_wake_queue(dev);
+
+ spin_unlock_irq(&gp->lock);
}
/* Eventually add support for changing the advertisement
@@ -2405,11 +2596,13 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings if HW is on. */
+ spin_lock_irq(&gp->lock);
if (gp->hw_running) {
bmcr = phy_read(gp, MII_BMCR);
gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
} else
bmcr = 0;
+ spin_unlock_irq(&gp->lock);
if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
@@ -2443,18 +2636,22 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.duplex != DUPLEX_FULL)))
return -EINVAL;
- /* Apply settings and restart link process */
- if (gp->hw_running)
- del_timer(&gp->link_timer);
+ /* Apply settings and restart link process. */
+ spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, &ecmd);
+ spin_unlock_irq(&gp->lock);
+
return 0;
case ETHTOOL_NWAY_RST:
if ((gp->link_cntl & BMCR_ANENABLE) == 0)
return -EINVAL;
- if (gp->hw_running)
- del_timer(&gp->link_timer);
+
+ /* Restart link process. */
+ spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
+ spin_unlock_irq(&gp->lock);
+
return 0;
case ETHTOOL_GWOL:
@@ -2570,13 +2767,74 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return rc;
}
+#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC))
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr)
+{
+ int this_offset;
+
+ for (this_offset = 0x20; this_offset < len; this_offset++) {
+ void *p = rom_base + this_offset;
+ int i;
+
+ if (readb(p + 0) != 0x90 ||
+ readb(p + 1) != 0x00 ||
+ readb(p + 2) != 0x09 ||
+ readb(p + 3) != 0x4e ||
+ readb(p + 4) != 0x41 ||
+ readb(p + 5) != 0x06)
+ continue;
+
+ this_offset += 6;
+ p += 6;
+
+ for (i = 0; i < 6; i++)
+ dev_addr[i] = readb(p + i);
+ break;
+ }
+}
+
+static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+ u32 rom_reg_orig;
+ void *p;
+
+ if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+ if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+ goto use_random;
+ }
+
+ pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+ pci_write_config_dword(pdev, pdev->rom_base_reg,
+ rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+ p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+ if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+ find_eth_addr_in_vpd(p, (64 * 1024), dev_addr);
+
+ if (p != NULL)
+ iounmap(p);
+
+ pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+ return;
+
+use_random:
+ /* Sun MAC prefix then 3 random bytes. */
+ dev_addr[0] = 0x08;
+ dev_addr[1] = 0x00;
+ dev_addr[2] = 0x20;
+ get_random_bytes(dev_addr, 3);
+ return;
+}
+#endif /* not Sparc and not PPC */
+
static int __devinit gem_get_device_address(struct gem *gp)
{
#if defined(__sparc__) || defined(CONFIG_ALL_PPC)
struct net_device *dev = gp->dev;
#endif
-#ifdef __sparc__
+#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
int node = -1;
@@ -2591,8 +2849,7 @@ static int __devinit gem_get_device_address(struct gem *gp)
}
if (node == -1)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#endif
-#ifdef CONFIG_ALL_PPC
+#elif defined(CONFIG_ALL_PPC)
unsigned char *addr;
addr = get_property(gp->of_node, "local-mac-address", NULL);
@@ -2602,6 +2859,8 @@ static int __devinit gem_get_device_address(struct gem *gp)
return -1;
}
memcpy(dev->dev_addr, addr, MAX_ADDR_LEN);
+#else
+ get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr);
#endif
return 0;
}
@@ -2664,21 +2923,21 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
return -ENODEV;
}
- dev = init_etherdev(NULL, sizeof(*gp));
+ dev = alloc_etherdev(sizeof(*gp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev init failed, aborting.\n");
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
- if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) {
- printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, "
- "aborting.\n", gemreg_base, gemreg_len);
+ gp = dev->priv;
+
+ if (pci_request_regions(pdev, dev->name)) {
+ printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+ "aborting.\n");
goto err_out_free_netdev;
}
- gp = dev->priv;
-
gp->pdev = pdev;
dev->base_addr = (long) pdev;
gp->dev = dev;
@@ -2711,7 +2970,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (gp->regs == 0UL) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
- goto err_out_free_mmio_res;
+ goto err_out_free_res;
}
/* On Apple, we power the chip up now in order for check
@@ -2722,12 +2981,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerup(gp);
#endif
+ spin_lock_irq(&gp->lock);
gem_stop(gp);
+ spin_unlock_irq(&gp->lock);
+
if (gem_check_invariants(gp))
goto err_out_iounmap;
+
+ spin_lock_irq(&gp->lock);
gp->hw_running = 1;
gem_init_phy(gp);
gem_begin_auto_negotiation(gp, NULL);
+ spin_unlock_irq(&gp->lock);
/* It is guarenteed that the returned buffer will be at least
* PAGE_SIZE aligned.
@@ -2741,22 +3006,28 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- pci_set_drvdata(pdev, dev);
-
- printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
- dev->name);
-
#ifdef CONFIG_ALL_PPC
gp->of_node = pci_device_to_OF_node(pdev);
#endif
if (gem_get_device_address(gp))
- goto err_out_iounmap;
+ goto err_out_free_consistent;
+
+ if (register_netdev(dev)) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_consistent;
+ }
+
+ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
+ dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i],
i == 5 ? ' ' : ':');
printk("\n");
+ pci_set_drvdata(pdev, dev);
+
dev->open = gem_open;
dev->stop = gem_close;
dev->hard_start_xmit = gem_start_xmit;
@@ -2780,6 +3051,12 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
return 0;
+err_out_free_consistent:
+ pci_free_consistent(pdev,
+ sizeof(struct gem_init_block),
+ gp->init_block,
+ gp->gblock_dvma);
+
err_out_iounmap:
down(&gp->pm_sem);
/* Stop the PM timer & task */
@@ -2788,13 +3065,13 @@ err_out_iounmap:
if (gp->hw_running)
gem_shutdown(gp);
up(&gp->pm_sem);
+
iounmap((void *) gp->regs);
-err_out_free_mmio_res:
- release_mem_region(gemreg_base, gemreg_len);
+err_out_free_res:
+ pci_release_regions(pdev);
err_out_free_netdev:
- unregister_netdev(dev);
kfree(dev);
return -ENODEV;
@@ -2823,8 +3100,7 @@ static void __devexit gem_remove_one(struct pci_dev *pdev)
gp->init_block,
gp->gblock_dvma);
iounmap((void *) gp->regs);
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ pci_release_regions(pdev);
kfree(dev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 971db64a446a..d26652f9d64e 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -94,6 +94,8 @@
#define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */
#define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */
#define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */
+#define GREG_SWRST_CACHESIZE 0x00ff0000 /* RIO only: cache line size */
+#define GREG_SWRST_CACHE_SHIFT 16
/* TX DMA Registers */
#define TXDMA_KICK 0x2000UL /* TX Kick Register */
@@ -986,6 +988,9 @@ struct gem {
int mii_phy_addr;
int gigabit_capable;
+ u32 mac_rx_cfg;
+ u32 swrst_base;
+
/* Autoneg & PHY control */
int link_cntl;
int link_advertise;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 14c3e26652a8..0a8aba5d08ab 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3,7 +3,7 @@
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
- * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -14,7 +14,7 @@
*/
static char version[] =
- "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+ "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
#include <linux/module.h>
@@ -34,6 +34,7 @@ static char version[] =
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/crc32.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -696,7 +697,7 @@ no_response:
return 1;
}
-static int happy_meal_init(struct happy_meal *hp, int from_irq);
+static int happy_meal_init(struct happy_meal *hp);
static int is_lucent_phy(struct happy_meal *hp)
{
@@ -707,12 +708,8 @@ static int is_lucent_phy(struct happy_meal *hp)
mr2 = happy_meal_tcvr_read(hp, tregs, 2);
mr3 = happy_meal_tcvr_read(hp, tregs, 3);
if ((mr2 & 0xffff) == 0x0180 &&
- ((mr3 & 0xffff) >> 10) == 0x1d) {
-#if 0
- printk("HMEDEBUG: Lucent PHY detected.\n");
-#endif
+ ((mr3 & 0xffff) >> 10) == 0x1d)
ret = 1;
- }
return ret;
}
@@ -723,6 +720,8 @@ static void happy_meal_timer(unsigned long data)
unsigned long tregs = hp->tcvregs;
int restart_timer = 0;
+ spin_lock_irq(&hp->happy_lock);
+
hp->timer_ticks++;
switch(hp->timer_state) {
case arbwait:
@@ -852,13 +851,13 @@ static void happy_meal_timer(unsigned long data)
printk(KERN_NOTICE "%s: Link down, cable problem?\n",
hp->dev->name);
- ret = happy_meal_init(hp, 0);
+ ret = happy_meal_init(hp);
if (ret) {
/* ho hum... */
printk(KERN_ERR "%s: Error, cannot re-init the "
"Happy Meal.\n", hp->dev->name);
}
- return;
+ goto out;
}
if (!is_lucent_phy(hp)) {
hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
@@ -890,11 +889,15 @@ static void happy_meal_timer(unsigned long data)
hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
add_timer(&hp->happy_timer);
}
+
+out:
+ spin_unlock_irq(&hp->happy_lock);
}
#define TX_RESET_TRIES 32
#define RX_RESET_TRIES 32
+/* hp->happy_lock must be held */
static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
{
int tries = TX_RESET_TRIES;
@@ -914,6 +917,7 @@ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
{
int tries = RX_RESET_TRIES;
@@ -935,6 +939,7 @@ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
#define STOP_TRIES 16
+/* hp->happy_lock must be held */
static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
{
int tries = STOP_TRIES;
@@ -954,6 +959,7 @@ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
{
struct net_device_stats *stats = &hp->net_stats;
@@ -976,53 +982,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
hme_write32(hp, bregs + BMAC_LTCTR, 0);
}
-#if 0
-static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs)
-{
- u32 tmp;
- int speed;
-
- ASD(("happy_meal_poll_start: "));
- if (!(hp->happy_flags & HFLAG_POLLENABLE)) {
- HMD(("polling disabled, return\n"));
- return;
- }
-
- /* Start the MIF polling on the external transceiver. */
- ASD(("polling on, "));
- tmp = hme_read32(hp, tregs + TCVR_CFG);
- tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
- tmp |= ((hp->paddr & 0x1f) << 10);
- tmp |= (TCV_PADDR_ETX << 3);
- tmp |= TCV_CFG_PENABLE;
- hme_write32(hp, tregs + TCVR_CFG, tmp);
-
- /* Let the bits set. */
- udelay(200);
-
- /* We are polling now. */
- ASD(("now polling, "));
- hp->happy_flags |= HFLAG_POLL;
-
- /* Clear the poll flags, get the basic status as of now. */
- hp->poll_flag = 0;
- hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;
-
- if (hp->happy_flags & HFLAG_AUTO)
- speed = hp->auto_speed;
- else
- speed = hp->forced_speed;
-
- /* Listen only for the MIF interrupts we want to hear. */
- ASD(("mif ints on, "));
- if (speed == 100)
- hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);
- else
- hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);
- ASD(("done\n"));
-}
-#endif
-
+/* hp->happy_lock must be held */
static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
{
ASD(("happy_meal_poll_stop: "));
@@ -1057,6 +1017,7 @@ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
#define TCVR_RESET_TRIES 16 /* It should reset quickly */
#define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */
+/* hp->happy_lock must be held */
static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
{
u32 tconfig;
@@ -1151,7 +1112,10 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
return 0;
}
-/* Figure out whether we have an internal or external transceiver. */
+/* Figure out whether we have an internal or external transceiver.
+ *
+ * hp->happy_lock must be held
+ */
static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs)
{
unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG);
@@ -1303,14 +1267,12 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
}
}
-static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static void happy_meal_init_rings(struct happy_meal *hp)
{
struct hmeal_init_block *hb = hp->happy_block;
struct net_device *dev = hp->dev;
- int i, gfp_flags = GFP_KERNEL;
-
- if (from_irq || in_interrupt())
- gfp_flags = GFP_ATOMIC;
+ int i;
HMD(("happy_meal_init_rings: counters to zero, "));
hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
@@ -1324,7 +1286,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
- skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+ skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) {
hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);
continue;
@@ -1347,6 +1309,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
unsigned long tregs,
struct ethtool_cmd *ep)
@@ -1470,7 +1433,8 @@ force_link:
add_timer(&hp->happy_timer);
}
-static int happy_meal_init(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static int happy_meal_init(struct happy_meal *hp)
{
unsigned long gregs = hp->gregs;
unsigned long etxregs = hp->etxregs;
@@ -1501,7 +1465,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Alloc and reset the tx/rx descriptor chains. */
HMD(("happy_meal_init: to happy_meal_init_rings\n"));
- happy_meal_init_rings(hp, from_irq);
+ happy_meal_init_rings(hp);
/* Shut up the MIF. */
HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
@@ -1618,6 +1582,17 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
hme_write32(hp, etxregs + ETX_RING,
((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
+ /* Parity issues in the ERX unit of some HME revisions can cause some
+ * registers to not be written unless their parity is even. Detect such
+ * lost writes and simply rewrite with a low bit set (which will be ignored
+ * since the rxring needs to be 2K aligned).
+ */
+ if (hme_read32(hp, erxregs + ERX_RING) !=
+ ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)))
+ hme_write32(hp, erxregs + ERX_RING,
+ ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))
+ | 0x4);
+
/* Set the supported burst sizes. */
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
@@ -1698,7 +1673,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Enable Big Mac hash table filter. */
HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
hme_read32(hp, bregs + BMAC_RXCFG)));
- rxcfg = BIGMAC_RXCFG_HENABLE;
+ rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME;
if (hp->dev->flags & IFF_PROMISC)
rxcfg |= BIGMAC_RXCFG_PMISC;
hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);
@@ -1711,7 +1686,14 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
regtmp = 0;
if (hp->happy_flags & HFLAG_FULL)
regtmp |= BIGMAC_TXCFG_FULLDPLX;
- hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);
+
+ /* Don't turn on the "don't give up" bit for now. It could cause hme
+ * to deadlock with the PHY if a Jabber occurs.
+ */
+ hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/);
+
+ /* Give up after 16 TX attempts. */
+ hme_write32(hp, bregs + BMAC_ALIMIT, 16);
/* Enable the output drivers no matter what. */
regtmp = BIGMAC_XCFG_ODENABLE;
@@ -1744,6 +1726,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
return 0;
}
+/* hp->happy_lock must be held */
static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
{
unsigned long tregs = hp->tcvregs;
@@ -1801,6 +1784,8 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
/* Once status is latched (by happy_meal_interrupt) it is cleared by
* the hardware, so we cannot re-read it and get a correct value.
+ *
+ * hp->happy_lock must be held
*/
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{
@@ -1909,12 +1894,13 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
if (reset) {
printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
- happy_meal_init(hp, 1);
+ happy_meal_init(hp);
return 1;
}
return 0;
}
+/* hp->happy_lock must be held */
static void happy_meal_mif_interrupt(struct happy_meal *hp)
{
unsigned long tregs = hp->tcvregs;
@@ -1948,6 +1934,7 @@ static void happy_meal_mif_interrupt(struct happy_meal *hp)
#define TXD(x)
#endif
+/* hp->happy_lock must be held */
static void happy_meal_tx(struct happy_meal *hp)
{
struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1955,8 +1942,6 @@ static void happy_meal_tx(struct happy_meal *hp)
struct net_device *dev = hp->dev;
int elem;
- spin_lock(&hp->happy_lock);
-
elem = hp->tx_old;
TXD(("TX<"));
while (elem != hp->tx_new) {
@@ -2000,10 +1985,8 @@ static void happy_meal_tx(struct happy_meal *hp)
TXD((">"));
if (netif_queue_stopped(dev) &&
- TX_BUFFS_AVAIL(hp) > 0)
+ TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev);
-
- spin_unlock(&hp->happy_lock);
}
#ifdef RXDEBUG
@@ -2018,6 +2001,8 @@ static void happy_meal_tx(struct happy_meal *hp)
* with all of the packets it has DMA'd in. So now I just drop the entire
* ring when we cannot get a new skb and give them all back to the happy meal,
* maybe things will be "happier" now.
+ *
+ * hp->happy_lock must be held
*/
static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
{
@@ -2127,10 +2112,12 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
HMD(("happy_meal_interrupt: status=%08x ", happy_status));
+ spin_lock(&hp->happy_lock);
+
if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
- return;
+ goto out;
}
if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2149,6 +2136,8 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
HMD(("done\n"));
+out:
+ spin_unlock(&hp->happy_lock);
}
#ifdef CONFIG_SBUS
@@ -2170,10 +2159,12 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
GREG_STAT_RXTOHOST)))
continue;
+ spin_lock(&hp->happy_lock);
+
if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, happy_status))
- break;
+ goto next;
}
if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2190,6 +2181,9 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
HMD(("RXTOHOST "));
happy_meal_rx(hp, dev);
}
+
+ next:
+ spin_unlock(&hp->happy_lock);
}
HMD(("done\n"));
}
@@ -2222,7 +2216,11 @@ static int happy_meal_open(struct net_device *dev)
}
HMD(("to happy_meal_init\n"));
- res = happy_meal_init(hp, 0);
+
+ spin_lock_irq(&hp->happy_lock);
+ res = happy_meal_init(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO))
free_irq(dev->irq, dev);
return res;
@@ -2232,12 +2230,15 @@ static int happy_meal_close(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
+ spin_lock_irq(&hp->happy_lock);
happy_meal_stop(hp, hp->gregs);
happy_meal_clean_rings(hp);
/* If auto-negotiation timer is running, kill it. */
del_timer(&hp->happy_timer);
+ spin_unlock_irq(&hp->happy_lock);
+
/* On Quattro QFE cards, all hme interrupts are concentrated
* into a single source which we register handling at probe
* time and never unregister.
@@ -2254,7 +2255,6 @@ static int happy_meal_close(struct net_device *dev)
#define SXD(x)
#endif
-#ifdef CONFIG_SBUS
static void happy_meal_tx_timeout(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
@@ -2265,10 +2265,13 @@ static void happy_meal_tx_timeout(struct net_device *dev)
hme_read32(hp, hp->gregs + GREG_STAT),
hme_read32(hp, hp->etxregs + ETX_CFG),
hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
- happy_meal_init(hp, 0);
+
+ spin_lock_irq(&hp->happy_lock);
+ happy_meal_init(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
netif_wake_queue(dev);
}
-#endif
static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -2293,6 +2296,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&hp->happy_lock);
+ printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+ dev->name);
return 1;
}
@@ -2345,7 +2350,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
hp->tx_new = entry;
- if (TX_BUFFS_AVAIL(hp) <= 0)
+ if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
/* Get it going. */
@@ -2363,7 +2368,10 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
+ spin_lock_irq(&hp->happy_lock);
happy_meal_get_counters(hp, hp->bigmacregs);
+ spin_unlock_irq(&hp->happy_lock);
+
return &hp->net_stats;
}
@@ -2376,7 +2384,8 @@ static void happy_meal_set_multicast(struct net_device *dev)
int i;
u32 crc;
- /* Lock out others. */
+ spin_lock_irq(&hp->happy_lock);
+
netif_stop_queue(dev);
if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
@@ -2410,8 +2419,9 @@ static void happy_meal_set_multicast(struct net_device *dev)
hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);
}
- /* Let us get going again. */
netif_wake_queue(dev);
+
+ spin_unlock_irq(&hp->happy_lock);
}
/* Ethtool support... */
@@ -2439,8 +2449,11 @@ static int happy_meal_ioctl(struct net_device *dev,
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings. */
+ spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
+ spin_unlock_irq(&hp->happy_lock);
+
if (hp->sw_bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed =
@@ -2482,10 +2495,12 @@ static int happy_meal_ioctl(struct net_device *dev,
return -EINVAL;
/* Ok, do it to it. */
+ spin_lock_irq(&hp->happy_lock);
del_timer(&hp->happy_timer);
happy_meal_begin_auto_negotiation(hp,
hp->tcvregs,
&ecmd);
+ spin_unlock_irq(&hp->happy_lock);
return 0;
} else
@@ -2657,7 +2672,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
}
err = -ENOMEM;
- dev = init_etherdev(NULL, sizeof(struct happy_meal));
+ dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
@@ -2665,13 +2680,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- if (qfe_slot != -1)
- printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
- dev->name, qfe_slot);
- else
- printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
- dev->name);
-
/* If user did not specify a MAC address specifically, use
* the Quattro local-mac-address property...
*/
@@ -2682,6 +2690,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (i < 6) { /* a mac address was given */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
+ macaddr[5]++;
} else if (qfe_slot != -1 &&
prom_getproplen(sdev->prom_node,
"local-mac-address") == 6) {
@@ -2691,11 +2700,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",
- dev->dev_addr[i], i == 5 ? ' ' : ':');
- printk("\n");
-
hp = dev->priv;
memset(hp, 0, sizeof(*hp));
@@ -2818,19 +2822,42 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
/* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this.
*/
+ spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp);
+ spin_unlock_irq(&hp->happy_lock);
- ether_setup(dev);
+ if (register_netdev(hp->dev)) {
+ printk(KERN_ERR "happymeal: Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_consistent;
+ }
+
+ if (qfe_slot != -1)
+ printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+ dev->name, qfe_slot);
+ else
+ printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+ dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c",
+ dev->dev_addr[i], i == 5 ? ' ' : ':');
+ printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
- dev->ifindex = dev_new_index();
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
+err_out_free_consistent:
+ sbus_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+
err_out_iounmap:
if (hp->gregs)
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
@@ -2844,7 +2871,6 @@ err_out_iounmap:
sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
err_out_free_netdev:
- unregister_netdev(dev);
kfree(dev);
err_out:
@@ -2853,6 +2879,104 @@ err_out:
#endif
#ifdef CONFIG_PCI
+#ifndef __sparc__
+static int is_quattro_p(struct pci_dev *pdev)
+{
+ struct pci_dev *busdev = pdev->bus->self;
+ struct list_head *tmp;
+ int n_hmes;
+
+ if (busdev->vendor != PCI_VENDOR_ID_DEC ||
+ busdev->device != PCI_DEVICE_ID_DEC_21153)
+ return 0;
+
+ n_hmes = 0;
+ tmp = pdev->bus->devices.next;
+ while (tmp != &pdev->bus->devices) {
+ struct pci_dev *this_pdev = pci_dev_b(tmp);
+
+ if (this_pdev->vendor == PCI_VENDOR_ID_SUN &&
+ this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)
+ n_hmes++;
+
+ tmp = tmp->next;
+ }
+
+ if (n_hmes != 4)
+ return 0;
+
+ return 1;
+}
+
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr)
+{
+ int this_offset;
+
+ for (this_offset = 0x20; this_offset < len; this_offset++) {
+ void *p = rom_base + this_offset;
+
+ if (readb(p + 0) != 0x90 ||
+ readb(p + 1) != 0x00 ||
+ readb(p + 2) != 0x09 ||
+ readb(p + 3) != 0x4e ||
+ readb(p + 4) != 0x41 ||
+ readb(p + 5) != 0x06)
+ continue;
+
+ this_offset += 6;
+ p += 6;
+
+ if (index == 0) {
+ int i;
+
+ for (i = 0; i < 6; i++)
+ dev_addr[i] = readb(p + i);
+ break;
+ }
+ index--;
+ }
+}
+
+static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+ u32 rom_reg_orig;
+ void *p;
+ int index;
+
+ index = 0;
+ if (is_quattro_p(pdev))
+ index = PCI_SLOT(pdev->devfn);
+
+ if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+ if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+ goto use_random;
+ }
+
+ pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+ pci_write_config_dword(pdev, pdev->rom_base_reg,
+ rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+ p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+ if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+ find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
+
+ if (p != NULL)
+ iounmap(p);
+
+ pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+ return;
+
+use_random:
+ /* Sun MAC prefix then 3 random bytes. */
+ dev_addr[0] = 0x08;
+ dev_addr[1] = 0x00;
+ dev_addr[2] = 0x20;
+ get_random_bytes(dev_addr, 3);
+ return;
+}
+#endif /* !(__sparc__) */
+
static int __init happy_meal_pci_init(struct pci_dev *pdev)
{
struct quattro *qp = NULL;
@@ -2878,8 +3002,10 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
prom_getstring(node, "name", prom_name, sizeof(prom_name));
#else
-/* This needs to be corrected... -DaveM */
- strcpy(prom_name, "qfe");
+ if (is_quattro_p(pdev))
+ strcpy(prom_name, "SUNW,qfe");
+ else
+ strcpy(prom_name, "SUNW,hme");
#endif
err = -ENODEV;
@@ -2894,7 +3020,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out;
}
- dev = init_etherdev(NULL, sizeof(struct happy_meal));
+ dev = alloc_etherdev(sizeof(struct happy_meal));
err = -ENOMEM;
if (!dev)
goto err_out;
@@ -2903,29 +3029,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- if (!qfe_slot) {
- struct pci_dev *qpdev = qp->quattro_dev;
-
- prom_name[0] = 0;
- if (!strncmp(dev->name, "eth", 3)) {
- int i = simple_strtoul(dev->name + 3, NULL, 10);
- sprintf(prom_name, "-%d", i + 3);
- }
- printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
- if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
- qpdev->device == PCI_DEVICE_ID_DEC_21153)
- printk("DEC 21153 PCI Bridge\n");
- else
- printk("unknown bridge %04x.%04x\n",
- qpdev->vendor, qpdev->device);
- }
- if (qfe_slot != -1)
- printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
- dev->name, qfe_slot);
- else
- printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
- dev->name);
-
dev->base_addr = (long) pdev;
hp = (struct happy_meal *)dev->priv;
@@ -2947,9 +3050,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
goto err_out_clear_quattro;
}
+ if (pci_request_regions(pdev, dev->name)) {
+ printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, "
+ "aborting.\n");
+ goto err_out_clear_quattro;
+ }
+
if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) {
printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
- return -ENODEV;
+ goto err_out_free_res;
}
for (i = 0; i < 6; i++) {
@@ -2959,6 +3068,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
if (i < 6) { /* a mac address was given */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
+ macaddr[5]++;
} else {
#ifdef __sparc__
if (qfe_slot != -1 &&
@@ -2969,15 +3079,10 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
#else
- memset(dev->dev_addr, 0, 6);
+ get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
#endif
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
- printk("\n");
-
/* Layout registers. */
hp->gregs = (hpreg_base + 0x0000UL);
hp->etxregs = (hpreg_base + 0x2000UL);
@@ -3032,6 +3137,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->hard_start_xmit = &happy_meal_start_xmit;
dev->get_stats = &happy_meal_get_stats;
dev->set_multicast_list = &happy_meal_set_multicast;
+ dev->tx_timeout = &happy_meal_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
dev->do_ioctl = &happy_meal_ioctl;
dev->irq = pdev->irq;
dev->dma = 0;
@@ -3054,14 +3161,48 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this.
*/
+ spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
+ if (register_netdev(hp->dev)) {
+ printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ if (!qfe_slot) {
+ struct pci_dev *qpdev = qp->quattro_dev;
- ether_setup(dev);
+ prom_name[0] = 0;
+ if (!strncmp(dev->name, "eth", 3)) {
+ int i = simple_strtoul(dev->name + 3, NULL, 10);
+ sprintf(prom_name, "-%d", i + 3);
+ }
+ printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+ if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
+ qpdev->device == PCI_DEVICE_ID_DEC_21153)
+ printk("DEC 21153 PCI Bridge\n");
+ else
+ printk("unknown bridge %04x.%04x\n",
+ qpdev->vendor, qpdev->device);
+ }
+
+ if (qfe_slot != -1)
+ printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+ dev->name, qfe_slot);
+ else
+ printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+ dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
+
+ printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
- dev->ifindex = dev_new_index();
hp->next_module = root_happy_dev;
root_happy_dev = hp;
@@ -3070,11 +3211,13 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
err_out_iounmap:
iounmap((void *)hp->gregs);
+err_out_free_res:
+ pci_release_regions(pdev);
+
err_out_clear_quattro:
if (qp != NULL)
qp->happy_meals[qfe_slot] = NULL;
- unregister_netdev(dev);
kfree(dev);
err_out:
@@ -3125,6 +3268,7 @@ static int __init happy_meal_pci_probe(void)
PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
if (pci_enable_device(pdev))
continue;
+ pci_set_master(pdev);
cards++;
happy_meal_pci_init(pdev);
}
@@ -3165,12 +3309,18 @@ static void __exit happy_meal_cleanup_module(void)
while (root_happy_dev) {
struct happy_meal *hp = root_happy_dev;
struct happy_meal *next = root_happy_dev->next_module;
+ struct net_device *dev = hp->dev;
+
+ /* Unregister netdev before unmapping registers as this
+ * call can end up trying to access those registers.
+ */
+ unregister_netdev(dev);
#ifdef CONFIG_SBUS
if (!(hp->happy_flags & HFLAG_PCI)) {
if (hp->happy_flags & HFLAG_QUATTRO) {
if (hp->qfe_parent != last_seen_qfe) {
- free_irq(hp->dev->irq, hp->qfe_parent);
+ free_irq(dev->irq, hp->qfe_parent);
last_seen_qfe = hp->qfe_parent;
}
}
@@ -3193,12 +3343,35 @@ static void __exit happy_meal_cleanup_module(void)
hp->happy_block,
hp->hblock_dvma);
iounmap((void *)hp->gregs);
+ pci_release_regions(hp->happy_dev);
}
#endif
- unregister_netdev(hp->dev);
- kfree(hp->dev);
+ kfree(dev);
+
root_happy_dev = next;
}
+
+ /* Now cleanup the quattro lists. */
+#ifdef CONFIG_SBUS
+ while (qfe_sbus_list) {
+ struct quattro *qfe = qfe_sbus_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_sbus_list = next;
+ }
+#endif
+#ifdef CONFIG_PCI
+ while (qfe_pci_list) {
+ struct quattro *qfe = qfe_pci_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_pci_list = next;
+ }
+#endif
}
module_init(happy_meal_probe);
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 8c177c199904..efa319e0ed1a 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -227,7 +227,7 @@
#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */
#define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */
#define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */
-#define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */
+#define BIGMAC_RXCFG_REJME 0x00000200 /* Reject packets addressed to me */
#define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */
#define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */
#define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
new file mode 100644
index 000000000000..51235569651a
--- /dev/null
+++ b/drivers/net/tc35815.c
@@ -0,0 +1,1779 @@
+/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ *
+ * Based on skelton.c by Donald Becker.
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static const char *version =
+ "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/byteorder.h>
+
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = "TC35815CF";
+#define TC35815_PROC_ENTRY "net/tc35815"
+
+#define TC35815_MODULE_NAME "TC35815CF"
+#define TX_TIMEOUT (4*HZ)
+
+/* First, a few definitions that the brave might change. */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef TC35815_DEBUG
+#define TC35815_DEBUG 1
+#endif
+static unsigned int tc35815_debug = TC35815_DEBUG;
+
+#define GATHER_TXINT /* On-Demand Tx Interrupt */
+
+#define vtonocache(p) KSEG1ADDR(virt_to_phys(p))
+
+/*
+ * Registers
+ */
+struct tc35815_regs {
+ volatile __u32 DMA_Ctl; /* 0x00 */
+ volatile __u32 TxFrmPtr;
+ volatile __u32 TxThrsh;
+ volatile __u32 TxPollCtr;
+ volatile __u32 BLFrmPtr;
+ volatile __u32 RxFragSize;
+ volatile __u32 Int_En;
+ volatile __u32 FDA_Bas;
+ volatile __u32 FDA_Lim; /* 0x20 */
+ volatile __u32 Int_Src;
+ volatile __u32 unused0[2];
+ volatile __u32 PauseCnt;
+ volatile __u32 RemPauCnt;
+ volatile __u32 TxCtlFrmStat;
+ volatile __u32 unused1;
+ volatile __u32 MAC_Ctl; /* 0x40 */
+ volatile __u32 CAM_Ctl;
+ volatile __u32 Tx_Ctl;
+ volatile __u32 Tx_Stat;
+ volatile __u32 Rx_Ctl;
+ volatile __u32 Rx_Stat;
+ volatile __u32 MD_Data;
+ volatile __u32 MD_CA;
+ volatile __u32 CAM_Adr; /* 0x60 */
+ volatile __u32 CAM_Data;
+ volatile __u32 CAM_Ena;
+ volatile __u32 PROM_Ctl;
+ volatile __u32 PROM_Data;
+ volatile __u32 Algn_Cnt;
+ volatile __u32 CRC_Cnt;
+ volatile __u32 Miss_Cnt;
+};
+
+/*
+ * Bit assignments
+ */
+/* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_IntMask 0x00040000 /* 1:Interupt mask */
+#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */
+#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */
+#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */
+#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */
+#define DMA_TestMode 0x00002000 /* 1:Test Mode */
+#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */
+#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */
+
+/* RxFragSize bit asign ---------------------------------------------------- */
+#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */
+#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */
+
+/* MAC_Ctl bit asign ------------------------------------------------------- */
+#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */
+#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */
+#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */
+#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */
+#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */
+#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/
+#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */
+#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */
+#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */
+#define MAC_Reset 0x00000004 /* 1:Software Reset */
+#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */
+#define MAC_HaltReq 0x00000001 /* 1:Halt request */
+
+/* PROM_Ctl bit asign ------------------------------------------------------ */
+#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */
+#define PROM_Read 0x00004000 /*10:Read operation */
+#define PROM_Write 0x00002000 /*01:Write operation */
+#define PROM_Erase 0x00006000 /*11:Erase operation */
+ /*00:Enable or Disable Writting, */
+ /* as specified in PROM_Addr. */
+#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */
+ /*00xxxx: disable */
+
+/* CAM_Ctl bit asign ------------------------------------------------------- */
+#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */
+#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/
+ /* accept other */
+#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */
+#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */
+#define CAM_StationAcc 0x00000001 /* 1:unicast accept */
+
+/* CAM_Ena bit asign ------------------------------------------------------- */
+#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */
+#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits) */
+#define CAM_Ena_Bit(index) (1<<(index))
+#define CAM_ENTRY_DESTINATION 0
+#define CAM_ENTRY_SOURCE 1
+#define CAM_ENTRY_MACCTL 20
+
+/* Tx_Ctl bit asign -------------------------------------------------------- */
+#define Tx_En 0x00000001 /* 1:Transmit enable */
+#define Tx_TxHalt 0x00000002 /* 1:Transmit Halt Request */
+#define Tx_NoPad 0x00000004 /* 1:Suppress Padding */
+#define Tx_NoCRC 0x00000008 /* 1:Suppress Padding */
+#define Tx_FBack 0x00000010 /* 1:Fast Back-off */
+#define Tx_EnUnder 0x00000100 /* 1:Enable Underrun */
+#define Tx_EnExDefer 0x00000200 /* 1:Enable Excessive Deferral */
+#define Tx_EnLCarr 0x00000400 /* 1:Enable Lost Carrier */
+#define Tx_EnExColl 0x00000800 /* 1:Enable Excessive Collision */
+#define Tx_EnLateColl 0x00001000 /* 1:Enable Late Collision */
+#define Tx_EnTxPar 0x00002000 /* 1:Enable Transmit Parity */
+#define Tx_EnComp 0x00004000 /* 1:Enable Completion */
+
+/* Tx_Stat bit asign ------------------------------------------------------- */
+#define Tx_TxColl_MASK 0x0000000F /* Tx Collision Count */
+#define Tx_ExColl 0x00000010 /* Excessive Collision */
+#define Tx_TXDefer 0x00000020 /* Transmit Defered */
+#define Tx_Paused 0x00000040 /* Transmit Paused */
+#define Tx_IntTx 0x00000080 /* Interrupt on Tx */
+#define Tx_Under 0x00000100 /* Underrun */
+#define Tx_Defer 0x00000200 /* Deferral */
+#define Tx_NCarr 0x00000400 /* No Carrier */
+#define Tx_10Stat 0x00000800 /* 10Mbps Status */
+#define Tx_LateColl 0x00001000 /* Late Collision */
+#define Tx_TxPar 0x00002000 /* Tx Parity Error */
+#define Tx_Comp 0x00004000 /* Completion */
+#define Tx_Halted 0x00008000 /* Tx Halted */
+#define Tx_SQErr 0x00010000 /* Signal Quality Error(SQE) */
+
+/* Rx_Ctl bit asign -------------------------------------------------------- */
+#define Rx_EnGood 0x00004000 /* 1:Enable Good */
+#define Rx_EnRxPar 0x00002000 /* 1:Enable Receive Parity */
+#define Rx_EnLongErr 0x00000800 /* 1:Enable Long Error */
+#define Rx_EnOver 0x00000400 /* 1:Enable OverFlow */
+#define Rx_EnCRCErr 0x00000200 /* 1:Enable CRC Error */
+#define Rx_EnAlign 0x00000100 /* 1:Enable Alignment */
+#define Rx_IgnoreCRC 0x00000040 /* 1:Ignore CRC Value */
+#define Rx_StripCRC 0x00000010 /* 1:Strip CRC Value */
+#define Rx_ShortEn 0x00000008 /* 1:Short Enable */
+#define Rx_LongEn 0x00000004 /* 1:Long Enable */
+#define Rx_RxHalt 0x00000002 /* 1:Receive Halt Request */
+#define Rx_RxEn 0x00000001 /* 1:Receive Intrrupt Enable */
+
+/* Rx_Stat bit asign ------------------------------------------------------- */
+#define Rx_Halted 0x00008000 /* Rx Halted */
+#define Rx_Good 0x00004000 /* Rx Good */
+#define Rx_RxPar 0x00002000 /* Rx Parity Error */
+ /* 0x00001000 not use */
+#define Rx_LongErr 0x00000800 /* Rx Long Error */
+#define Rx_Over 0x00000400 /* Rx Overflow */
+#define Rx_CRCErr 0x00000200 /* Rx CRC Error */
+#define Rx_Align 0x00000100 /* Rx Alignment Error */
+#define Rx_10Stat 0x00000080 /* Rx 10Mbps Status */
+#define Rx_IntRx 0x00000040 /* Rx Interrupt */
+#define Rx_CtlRecd 0x00000020 /* Rx Control Receive */
+
+#define Rx_Stat_Mask 0x0000EFC0 /* Rx All Status Mask */
+
+/* Int_En bit asign -------------------------------------------------------- */
+#define Int_NRAbtEn 0x00000800 /* 1:Non-recoverable Abort Enable */
+#define Int_TxCtlCmpEn 0x00000400 /* 1:Transmit Control Complete Enable */
+#define Int_DmParErrEn 0x00000200 /* 1:DMA Parity Error Enable */
+#define Int_DParDEn 0x00000100 /* 1:Data Parity Error Enable */
+#define Int_EarNotEn 0x00000080 /* 1:Early Notify Enable */
+#define Int_DParErrEn 0x00000040 /* 1:Detected Parity Error Enable */
+#define Int_SSysErrEn 0x00000020 /* 1:Signalled System Error Enable */
+#define Int_RMasAbtEn 0x00000010 /* 1:Received Master Abort Enable */
+#define Int_RTargAbtEn 0x00000008 /* 1:Received Target Abort Enable */
+#define Int_STargAbtEn 0x00000004 /* 1:Signalled Target Abort Enable */
+#define Int_BLExEn 0x00000002 /* 1:Buffer List Exhausted Enable */
+#define Int_FDAExEn 0x00000001 /* 1:Free Descriptor Area */
+ /* Exhausted Enable */
+
+/* Int_Src bit asign ------------------------------------------------------- */
+#define Int_NRabt 0x00004000 /* 1:Non Recoverable error */
+#define Int_DmParErrStat 0x00002000 /* 1:DMA Parity Error & Clear */
+#define Int_BLEx 0x00001000 /* 1:Buffer List Empty & Clear */
+#define Int_FDAEx 0x00000800 /* 1:FDA Empty & Clear */
+#define Int_IntNRAbt 0x00000400 /* 1:Non Recoverable Abort */
+#define Int_IntCmp 0x00000200 /* 1:MAC control packet complete */
+#define Int_IntExBD 0x00000100 /* 1:Interrupt Extra BD & Clear */
+#define Int_DmParErr 0x00000080 /* 1:DMA Parity Error & Clear */
+#define Int_IntEarNot 0x00000040 /* 1:Receive Data write & Clear */
+#define Int_SWInt 0x00000020 /* 1:Software request & Clear */
+#define Int_IntBLEx 0x00000010 /* 1:Buffer List Empty & Clear */
+#define Int_IntFDAEx 0x00000008 /* 1:FDA Empty & Clear */
+#define Int_IntPCI 0x00000004 /* 1:PCI controller & Clear */
+#define Int_IntMacRx 0x00000002 /* 1:Rx controller & Clear */
+#define Int_IntMacTx 0x00000001 /* 1:Tx controller & Clear */
+
+/* MD_CA bit asign --------------------------------------------------------- */
+#define MD_CA_PreSup 0x00001000 /* 1:Preamble Supress */
+#define MD_CA_Busy 0x00000800 /* 1:Busy (Start Operation) */
+#define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */
+
+
+/* MII register offsets */
+#define MII_CONTROL 0x0000
+#define MII_STATUS 0x0001
+#define MII_PHY_ID0 0x0002
+#define MII_PHY_ID1 0x0003
+#define MII_ANAR 0x0004
+#define MII_ANLPAR 0x0005
+#define MII_ANER 0x0006
+/* MII Control register bit definitions. */
+#define MIICNTL_FDX 0x0100
+#define MIICNTL_RST_AUTO 0x0200
+#define MIICNTL_ISOLATE 0x0400
+#define MIICNTL_PWRDWN 0x0800
+#define MIICNTL_AUTO 0x1000
+#define MIICNTL_SPEED 0x2000
+#define MIICNTL_LPBK 0x4000
+#define MIICNTL_RESET 0x8000
+/* MII Status register bit significance. */
+#define MIISTAT_EXT 0x0001
+#define MIISTAT_JAB 0x0002
+#define MIISTAT_LINK 0x0004
+#define MIISTAT_CAN_AUTO 0x0008
+#define MIISTAT_FAULT 0x0010
+#define MIISTAT_AUTO_DONE 0x0020
+#define MIISTAT_CAN_T 0x0800
+#define MIISTAT_CAN_T_FDX 0x1000
+#define MIISTAT_CAN_TX 0x2000
+#define MIISTAT_CAN_TX_FDX 0x4000
+#define MIISTAT_CAN_T4 0x8000
+/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
+#define MII_AN_TX_FDX 0x0100
+#define MII_AN_TX_HDX 0x0080
+#define MII_AN_10_FDX 0x0040
+#define MII_AN_10_HDX 0x0020
+
+
+/*
+ * Descriptors
+ */
+
+/* Frame descripter */
+struct FDesc {
+ volatile __u32 FDNext;
+ volatile __u32 FDSystem;
+ volatile __u32 FDStat;
+ volatile __u32 FDCtl;
+};
+
+/* Buffer descripter */
+struct BDesc {
+ volatile __u32 BuffData;
+ volatile __u32 BDCtl;
+};
+
+#define FD_ALIGN 16
+
+/* Frame Descripter bit asign ---------------------------------------------- */
+#define FD_FDLength_MASK 0x0000FFFF /* Length MASK */
+#define FD_BDCnt_MASK 0x001F0000 /* BD count MASK in FD */
+#define FD_FrmOpt_MASK 0x7C000000 /* Frame option MASK */
+#define FD_FrmOpt_BigEndian 0x40000000 /* Tx/Rx */
+#define FD_FrmOpt_IntTx 0x20000000 /* Tx only */
+#define FD_FrmOpt_NoCRC 0x10000000 /* Tx only */
+#define FD_FrmOpt_NoPadding 0x08000000 /* Tx only */
+#define FD_FrmOpt_Packing 0x04000000 /* Rx only */
+#define FD_CownsFD 0x80000000 /* FD Controller owner bit */
+#define FD_Next_EOL 0x00000001 /* FD EOL indicator */
+#define FD_BDCnt_SHIFT 16
+
+/* Buffer Descripter bit asign --------------------------------------------- */
+#define BD_BuffLength_MASK 0x0000FFFF /* Recieve Data Size */
+#define BD_RxBDID_MASK 0x00FF0000 /* BD ID Number MASK */
+#define BD_RxBDSeqN_MASK 0x7F000000 /* Rx BD Sequence Number */
+#define BD_CownsBD 0x80000000 /* BD Controller owner bit */
+#define BD_RxBDID_SHIFT 16
+#define BD_RxBDSeqN_SHIFT 24
+
+
+/* Some useful constants. */
+#undef NO_CHECK_CARRIER /* Does not check No-Carrier with TP */
+
+#ifdef NO_CHECK_CARRIER
+#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+ Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7d01 */
+#else
+#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+ Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7f01 */
+#endif
+#define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
+ | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
+
+#define INT_EN_CMD (Int_NRAbtEn | \
+ Int_DParDEn | Int_DParErrEn | \
+ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \
+ Int_STargAbtEn | \
+ Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/
+
+/* Tuning parameters */
+#define DMA_BURST_SIZE 32
+#define TX_THRESHOLD 1024
+
+#define FD_PAGE_NUM 2
+#define FD_PAGE_ORDER 1
+/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
+#define RX_BUF_PAGES 8 /* >= 2 */
+#define RX_FD_NUM 250 /* >= 32 */
+#define TX_FD_NUM 128
+
+struct TxFD {
+ struct FDesc fd;
+ struct BDesc bd;
+ struct BDesc unused;
+};
+
+struct RxFD {
+ struct FDesc fd;
+ struct BDesc bd[0]; /* variable length */
+};
+
+struct FrFD {
+ struct FDesc fd;
+ struct BDesc bd[RX_BUF_PAGES];
+};
+
+
+extern unsigned long tc_readl(volatile __u32 *addr);
+extern void tc_writel(unsigned long data, volatile __u32 *addr);
+
+dma_addr_t priv_dma_handle;
+
+/* Information that need to be kept for each board. */
+struct tc35815_local {
+ struct net_device *next_module;
+
+ /* statistics */
+ struct net_device_stats stats;
+ struct {
+ int max_tx_qlen;
+ int tx_ints;
+ int rx_ints;
+ } lstats;
+
+ int tbusy;
+ int option;
+#define TC35815_OPT_AUTO 0x00
+#define TC35815_OPT_10M 0x01
+#define TC35815_OPT_100M 0x02
+#define TC35815_OPT_FULLDUP 0x04
+ int linkspeed; /* 10 or 100 */
+ int fullduplex;
+
+ /*
+ * Transmitting: Batch Mode.
+ * 1 BD in 1 TxFD.
+ * Receiving: Packing Mode.
+ * 1 circular FD for Free Buffer List.
+ * RX_BUG_PAGES BD in Free Buffer FD.
+ * One Free Buffer BD has PAGE_SIZE data buffer.
+ */
+ struct pci_dev *pdev;
+ dma_addr_t fd_buf_dma_handle;
+ void * fd_buf; /* for TxFD, TxFD, FrFD */
+ struct TxFD *tfd_base;
+ int tfd_start;
+ int tfd_end;
+ struct RxFD *rfd_base;
+ struct RxFD *rfd_limit;
+ struct RxFD *rfd_cur;
+ struct FrFD *fbl_ptr;
+ unsigned char fbl_curid;
+ dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
+ void * data_buf[RX_BUF_PAGES]; /* packing */
+};
+
+/* Index to functions, as function prototypes. */
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+
+static int tc35815_open(struct net_device *dev);
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void tc35815_tx_timeout(struct net_device *dev);
+static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void tc35815_rx(struct net_device *dev);
+static void tc35815_txdone(struct net_device *dev);
+static int tc35815_close(struct net_device *dev);
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev);
+static void tc35815_set_multicast_list(struct net_device *dev);
+
+static void tc35815_chip_reset(struct net_device *dev);
+static void tc35815_chip_init(struct net_device *dev);
+static void tc35815_phy_chip_init(struct net_device *dev);
+static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+
+/* A list of all installed tc35815 devices. */
+static struct net_device *root_tc35815_dev = NULL;
+
+/*
+ * PCI device identifiers for "new style" Linux PCI Device Drivers
+ */
+static struct pci_device_id tc35815_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+
+int
+tc35815_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int called = 0;
+ int err = 0;
+ int ret;
+
+ if (called)
+ return -ENODEV;
+ called++;
+
+ if (!pci_present())
+ return -ENODEV;
+
+ if (pdev) {
+ unsigned int pci_memaddr;
+ unsigned int pci_irq_line;
+
+ printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+
+ pci_memaddr = pci_resource_start (pdev, 1);
+
+ printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+
+ if (!pci_memaddr) {
+ printk(KERN_WARNING "no PCI MEM resources, aborting\n");
+ return -ENODEV;
+ }
+ pci_irq_line = pdev->irq;
+ /* irq disabled. */
+ if (pci_irq_line == 0) {
+ printk(KERN_WARNING "no PCI irq, aborting\n");
+ return -ENODEV;
+ }
+
+ ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
+
+ if (!ret) {
+ if ((err = pci_enable_device(pdev)) < 0) {
+ printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err);
+ return err;
+ }
+ pci_set_master(pdev);
+ }
+
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
+{
+ static unsigned version_printed = 0;
+ int i;
+ struct tc35815_local *lp;
+ struct tc35815_regs *tr;
+ struct net_device *dev;
+
+ /* Allocate a new 'dev' if needed. */
+ dev = init_etherdev(NULL, 0);
+ if (dev == NULL)
+ return -ENOMEM;
+
+ if (tc35815_debug && version_printed++ == 0)
+ printk(KERN_DEBUG "%s", version);
+
+ printk(KERN_INFO "%s: %s found at %#x, irq %d\n",
+ dev->name, cardname, base_addr, irq);
+
+ /* Fill in the 'dev' fields. */
+ dev->irq = irq;
+ dev->base_addr = (unsigned long)ioremap(base_addr,
+ sizeof(struct tc35815_regs));
+ tr = (struct tc35815_regs*)dev->base_addr;
+
+ tc35815_chip_reset(dev);
+
+ /* Retrieve and print the ethernet address. */
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ for (i = 0; i < 6; i += 2) {
+ unsigned short data;
+ tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ data = tc_readl(&tr->PROM_Data);
+ dev->dev_addr[i] = data & 0xff;
+ dev->dev_addr[i+1] = data >> 8;
+ }
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i]);
+ printk("\n");
+
+ /* Initialize the device structure. */
+ if (dev->priv == NULL) {
+ dev->priv = kmalloc(sizeof(struct tc35815_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENODEV;
+ }
+ lp = dev->priv;
+
+ lp->pdev = pdev;
+
+ memset(lp, 0, sizeof(struct tc35815_local));
+
+ lp->next_module = root_tc35815_dev;
+ root_tc35815_dev = dev;
+
+ if (dev->mem_start > 0) {
+ lp->option = dev->mem_start;
+ if ((lp->option & TC35815_OPT_10M) &&
+ (lp->option & TC35815_OPT_100M)) {
+ /* if both speed speficied, auto select. */
+ lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
+ }
+ }
+ //XXX fixme
+ lp->option |= TC35815_OPT_10M;
+
+ /* do auto negotiation */
+ tc35815_phy_chip_init(dev);
+ printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
+ dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+
+ dev->open = tc35815_open;
+ dev->stop = tc35815_close;
+ dev->tx_timeout = tc35815_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->hard_start_xmit = tc35815_send_packet;
+ dev->get_stats = tc35815_get_stats;
+ dev->set_multicast_list = tc35815_set_multicast_list;
+
+#if 0 /* XXX called in init_etherdev */
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+#endif
+
+ return 0;
+}
+
+
+static int
+tc35815_init_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+ unsigned long fd_addr;
+
+ if (!lp->fd_buf) {
+ if (sizeof(struct FDesc) +
+ sizeof(struct BDesc) * RX_BUF_PAGES +
+ sizeof(struct FDesc) * RX_FD_NUM +
+ sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
+ printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
+ return -ENOMEM;
+ }
+
+ if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+ return -ENOMEM;
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) {
+ while (--i >= 0) {
+ free_page((unsigned long)lp->data_buf[i]);
+ lp->data_buf[i] = 0;
+ }
+ free_page((unsigned long)lp->fd_buf);
+ lp->fd_buf = 0;
+ return -ENOMEM;
+ }
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ }
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ } else {
+ clear_page(lp->fd_buf);
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ }
+#ifdef __mips__
+ fd_addr = (unsigned long)vtonocache(lp->fd_buf);
+#else
+ fd_addr = (unsigned long)lp->fd_buf;
+#endif
+
+ /* Free Descriptors (for Receive) */
+ lp->rfd_base = (struct RxFD *)fd_addr;
+ fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
+ for (i = 0; i < RX_FD_NUM; i++) {
+ lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
+ }
+ lp->rfd_cur = lp->rfd_base;
+ lp->rfd_limit = (struct RxFD *)(fd_addr -
+ sizeof(struct FDesc) -
+ sizeof(struct BDesc) * 30);
+
+ /* Transmit Descriptors */
+ lp->tfd_base = (struct TxFD *)fd_addr;
+ fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
+ for (i = 0; i < TX_FD_NUM; i++) {
+ lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
+ }
+ lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+ lp->tfd_start = 0;
+ lp->tfd_end = 0;
+
+ /* Buffer List (for Receive) */
+ lp->fbl_ptr = (struct FrFD *)fd_addr;
+ lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
+ lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+ /* BDID is index of FrFD.bd[] */
+ lp->fbl_ptr->bd[i].BDCtl =
+ cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+ }
+ lp->fbl_curid = 0;
+
+ return 0;
+}
+
+static void
+tc35815_clear_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ for (i = 0; i < TX_FD_NUM; i++) {
+ struct sk_buff *skb = (struct sk_buff *)
+ le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ if (skb)
+ dev_kfree_skb_any(skb);
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ }
+
+ tc35815_init_queues(dev);
+}
+
+static void
+tc35815_free_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ if (lp->tfd_base) {
+ for (i = 0; i < TX_FD_NUM; i++) {
+ struct sk_buff *skb = (struct sk_buff *)
+ le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ if (skb)
+ dev_kfree_skb_any(skb);
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ }
+ }
+
+ lp->rfd_base = NULL;
+ lp->rfd_base = NULL;
+ lp->rfd_limit = NULL;
+ lp->rfd_cur = NULL;
+ lp->fbl_ptr = NULL;
+
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ if (lp->data_buf[i])
+ free_page((unsigned long)lp->data_buf[i]);
+ lp->data_buf[i] = 0;
+ }
+ if (lp->fd_buf)
+ __free_pages(lp->fd_buf, FD_PAGE_ORDER);
+ lp->fd_buf = NULL;
+}
+
+static void
+dump_txfd(struct TxFD *fd)
+{
+ printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ printk("BD: ");
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd.BuffData),
+ le32_to_cpu(fd->bd.BDCtl));
+ printk("\n");
+}
+
+static int
+dump_rxfd(struct RxFD *fd)
+{
+ int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+ if (bd_count > 8)
+ bd_count = 8;
+ printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
+ return 0;
+ printk("BD: ");
+ for (i = 0; i < bd_count; i++)
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd[i].BuffData),
+ le32_to_cpu(fd->bd[i].BDCtl));
+ printk("\n");
+ return bd_count;
+}
+
+static void
+dump_frfd(struct FrFD *fd)
+{
+ int i;
+ printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ printk("BD: ");
+ for (i = 0; i < RX_BUF_PAGES; i++)
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd[i].BuffData),
+ le32_to_cpu(fd->bd[i].BDCtl));
+ printk("\n");
+}
+
+static void
+panic_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ printk("TxFD base %p, start %d, end %d\n",
+ lp->tfd_base, lp->tfd_start, lp->tfd_end);
+ printk("RxFD base %p limit %p cur %p\n",
+ lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
+ printk("FrFD %p\n", lp->fbl_ptr);
+ for (i = 0; i < TX_FD_NUM; i++)
+ dump_txfd(&lp->tfd_base[i]);
+ for (i = 0; i < RX_FD_NUM; i++) {
+ int bd_count = dump_rxfd(&lp->rfd_base[i]);
+ i += (bd_count + 1) / 2; /* skip BDs */
+ }
+ dump_frfd(lp->fbl_ptr);
+ panic("%s: Illegal queue state.", dev->name);
+}
+
+static void print_buf(char *add, int length)
+{
+ int i;
+ int len = length;
+
+ printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
+
+ if (len > 100)
+ len = 100;
+ for (i = 0; i < len; i++) {
+ printk(" %2.2X", (unsigned char) add[i]);
+ if (!(i % 16))
+ printk("\n");
+ }
+ printk("\n");
+}
+
+static void print_eth(char *add)
+{
+ int i;
+
+ printk("print_eth(%08x)\n", (unsigned int) add);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i + 6]);
+ printk(" =>");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i]);
+ printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+tc35815_open(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ /*
+ * This is used if the interrupt line can turned off (shared).
+ * See 3c503.c for an example of selecting the IRQ at config-time.
+ */
+
+ if (dev->irq == 0 ||
+ request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) {
+ return -EAGAIN;
+ }
+
+ tc35815_chip_reset(dev);
+
+ if (tc35815_init_queues(dev) != 0) {
+ free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ /* Reset the hardware here. Don't forget to set the station address. */
+ tc35815_chip_init(dev);
+
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+ int flags;
+
+ save_and_cli(flags);
+ printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+ dev->name, tc_readl(&tr->Tx_Stat));
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+ lp->tbusy=0;
+ restore_flags(flags);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+
+ if (netif_queue_stopped(dev)) {
+ /*
+ * If we get here, some higher level has decided we are broken.
+ * There should really be a "kick me" function call instead.
+ */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+ dev->name, tc_readl(&tr->Tx_Stat));
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+ lp->tbusy=0;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ }
+
+ /*
+ * Block a timer-based transmit from overlapping. This could better be
+ * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+ */
+ if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+ dev_kfree_skb_any(skb);
+ } else {
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
+ int flags;
+ lp->stats.tx_bytes += skb->len;
+
+
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)buf, length);
+#endif
+
+ save_and_cli(flags);
+
+ /* failsafe... */
+ if (lp->tfd_start != lp->tfd_end)
+ tc35815_txdone(dev);
+
+
+ txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
+
+ txfd->bd.BDCtl = cpu_to_le32(length);
+ txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
+ txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+ if (lp->tfd_start == lp->tfd_end) {
+ /* Start DMA Transmitter. */
+ txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+ txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+ if (tc35815_debug > 2) {
+ printk("%s: starting TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ if (tc35815_debug > 3)
+ print_eth(buf);
+ }
+ tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+ } else {
+ txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+ if (tc35815_debug > 2) {
+ printk("%s: queueing TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ if (tc35815_debug > 3)
+ print_eth(buf);
+ }
+ }
+ lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+
+ dev->trans_start = jiffies;
+
+ if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
+ /* we can send another packet */
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+ } else {
+ netif_stop_queue(dev);
+ if (tc35815_debug > 1)
+ printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+ }
+ restore_flags(flags);
+ }
+
+ return 0;
+}
+
+#define FATAL_ERROR_INT \
+ (Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+{
+ static int count;
+ printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
+ dev->name, status);
+
+ if (status & Int_IntPCI)
+ printk(" IntPCI");
+ if (status & Int_DmParErr)
+ printk(" DmParErr");
+ if (status & Int_IntNRAbt)
+ printk(" IntNRAbt");
+ printk("\n");
+ if (count++ > 100)
+ panic("%s: Too many fatal errors.", dev->name);
+ printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+ struct tc35815_regs *tr;
+ struct tc35815_local *lp;
+ int status, boguscount = 0;
+
+ if (dev == NULL) {
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+ return;
+ }
+
+ tr = (struct tc35815_regs*)dev->base_addr;
+ lp = (struct tc35815_local *)dev->priv;
+
+ do {
+ status = tc_readl(&tr->Int_Src);
+ if (status == 0)
+ break;
+ tc_writel(status, &tr->Int_Src); /* write to clear */
+
+ /* Fatal errors... */
+ if (status & FATAL_ERROR_INT) {
+ tc35815_fatal_error_interrupt(dev, status);
+ break;
+ }
+ /* recoverable errors */
+ if (status & Int_IntFDAEx) {
+ /* disable FDAEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Free Descriptor Area Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ }
+ if (status & Int_IntBLEx) {
+ /* disable BLEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Buffer List Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ }
+ if (status & Int_IntExBD) {
+ printk(KERN_WARNING
+ "%s: Excessive Buffer Descriptiors (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_length_errors++;
+ }
+ /* normal notification */
+ if (status & Int_IntMacRx) {
+ /* Got a packet(s). */
+ lp->lstats.rx_ints++;
+ tc35815_rx(dev);
+ }
+ if (status & Int_IntMacTx) {
+ lp->lstats.tx_ints++;
+ tc35815_txdone(dev);
+ }
+ } while (++boguscount < 20) ;
+
+ return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+tc35815_rx(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ unsigned int fdctl;
+ int i;
+ int buf_free_count = 0;
+ int fd_free_count = 0;
+
+ while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
+ int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
+ int pkt_len = fdctl & FD_FDLength_MASK;
+ struct RxFD *next_rfd;
+ int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+
+ if (tc35815_debug > 2)
+ dump_rxfd(lp->rfd_cur);
+ if (status & Rx_Good) {
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+ unsigned char *data;
+ int cur_bd, offset;
+
+ lp->stats.rx_bytes += pkt_len;
+
+ skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ break;
+ }
+ skb_reserve(skb, 2); /* 16 bit alignment */
+ skb->dev = dev;
+
+ data = skb_put(skb, pkt_len);
+
+ /* copy from receive buffer */
+ cur_bd = 0;
+ offset = 0;
+ while (offset < pkt_len && cur_bd < bd_count) {
+ int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
+ BD_BuffLength_MASK;
+ void *rxbuf =
+ bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
+#ifdef __mips__
+ dma_cache_inv((unsigned long)rxbuf, len);
+#endif
+ memcpy(data + offset, rxbuf, len);
+ offset += len;
+ cur_bd++;
+ }
+ // print_buf(data,pkt_len);
+ if (tc35815_debug > 3)
+ print_eth(data);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ } else {
+ lp->stats.rx_errors++;
+ /* WORKAROUND: LongErr and CRCErr means Overflow. */
+ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
+ status &= ~(Rx_LongErr|Rx_CRCErr);
+ status |= Rx_Over;
+ }
+ if (status & Rx_LongErr) lp->stats.rx_length_errors++;
+ if (status & Rx_Over) lp->stats.rx_fifo_errors++;
+ if (status & Rx_CRCErr) lp->stats.rx_crc_errors++;
+ if (status & Rx_Align) lp->stats.rx_frame_errors++;
+ }
+
+ if (bd_count > 0) {
+ /* put Free Buffer back to controller */
+ int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
+ unsigned char id =
+ (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+ if (id >= RX_BUF_PAGES) {
+ printk("%s: invalid BDID.\n", dev->name);
+ panic_queues(dev);
+ }
+ /* free old buffers */
+ while (lp->fbl_curid != id) {
+ bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+ if (bdctl & BD_CownsBD) {
+ printk("%s: Freeing invalid BD.\n",
+ dev->name);
+ panic_queues(dev);
+ }
+ /* pass BD to controler */
+ /* Note: BDLength was modified by chip. */
+ lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
+ cpu_to_le32(BD_CownsBD |
+ (lp->fbl_curid << BD_RxBDID_SHIFT) |
+ PAGE_SIZE);
+ lp->fbl_curid =
+ (lp->fbl_curid + 1) % RX_BUF_PAGES;
+ if (tc35815_debug > 2) {
+ printk("%s: Entering new FBD %d\n",
+ dev->name, lp->fbl_curid);
+ dump_frfd(lp->fbl_ptr);
+ }
+ buf_free_count++;
+ }
+ }
+
+ /* put RxFD back to controller */
+ next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
+#ifdef __mips__
+ next_rfd = (struct RxFD *)vtonocache(next_rfd);
+#endif
+ if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
+ printk("%s: RxFD FDNext invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
+ /* pass FD to controler */
+ lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */
+ lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
+ lp->rfd_cur++;
+ fd_free_count++;
+ }
+
+ lp->rfd_cur = next_rfd;
+ }
+
+ /* re-enable BL/FDA Exhaust interupts. */
+ if (fd_free_count) {
+ tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+ if (buf_free_count)
+ tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+ }
+}
+
+#ifdef NO_CHECK_CARRIER
+#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#else
+#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#endif
+
+static void
+tc35815_check_tx_stat(struct net_device *dev, int status)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ const char *msg = NULL;
+
+ /* count collisions */
+ if (status & Tx_ExColl)
+ lp->stats.collisions += 16;
+ if (status & Tx_TxColl_MASK)
+ lp->stats.collisions += status & Tx_TxColl_MASK;
+
+ /* WORKAROUND: ignore LostCrS in full duplex operation */
+ if (lp->fullduplex)
+ status &= ~Tx_NCarr;
+
+ if (!(status & TX_STA_ERR)) {
+ /* no error. */
+ lp->stats.tx_packets++;
+ return;
+ }
+
+ lp->stats.tx_errors++;
+ if (status & Tx_ExColl) {
+ lp->stats.tx_aborted_errors++;
+ msg = "Excessive Collision.";
+ }
+ if (status & Tx_Under) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Tx FIFO Underrun.";
+ }
+ if (status & Tx_Defer) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Excessive Deferral.";
+ }
+#ifndef NO_CHECK_CARRIER
+ if (status & Tx_NCarr) {
+ lp->stats.tx_carrier_errors++;
+ msg = "Lost Carrier Sense.";
+ }
+#endif
+ if (status & Tx_LateColl) {
+ lp->stats.tx_aborted_errors++;
+ msg = "Late Collision.";
+ }
+ if (status & Tx_TxPar) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Transmit Parity Error.";
+ }
+ if (status & Tx_SQErr) {
+ lp->stats.tx_heartbeat_errors++;
+ msg = "Signal Quality Error.";
+ }
+ if (msg)
+ printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
+}
+
+static void
+tc35815_txdone(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ struct TxFD *txfd;
+ unsigned int fdctl;
+ int num_done = 0;
+
+ txfd = &lp->tfd_base[lp->tfd_end];
+ while (lp->tfd_start != lp->tfd_end &&
+ !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
+ int status = le32_to_cpu(txfd->fd.FDStat);
+ struct sk_buff *skb;
+ unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+
+ if (tc35815_debug > 2) {
+ printk("%s: complete TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ }
+ tc35815_check_tx_stat(dev, status);
+
+ skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ }
+ txfd->fd.FDSystem = cpu_to_le32(0);
+
+ num_done++;
+ lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
+ txfd = &lp->tfd_base[lp->tfd_end];
+ if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+ printk("%s: TxFD FDNext invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ if (fdnext & FD_Next_EOL) {
+ /* DMA Transmitter has been stopping... */
+ if (lp->tfd_end != lp->tfd_start) {
+ int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
+ struct TxFD* txhead = &lp->tfd_base[head];
+ int qlen = (lp->tfd_start + TX_FD_NUM
+ - lp->tfd_end) % TX_FD_NUM;
+
+ if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
+ printk("%s: TxFD FDCtl invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ /* log max queue length */
+ if (lp->lstats.max_tx_qlen < qlen)
+ lp->lstats.max_tx_qlen = qlen;
+
+
+ /* start DMA Transmitter again */
+ txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+ txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+ if (tc35815_debug > 2) {
+ printk("%s: start TxFD on queue.\n",
+ dev->name);
+ dump_txfd(txfd);
+ }
+ tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+ }
+ break;
+ }
+ }
+
+ if (num_done > 0 && lp->tbusy) {
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+ }
+}
+
+/* The inverse routine to tc35815_open(). */
+static int
+tc35815_close(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+
+ lp->tbusy = 1;
+ netif_stop_queue(dev);
+
+ /* Flush the Tx and disable Rx here. */
+
+ tc35815_chip_reset(dev);
+ free_irq(dev->irq, dev);
+
+ tc35815_free_queues(dev);
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ unsigned long flags;
+
+ if (netif_running(dev)) {
+ save_and_cli(flags);
+ /* Update the statistics from the device registers. */
+ lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
+ restore_flags(flags);
+ }
+
+ return &lp->stats;
+}
+
+static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+{
+ int cam_index = index * 6;
+ unsigned long cam_data;
+ unsigned long saved_addr;
+ saved_addr = tc_readl(&tr->CAM_Adr);
+
+ if (tc35815_debug > 1) {
+ int i;
+ printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+ for (i = 0; i < 6; i++)
+ printk(" %02x", addr[i]);
+ printk("\n");
+ }
+ if (index & 1) {
+ /* read modify write */
+ tc_writel(cam_index - 2, &tr->CAM_Adr);
+ cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
+ cam_data |= addr[0] << 8 | addr[1];
+ tc_writel(cam_data, &tr->CAM_Data);
+ /* write whole word */
+ tc_writel(cam_index + 2, &tr->CAM_Adr);
+ cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+ tc_writel(cam_data, &tr->CAM_Data);
+ } else {
+ /* write whole word */
+ tc_writel(cam_index, &tr->CAM_Adr);
+ cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+ tc_writel(cam_data, &tr->CAM_Data);
+ /* read modify write */
+ tc_writel(cam_index + 4, &tr->CAM_Adr);
+ cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
+ cam_data |= addr[4] << 24 | (addr[5] << 16);
+ tc_writel(cam_data, &tr->CAM_Data);
+ }
+
+ if (tc35815_debug > 2) {
+ int i;
+ for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
+ tc_writel(i * 4, &tr->CAM_Adr);
+ printk("CAM 0x%x: %08x",
+ i * 4, tc_readl(&tr->CAM_Data));
+ }
+ }
+ tc_writel(saved_addr, &tr->CAM_Adr);
+}
+
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, clear multicast list
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ */
+static void
+tc35815_set_multicast_list(struct net_device *dev)
+{
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+ if (dev->flags&IFF_PROMISC)
+ {
+ /* Enable promiscuous mode */
+ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
+ }
+ else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3)
+ {
+ /* CAM 0, 1, 20 are reserved. */
+ /* Disable promiscuous mode, use normal mode. */
+ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
+ }
+ else if(dev->mc_count)
+ {
+ struct dev_mc_list* cur_addr = dev->mc_list;
+ int i;
+ int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
+
+ tc_writel(0, &tr->CAM_Ctl);
+ /* Walk the address list, and load the filter */
+ for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
+ if (!cur_addr)
+ break;
+ /* entry 0,1 is reserved. */
+ tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+ ena_bits |= CAM_Ena_Bit(i + 2);
+ }
+ tc_writel(ena_bits, &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+ }
+ else {
+ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+ }
+}
+
+static unsigned long tc_phy_read(struct tc35815_regs *tr, int phy, int phy_reg)
+{
+ unsigned long data;
+ int flags;
+ save_and_cli(flags);
+ tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
+ data = tc_readl(&tr->MD_Data);
+ restore_flags(flags);
+ return data;
+}
+
+static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+{
+ int flags;
+ save_and_cli(flags);
+ tc_writel(d, &tr->MD_Data);
+ tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
+ restore_flags(flags);
+}
+
+static void tc35815_phy_chip_init(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ static int first = 1;
+ unsigned short ctl;
+
+ if (first) {
+ unsigned short id0, id1;
+ int count;
+ first = 0;
+
+ /* first data written to the PHY will be an ID number */
+ tc_phy_write(0, tr, 0, MII_CONTROL); /* ID:0 */
+#if 0
+ tc_phy_write(MIICNTL_RESET, tr, 0, MII_CONTROL);
+ printk(KERN_INFO "%s: Resetting PHY...", dev->name);
+ while (tc_phy_read(tr, 0, MII_CONTROL) & MIICNTL_RESET)
+ ;
+ printk("\n");
+ tc_phy_write(MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
+ MII_CONTROL);
+#endif
+ id0 = tc_phy_read(tr, 0, MII_PHY_ID0);
+ id1 = tc_phy_read(tr, 0, MII_PHY_ID1);
+ printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
+ id0, id1);
+ if (lp->option & TC35815_OPT_10M) {
+ lp->linkspeed = 10;
+ lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ } else if (lp->option & TC35815_OPT_100M) {
+ lp->linkspeed = 100;
+ lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ } else {
+ /* auto negotiation */
+ unsigned long neg_result;
+ tc_phy_write(MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
+ printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
+ count = 0;
+ while (!(tc_phy_read(tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
+ if (count++ > 5000) {
+ printk(" failed. Assume 10Mbps\n");
+ lp->linkspeed = 10;
+ lp->fullduplex = 0;
+ goto done;
+ }
+ if (count % 512 == 0)
+ printk(".");
+ mdelay(1);
+ }
+ printk(" done.\n");
+ neg_result = tc_phy_read(tr, 0, MII_ANLPAR);
+ if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
+ lp->linkspeed = 100;
+ else
+ lp->linkspeed = 10;
+ if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ done:
+ ;
+ }
+ }
+
+ ctl = 0;
+ if (lp->linkspeed == 100)
+ ctl |= MIICNTL_SPEED;
+ if (lp->fullduplex)
+ ctl |= MIICNTL_FDX;
+ tc_phy_write(ctl, tr, 0, MII_CONTROL);
+
+ if (lp->fullduplex) {
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+ }
+}
+
+static void tc35815_chip_reset(struct net_device *dev)
+{
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+ /* reset the controller */
+ tc_writel(MAC_Reset, &tr->MAC_Ctl);
+ while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
+ ;
+
+ tc_writel(0, &tr->MAC_Ctl);
+
+ /* initialize registers to default value */
+ tc_writel(0, &tr->DMA_Ctl);
+ tc_writel(0, &tr->TxThrsh);
+ tc_writel(0, &tr->TxPollCtr);
+ tc_writel(0, &tr->RxFragSize);
+ tc_writel(0, &tr->Int_En);
+ tc_writel(0, &tr->FDA_Bas);
+ tc_writel(0, &tr->FDA_Lim);
+ tc_writel(0xffffffff, &tr->Int_Src); /* Write 1 to clear */
+ tc_writel(0, &tr->CAM_Ctl);
+ tc_writel(0, &tr->Tx_Ctl);
+ tc_writel(0, &tr->Rx_Ctl);
+ tc_writel(0, &tr->CAM_Ena);
+ (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */
+
+}
+
+static void tc35815_chip_init(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ int flags;
+ unsigned long txctl = TX_CTL_CMD;
+
+ tc35815_phy_chip_init(dev);
+
+ /* load station address to CAM */
+ tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+
+ /* Enable CAM (broadcast and unicast) */
+ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+
+ save_and_cli(flags);
+
+ tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+
+ tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */
+ tc_writel(0, &tr->TxPollCtr); /* Batch mode */
+ tc_writel(TX_THRESHOLD, &tr->TxThrsh);
+ tc_writel(INT_EN_CMD, &tr->Int_En);
+
+ /* set queues */
+ tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+ tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
+ &tr->FDA_Lim);
+ /*
+ * Activation method:
+ * First, enable eht MAC Transmitter and the DMA Receive circuits.
+ * Then enable the DMA Transmitter and the MAC Receive circuits.
+ */
+ tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */
+ tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */
+ /* start MAC transmitter */
+ /* WORKAROUND: ignore LostCrS in full duplex operation */
+ if (lp->fullduplex)
+ txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+#ifdef GATHER_TXINT
+ txctl &= ~Tx_EnComp; /* disable global tx completion int. */
+#endif
+ tc_writel(txctl, &tr->Tx_Ctl);
+#if 0 /* No need to polling */
+ tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */
+#endif
+ restore_flags(flags);
+}
+
+static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ struct net_device *dev;
+
+ len += sprintf(buffer, "TC35815 statistics:\n");
+ for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ len += sprintf(buffer + len,
+ "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n",
+ dev->name,
+ lp->lstats.tx_ints,
+ lp->lstats.rx_ints,
+ lp->lstats.max_tx_qlen);
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset+length) break;
+ }
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return len;
+}
+
+/* XXX */
+void
+tc35815_killall(void)
+{
+ struct net_device *dev;
+
+ for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+ if (dev->flags&IFF_UP){
+ dev->stop(dev);
+ }
+ }
+}
+
+static struct pci_driver tc35815_driver = {
+ name: TC35815_MODULE_NAME,
+ probe: tc35815_probe,
+ remove: NULL,
+ id_table: tc35815_pci_tbl,
+};
+
+static int __init tc35815_init_module(void)
+{
+ int err;
+
+ if ((err = pci_module_init(&tc35815_driver)) < 0 )
+ return err;
+ else
+ return 0;
+}
+
+static void __exit tc35815_cleanup_module(void)
+{
+ struct net_device *next_dev;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (root_tc35815_dev) {
+ struct net_device *dev = root_tc35815_dev;
+ next_dev = ((struct tc35815_local *)dev->priv)->next_module;
+ kfree(dev->priv);
+ iounmap((void *)(dev->base_addr));
+ unregister_netdev(dev);
+ kfree(dev);
+ root_tc35815_dev = next_dev;
+ }
+}
+module_init(tc35815_init_module);
+module_exit(tc35815_cleanup_module);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7261252d2401..1235fc86fd9e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1509,7 +1509,8 @@ static void tg3_tx(struct tg3 *tp)
if (unlikely(skb == NULL))
BUG();
- pci_unmap_single(tp->pdev, ri->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(ri, mapping),
(skb->len - skb->data_len),
PCI_DMA_TODEVICE);
@@ -1526,7 +1527,7 @@ static void tg3_tx(struct tg3 *tp)
BUG();
pci_unmap_page(tp->pdev,
- ri->mapping,
+ pci_unmap_addr(ri, mapping),
skb_shinfo(skb)->frags[i].size,
PCI_DMA_TODEVICE);
@@ -1614,7 +1615,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
PCI_DMA_FROMDEVICE);
map->skb = skb;
- map->mapping = mapping;
+ pci_unmap_addr_set(map, mapping, mapping);
if (src_map != NULL)
src_map->skb = NULL;
@@ -1666,7 +1667,8 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
};
dest_map->skb = src_map->skb;
- dest_map->mapping = src_map->mapping;
+ pci_unmap_addr_set(dest_map, mapping,
+ pci_unmap_addr(src_map, mapping));
dest_desc->addr_hi = src_desc->addr_hi;
dest_desc->addr_lo = src_desc->addr_lo;
@@ -1723,17 +1725,20 @@ static void tg3_rx(struct tg3 *tp)
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
if (opaque_key == RXD_OPAQUE_RING_STD) {
- dma_addr = tp->rx_std_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx],
+ mapping);
skb = tp->rx_std_buffers[desc_idx].skb;
post_ptr = &tp->rx_std_ptr;
} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
- dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx],
+ mapping);
skb = tp->rx_jumbo_buffers[desc_idx].skb;
post_ptr = &tp->rx_jumbo_ptr;
}
#if TG3_MINI_RING_WORKS
else if (opaque_key == RXD_OPAQUE_RING_MINI) {
- dma_addr = tp->rx_mini_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
+ mapping);
skb = tp->rx_mini_buffers[desc_idx].skb;
post_ptr = &tp->rx_mini_ptr;
}
@@ -2072,8 +2077,9 @@ static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
NIC_SRAM_TX_BUFFER_DESC);
txd += (entry * TXD_SIZE);
- writel(((u64) mapping >> 32),
- txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+ if (sizeof(dma_addr_t) != sizeof(u32))
+ writel(((u64) mapping >> 32),
+ txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
writel(((u64) mapping & 0xffffffff),
txd + TXD_ADDR + TG3_64BIT_REG_LOW);
@@ -2111,10 +2117,12 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
frag->page, frag->page_offset,
guilty_len, PCI_DMA_TODEVICE);
}
- pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping,
+ pci_unmap_single(tp->pdev, pci_unmap_addr(&tp->tx_buffers[guilty_entry],
+ mapping),
guilty_len, PCI_DMA_TODEVICE);
tg3_set_txd_addr(tp, guilty_entry, new_addr);
- tp->tx_buffers[guilty_entry].mapping = new_addr;
+ pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping,
+ new_addr);
*start = last_plus_one;
#else
/* Oh well, no IOMMU, have to allocate a whole new SKB. */
@@ -2148,11 +2156,12 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
len = skb->len - skb->data_len;
else
len = skb_shinfo(skb)->frags[i-1].size;
- pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(&tp->tx_buffers[entry], mapping),
len, PCI_DMA_TODEVICE);
if (i == 0) {
tp->tx_buffers[entry].skb = new_skb;
- tp->tx_buffers[entry].mapping = new_addr;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
} else {
tp->tx_buffers[entry].skb = NULL;
}
@@ -2199,8 +2208,7 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
txd += (entry * TXD_SIZE);
/* Save some PIOs */
- if (((u64) tp->tx_buffers[entry].mapping >> 32) !=
- ((u64) mapping >> 32))
+ if (sizeof(dma_addr_t) != sizeof(u32))
writel(((u64) mapping >> 32),
txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
@@ -2257,9 +2265,12 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- would_hit_hwbug = tg3_4g_overflow_test(mapping, len);
+ would_hit_hwbug = 0;
+
+ if (tg3_4g_overflow_test(mapping, len))
+ would_hit_hwbug = entry + 1;
tg3_set_txd(tp, entry, mapping, len, base_flags,
(skb_shinfo(skb)->nr_frags == 0));
@@ -2281,10 +2292,14 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = NULL;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- would_hit_hwbug |=
- tg3_4g_overflow_test(mapping, len);
+ if (tg3_4g_overflow_test(mapping, len)) {
+ /* Only one should match. */
+ if (would_hit_hwbug)
+ BUG();
+ would_hit_hwbug = entry + 1;
+ }
tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last));
@@ -2298,19 +2313,18 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
u32 start;
unsigned int len = 0;
+ would_hit_hwbug -= 1;
entry = entry - 1 - skb_shinfo(skb)->nr_frags;
entry &= (TG3_TX_RING_SIZE - 1);
start = entry;
i = 0;
while (entry != last_plus_one) {
- dma_addr_t mapping = tp->tx_buffers[entry].mapping;
-
if (i == 0)
len = skb->len - skb->data_len;
else
len = skb_shinfo(skb)->frags[i-1].size;
- if (tg3_4g_overflow_test(mapping, len))
+ if (entry == would_hit_hwbug)
break;
i++;
@@ -2390,7 +2404,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len, base_flags,
(skb_shinfo(skb)->nr_frags == 0));
@@ -2413,7 +2427,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = NULL;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last));
@@ -2497,7 +2511,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2509,7 +2524,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_MINI_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2521,7 +2537,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2541,7 +2558,8 @@ static void tg3_free_rings(struct tg3 *tp)
continue;
}
- pci_unmap_single(tp->pdev, txp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(txp, mapping),
(skb->len - skb->data_len),
PCI_DMA_TODEVICE);
txp->skb = NULL;
@@ -2550,7 +2568,8 @@ static void tg3_free_rings(struct tg3 *tp)
for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
- pci_unmap_page(tp->pdev, txp->mapping,
+ pci_unmap_page(tp->pdev,
+ pci_unmap_addr(txp, mapping),
skb_shinfo(skb)->frags[j].size,
PCI_DMA_TODEVICE);
i++;
@@ -4770,6 +4789,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
+ return 0;
}
case ETHTOOL_GCOALESCE: {
struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
@@ -5441,10 +5461,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
&cacheline_sz_reg);
- tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff;
- tp->pci_lat_timer = (cacheline_sz_reg >> 16) & 0xff;
- tp->pci_hdr_type = (cacheline_sz_reg >> 8) & 0xff;
- tp->pci_bist = (cacheline_sz_reg >> 0) & 0xff;
+ tp->pci_cacheline_sz = (cacheline_sz_reg >> 0) & 0xff;
+ tp->pci_lat_timer = (cacheline_sz_reg >> 8) & 0xff;
+ tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff;
+ tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+ tp->pci_lat_timer < 64) {
+ tp->pci_lat_timer = 64;
+
+ cacheline_sz_reg = ((tp->pci_cacheline_sz & 0xff) << 0);
+ cacheline_sz_reg |= ((tp->pci_lat_timer & 0xff) << 8);
+ cacheline_sz_reg |= ((tp->pci_hdr_type & 0xff) << 16);
+ cacheline_sz_reg |= ((tp->pci_bist & 0xff) << 24);
+
+ pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
+ cacheline_sz_reg);
+ }
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
@@ -5924,6 +5957,10 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+ return 0;
+
ret = 0;
while (1) {
u32 *p, i;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5beda44b61c1..1ad86220d9aa 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1654,7 +1654,7 @@ enum phy_led_mode {
*/
struct ring_info {
struct sk_buff *skb;
- dma_addr_t mapping;
+ DECLARE_PCI_UNMAP_ADDR(mapping)
};
struct tg3_config_info {
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index bbc7fd183399..c3a33e385864 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3718,8 +3718,8 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr)
}
tp = (struct net_local *)dev->priv;
- dev->rmem_start = dev->mem_start = tp->ram_base;
- dev->rmem_end = dev->mem_end = dev->mem_start + 0x10000;
+ dev->mem_start = tp->ram_base;
+ dev->mem_end = dev->mem_start + 0x10000;
ram = (__u32 *)phys_to_virt(dev->mem_start);
tp->ram_access = *(__u32 *)&ram;
tp->status = NOT_INITIALIZED;
diff --git a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c
index 4f73023d6cd6..76e41b5109ad 100644
--- a/drivers/net/wan/comx-hw-locomx.c
+++ b/drivers/net/wan/comx-hw-locomx.c
@@ -154,12 +154,10 @@ static int LOCOMX_open(struct net_device *dev)
return -ENODEV;
}
- if (check_region(dev->base_addr, hw->io_extent)) {
+ if (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
return -EAGAIN;
}
- request_region(dev->base_addr, hw->io_extent, dev->name);
-
hw->board.chanA.ctrlio=dev->base_addr + 5;
hw->board.chanA.dataio=dev->base_addr + 7;
diff --git a/drivers/net/wan/comx-hw-mixcom.c b/drivers/net/wan/comx-hw-mixcom.c
index 3936d97163e0..59b392748338 100644
--- a/drivers/net/wan/comx-hw-mixcom.c
+++ b/drivers/net/wan/comx-hw-mixcom.c
@@ -566,8 +566,6 @@ static int MIXCOM_open(struct net_device *dev)
return 0;
-err_restore_flags:
- restore_flags(flags);
err_release_region:
release_region(dev->base_addr, MIXCOM_IO_EXTENT);
err_ret:
diff --git a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
index 87b92433b730..b69c983bcbb8 100644
--- a/drivers/net/wan/comx-hw-munich.c
+++ b/drivers/net/wan/comx-hw-munich.c
@@ -1397,15 +1397,6 @@ udelay(10000);
return;
}
-void free_stuff(munich_board_t *board, struct comx_channel *ch)
-{
-/* Free CCB and the interrupt queues */
- if (board->ccb) kfree((void *)board->ccb);
- if (board->tiq) kfree((void *)board->tiq);
- if (board->riq) kfree((void *)board->riq);
- if (board->piq) kfree((void *)board->piq);
-}
-
/*
* Hardware open routine.
* Called by comx (upper) layer when the user wants to bring up the interface
@@ -1488,7 +1479,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->tiq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
@@ -1497,7 +1487,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->riq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->riq, 0, MUNICH_INTQSIZE);
@@ -1506,7 +1495,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->piq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->piq, 0, MUNICH_PIQSIZE);
@@ -1527,7 +1515,6 @@ static int MUNICH_open(struct net_device *dev)
board->pci->irq);
/* TOD: free other resources (a sok malloc feljebb) */
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EAGAIN;
}
board->irq = board->pci->irq; /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
@@ -1597,7 +1584,6 @@ static int MUNICH_open(struct net_device *dev)
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut down hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EAGAIN;
}
else if (!(stat & STAT_PCMA))
@@ -1608,7 +1594,6 @@ static int MUNICH_open(struct net_device *dev)
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut off the hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EIO;
}
@@ -1670,7 +1655,7 @@ static int MUNICH_open(struct net_device *dev)
spin_unlock_irqrestore(&mister_lock, flags);
dev->irq = board->irq; /* hogy szep legyen az ifconfig outputja */
- ccb = board->ccb; /* TOD: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
+ ccb = board->ccb; /* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
spin_lock_irqsave(&mister_lock, flags);
@@ -1680,13 +1665,12 @@ static int MUNICH_open(struct net_device *dev)
/* Check if the selected timeslots aren't used already */
for (i = 0; i < 32; i++)
- if (((1 << i) & timeslots) && ccb->timeslot_spec[i].tti == 0)
+ if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti)
{
printk("MUNICH_open: %s: timeslot %d already used by %s\n",
dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
- return -EBUSY; /* TOD: lehet hogy valami mas errno kellene? */
+ return -EBUSY; /* TODO: lehet hogy valami mas errno kellene? */
}
/* find a free channel: */
@@ -1700,7 +1684,6 @@ static int MUNICH_open(struct net_device *dev)
("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
dev->name);
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENODEV;
}
if (board->twins[channel] == NULL)
@@ -1998,7 +1981,7 @@ static int MUNICH_close(struct net_device *dev)
spin_lock_irqsave(&mister_lock, flags);
- board->use_count--;
+ if (board->use_count) board->use_count--;
if (!board->use_count) /* we were the last user of the board */
{
@@ -2020,7 +2003,12 @@ static int MUNICH_close(struct net_device *dev)
free_irq(board->irq, (void *)board); /* Ha nem inicializalta magat, akkor meg nincs irq */
board->irq = 0;
- free_stuff(board, ch);
+ /* Free CCB and the interrupt queues */
+ if (board->ccb) kfree((void *)board->ccb);
+ if (board->tiq) kfree((void *)board->tiq);
+ if (board->riq) kfree((void *)board->riq);
+ if (board->piq) kfree((void *)board->piq);
+ board->ccb = board->tiq = board->riq = board->piq = NULL;
}
/* Enable setting of hw parameters */
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 883d064de3ec..30af146bb972 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -105,13 +105,6 @@
#include <net/syncppp.h>
#include "cosa.h"
-/* Linux version stuff */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
- struct wait_queue wait = { current, NULL }
-#endif
-
/* Maximum length of the identification string. */
#define COSA_MAX_ID_STRING 128
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 991996da0fb1..da81e5390439 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -515,8 +515,9 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
stats->rx_bytes += pkt_len;
skb->tail += pkt_len;
skb->len = pkt_len;
- if (netif_running(dev))
+ if (netif_running(dev))
skb->protocol = htons(ETH_P_HDLC);
+ skb->dev->last_rx = jiffies;
netif_rx(skb);
try_get_rx_skb(dpriv, cur, dev);
} else {
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index 7f8677c62a04..cd2645791d1e 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -291,6 +291,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
#endif
port->hdlc.stats.rx_packets++;
port->hdlc.stats.rx_bytes += skb->len;
+ skb->dev->last_rx = jiffies;
skb->mac.raw = skb->data;
skb->dev = hdlc_to_dev(&port->hdlc);
skb->protocol = htons(ETH_P_HDLC);
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
index 73a9d033e8c6..f3badbcdf3f6 100644
--- a/drivers/net/wan/sdla_ppp.c
+++ b/drivers/net/wan/sdla_ppp.c
@@ -1463,11 +1463,11 @@ static int tokenize (char *str, char **tokens)
{
int cnt = 0;
- tokens[0] = strtok(str, "/");
+ tokens[0] = strsep(&str, "/");
while (tokens[cnt] && (cnt < 32 - 1))
{
tokens[cnt] = strstrip(tokens[cnt], " \t");
- tokens[++cnt] = strtok(NULL, "/");
+ tokens[++cnt] = strsep(&str, "/");
}
return cnt;
}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index b6c5f8701bbe..3f244b70ed39 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -97,7 +97,7 @@ int __init wd_probe(struct net_device *dev)
return -EBUSY;
i = wd_probe1(dev, base_addr);
if (i != 0)
- release_resource(r);
+ release_region(base_addr, WD_IO_EXTENT);
else
r->name = dev->name;
return i;
@@ -114,7 +114,7 @@ int __init wd_probe(struct net_device *dev)
r->name = dev->name;
return 0;
}
- release_resource(r);
+ release_region(ioaddr, WD_IO_EXTENT);
}
return -ENODEV;
@@ -281,7 +281,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
/* Don't map in the shared memory until the board is actually opened. */
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
if (dev->mem_end != 0) {
@@ -290,7 +290,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
}
- dev->rmem_end = dev->mem_end;
+ ei_status.rmem_end = dev->mem_end;
printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
model_name, dev->irq, dev->mem_start, dev->mem_end-1);
@@ -384,12 +384,12 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 9c84936c43ad..0bdd8a952cf7 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -267,21 +267,28 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-
static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
- {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},
+ {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
+#if 0
+ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga */
+#endif
+ {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W,
+ Eumitcom PCI WL11000,
+ Addtron AWA-100*/
+ {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */
+ {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */
+ {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */
+ {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */
+ {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 */
{0,},
};
-
MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
static struct pci_driver orinoco_plx_driver = {
- name:"orinoco_plx",
- id_table:orinoco_plx_pci_id_table,
- probe:orinoco_plx_init_one,
- remove:__devexit_p(orinoco_plx_remove_one),
- suspend:0,
- resume:0
+ name: "orinoco_plx",
+ id_table: orinoco_plx_pci_id_table,
+ probe: orinoco_plx_init_one,
+ remove: __devexit_p(orinoco_plx_remove_one),
};
static int __init orinoco_plx_init(void)
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 41cc106ba7ef..200a5f378ef4 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -408,6 +408,7 @@ void __exit parport_mfc3_exit(void)
MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+MODULE_LICENSE("GPL");
module_init(parport_mfc3_init)
module_exit(parport_mfc3_exit)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a8fa051737f8..b9b10a1b4f7a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -893,7 +893,7 @@ pci_generic_prep_mwi(struct pci_dev *dev)
#endif /* !HAVE_ARCH_PCI_MWI */
/**
- * pci_set_mwi - enables memory-write-validate PCI transaction
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
*
* Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 29a97f2b8138..4d8e32e5b1c4 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -824,6 +824,7 @@
0074 56k Voice Modem
1033 8014 RCV56ACF 56k Voice Modem
009b Vrc5476
+ 00a6 VRC5477 AC97
00e0 USB 2.0
1034 Framatome Connectors USA Inc.
1035 Comp. & Comm. Research Lab
@@ -1108,12 +1109,14 @@
1059 Teknor Industrial Computers Inc
105a Promise Technology, Inc.
0d30 20265
+ 1275 20275
4d30 20267
4d33 20246
4d38 20262
4d68 20268
6268 20268R
4d69 20269
+ 5275 20276
5300 DC5300
105b Foxconn International, Inc.
105c Wipro Infotech Limited
@@ -1192,11 +1195,21 @@
0017 Paddington Mac I/O
0018 UniNorth FireWire
0019 KeyLargo USB
- 001e UniNorth PCI
+ 001e UniNorth Internal PCI
001f UniNorth PCI
0020 UniNorth AGP
- 0021 UniNorth GMAC
+ 0021 UniNorth GMAC (Sun GEM)
0022 KeyLargo Mac I/O
+ 0024 UniNorth/Pangea GMAC (Sun GEM)
+ 0025 KeyLargo/Pangea Mac I/O
+ 0026 KeyLargo/Pangea USB
+ 0027 UniNorth/Pangea AGP
+ 0028 UniNorth/Pangea PCI
+ 0029 UniNorth/Pangea Internal PCI
+ 002d UniNorth 1.5 AGP
+ 002e UniNorth 1.5 PCI
+ 002f UniNorth 1.5 Internal PCI
+ 0030 UniNorth/Pangea FireWire
106c Hyundai Electronics America
8801 Dual Pentium ISA/PCI Motherboard
8802 PowerPC ISA/PCI Motherboard
@@ -2620,6 +2633,8 @@
0005 ATP850UF
0006 ATP860 NO-BIOS
0007 ATP860
+ 0008 ATP865 NO-ROM
+ 0009 ATP865
8002 AEC6710 SCSI-2 Host Adapter
8010 AEC6712UW SCSI
8020 AEC6712U SCSI
@@ -3965,7 +3980,7 @@
9511 16PCI954 Function 1
15ed 2000 Macrolink MCCR Serial p4-7 of 8
15ed 2001 Macrolink MCCR Serial p4-15 of 16
- 9521 Oxford Semi OX16PCI952 PCI/dual 16950 UART
+ 9521 16PCI952 PCI/dual 16950 UART
1416 Multiwave Innovation pte Ltd
1417 Convergenet Technologies Inc
1418 Kyushu electronics systems Inc
diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
index ae5294fa23db..adb380b85511 100644
--- a/drivers/pcmcia/Config.in
+++ b/drivers/pcmcia/Config.in
@@ -24,6 +24,8 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
fi
fi
-dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+fi
endmenu
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 6f921871df33..2bd40cd6d57a 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -43,7 +43,7 @@ static struct pci_driver i82092aa_pci_drv = {
name: "i82092aa",
id_table: i82092aa_pci_ids,
probe: i82092aa_pci_probe,
- remove: i82092aa_pci_remove,
+ remove: __devexit_p(i82092aa_pci_remove),
suspend: NULL,
resume: NULL
};
@@ -168,7 +168,7 @@ err_out_disable:
return ret;
}
-static void __exit i82092aa_pci_remove(struct pci_dev *dev)
+static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
{
enter("i82092aa_pci_remove");
diff --git a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
index 6f2eda9cb3f6..5c39209bb52b 100644
--- a/drivers/pnp/pnpbios_core.c
+++ b/drivers/pnp/pnpbios_core.c
@@ -4,7 +4,7 @@
* Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
* Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
* Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
- * Modifications (c) 2001 by Thomas Hood <jdthood@mail.com>
+ * Modifications (c) 2001,2002 by Thomas Hood <jdthood@mail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -190,8 +190,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
/* If we get here and this is set then the PnP BIOS faulted on us. */
if(pnp_bios_is_utter_crap)
{
- printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
- printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n");
+ printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
+ printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably\n");
printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
}
@@ -205,11 +205,16 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
*
*/
+static void pnpbios_warn_unexpected_status(const char * module, u16 status)
+{
+ printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status);
+}
+
void *pnpbios_kmalloc(size_t size, int f)
{
void *p = kmalloc( size, f );
if ( p == NULL )
- printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n");
+ printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
return p;
}
@@ -251,7 +256,7 @@ static void update_devlist( u8 nodenum, struct pnp_bios_node *data );
static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -263,7 +268,7 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
int status = __pnp_bios_dev_node_info( data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "dev_node_info", status );
return status;
}
@@ -284,7 +289,7 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
if ( !boot & pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
@@ -299,7 +304,7 @@ int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
int status;
status = __pnp_bios_get_dev_node( nodenum, boot, data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "get_dev_node", status );
return status;
}
@@ -313,7 +318,7 @@ int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
if ( !boot & pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
@@ -327,17 +332,14 @@ int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
int status;
status = __pnp_bios_set_dev_node( nodenum, boot, data );
if ( status ) {
- printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "set_dev_node", status );
return status;
}
- if ( !boot ) {
- /* Update devlist */
+ if ( !boot ) { /* Update devlist */
u8 thisnodenum = nodenum;
- status = __pnp_bios_get_dev_node( &nodenum, boot, data );
- if ( status ) {
- printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status )
return status;
- }
update_devlist( thisnodenum, data );
}
return status;
@@ -350,7 +352,7 @@ int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
static int pnp_bios_get_event(u16 *event)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -365,7 +367,7 @@ static int pnp_bios_get_event(u16 *event)
static int pnp_bios_send_message(u16 message)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
return status;
@@ -379,7 +381,7 @@ static int pnp_bios_send_message(u16 message)
static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +397,7 @@ static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
static int pnp_bios_set_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -403,21 +405,28 @@ static int pnp_bios_set_stat_res(char *info)
}
#endif
-#if needed
/*
* Call PnP BIOS with function 0x0a, "get statically allocated resource
* information"
*/
-static int pnp_bios_get_stat_res(char *info)
+static int __pnp_bios_get_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
-#endif
+
+int pnp_bios_get_stat_res(char *info)
+{
+ int status;
+ status = __pnp_bios_get_stat_res( info );
+ if ( status )
+ pnpbios_warn_unexpected_status( "get_stat_res", status );
+ return status;
+}
#if needed
/*
@@ -426,7 +435,7 @@ static int pnp_bios_get_stat_res(char *info)
static int pnp_bios_apm_id_table(char *table, u16 *size)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, table, *size);
Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -435,45 +444,58 @@ static int pnp_bios_apm_id_table(char *table, u16 *size)
}
#endif
-#if needed
/*
* Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
*/
-static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
-#endif
-#if needed
+int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+ int status;
+ status = __pnp_bios_isapnp_config( data );
+ if ( status )
+ pnpbios_warn_unexpected_status( "isapnp_config", status );
+ return status;
+}
+
/*
* Call PnP BIOS with function 0x41, "get ESCD info"
*/
-static int pnp_bios_escd_info(struct escd_info_struc *data)
+static int __pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
return status;
}
-#endif
-#if needed
+int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+ int status;
+ status = __pnp_bios_escd_info( data );
+ if ( status )
+ pnpbios_warn_unexpected_status( "escd_info", status );
+ return status;
+}
+
/*
* Call PnP BIOS function 0x42, "read ESCD"
* nvram_base is determined by calling escd_info
*/
-static int pnp_bios_read_escd(char *data, u32 nvram_base)
+static int __pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -481,7 +503,15 @@ static int pnp_bios_read_escd(char *data, u32 nvram_base)
status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
return status;
}
-#endif
+
+int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+ int status;
+ status = __pnp_bios_read_escd( data, nvram_base );
+ if ( status )
+ pnpbios_warn_unexpected_status( "read_escd", status );
+ return status;
+}
#if needed
/*
@@ -490,7 +520,7 @@ static int pnp_bios_read_escd(char *data, u32 nvram_base)
static int pnp_bios_write_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -574,13 +604,13 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
static int pnp_dock_thread(void * unused)
{
static struct pnp_docking_station_info now;
- int docked = -1, d;
+ int docked = -1, d = 0;
daemonize();
reparent_to_init();
- strcpy(current->comm, "kpnpbios");
+ strcpy(current->comm, "kpnpbiosd");
while(!unloading && !signal_pending(current))
{
- int err;
+ int status;
/*
* Poll every 2 seconds
@@ -590,9 +620,9 @@ static int pnp_dock_thread(void * unused)
if(signal_pending(current))
break;
- err = pnp_bios_dock_station_info(&now);
+ status = pnp_bios_dock_station_info(&now);
- switch(err)
+ switch(status)
{
/*
* No dock to manage
@@ -606,7 +636,7 @@ static int pnp_dock_thread(void * unused)
d = 1;
break;
default:
- printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
+ pnpbios_warn_unexpected_status( "pnp_dock_thread", status );
continue;
}
if(d != docked)
@@ -615,7 +645,7 @@ static int pnp_dock_thread(void * unused)
{
docked = d;
#if 0
- printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+ printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
#endif
}
}
@@ -848,15 +878,14 @@ static void inline pnpid32_to_pnpid(u32 id, char *str)
*/
static void __init build_devlist(void)
{
- int i;
- int nodenum;
- int nodes_got = 0;
- int devs = 0;
+ u8 nodenum;
+ unsigned int nodes_got = 0;
+ unsigned int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return;
if (pnp_bios_dev_node_info(&node_info) != 0)
@@ -866,26 +895,20 @@ static void __init build_devlist(void)
if (!node)
return;
- for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) {
- int thisnodenum = nodenum;
- /* For now we build the list from the "boot" config
- * because asking for the "current" config causes
- * some BIOSes to crash. */
- if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) {
- printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n");
- break;
- }
- /* The BIOS returns with nodenum = the next node number */
- if (nodenum < thisnodenum) {
- printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n");
+ for(nodenum=0; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
+ /* We build the list from the "boot" config because
+ * asking for the "current" config causes some
+ * BIOSes to crash.
+ */
+ if (pnp_bios_get_dev_node(&nodenum, (char )1 , node))
break;
- }
nodes_got++;
dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
memset(dev,0,sizeof(struct pci_dev));
- dev->devfn=thisnodenum;
+ dev->devfn = thisnodenum;
memcpy(dev->name,"PNPBIOS",8);
pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
node_resource_data_to_dev(node,dev);
@@ -893,10 +916,14 @@ static void __init build_devlist(void)
kfree(dev);
else
devs++;
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ break;
+ }
}
kfree(node);
- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
nodes_got, nodes_got != 1 ? "s" : "", devs);
}
@@ -1062,7 +1089,7 @@ static void __init reserve_ioport_range(char *pnpid, int start, int end)
regionid = pnpbios_kmalloc(16, GFP_KERNEL);
if ( regionid == NULL )
return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
+ snprintf(regionid, 16, "PnPBIOS %s", pnpid);
res = request_region(start,end-start+1,regionid);
if ( res == NULL )
kfree( regionid );
@@ -1074,7 +1101,7 @@ static void __init reserve_ioport_range(char *pnpid, int start, int end)
* have double reservations.
*/
printk(KERN_INFO
- "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n",
+ "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n",
pnpid, start, end,
NULL != res ? "has been" : "could not be"
);
@@ -1193,14 +1220,14 @@ int __init pnpbios_init(void)
{
union pnp_bios_expansion_header *check;
u8 sum;
- int i, length;
+ int i, length, r;
spin_lock_init(&pnp_bios_lock);
spin_lock_init(&pnpbios_devices_lock);
if(pnpbios_disabled) {
- printk(KERN_INFO "PnPBIOS: Disabled.\n");
- return 0;
+ printk(KERN_INFO "PnPBIOS: Disabled\n");
+ return -ENODEV;
}
if ( is_sony_vaio_laptop )
@@ -1224,13 +1251,13 @@ int __init pnpbios_init(void)
if (sum)
continue;
if (check->fields.version < 0x10) {
- printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n",
+ printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
check->fields.version >> 4,
check->fields.version & 15);
continue;
}
- printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check);
- printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n",
+ printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+ printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
check->fields.version >> 4, check->fields.version & 15,
check->fields.pm16cseg, check->fields.pm16offset,
check->fields.pm16dseg);
@@ -1242,12 +1269,21 @@ int __init pnpbios_init(void)
pnp_bios_hdr = check;
break;
}
+ if (!pnp_bios_present())
+ return -ENODEV;
build_devlist();
if ( ! dont_reserve_resources )
reserve_resources();
#ifdef CONFIG_PROC_FS
- pnpbios_proc_init();
+ r = pnpbios_proc_init();
+ if (r)
+ return r;
#endif
+ return 0;
+}
+
+static int __init pnpbios_thread_init(void)
+{
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
@@ -1256,23 +1292,46 @@ int __init pnpbios_init(void)
return 0;
}
-#ifdef MODULE
+#ifndef MODULE
+
+/* init/main.c calls pnpbios_init early */
+
+/* Start the kernel thread later: */
+module_init(pnpbios_thread_init);
+
+#else
+
+/*
+ * N.B.: Building pnpbios as a module hasn't been fully implemented
+ */
MODULE_LICENSE("GPL");
-/* We have to run it early and not as a module. */
-module_init(pnpbios_init);
+static int __init pnpbios_init_all(void)
+{
+ int r;
+
+ r = pnpbios_init();
+ if (r)
+ return r;
+ r = pnpbios_thread_init();
+ if (r)
+ return r;
+ return 0;
+}
-#ifdef CONFIG_HOTPLUG
-static void pnpbios_exit(void)
+static void __exit pnpbios_exit(void)
{
- /* free_resources() ought to go here */
- /* pnpbios_proc_done() */
+#ifdef CONFIG_HOTPLUG
unloading = 1;
wait_for_completion(&unload_sem);
+#endif
+ pnpbios_proc_exit();
+ /* We ought to free resources here */
+ return;
}
+module_init(pnpbios_init_all);
module_exit(pnpbios_exit);
#endif
-#endif
diff --git a/drivers/pnp/pnpbios_proc.c b/drivers/pnp/pnpbios_proc.c
index efa39987dc92..6321c32ed1a3 100644
--- a/drivers/pnp/pnpbios_proc.c
+++ b/drivers/pnp/pnpbios_proc.c
@@ -1,7 +1,21 @@
/*
- * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ * /proc/bus/pnp interface for Plug and Play devices
*
* Written by David Hinds, dahinds@users.sourceforge.net
+ * Modified by Thomas Hood, jdthood@mail.com
+ *
+ * The .../devices and .../<node> and .../boot/<node> files are
+ * utilized by the lspnp and setpnp utilities, supplied with the
+ * pcmcia-cs package.
+ * http://pcmcia-cs.sourceforge.net
+ *
+ * The .../escd file is utilized by the lsescd utility written by
+ * Gunther Mayer.
+ * http://home.t-online.de/home/gunther.mayer/lsescd
+ *
+ * The .../legacy_device_resources file is not used yet.
+ *
+ * The other files are human-readable.
*/
//#include <pcmcia/config.h>
@@ -19,30 +33,118 @@ static struct proc_dir_entry *proc_pnp = NULL;
static struct proc_dir_entry *proc_pnp_boot = NULL;
static struct pnp_dev_node_info node_info;
+static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct pnp_isa_config_struc pnps;
+
+ if (pnp_bios_isapnp_config(&pnps))
+ return -EIO;
+ return snprintf(buf, count,
+ "structure_revision %d\n"
+ "number_of_CSNs %d\n"
+ "ISA_read_data_port 0x%x\n",
+ pnps.revision,
+ pnps.no_csns,
+ pnps.isa_rd_data_port
+ );
+}
+
+static int proc_read_escdinfo(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct escd_info_struc escd;
+
+ if (pnp_bios_escd_info(&escd))
+ return -EIO;
+ return snprintf(buf, count,
+ "min_ESCD_write_size %d\n"
+ "ESCD_size %d\n"
+ "NVRAM_base 0x%x\n",
+ escd.min_escd_write_size,
+ escd.escd_size,
+ escd.nv_storage_base
+ );
+}
+
+static int proc_read_escd(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct escd_info_struc escd;
+ char *tmpbuf;
+ int escd_size, escd_left_to_read, n;
+
+ if (pnp_bios_escd_info(&escd))
+ return -EIO;
+
+ /* sanity check */
+ if (escd.escd_size > (32*1024)) {
+ printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size is too great\n");
+ return -EFBIG;
+ }
+
+ tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+ if (!tmpbuf) return -ENOMEM;
+
+ if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base))
+ return -EIO;
+
+ escd_size = (unsigned char)(buf[0]) + (unsigned char)(buf[1])*256;
+ escd_left_to_read = escd_size - pos;
+ if (escd_left_to_read < 0) escd_left_to_read = 0;
+ if (escd_left_to_read == 0) *eof = 1;
+ n = min(count,escd_left_to_read);
+ memcpy(buf, tmpbuf + pos, n);
+ kfree(tmpbuf);
+ *start = buf;
+ return n;
+}
+
+static int proc_read_legacyres(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ /* Assume that the following won't overflow the buffer */
+ if (pnp_bios_get_stat_res(buf))
+ return -EIO;
+
+ return count; // FIXME: Return actual length
+}
+
static int proc_read_devices(char *buf, char **start, off_t pos,
int count, int *eof, void *data)
{
struct pnp_bios_node *node;
- int i;
u8 nodenum;
char *p = buf;
- if (pos != 0) {
- *eof = 1;
- return 0;
- }
+ if (pos >= 0xff)
+ return 0;
+
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+
+ for (nodenum=pos; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
+ /* 26 = the number of characters per line sprintf'ed */
+ if ((p - buf + 26) > count)
+ break;
+ if (pnp_bios_get_dev_node(&nodenum, 1, node))
break;
p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
node->handle, node->eisa_id,
node->type_code[0], node->type_code[1],
node->type_code[2], node->flags);
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ *eof = 1;
+ break;
+ }
}
kfree(node);
- return (p-buf);
+ if (nodenum == 0xff)
+ *eof = 1;
+ *start = (char *)((off_t)nodenum - pos);
+ return p - buf;
}
static int proc_read_node(char *buf, char **start, off_t pos,
@@ -53,13 +155,9 @@ static int proc_read_node(char *buf, char **start, off_t pos,
u8 nodenum = (long)data;
int len;
- if (pos != 0) {
- *eof = 1;
- return 0;
- }
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if (pnp_bios_get_dev_node(&nodenum, boot, node))
return -EIO;
len = node->size - sizeof(struct pnp_bios_node);
memcpy(buf, node->data, len);
@@ -92,25 +190,34 @@ static int proc_write_node(struct file *file, const char *buf,
* work and the pnpbios_dont_use_current_config flag
* should already have been set to the appropriate value
*/
-void pnpbios_proc_init( void )
+int __init pnpbios_proc_init( void )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
char name[3];
- int i;
u8 nodenum;
- if (pnp_bios_dev_node_info(&node_info) != 0) return;
+ if (pnp_bios_dev_node_info(&node_info))
+ return -EIO;
proc_pnp = proc_mkdir("pnp", proc_bus);
- if (!proc_pnp) return;
+ if (!proc_pnp)
+ return -EIO;
proc_pnp_boot = proc_mkdir("boot", proc_pnp);
- if (!proc_pnp_boot) return;
+ if (!proc_pnp_boot)
+ return -EIO;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
+ create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
+ create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
+ create_proc_read_entry("escd", 0, proc_pnp, proc_read_escd, NULL);
+ create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
- if (!node) return;
- for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
+ if (!node)
+ return -ENOMEM;
+
+ for (nodenum=0; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
@@ -128,11 +235,17 @@ void pnpbios_proc_init( void )
ent->write_proc = proc_write_node;
ent->data = (void *)(long)(node->handle+0x100);
}
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ break;
+ }
}
kfree(node);
+
+ return 0;
}
-void pnpbios_proc_done(void)
+void __exit pnpbios_proc_exit(void)
{
int i;
char name[3];
@@ -145,7 +258,13 @@ void pnpbios_proc_done(void)
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}
- remove_proc_entry("boot", proc_pnp);
+ remove_proc_entry("legacy_device_resources", proc_pnp);
+ remove_proc_entry("escd", proc_pnp);
+ remove_proc_entry("escd_info", proc_pnp);
+ remove_proc_entry("configuration_info", proc_pnp);
remove_proc_entry("devices", proc_pnp);
+ remove_proc_entry("boot", proc_pnp);
remove_proc_entry("pnp", proc_bus);
+
+ return;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 1f5259ff728c..f3b848251725 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2618,7 +2618,7 @@ dasd_release (struct inode *inp, struct file *filp)
}
count = atomic_dec_return (&device->open_count);
if ( count == 0) {
- invalidate_buffers (inp->i_rdev);
+ invalidate_bdev (inp->i_bdev, 0);
if ( device->discipline->owner )
__MOD_DEC_USE_COUNT(device->discipline->owner);
MOD_DEC_USE_COUNT;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index bb14996daf66..c0278e300cd8 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -201,14 +201,14 @@ do {\
debug_sprintf_event(d_device->debug_area,d_level,\
DASD_DEVICE_FORMAT_STRING d_str "\n",\
d_device, d_data);\
-} while(0);
+} while(0)
#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
do {\
if ( d_device->debug_area != NULL )\
debug_sprintf_exception(d_device->debug_area,d_level,\
DASD_DEVICE_FORMAT_STRING d_str "\n",\
d_device, d_data);\
-} while(0);
+} while(0)
#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
@@ -217,14 +217,14 @@ do {\
debug_sprintf_event(dasd_debug_area, d_level,\
DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
d_fn, d_data);\
-} while(0);
+} while(0)
#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
do {\
if ( dasd_debug_area != NULL )\
debug_sprintf_exception(dasd_debug_area, d_level,\
DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
d_fn, d_data);\
-} while(0);
+} while(0)
struct dasd_device_t;
struct request;
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 7e91ea6b2035..f494eff5a34d 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -655,7 +655,7 @@ int xpram_ioctl (struct inode *inode, struct file *filp,
case BLKFLSBUF: /* flush, 0x1261 */
fsync_bdev(inode->i_bdev);
- if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
+ if ( capable(CAP_SYS_ADMIN) )invalidate_bdev(inode->i_bdev, 0);
return 0;
case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
diff --git a/drivers/s390/char/tapeblock.c b/drivers/s390/char/tapeblock.c
index fd186360aa4b..5053228602e6 100644
--- a/drivers/s390/char/tapeblock.c
+++ b/drivers/s390/char/tapeblock.c
@@ -217,7 +217,7 @@ tapeblock_release(struct inode *inode, struct file *filp) {
s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
tapestate_set (ti, TS_UNUSED);
s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
return 0;
}
diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
index e2eece1727a1..3f37e962d216 100644
--- a/drivers/sbus/audio/amd7930.c
+++ b/drivers/sbus/audio/amd7930.c
@@ -1619,7 +1619,6 @@ static int amd7930_attach(struct sparcaudio_driver *drv, int node,
info->irq = irq.pri;
request_irq(info->irq, amd7930_interrupt,
SA_INTERRUPT, "amd7930", drv);
- enable_irq(info->irq);
amd7930_enable_ints(info);
/* Initalize the local copy of the MAP registers. */
@@ -1644,7 +1643,6 @@ static int amd7930_attach(struct sparcaudio_driver *drv, int node,
err = register_sparcaudio_driver(drv, 1);
if (err < 0) {
printk(KERN_ERR "amd7930: unable to register\n");
- disable_irq(info->irq);
free_irq(info->irq, drv);
sbus_iounmap(info->regs, info->regs_size);
kfree(drv->private);
@@ -1666,7 +1664,6 @@ static void __exit amd7930_detach(struct sparcaudio_driver *drv)
unregister_sparcaudio_driver(drv, 1);
amd7930_idle(info);
- disable_irq(info->irq);
free_irq(info->irq, drv);
sbus_iounmap(info->regs, info->regs_size);
kfree(drv->private);
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index 1ec3880f5da8..75d926058278 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -2210,7 +2210,6 @@ static int cs4231_attach(struct sparcaudio_driver *drv,
/* Attach the interrupt handler to the audio interrupt. */
cs4231_chip->irq = sdev->irqs[0];
request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
- enable_irq(cs4231_chip->irq);
cs4231_chip->nirqs = 1;
cs4231_enable_interrupts(drv);
@@ -2224,7 +2223,6 @@ static int cs4231_attach(struct sparcaudio_driver *drv,
if (err < 0) {
printk(KERN_ERR "cs4231: unable to register\n");
cs4231_disable_interrupts(drv);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
kfree(drv->private);
@@ -2312,9 +2310,7 @@ static int eb4231_attach(struct sparcaudio_driver *drv,
bail:
printk(KERN_ERR "cs4231: unable to register\n");
cs4231_disable_interrupts(drv);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
- disable_irq(cs4231_chip->irq2);
free_irq(cs4231_chip->irq2, drv);
kfree(drv->private);
return -EIO;
@@ -2371,7 +2367,6 @@ static void __exit cs4231_detach(struct sparcaudio_driver *drv)
cs4231_disable_interrupts(drv);
unregister_sparcaudio_driver(drv, 1);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
@@ -2380,7 +2375,6 @@ static void __exit cs4231_detach(struct sparcaudio_driver *drv)
iounmap(cs4231_chip->regs);
iounmap(cs4231_chip->eb2p);
iounmap(cs4231_chip->eb2c);
- disable_irq(cs4231_chip->irq2);
free_irq(cs4231_chip->irq2, drv);
#endif
}
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 86b08d5cb827..cc89c4c54c38 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -179,7 +179,7 @@ extern inline void aurora_long_delay(unsigned long delay)
#ifdef AURORA_DEBUG
printk("aurora_long_delay: start\n");
#endif
- for (i = jiffies + delay; i > jiffies; ) ;
+ for (i = jiffies + delay; time_before(jiffies, i); ) ;
#ifdef AURORA_DEBUG
printk("aurora_long_delay: end\n");
#endif
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index f3a2713d8fa1..b1571efa47ce 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -389,15 +389,11 @@ static int __init ts102_uctrl_init(void)
if(!driver->irq)
driver->irq = tmp_irq[0].pri;
- request_irq(driver->irq, uctrl_interrupt, 0,
- "uctrl", driver);
-
- enable_irq(driver->irq);
+ request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
__FUNCTION__, uctrl_dev.minor);
- disable_irq(driver->irq);
free_irq(driver->irq, driver);
return -ENODEV;
}
@@ -414,10 +410,8 @@ static void __exit ts102_uctrl_cleanup(void)
struct uctrl_driver *driver = &drv;
misc_deregister(&uctrl_dev);
- if (driver->irq) {
- disable_irq(driver->irq);
+ if (driver->irq)
free_irq(driver->irq, driver);
- }
if (driver->regs)
driver->regs = 0;
}
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 89a4cc2f9a7e..8fd7d45522ab 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -392,6 +392,10 @@ static int __init sbus_init(void)
sbus_bus_ranges_init(iommund, sbus);
sbus_devs = prom_getchild(this_sbus);
+ if (!sbus_devs) {
+ sbus->devices = NULL;
+ goto next_bus;
+ }
sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
@@ -455,7 +459,7 @@ static int __init sbus_init(void)
sbus_fixup_all_regs(sbus->devices);
dvma_init(sbus);
-
+ next_bus:
num_sbus++;
if(sparc_cpu_model == sun4u) {
this_sbus = prom_getsibling(this_sbus);
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 4b02451d2877..c7ccb6c0ad21 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -133,6 +133,14 @@
some SMP systems.
1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
pci_alloc/free_consistent().
+ Better alignment checking in tw_allocate_memory().
+ Cleanup tw_initialize_device_extension().
+ 1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
+ Improve handling of errors in tw_interrupt().
+ Add handling/clearing of controller queue error.
+ Empty stale responses before draining aen queue.
+ Fix tw_scsi_eh_abort() to not reset on every io abort.
+ Set can_queue in SHT to 255 to prevent hang from AEN.
*/
#include <linux/module.h>
@@ -182,7 +190,7 @@ static struct notifier_block tw_notifier = {
};
/* Globals */
-char *tw_driver_version="1.02.00.020";
+char *tw_driver_version="1.02.00.021";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
@@ -284,6 +292,9 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
}
tw_clear_attention_interrupt(tw_dev);
+ /* Empty response queue */
+ tw_empty_response_que(tw_dev);
+
/* Initialize command packet */
if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
@@ -337,7 +348,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -451,7 +462,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
return 1;
}
if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -571,13 +582,23 @@ int tw_check_errors(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
return 0;
} /* End tw_check_errors() */
+/* This function will clear all interrupts on the controller */
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
+{
+ u32 control_reg_addr, control_reg_value;
+
+ control_reg_addr = tw_dev->registers.control_reg_addr;
+ control_reg_value = TW_STATUS_VALID_INTERRUPT;
+ outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_all_interrupts() */
+
/* This function will clear the attention interrupt */
void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
{
@@ -632,30 +653,51 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len)
}
} /* End tw_copy_mem_info() */
-/* This function will print readable messages from statsu register errors */
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+/* This function will print readable messages from status register errors */
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
{
+ char host[16];
+
dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+ if (print_host)
+ sprintf(host, " scsi%d:", tw_dev->host->host_no);
+ else
+ host[0] = '\0';
+
switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
case TW_STATUS_PCI_PARITY_ERROR:
- printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
+ printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
break;
case TW_STATUS_MICROCONTROLLER_ERROR:
- printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
- break;
+ if (tw_dev->reset_print == 0) {
+ printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+ tw_dev->reset_print = 1;
+ }
+ return 1;
case TW_STATUS_PCI_ABORT:
- printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+ printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
break;
- }
+ case TW_STATUS_QUEUE_ERROR:
+ printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+ outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
+ break;
+ case TW_STATUS_SBUF_WRITE_ERROR:
+ printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+ outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
+ break;
+ }
+
+ return 0;
} /* End tw_decode_bits() */
/* This function will return valid sense buffer information for failed cmds */
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
{
- int i, found=0;
+ int i;
TW_Command *command;
dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
@@ -668,7 +710,6 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense
if ((command->status == 0xc7) || (command->status == 0xcb)) {
for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
if (command->flags == tw_sense_table[i][0]) {
- found=1;
/* Valid bit and 'current errors' */
tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
@@ -686,13 +727,16 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense
tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
}
}
}
+
/* If no table match, error so we get a reset */
- if (found == 0)
- tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ return 1;
}
+
+ return 0;
} /* End tw_decode_sense() */
/* This function will disable interrupts on the controller */
@@ -706,7 +750,7 @@ void tw_disable_interrupts(TW_Device_Extension *tw_dev)
} /* End tw_disable_interrupts() */
/* This function will empty the response que */
-int tw_empty_response_que(TW_Device_Extension *tw_dev)
+void tw_empty_response_que(TW_Device_Extension *tw_dev)
{
u32 status_reg_addr, status_reg_value;
u32 response_que_addr, response_que_value;
@@ -716,22 +760,10 @@ int tw_empty_response_que(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- return 1;
- }
-
while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
response_que_value = inl(response_que_addr);
status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- return 1;
- }
}
- return 0;
} /* End tw_empty_response_que() */
/* This function will enable interrupts on the controller */
@@ -811,8 +843,8 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Check for errors and clear them */
status_reg_value = inl(tw_dev->registers.status_reg_addr);
- if (TW_STATUS_ERRORS(status_reg_value))
- tw_decode_bits(tw_dev, status_reg_value);
+ if (TW_STATUS_ERRORS(status_reg_value))
+ tw_decode_bits(tw_dev, status_reg_value, 0);
/* Poll status register for 60 secs for 'Controller Ready' flag */
if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
@@ -843,14 +875,6 @@ int tw_findcards(Scsi_Host_Template *tw_host)
continue;
}
- /* Empty the response queue */
- error = tw_empty_response_que(tw_dev);
- if (error) {
- printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
- tries++;
- continue;
- }
-
/* Now the controller is in a good state */
break;
}
@@ -877,7 +901,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
error = tw_initialize_units(tw_dev);
if (error) {
- printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+ printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", numcards);
release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
tw_free_device_extension(tw_dev);
kfree(tw_dev);
@@ -895,7 +919,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Calculate max cmds per lun, and setup queues */
if (tw_dev->num_units > 0) {
- tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+ /* Use SHT cmd_per_lun here */
tw_dev->free_head = TW_Q_START;
tw_dev->free_tail = TW_Q_LENGTH - 1;
tw_dev->free_wrap = TW_Q_LENGTH - 1;
@@ -1064,7 +1088,7 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1191,7 +1215,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1251,51 +1275,52 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
u32 response_que_addr;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
TW_Response_Queue response_que;
- int error = 0;
- int do_response_interrupt=0;
- int do_attention_interrupt=0;
- int do_host_interrupt=0;
- int do_command_interrupt=0;
+ int error = 0, retval = 0;
unsigned long flags = 0;
TW_Command *command_packet;
+
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+
+ /* See if we are already running on another processor */
if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
return;
+
+ /* Get the host lock for io completions */
spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ /* See if the interrupt matches this instance */
if (tw_dev->tw_pci_dev->irq == irq) {
+
+ /* Make sure io isn't queueing */
spin_lock(&tw_dev->tw_lock);
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
/* Read the registers */
status_reg_addr = tw_dev->registers.status_reg_addr;
response_que_addr = tw_dev->registers.response_que_addr;
status_reg_value = inl(status_reg_addr);
+ /* Check if this is our interrupt, otherwise bail */
+ if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+ goto tw_interrupt_bail;
+
+ /* Check controller for errors */
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+ tw_clear_all_interrupts(tw_dev);
+ goto tw_interrupt_bail;
+ }
}
- /* Check which interrupt */
- if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
- do_host_interrupt=1;
- if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT)
- do_attention_interrupt=1;
- if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT)
- do_command_interrupt=1;
- if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT)
- do_response_interrupt=1;
-
/* Handle host interrupt */
- if (do_host_interrupt) {
+ if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
tw_clear_host_interrupt(tw_dev);
}
/* Handle attention interrupt */
- if (do_attention_interrupt) {
+ if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
tw_clear_attention_interrupt(tw_dev);
tw_state_request_start(tw_dev, &request_id);
error = tw_aen_read_queue(tw_dev, request_id);
@@ -1307,7 +1332,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Handle command interrupt */
- if (do_command_interrupt) {
+ if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
/* Drain as many pending commands as we can */
while (tw_dev->pending_request_count > 0) {
request_id = tw_dev->pending_queue[tw_dev->pending_head];
@@ -1323,6 +1348,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
tw_dev->pending_request_count--;
} else {
+ printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no);
break;
}
}
@@ -1332,40 +1358,40 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Handle response interrupt */
- if (do_response_interrupt) {
+ if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
/* Drain the response queue from the board */
while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+ /* Read response queue register */
response_que.value = inl(response_que_addr);
request_id = response_que.u.response_id;
command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
error = 0;
+
+ /* Check for bad response */
if (command_packet->status != 0) {
- /* Bad response */
- if (tw_dev->srb[request_id] != 0)
- tw_decode_sense(tw_dev, request_id, 1);
- error = 3;
+ /* If internal command, don't error, don't fill sense */
+ if (tw_dev->srb[request_id] == 0) {
+ tw_decode_sense(tw_dev, request_id, 0);
+ } else {
+ error = tw_decode_sense(tw_dev, request_id, 1);
+ }
}
+
+ /* Check for correct state */
if (tw_dev->state[request_id] != TW_S_POSTED) {
printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
error = 1;
}
- if (TW_STATUS_ERRORS(status_reg_value)) {
- tw_decode_bits(tw_dev, status_reg_value);
- error = 1;
- }
+
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
- /* Check for internal command */
+
+ /* Check for internal command completion */
if (tw_dev->srb[request_id] == 0) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
- error = tw_aen_complete(tw_dev, request_id);
- if (error) {
+ retval = tw_aen_complete(tw_dev, request_id);
+ if (retval) {
printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
}
- status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- }
} else {
switch (tw_dev->srb[request_id]->cmnd[0]) {
case READ_10:
@@ -1389,20 +1415,22 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
error = tw_ioctl_complete(tw_dev, request_id);
break;
default:
- printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]);
- tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
- }
- if (error == 1) {
- /* Tell scsi layer there was an error */
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
- tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+ error = 1;
}
+
+ /* If no error command was a success */
if (error == 0) {
- /* Tell scsi layer command was a success */
tw_dev->srb[request_id]->result = (DID_OK << 16);
}
- if (error != 2) {
+
+ /* If error, command failed */
+ if (error == 1) {
+ tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ }
+
+ /* Now complete the io */
+ if ((error != TW_ISR_DONT_COMPLETE)) {
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
tw_dev->posted_request_count--;
@@ -1410,16 +1438,24 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
}
- status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ }
+
+ /* Check for valid status after each drain */
+ status_reg_value = inl(status_reg_addr);
+ if (tw_check_bits(status_reg_value)) {
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+ if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+ tw_clear_all_interrupts(tw_dev);
+ goto tw_interrupt_bail;
}
}
}
}
+tw_interrupt_bail:
spin_unlock(&tw_dev->tw_lock);
- }
+ } else
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+
spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
clear_bit(TW_IN_INTR, &tw_dev->flags);
} /* End tw_interrupt() */
@@ -1782,7 +1818,7 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
break;
case TW_CMD_PACKET_WITH_DATA:
dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
- return 2; /* Special case for isr to not complete io */
+ return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
default:
memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1852,7 +1888,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
}
while ((status_reg_value & flag) != flag) {
@@ -1860,7 +1896,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
}
do_gettimeofday(&timeout);
@@ -1887,7 +1923,7 @@ int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
}
if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
@@ -1941,7 +1977,6 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
(tw_dev->state[i] != TW_S_COMPLETED)) {
srb = tw_dev->srb[i];
if (srb != NULL) {
- srb = tw_dev->srb[i];
srb->result = (DID_RESET << 16);
tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
@@ -1960,6 +1995,7 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
tw_dev->pending_request_count = 0;
tw_dev->pending_head = TW_Q_START;
tw_dev->pending_tail = TW_Q_START;
+ tw_dev->reset_print = 0;
return 0;
} /* End tw_reset_device_extension() */
@@ -1991,14 +2027,6 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev)
continue;
}
- /* Empty the response queue again */
- error = tw_empty_response_que(tw_dev);
- if (error) {
- printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no);
- tries++;
- continue;
- }
-
/* Now the controller is in a good state */
break;
}
@@ -2086,11 +2114,6 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
return (FAILED);
}
- /* We have to let AEN requests through before the reset */
- spin_unlock_irq(tw_dev->host->host_lock);
- mdelay(TW_AEN_WAIT_TIME);
- spin_lock_irq(tw_dev->host->host_lock);
-
spin_lock(&tw_dev->tw_lock);
tw_dev->num_aborts++;
@@ -2117,18 +2140,26 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
spin_unlock(&tw_dev->tw_lock);
return (SUCCESS);
}
+ if (tw_dev->state[i] == TW_S_POSTED) {
+ /* If the command has already been posted, we have to reset the card */
+ printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
+ /* We have to let AEN requests through before the reset */
+ spin_unlock(&tw_dev->tw_lock);
+ spin_unlock_irq(tw_dev->host->host_lock);
+ mdelay(TW_AEN_WAIT_TIME);
+ spin_lock_irq(tw_dev->host->host_lock);
+ spin_lock(&tw_dev->tw_lock);
+
+ if (tw_reset_device_extension(tw_dev)) {
+ dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
+ spin_unlock(&tw_dev->tw_lock);
+ return (FAILED);
+ }
+ }
}
}
- /* If the command has already been posted, we have to reset the card */
- printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
- if (tw_reset_device_extension(tw_dev)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
- spin_unlock(&tw_dev->tw_lock);
- return (FAILED);
- }
spin_unlock(&tw_dev->tw_lock);
-
return (SUCCESS);
} /* End tw_scsi_eh_abort() */
@@ -2593,7 +2624,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
}
command_packet->byte0.sgl_offset = 3;
- command_packet->size = 5;
+ command_packet->size = 3;
command_packet->request_id = request_id;
command_packet->byte3.unit = srb->target;
command_packet->byte3.host_id = 0;
@@ -2628,6 +2659,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
command_packet->byte8.io.sgl[0].address = buffaddr;
command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ command_packet->size+=2;
}
/* Do this if we have multiple sg list entries */
@@ -2638,8 +2670,6 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
command_packet->size+=2;
}
- if (tw_dev->srb[request_id]->use_sg >= 1)
- command_packet->size-=2;
}
/* Update SG statistics */
@@ -2754,7 +2784,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 5ab618c7168b..37ae5521d0d9 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -92,10 +92,11 @@ static char *tw_aen_string[] = {
"Verify failed: Port #", // 0x02A
"Verify complete: Unit #", // 0x02B
"Overwrote bad sector during rebuild: Port #", //0x2C
- "Encountered bad sector during rebuild: Port #" //0x2D
+ "Encountered bad sector during rebuild: Port #", //0x2D
+ "Replacement drive is too small: Port #" //0x2E
};
-#define TW_AEN_STRING_MAX 0x02E
+#define TW_AEN_STRING_MAX 0x02F
/*
Sense key lookup table
@@ -134,7 +135,9 @@ static unsigned char tw_sense_table[][4] =
#define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040
#define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000
#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008
/* Status register bit definitions */
#define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000
@@ -154,7 +157,9 @@ static unsigned char tw_sense_table[][4] =
#define TW_STATUS_ALL_INTERRUPTS 0x000F0000
#define TW_STATUS_CLEARABLE_BITS 0x00D00000
#define TW_STATUS_EXPECTED_BITS 0x00002000
-#define TW_STATUS_UNEXPECTED_BITS 0x00F80000
+#define TW_STATUS_UNEXPECTED_BITS 0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008
+#define TW_STATUS_VALID_INTERRUPT 0x00DF0008
/* RESPONSE QUEUE BIT DEFINITIONS */
#define TW_RESPONSE_ID_MASK 0x00000FF0
@@ -214,7 +219,7 @@ static unsigned char tw_sense_table[][4] =
#define TW_MAX_PCI_BUSES 255
#define TW_MAX_RESET_TRIES 3
#define TW_UNIT_INFORMATION_TABLE_BASE 0x300
-#define TW_MAX_CMDS_PER_LUN (TW_Q_LENGTH-2)/TW_MAX_UNITS
+#define TW_MAX_CMDS_PER_LUN 255
#define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */
#define TW_IOCTL 0x80
#define TW_MAX_AEN_TRIES 100
@@ -223,6 +228,8 @@ static unsigned char tw_sense_table[][4] =
#define TW_MAX_SECTORS 256
#define TW_AEN_WAIT_TIME 1000
#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */
+#define TW_ISR_DONT_COMPLETE 2
+#define TW_ISR_DONT_RESULT 3
/* Macros */
#define TW_STATUS_ERRORS(x) \
@@ -235,7 +242,7 @@ static unsigned char tw_sense_table[][4] =
#ifdef TW_DEBUG
#define dprintk(msg...) printk(msg)
#else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
#endif
/* Scatter Gather List Entry */
@@ -402,8 +409,9 @@ typedef struct TAG_TW_Device_Extension {
unsigned short aen_queue[TW_Q_LENGTH];
unsigned char aen_head;
unsigned char aen_tail;
- long flags; /* long req'd for set_bit --RR */
+ volatile long flags; /* long req'd for set_bit --RR */
char *ioctl_data[TW_Q_LENGTH];
+ int reset_print;
} TW_Device_Extension;
/* Function prototypes */
@@ -413,12 +421,13 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
int tw_check_bits(u32 status_reg_value);
int tw_check_errors(TW_Device_Extension *tw_dev);
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host);
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
void tw_disable_interrupts(TW_Device_Extension *tw_dev);
-int tw_empty_response_que(TW_Device_Extension *tw_dev);
+void tw_empty_response_que(TW_Device_Extension *tw_dev);
void tw_enable_interrupts(TW_Device_Extension *tw_dev);
void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
int tw_findcards(Scsi_Host_Template *tw_host);
@@ -478,7 +487,7 @@ void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
reset : NULL, \
slave_attach : NULL, \
bios_param : tw_scsi_biosparam, \
- can_queue : TW_Q_LENGTH, \
+ can_queue : TW_Q_LENGTH-1, \
this_id: -1, \
sg_tablesize : TW_MAX_SGL_LENGTH, \
cmd_per_lun: TW_MAX_CMDS_PER_LUN, \
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index a944ae49708e..3dd98eab9650 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -1869,7 +1869,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
*/
timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && jiffies < timeout) {
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
barrier();
cpu_relax();
}
@@ -1955,7 +1955,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
restore_flags(flags);
timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout) {
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
barrier();
cpu_relax();
}
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index ee9e02d95522..686231ba083c 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -1627,7 +1627,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
*/
timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && jiffies < timeout)
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
barrier();
failed = 1;
@@ -1713,7 +1713,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
restore_flags(flags);
timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout)
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
barrier();
NCR53c7x0_write32 (DSA_REG, 0);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 1aa7cfc855f5..6d40aa0cbff5 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -3615,3 +3615,5 @@ void esp_release(void)
esps_running = esps_in_use;
}
#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 08cafe0f88b5..6aba3e11c652 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -248,3 +248,5 @@ int a2091_release(struct Scsi_Host *instance)
#endif
return 1;
}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
index 5e0029feecc8..2edba37b5aa1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -906,7 +906,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
}
static void
-ahc_linux_setup_tag_info(char *p, char *end)
+ahc_linux_setup_tag_info(char *p, char *end, char *s)
{
char *base;
char *tok;
@@ -986,7 +986,7 @@ ahc_linux_setup_tag_info(char *p, char *end)
}
}
while ((p != base) && (p != NULL))
- p = strtok(NULL, ",.");
+ p = strsep(&s, ",.");
}
/*
@@ -1018,7 +1018,8 @@ aic7xxx_setup(char *s)
end = strchr(s, '\0');
- for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) {
+ while ((p = strsep(&s, ",.")) != NULL) {
+ if (!*p) continue;
for (i = 0; i < NUM_ELEMENTS(options); i++) {
n = strlen(options[i].name);
@@ -1026,7 +1027,7 @@ aic7xxx_setup(char *s)
continue;
if (strncmp(p, "tag_info", n) == 0) {
- ahc_linux_setup_tag_info(p + n, end);
+ ahc_linux_setup_tag_info(p + n, end, s);
} else if (p[n] == ':') {
*(options[i].flag) =
simple_strtoul(p + n + 1, NULL, 0);
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 0c64cd55f048..86c41aae013f 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -1443,7 +1443,7 @@ aic7xxx_setup(char *s)
end = strchr(s, '\0');
- for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
+ while ((p = strsep(&s, ",.")) != NULL)
{
for (i = 0; i < NUMBER(options); i++)
{
@@ -1525,7 +1525,7 @@ aic7xxx_setup(char *s)
}
}
while((p != base) && (p != NULL))
- p = strtok(NULL, ",.");
+ p = strsep(&s, ",.");
}
}
else if (p[n] == ':')
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 27cda3b515f6..5a84221d5d5c 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -311,7 +311,7 @@
* include in the list of i/o ports to be probed all the PCI SCSI controllers.
*
* Due to a DPT BIOS "feature", it might not be possible to force an EISA
- * address on more then a single DPT PCI board, so in this case you have to
+ * address on more than a single DPT PCI board, so in this case you have to
* let the PCI BIOS assign the addresses.
*
* The sequence of detection probes is:
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index f11acf771c1c..c853eabf386f 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -78,7 +78,7 @@
Please note that the drive ordering that Future Domain implemented in BIOS
versions 3.4 and 3.5 is the opposite of the order (currently) used by the
rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have
- more then one drive, then the drive ordering will be the reverse of that
+ more than one drive, then the drive ordering will be the reverse of that
which you see under DOS. For example, under DOS SCSI ID 0 will be D: and
SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be
/dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 80554c4b6946..c076125c87e9 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -331,7 +331,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
pc->actually_transferred=pc->request_transfer;
- (void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+ (void) drive->channel->dmaproc(ide_dma_end, drive);
}
status = GET_STAT(); /* Clear the interrupt */
@@ -434,9 +434,9 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
bcount = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */
if (drive->using_dma && rq->bio)
- dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
- SELECT_DRIVE(HWIF(drive), drive);
+ SELECT_DRIVE(drive->channel, drive);
if (IDE_CONTROL_REG)
OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
OUT_BYTE (dma_ok,IDE_FEATURE_REG);
@@ -444,8 +444,8 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
if (dma_ok) {
- set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
@@ -508,7 +508,7 @@ static void idescsi_add_settings(ide_drive_t *drive)
*/
static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
{
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
idescsi_drives[id] = drive;
drive->driver_data = scsi;
@@ -629,8 +629,9 @@ int idescsi_release (struct Scsi_Host *host)
for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
drive = idescsi_drives[id];
- if (drive)
- ata_ops(drive)->busy--;
+ if (drive) {
+ MOD_DEC_USE_COUNT;
+ }
}
return 0;
}
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index fdcbca13cf53..f0618cd93f6b 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -702,7 +702,7 @@ static int ppa_completion(Scsi_Cmnd * cmd)
* change things for "normal" hardware since generally
* the 6th bit is always high.
* This makes the CPU load higher on some hardware
- * but otherwise we can not get more then 50K/secs
+ * but otherwise we can not get more than 50K/secs
* on this problem hardware.
*/
if ((r & 0xc0) != 0xc0) {
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 7afe0407e245..0aea0993fa10 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -376,3 +376,5 @@ static void dma_advance_sg (Scsi_Cmnd *sp)
static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP;
#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 24ab22011388..ea61de3cacb6 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2468,68 +2468,68 @@ void dc390_sendstart (PACB pACB, PDCB pDCB)
* '-' means no change
*******************************************************************/
-static int dc390_scanf (char** p1, char** p2, int* var)
+static int dc390_scanf (char** buffer, char** pos, char** p0, int* var)
{
- *p2 = *p1;
- *var = simple_strtoul (*p2, p1, 10);
- if (*p2 == *p1) return -1;
- *p1 = strtok (0, " \t\n:=,;.");
+ *p0 = *pos;
+ *var = simple_strtoul (*p0, pos, 10);
+ if (*p0 == *pos) return -1;
+ *pos = strsep (buffer, " \t\n:=,;.");
return 0;
};
-#define SCANF(p1, p2, var, min, max) \
-if (dc390_scanf (&p1, &p2, &var)) goto einv; \
+#define SCANF(buffer, pos, p0, var, min, max) \
+if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv; \
else if (var<min || var>max) goto einv2
-static int dc390_yesno (char** p, char* var, char bmask)
+static int dc390_yesno (char** buffer, char** pos, char* var, char bmask)
{
- switch (**p)
+ switch (**pos)
{
case 'Y': *var |= bmask; break;
case 'N': *var &= ~bmask; break;
case '-': break;
default: return -1;
}
- *p = strtok (0, " \t\n:=,;");
+ *pos = strsep (buffer, " \t\n:=,;");
return 0;
};
-#define YESNO(p, var, bmask) \
-if (dc390_yesno (&p, &var, bmask)) goto einv; \
+#define YESNO(buffer, pos, var, bmask) \
+if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv; \
else dc390_updateDCB (pACB, pDCB); \
if (!p) goto ok
-static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
+static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign)
{
int dum;
- if (! memcmp (*p1, txt, strlen(txt)))
+ if (! memcmp (*pos, txt, strlen(txt)))
{
- *p2 = strtok (0, " \t\n:=,;");
- if (!*p2) return -1;
- dum = simple_strtoul (*p2, p1, 10);
- if (*p2 == *p1) return -1;
+ *p0 = strsep (buffer, " \t\n:=,;");
+ if (!*p0) return -1;
+ dum = simple_strtoul (*p0, pos, 10);
+ if (*p0 == *pos) return -1;
if (dum >= 0 && dum <= max)
{ *var = (dum * 100) / scale; }
else return -2;
- *p1 = strtok (0, " \t\n:=,;");
- if (*ign && *p1 && strlen(*p1) >= strlen(ign) &&
- !(memcmp (*p1, ign, strlen(ign))))
- *p1 = strtok (0, " \t\n:=,;");
+ *pos = strsep (buffer, " \t\n:=,;");
+ if (*ign && *pos && strlen(*pos) >= strlen(ign) &&
+ !(memcmp (*pos, ign, strlen(ign))))
+ *pos = strsep (buffer, " \t\n:=,;");
}
return 0;
};
-#define SEARCH(p1, p2, var, txt, max) \
-if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
+#define SEARCH(buffer, pos, p0, var, txt, max) \
+if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
else if (!p1) goto ok2
-#define SEARCH2(p1, p2, var, txt, max, scale) \
-if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \
+#define SEARCH2(buffer, pos, p0, var, txt, max, scale) \
+if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \
else if (!p1) goto ok2
-#define SEARCH3(p1, p2, var, txt, max, scale, ign) \
-if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \
+#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \
+if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \
else if (!p1) goto ok2
@@ -2565,12 +2565,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
while (*pos)
{ if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
- /* We should protect __strtok ! */
- /* spin_lock (strtok_lock); */
-
/* Remove WS */
- pos = strtok (buffer, " \t:\n=,;");
- if (!pos) goto ok;
+ pos = strsep (&buffer, " \t:\n=,;");
+ if (!*pos) goto ok;
next:
if (!memcmp (pos, "RESET", 5)) goto reset;
@@ -2586,10 +2583,10 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
int dev, id, lun; char* pdec;
char olddevmode;
- SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
- if (!pos) goto einv;
+ SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1);
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
+ if (!*pos) goto einv;
PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
pDCB = pACB->pLinkDCB;
@@ -2610,20 +2607,20 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
};
olddevmode = pDCB->DevMode;
- YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+ YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_);
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+ YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_);
if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+ YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_);
if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
- YESNO (pos, pDCB->DevMode, SEND_START_);
+ YESNO (buffer, pos, pDCB->DevMode, SEND_START_);
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+ YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_);
if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
dc390_updateDCB (pACB, pDCB);
- if (!pos) goto ok;
+ if (!*pos) goto ok;
olddevmode = pDCB->NegoPeriod;
/* Look for decimal point (Speed) */
@@ -2632,22 +2629,22 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
/* NegoPeriod */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 72, 800);
+ SCANF (buffer, pos, p0, dum, 72, 800);
pDCB->NegoPeriod = dum >> 2;
if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
if (!pos) goto ok;
- if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+ if (memcmp (pos, "NS", 2) == 0) pos = strsep (*pos, " \t\n:=,;.");
}
- else pos = strtok (0, " \t\n:=,;.");
- if (!pos) goto ok;
+ else pos = strsep (*pos, " \t\n:=,;.");
+ if (!*pos) goto ok;
/* Sync Speed in MHz */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 1, 13);
+ SCANF (buffer, pos, p0, dum, 1, 13);
pDCB->NegoPeriod = (1000/dum) >> 2;
if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
- if (!pos) goto ok;
+ if (!*pos) goto ok;
/* decimal */
if (pos-1 == pdec)
{
@@ -2656,38 +2653,38 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
for (; p0-pos > 1; p0--) dum /= 10;
pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
- pos = strtok (0, " \t\n:=,;");
- if (!pos) goto ok;
+ pos = strsep (*pos, " \t\n:=,;");
+ if (!*pos) goto ok;
};
- if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+ if (*pos == 'M') pos = strsep (*pos, " \t\n:=,;");
if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
}
- else pos = strtok (0, " \t\n:=,;");
+ else pos = strsep (*pos, " \t\n:=,;");
/* dc390_updateDCB (pACB, pDCB); */
- if (!pos) goto ok;
+ if (!*pos) goto ok;
olddevmode = pDCB->SyncOffset;
/* SyncOffs */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 0, 0x0f);
+ SCANF (buffer, pos, p0, dum, 0, 0x0f);
pDCB->SyncOffset = dum;
if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
}
- else pos = strtok (0, " \t\n:=,;");
- if (!pos) goto ok;
+ else pos = strsep (*pos, " \t\n:=,;");
+ if (!*pos) goto ok;
dc390_updateDCB (pACB, pDCB);
//olddevmode = pDCB->MaxCommand;
/* MaxCommand (Tags) */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
+ SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
if (pDCB->SyncMode & EN_TAG_QUEUEING)
pDCB->MaxCommand = dum;
else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
}
- else pos = strtok (0, " \t\n:=,;");
+ else pos = strsep (*pos, " \t\n:=,;");
}
else
@@ -2696,14 +2693,14 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
dum = GLITCH_TO_NS (pACB->glitch_cfg);
/* Adapter setting */
- SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
- SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
- SEARCH (pos, p0, newadaptid, "ADAPTERID", 7);
- SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
- SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
- SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
- SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
- SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
+ SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
+ SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
+ SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7);
+ SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+ SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+ SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+ SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+ SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
ok2:
pACB->glitch_cfg = NS_TO_GLITCH (dum);
if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
@@ -2719,10 +2716,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
// All devs should be INQUIRED now
if (pos == p1) goto einv;
}
- if (pos) goto next;
+ if (*pos) goto next;
ok:
- /* spin_unlock (strtok_lock); */
DC390_UNLOCK_ACB;
if (needs_inquiry)
{ dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
@@ -2732,7 +2728,6 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
einv2:
pos = p0;
einv:
- /* spin_unlock (strtok_lock); */
DC390_UNLOCK_ACB;
DC390_UNLOCK_IO(pACB.pScsiHost);
printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
@@ -2758,7 +2753,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
inquiry:
{
- pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
dev = simple_strtoul (pos, &p0, 10);
if (dev >= pACB->DCBCnt) goto einv_dev;
for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2772,7 +2767,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
remove:
{
- pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
dev = simple_strtoul (pos, &p0, 10);
if (dev >= pACB->DCBCnt) goto einv_dev;
for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2788,9 +2783,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
add:
{
int id, lun;
- pos = strtok (0, " \t\n.:;=");
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ pos = strsep (*pos, " \t\n.:;=");
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
pDCB = dc390_findDCB (pACB, id, lun);
if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; };
dc390_initDCB (pACB, &pDCB, id, lun);
@@ -2803,9 +2798,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
start:
{
int id, lun;
- pos = strtok (0, " \t\n.:;=");
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ pos = strsep (*pos, " \t\n.:;=");
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
pDCB = dc390_findDCB (pACB, id, lun);
if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
else dc390_initDCB (pACB, &pDCB, id, lun);
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 0948ed466431..5ae088c86547 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -171,7 +171,7 @@
* Auto detects if U14F boards have an old firmware revision.
* Max number of scatter/gather lists set to 16 for all boards
* (most installation run fine using 33 sglists, while other
- * has problems when using more then 16).
+ * has problems when using more than 16).
*
* 16 Jan 1995 rev. 1.13 for linux 1.1.81
* Display a message if check_region detects a port address
@@ -279,7 +279,7 @@
*
* For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01),
* the latest firmware prom is 28008-006. Older firmware 28008-005 has
- * problems when using more then 16 scatter/gather lists.
+ * problems when using more than 16 scatter/gather lists.
*
* The list of i/o ports to be probed can be totally replaced by the
* boot command line option: "u14-34f=port0,port1,port2,...", where the
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 6239675f8b9a..b54b10365519 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1472,7 +1472,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
schedule_timeout(char_time);
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
current->state = TASK_RUNNING;
diff --git a/drivers/usb/Config.help b/drivers/usb/Config.help
index 28a88d96a72c..97ff059a617a 100644
--- a/drivers/usb/Config.help
+++ b/drivers/usb/Config.help
@@ -94,9 +94,13 @@ CONFIG_USB_OHCI
CONFIG_USB_HID
Say Y here if you want full HID support to connect keyboards,
mice, joysticks, graphic tablets, or any other HID based devices
- to your computer via USB. You can't use this driver and the
- HIDBP (Boot Protocol) keyboard and mouse drivers at the same time.
- More information is available: <file:Documentation/input/input.txt>.
+ to your computer via USB. You also need to select HID Input layer
+ support (below) if you want to use keyboards, mice, joysticks and
+ the like.
+
+ You can't use this driver and the HIDBP (Boot Protocol) keyboard
+ and mouse drivers at the same time. More information is available:
+ <file:Documentation/input/input.txt>.
If unsure, say Y.
@@ -105,6 +109,13 @@ CONFIG_USB_HID
The module will be called hid.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_USB_HIDINPUT
+ Say Y here if you want to use a USB keyboard, mouse or joystick,
+ or any other HID input device. You also need Input layer support,
+ (CONFIG_INPUT) which you select under "Input core support".
+
+ If unsure, say Y.
+
CONFIG_USB_HIDDEV
Say Y here if you want to support HID devices (from the USB
specification standpoint) that aren't strictly user interface
@@ -114,31 +125,35 @@ CONFIG_USB_HIDDEV
event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
This driver requires CONFIG_USB_HID.
- If unsure, say N.
+ If unsure, say Y.
CONFIG_USB_KBD
- Say Y here if you don't want to use the generic HID driver for your
- USB keyboard and prefer to use the keyboard in its limited Boot
- Protocol mode instead. This driver is much smaller than the HID one.
+ Say Y here only if you are absolutely sure that you don't want
+ to use the generic HID driver for your USB keyboard and prefer
+ to use the keyboard in its limited Boot Protocol mode instead.
+
+ This is almost certainly not what you want.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usbkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
- If unsure, say N.
+ If even remotely unsure, say N.
CONFIG_USB_MOUSE
- Say Y here if you don't want to use the generic HID driver for your
- USB mouse and prefer to use the mouse in its limited Boot Protocol
- mode instead. This driver is much smaller than the HID one.
+ Say Y here only if you are absolutely sure that you don't want
+ to use the generic HID driver for your USB keyboard and prefer
+ to use the keyboard in its limited Boot Protocol mode instead.
+
+ This is almost certainly not what you want.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usbmouse.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
- If unsure, say N.
+ If even remotely unsure, say N.
CONFIG_USB_WACOM
Say Y here if you want to use the USB version of the Wacom Intuos
@@ -332,7 +347,7 @@ CONFIG_USB_PEGASUS
If in doubt then look at linux/drivers/usb/pegasus.h for the complete
list of supported devices.
If your particular adapter is not in the list and you are _sure_ it
- is Pegasus or Pegasus II based then send me (pmanolov@users.sourceforge.net)
+ is Pegasus or Pegasus II based then send me (petkan@users.sourceforge.net)
vendor and device IDs.
This code is also available as a module ( = code which can be
@@ -340,6 +355,16 @@ CONFIG_USB_PEGASUS
The module will be called pegasus.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_USB_RTL8150
+ Say Y here if you have RTL8150 based usb-ethernet adapter.
+ Send me (petkan@users.sourceforge.net) any comments you may have.
+ You can also check for updates at http://pegasus2.sourceforge.net/
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called rtl8150.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
CONFIG_USB_KAWETH
Say Y here if you want to use one of the following 10Mbps only
USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
@@ -626,3 +651,21 @@ CONFIG_USB_BLUETOOTH
The module will be called bluetooth.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_USB_TIGL
+ If you own a Texas Instruments graphing calculator and use a
+ TI-GRAPH LINK USB cable (aka SilverLink), then you might be
+ interested in this driver.
+
+ If you enable this driver, you will be able to communicate with
+ your calculator through a set of device nodes under /dev.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called tiglusb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+ If you don't know what the SilverLink cable is or what a Texas
+ Instruments graphing calculator is, then you probably don't need this
+ driver.
+
+ If unsure, say N.
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index ecb578af3bda..bc84a0f572e7 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -49,18 +49,19 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
comment 'USB Human Interface Devices (HID)'
+ dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB
if [ "$CONFIG_INPUT" = "n" ]; then
- comment ' Input core support is needed for USB HID'
- else
- dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
- dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
- if [ "$CONFIG_USB_HID" != "y" ]; then
- dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
- dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
- fi
- dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
+ comment ' Input core support is needed for USB HID input layer or HIDBP support'
fi
+ dep_mbool ' HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID
+ dep_mbool ' /dev/hiddev raw HID device support' CONFIG_USB_HIDDEV $CONFIG_USB_HID
+ if [ "$CONFIG_USB_HID" != "y" ]; then
+ dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
+ dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
+ fi
+ dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
+
comment 'USB Imaging devices'
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
@@ -88,6 +89,7 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
comment ' Networking support is needed for USB Networking device support'
else
dep_tristate ' USB Pegasus/Pegasus-II based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB RTL8150 based ethernet device support (EXPERIMENTAL)' CONFIG_USB_RTL8150 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
@@ -101,6 +103,7 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
comment 'USB Miscellaneous drivers'
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+ dep_tristate ' Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
fi
endmenu
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 7c9c04d9a882..d50fb801d0ce 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -2,8 +2,6 @@
# Makefile for the kernel USB device drivers.
#
-# Subdirs.
-
# The target object and module list name.
O_TARGET := usbdrv.o
@@ -14,9 +12,8 @@ export-objs := usb.o hcd.o ov511.o pwc-uncompress.o
# Multipart objects.
-list-multi := usbcore.o hid.o pwc.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o
-hid-objs := hid-core.o hid-input.o
+hid-objs := hid-core.o
pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
@@ -30,6 +27,10 @@ ifeq ($(CONFIG_USB_HIDDEV),y)
hid-objs += hiddev.o
endif
+ifeq ($(CONFIG_USB_HIDINPUT),y)
+ hid-objs += hid-input.o
+endif
+
# Object file lists.
obj-y :=
@@ -76,6 +77,7 @@ obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_STV680) += stv680.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
+obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_CATC) += catc.o
obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_CDCETHER) += CDCEther.o
@@ -86,6 +88,7 @@ obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o
obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
+obj-$(CONFIG_USB_TIGL) += tiglusb.o
# Object files in subdirectories
mod-subdirs := serial hcd
@@ -104,14 +107,3 @@ ifeq ($(CONFIG_USB_STORAGE),y)
endif
include $(TOPDIR)/Rules.make
-
-# Link rules for multi-part drivers.
-
-usbcore.o: $(usbcore-objs)
- $(LD) -r -o $@ $(usbcore-objs)
-
-hid.o: $(hid-objs)
- $(LD) -r -o $@ $(hid-objs)
-
-pwc.o: $(pwc-objs)
- $(LD) -r -o $@ $(pwc-objs)
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index de0573dab322..a30d939ef3a8 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -839,6 +839,7 @@ static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
urb->iso_frame_desc[i].length = maxsize;
urb->iso_frame_desc[i].offset = offs;
}
+ urb->interval = 1;
return 0;
}
@@ -938,6 +939,7 @@ static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
cp[1] = u->freqn >> 8;
cp[2] = u->freqn >> 16;
}
+ urb->interval = 1;
return 0;
}
diff --git a/drivers/usb/catc.c b/drivers/usb/catc.c
index 37a300d9e2d0..b6c2b2e7e515 100644
--- a/drivers/usb/catc.c
+++ b/drivers/usb/catc.c
@@ -476,7 +476,7 @@ static void catc_ctrl_done(struct urb *urb)
{
struct catc *catc = urb->context;
struct ctrl_queue *q;
- long flags;
+ unsigned long flags;
if (urb->status)
dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length);
@@ -510,7 +510,7 @@ static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,
{
struct ctrl_queue *q;
int retval = 0;
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&catc->ctrl_lock, flags);
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index 575a451d80ec..1ad0f76756c5 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -105,8 +105,8 @@ static char *format_iface =
"I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static char *format_endpt =
-/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
- "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
+ "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
/*
@@ -166,24 +166,71 @@ static const char *class_decode(const int class)
return (clas_info[ix].class_name);
}
-static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
+static char *usb_dump_endpoint_descriptor (
+ int speed,
+ char *start,
+ char *end,
+ const struct usb_endpoint_descriptor *desc
+)
{
- char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+ char dir, unit, *type;
+ unsigned interval, in, bandwidth = 1;
if (start > end)
return start;
- start += sprintf(start, format_endpt, desc->bEndpointAddress,
- (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL
- ? 'B' : /* bidirectional */
- (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
- desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK],
- desc->wMaxPacketSize, desc->bInterval);
- return start;
-}
+ in = (desc->bEndpointAddress & USB_DIR_IN);
+ dir = in ? 'I' : 'O';
+ if (speed == USB_SPEED_HIGH) {
+ switch (desc->wMaxPacketSize & (0x03 << 11)) {
+ case 1 << 11: bandwidth = 2; break;
+ case 2 << 11: bandwidth = 3; break;
+ }
+ }
-static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
-{
- return usb_dump_endpoint_descriptor(start, end, endpoint);
+ /* this isn't checking for illegal values */
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "Ctrl";
+ if (speed == USB_SPEED_HIGH) /* uframes per NAK */
+ interval = desc->bInterval;
+ else
+ interval = 0;
+ dir = 'B'; /* ctrl is bidirectional */
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ type = "Isoc";
+ interval = 1 << (desc->bInterval - 1);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = "Bulk";
+ if (speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
+ interval = desc->bInterval;
+ else
+ interval = 0;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = "Int.";
+ if (speed == USB_SPEED_HIGH) {
+ interval = 1 << (desc->bInterval - 1);
+ } else
+ interval = desc->bInterval;
+ break;
+ default: /* "can't happen" */
+ return start;
+ }
+ interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
+ if (interval % 1000)
+ unit = 'u';
+ else {
+ unit = 'm';
+ interval /= 1000;
+ }
+
+ start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
+ desc->bmAttributes, type,
+ (desc->wMaxPacketSize & 0x07ff) * bandwidth,
+ interval, unit);
+ return start;
}
static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
@@ -204,8 +251,13 @@ static char *usb_dump_interface_descriptor(char *start, char *end, const struct
return start;
}
-static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
-{
+static char *usb_dump_interface(
+ int speed,
+ char *start,
+ char *end,
+ const struct usb_interface *iface,
+ int setno
+) {
struct usb_interface_descriptor *desc = &iface->altsetting[setno];
int i;
@@ -213,7 +265,8 @@ static char *usb_dump_interface(char *start, char *end, const struct usb_interfa
for (i = 0; i < desc->bNumEndpoints; i++) {
if (start > end)
return start;
- start = usb_dump_endpoint(start, end, desc->endpoint + i);
+ start = usb_dump_endpoint_descriptor(speed,
+ start, end, desc->endpoint + i);
}
return start;
}
@@ -238,7 +291,13 @@ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb
return start;
}
-static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active)
+static char *usb_dump_config (
+ int speed,
+ char *start,
+ char *end,
+ const struct usb_config_descriptor *config,
+ int active
+)
{
int i, j;
struct usb_interface *interface;
@@ -255,7 +314,8 @@ static char *usb_dump_config(char *start, char *end, const struct usb_config_des
for (j = 0; j < interface->num_altsetting; j++) {
if (start > end)
return start;
- start = usb_dump_interface(start, end, interface, j);
+ start = usb_dump_interface(speed,
+ start, end, interface, j);
}
}
return start;
@@ -336,8 +396,10 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
return start;
- start = usb_dump_config(start, end, dev->config + i,
- (dev->config + i) == dev->actconfig); /* active ? */
+ start = usb_dump_config(dev->speed,
+ start, end, dev->config + i,
+ /* active ? */
+ (dev->config + i) == dev->actconfig);
}
return start;
}
@@ -429,16 +491,27 @@ static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes
* count = device count at this level
*/
/* If this is the root hub, display the bandwidth information */
- /* FIXME high speed reserves 20% frametime for non-periodic,
- * while full/low speed reserves only 10% ... so this is wrong
- * for high speed busses. also, change how bandwidth is recorded.
- */
- if (level == 0)
- data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated,
- FRAME_TIME_MAX_USECS_ALLOC,
- (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
- bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+ if (level == 0) {
+ int max;
+
+ /* high speed reserves 80%, full/low reserves 90% */
+ if (usbdev->speed == USB_SPEED_HIGH)
+ max = 800;
+ else
+ max = FRAME_TIME_MAX_USECS_ALLOC;
+
+ /* report "average" periodic allocation over a microsecond.
+ * the schedules are actually bursty, HCDs need to deal with
+ * that and just compute/report this average.
+ */
+ data_end += sprintf(data_end, format_bandwidth,
+ bus->bandwidth_allocated, max,
+ (100 * bus->bandwidth_allocated + max / 2)
+ / max,
+ bus->bandwidth_int_reqs,
+ bus->bandwidth_isoc_reqs);
+ }
data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c
index f947e7e13ec4..110c76926d6e 100644
--- a/drivers/usb/hcd.c
+++ b/drivers/usb/hcd.c
@@ -37,6 +37,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <linux/uts.h> /* for UTS_SYSNAME */
@@ -169,9 +170,9 @@ static const u8 usb11_rh_dev_descriptor [18] = {
/*-------------------------------------------------------------------------*/
-/* Configuration descriptor for all our root hubs */
+/* Configuration descriptors for our root hubs */
-static const u8 rh_config_descriptor [] = {
+static const u8 fs_rh_config_descriptor [] = {
/* one configuration */
0x09, /* __u8 bLength; */
@@ -215,7 +216,54 @@ static const u8 rh_config_descriptor [] = {
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
- 0x0c /* __u8 ep_bInterval; (12ms -- usb 2.0 spec) */
+ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const u8 hs_rh_config_descriptor [] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __u16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered,
+ 6: Self-powered,
+ 5 Remote-wakwup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+ 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
};
/*-------------------------------------------------------------------------*/
@@ -333,8 +381,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
len = 18;
break;
case USB_DT_CONFIG << 8:
- bufp = rh_config_descriptor;
- len = sizeof rh_config_descriptor;
+ if (hcd->driver->flags & HCD_USB2) {
+ bufp = hs_rh_config_descriptor;
+ len = sizeof hs_rh_config_descriptor;
+ } else {
+ bufp = fs_rh_config_descriptor;
+ len = sizeof fs_rh_config_descriptor;
+ }
break;
case USB_DT_STRING << 8:
urb->actual_length = rh_string (
@@ -428,10 +481,8 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
init_timer (&hcd->rh_timer);
hcd->rh_timer.function = rh_report_status;
hcd->rh_timer.data = (unsigned long) urb;
- hcd->rh_timer.expires = jiffies
- + (HZ * (urb->interval < 30
- ? 30
- : urb->interval)) / 1000;
+ /* USB 2.0 spec says 256msec; this is close enough */
+ hcd->rh_timer.expires = jiffies + HZ/4;
add_timer (&hcd->rh_timer);
return 0;
}
@@ -1256,8 +1307,29 @@ static void hc_died (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+static void urb_unlink (struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_device *dev;
+
+ /* Release any periodic transfer bandwidth */
+ if (urb->bandwidth)
+ usb_release_bandwidth (urb->dev, urb,
+ usb_pipeisoc (urb->pipe));
+
+ /* clear all state linking urb to this dev (and hcd) */
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_del_init (&urb->urb_list);
+ dev = urb->dev;
+ urb->dev = NULL;
+ usb_dec_dev_use (dev);
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+}
+
+
/* may be called in any context with a valid urb->dev usecount */
-/* caller surrenders "ownership" of urb (and chain at urb->next). */
+/* caller surrenders "ownership" of urb */
static int hcd_submit_urb (struct urb *urb, int mem_flags)
{
@@ -1265,13 +1337,14 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
struct usb_hcd *hcd;
struct hcd_dev *dev;
unsigned long flags;
- int pipe, temp;
+ int pipe, temp, max;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
+ urb->bandwidth = 0;
INIT_LIST_HEAD (&urb->urb_list);
if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
@@ -1290,7 +1363,62 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
usb_pipeout (pipe)))
return -EPIPE;
+ /* FIXME there should be a sharable lock protecting us against
+ * config/altsetting changes and disconnects, kicking in here.
+ */
+
+ /* Sanity check, so HCDs can rely on clean data */
+ max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+ if (max <= 0) {
+ err ("bogus endpoint (bad maxpacket)");
+ return -EINVAL;
+ }
+
+ /* "high bandwidth" mode, 1-3 packets/uframe? */
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ int mult;
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x03ff;
+ max *= mult;
+ }
+ }
+
+ /* periodic transfers limit size per frame/uframe */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS: {
+ int n, len;
+
+ if (urb->number_of_packets <= 0)
+ return -EINVAL;
+ for (n = 0; n < urb->number_of_packets; n++) {
+ len = urb->iso_frame_desc [n].length;
+ if (len < 0 || len > max)
+ return -EINVAL;
+ }
+
+ }
+ break;
+ case PIPE_INTERRUPT:
+ if (urb->transfer_buffer_length > max)
+ return -EINVAL;
+ }
+
+ /* the I/O buffer must usually be mapped/unmapped */
+ if (urb->transfer_buffer_length < 0)
+ return -EINVAL;
+
+ if (urb->next) {
+ warn ("use explicit queuing not urb->next");
+ return -EINVAL;
+ }
+
#ifdef DEBUG
+ /* stuff that drivers shouldn't do, but which shouldn't
+ * cause problems in HCDs if they get it wrong.
+ */
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
@@ -1315,10 +1443,12 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
}
urb->transfer_flags &= allowed;
- /* warn if submitter gave bogus flags */
- if (urb->transfer_flags != orig_flags)
+ /* fail if submitter gave bogus flags */
+ if (urb->transfer_flags != orig_flags) {
err ("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
+ return -EINVAL;
+ }
}
#endif
/*
@@ -1356,6 +1486,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
// NOTE usb and ohci handle up to 2^15
temp = 1024;
}
+ break;
default:
return -EINVAL;
}
@@ -1365,6 +1496,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
urb->interval = temp;
}
+
/*
* FIXME: make urb timeouts be generic, keeping the HCD cores
* as simple as possible.
@@ -1374,7 +1506,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
// It would catch submission paths for all urbs.
- /* increment the reference count of the urb, as we now also control it. */
+ /* increment urb's reference count, we now control it. */
urb = usb_get_urb(urb);
/*
@@ -1395,20 +1527,22 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
status = -ESHUTDOWN;
}
spin_unlock_irqrestore (&hcd_data_lock, flags);
+ if (status)
+ return status;
- if (!status) {
- if (urb->dev == hcd->bus->root_hub)
- status = rh_urb_enqueue (hcd, urb);
- else
- status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
- }
- if (status) {
- if (urb->dev) {
- urb->status = status;
- usb_hcd_giveback_urb (hcd, urb);
- }
- }
- return 0;
+ /* temporarily up refcount while queueing it in the HCD,
+ * since we report some queuing/setup errors ourselves
+ */
+ urb = usb_get_urb (urb);
+ if (urb->dev == hcd->bus->root_hub)
+ status = rh_urb_enqueue (hcd, urb);
+ else
+ status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+ /* urb->dev got nulled if hcd called giveback for us */
+ if (status && urb->dev)
+ urb_unlink (urb);
+ usb_put_urb (urb);
+ return status;
}
/*-------------------------------------------------------------------------*/
@@ -1424,7 +1558,7 @@ static int hcd_get_frame_number (struct usb_device *udev)
struct completion_splice { // modified urb context:
/* did we complete? */
- int done;
+ struct completion done;
/* original urb data */
void (*complete)(struct urb *);
@@ -1442,7 +1576,8 @@ static void unlink_complete (struct urb *urb)
urb->context = splice->context;
urb->complete (urb);
- splice->done = 1;
+ /* then let the synchronous unlink call complete */
+ complete (&splice->done);
}
/*
@@ -1509,7 +1644,7 @@ static int hcd_unlink_urb (struct urb *urb)
case PIPE_CONTROL:
case PIPE_BULK:
if (urb->status != -EINPROGRESS) {
- retval = 0;
+ retval = -EINVAL;
goto done;
}
}
@@ -1524,7 +1659,7 @@ static int hcd_unlink_urb (struct urb *urb)
goto done;
}
/* synchronous unlink: block till we see the completion */
- splice.done = 0;
+ init_completion (&splice.done);
splice.complete = urb->complete;
splice.context = urb->context;
urb->complete = unlink_complete;
@@ -1550,12 +1685,9 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
- while (!splice.done) {
- set_current_state (TASK_UNINTERRUPTIBLE);
- schedule_timeout ((2/*msec*/ * HZ) / 1000);
- dbg ("%s: wait for giveback urb %p",
- hcd->bus_name, urb);
- }
+ dbg ("%s: wait for giveback urb %p",
+ hcd->bus_name, urb);
+ wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
return -EINPROGRESS;
}
@@ -1656,27 +1788,13 @@ static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
* and will be reissued. They should just call their completion handlers
* until the urb is returned to the device driver by unlinking.
*
- * In common cases, urb->next will be submitted before the completion
- * function gets called. That's not done if the URB includes error
- * status (including unlinking).
+ * NOTE that no urb->next processing is done, even for isochronous URBs.
+ * ISO streaming functionality can be achieved by having completion handlers
+ * re-queue URBs. Such explicit queuing doesn't discard error reports.
*/
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
- struct usb_device *dev;
-
- /* Release periodic transfer bandwidth */
- if (urb->bandwidth)
- usb_release_bandwidth (urb->dev, urb,
- usb_pipeisoc (urb->pipe));
-
- /* clear all state linking urb to this dev (and hcd) */
-
- spin_lock_irqsave (&hcd_data_lock, flags);
- list_del_init (&urb->urb_list);
- dev = urb->dev;
- urb->dev = NULL;
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ urb_unlink (urb);
// NOTE: a generic device/urb monitoring hook would go here.
// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
@@ -1688,24 +1806,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
dbg ("giveback urb %p status %d len %d",
urb, urb->status, urb->actual_length);
- /* if no error, make sure urb->next progresses */
- else if (urb->next) {
- int status;
-
- status = usb_submit_urb (urb->next, GFP_ATOMIC);
- if (status) {
- dbg ("urb %p chain fail, %d", urb->next, status);
- urb->next->status = -ENOTCONN;
- }
-
- /* HCDs never modify the urb->next chain, and only use it here,
- * so that if urb->complete sees an URB there with -ENOTCONN,
- * it knows the driver chained it but it couldn't be submitted.
- */
- }
-
/* pass ownership to the completion handler */
- usb_dec_dev_use (dev);
urb->complete (urb);
usb_put_urb (urb);
}
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
index 42e0b4c25ee6..423378764081 100644
--- a/drivers/usb/hcd/ehci-hcd.c
+++ b/drivers/usb/hcd/ehci-hcd.c
@@ -89,12 +89,6 @@
// #define EHCI_VERBOSE_DEBUG
// #define have_split_iso
-#ifdef CONFIG_DEBUG_SLAB
-# define EHCI_SLAB_FLAGS (SLAB_POISON)
-#else
-# define EHCI_SLAB_FLAGS 0
-#endif
-
/* magic numbers that can affect system performance */
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
#define EHCI_TUNE_RL_HS 0 /* nak throttle; see 4.9 */
@@ -197,7 +191,7 @@ static int ehci_start (struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows.
*/
ehci->periodic_size = DEFAULT_I_TDPS;
- if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0)
+ if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
return retval;
hcc_params = readl (&ehci->caps->hcc_params);
@@ -214,6 +208,7 @@ static int ehci_start (struct usb_hcd *hcd)
/* controller state: unknown --> reset */
/* EHCI spec section 4.1 */
+ // FIXME require STS_HALT before reset...
ehci_reset (ehci);
writel (INTR_MASK, &ehci->regs->intr_enable);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
@@ -221,16 +216,17 @@ static int ehci_start (struct usb_hcd *hcd)
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
* be used; it constrains QH/ITD/SITD and QTD locations.
- * By default, pci_alloc_consistent() won't hand out addresses
- * above 4GB (via pdev->dma_mask) so we know this value.
- *
- * NOTE: that pdev->dma_mask setting means that all DMA mappings
- * for I/O buffers will have the same restriction, though it's
- * neither necessary nor desirable in that case.
+ * pci_pool consistent memory always uses segment zero.
*/
if (HCC_64BIT_ADDR (hcc_params)) {
writel (0, &ehci->regs->segment);
- info ("using segment 0 for 64bit DMA addresses ...");
+ /*
+ * FIXME Enlarge pci_set_dma_mask() when possible. The DMA
+ * mapping API spec now says that'll affect only single shot
+ * mappings, and the pci_pool data will stay safe in seg 0.
+ * That's what we want: no extra copies for USB transfers.
+ */
+ info ("restricting 64bit DMA mappings to segment 0 ...");
}
/* clear interrupt enables, set irq latency */
@@ -240,6 +236,9 @@ static int ehci_start (struct usb_hcd *hcd)
temp |= 1 << (16 + log2_irq_thresh);
// keeping default periodic framelist size
temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+ // Philips, Intel, and maybe others need CMD_RUN before the
+ // root hub will detect new devices (why?); NEC doesn't
+ temp |= CMD_RUN;
writel (temp, &ehci->regs->command);
dbg_cmd (ehci, "init", temp);
@@ -266,7 +265,7 @@ done2:
readl (&ehci->regs->command); /* unblock posted write */
/* PCI Serial Bus Release Number is at 0x60 offset */
- pci_read_config_byte(hcd->pdev, 0x60, &tempbyte);
+ pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
temp = readw (&ehci->caps->hci_version);
info ("USB %x.%x support enabled, EHCI rev %x.%2x",
((tempbyte & 0xf0)>>4),
@@ -393,6 +392,8 @@ static int ehci_resume (struct usb_hcd *hcd)
// restore pci FLADJ value
// khubd and drivers will set HC running, if needed;
hcd->state = USB_STATE_READY;
+ // FIXME Philips/Intel/... etc don't really have a "READY"
+ // state ... turn on CMD_RUN too
for (i = 0; i < ports; i++) {
int temp = readl (&ehci->regs->port_status [i]);
diff --git a/drivers/usb/hcd/ehci-hub.c b/drivers/usb/hcd/ehci-hub.c
index 6720f8f888e5..81343ece97c5 100644
--- a/drivers/usb/hcd/ehci-hub.c
+++ b/drivers/usb/hcd/ehci-hub.c
@@ -309,13 +309,6 @@ static int ehci_hub_control (
hcd->bus_name, wIndex + 1);
temp |= PORT_OWNER;
} else {
- /* Philips 1562 wants CMD_RUN to reset */
- if (!HCD_IS_RUNNING(ehci->hcd.state)) {
- u32 cmd = readl (&ehci->regs->command);
- cmd |= CMD_RUN;
- writel (cmd, &ehci->regs->command);
- ehci->hcd.state = USB_STATE_RUNNING;
- }
vdbg ("%s port %d reset",
hcd->bus_name, wIndex + 1);
temp |= PORT_RESET;
diff --git a/drivers/usb/hcd/ehci-mem.c b/drivers/usb/hcd/ehci-mem.c
index b2ee617c6c8b..422f4e26b798 100644
--- a/drivers/usb/hcd/ehci-mem.c
+++ b/drivers/usb/hcd/ehci-mem.c
@@ -224,8 +224,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
ehci->periodic [i] = EHCI_LIST_END;
/* software shadow of hardware table */
- ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *),
- flags & ~EHCI_SLAB_FLAGS);
+ ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
if (ehci->pshadow == 0) {
dbg ("no shadow periodic table");
ehci_mem_cleanup (ehci);
diff --git a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c
index d59d6039f593..ba90524d0eaa 100644
--- a/drivers/usb/hcd/ehci-q.c
+++ b/drivers/usb/hcd/ehci-q.c
@@ -436,14 +436,6 @@ qh_urb_transaction (
if (usb_pipecontrol (urb->pipe)) {
/* control request data is passed in the "setup" pid */
-
- /* NOTE: this isn't smart about 64bit DMA, since it uses the
- * default (32bit) mask rather than using the whole address
- * space. we could set pdev->dma_mask to all-ones while
- * getting this mapping, locking it and restoring before
- * allocating qtd/qh/... or maybe only do that for the main
- * data phase (below).
- */
qtd->buf_dma = pci_map_single (
ehci->hcd.pdev,
urb->setup_packet,
@@ -472,7 +464,6 @@ qh_urb_transaction (
*/
len = urb->transfer_buffer_length;
if (likely (len > 0)) {
- /* NOTE: sub-optimal mapping with 64bit DMA (see above) */
buf = map_buf = pci_map_single (ehci->hcd.pdev,
urb->transfer_buffer, len,
usb_pipein (urb->pipe)
diff --git a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
index 7984b00ff11b..cbc1a2dd0ad4 100644
--- a/drivers/usb/hcd/ohci-dbg.c
+++ b/drivers/usb/hcd/ohci-dbg.c
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
- * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
+ * $Id: ohci-dbg.c,v 1.4 2002/03/27 20:40:40 dbrownell Exp $
*/
/*-------------------------------------------------------------------------*/
@@ -52,7 +52,7 @@ static void urb_print (struct urb * urb, char * str, int small)
int i, len;
if (usb_pipecontrol (pipe)) {
- printk (KERN_DEBUG __FILE__ ": cmd(8):");
+ printk (KERN_DEBUG __FILE__ ": setup(8):");
for (i = 0; i < 8 ; i++)
printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
printk ("\n");
diff --git a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
index 20252c8805fb..c39c65a2bbea 100644
--- a/drivers/usb/hcd/ohci-hcd.c
+++ b/drivers/usb/hcd/ohci-hcd.c
@@ -56,7 +56,7 @@
* v1.0 1999/04/27 initial release
*
* This file is licenced under the GPL.
- * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
+ * $Id: ohci-hcd.c,v 1.9 2002/03/27 20:41:57 dbrownell Exp $
*/
#include <linux/config.h>
@@ -106,7 +106,7 @@
* - lots more testing!!
*/
-#define DRIVER_VERSION "$Revision: 1.7 $"
+#define DRIVER_VERSION "$Revision: 1.9 $"
#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -153,10 +153,8 @@ static int ohci_urb_enqueue (
#endif
/* every endpoint has a ed, locate and fill it */
- if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
- usb_dec_dev_use (urb->dev);
+ if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags)))
return -ENOMEM;
- }
/* for the private part of the URB we need the number of TDs (size) */
switch (usb_pipetype (pipe)) {
@@ -181,10 +179,8 @@ static int ohci_urb_enqueue (
break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets;
- if (size <= 0) {
- usb_dec_dev_use (urb->dev);
+ if (size <= 0)
return -EINVAL;
- }
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc [i].actual_length = 0;
urb->iso_frame_desc [i].status = -EXDEV;
@@ -198,10 +194,8 @@ static int ohci_urb_enqueue (
/* allocate the private part of the URB */
urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
mem_flags);
- if (!urb_priv) {
- usb_dec_dev_use (urb->dev);
+ if (!urb_priv)
return -ENOMEM;
- }
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
/* fill the private part of the URB */
@@ -216,7 +210,6 @@ static int ohci_urb_enqueue (
urb_priv->length = i;
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&ohci->lock, flags);
- usb_dec_dev_use (urb->dev);
return -ENOMEM;
}
}
@@ -242,7 +235,6 @@ static int ohci_urb_enqueue (
if (bustime < 0) {
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&ohci->lock, flags);
- usb_dec_dev_use (urb->dev);
return bustime;
}
usb_claim_bandwidth (urb->dev, urb,
@@ -356,9 +348,6 @@ static int ohci_get_frame (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-#ifdef OHCI_VERBOSE_DEBUG
- dbg ("%s: ohci_get_frame", hcd->bus_name);
-#endif
return le16_to_cpu (ohci->hcca->frame_no);
}
@@ -445,7 +434,7 @@ static int hc_start (struct ohci_hcd *ohci)
writel (ohci->hc_control, &ohci->regs->control);
/* Choose the interrupts we care about now, others later on demand */
- mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable);
@@ -517,10 +506,7 @@ static void ohci_irq (struct usb_hcd *hcd)
writel (OHCI_INTR_WDH, &regs->intrenable);
}
- if (ints & OHCI_INTR_SO) {
- dbg ("USB Schedule overrun");
- writel (OHCI_INTR_SO, &regs->intrenable);
- }
+ /* could track INTR_SO to reduce available PCI/... bandwidth */
// FIXME: this assumes SOF (1/ms) interrupts don't get lost...
if (ints & OHCI_INTR_SF) {
diff --git a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c
index 879e1abc036c..ab6e751557fc 100644
--- a/drivers/usb/hcd/ohci-hub.c
+++ b/drivers/usb/hcd/ohci-hub.c
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under GPL
- * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
+ * $Id: ohci-hub.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
*/
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c
index b775c71114d0..b015f8af9f41 100644
--- a/drivers/usb/hcd/ohci-mem.c
+++ b/drivers/usb/hcd/ohci-mem.c
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
- * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
+ * $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
*/
/*-------------------------------------------------------------------------*/
@@ -42,12 +42,6 @@ static void ohci_hcd_free (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_DEBUG_SLAB
-# define OHCI_MEM_FLAGS SLAB_POISON
-#else
-# define OHCI_MEM_FLAGS 0
-#endif
-
#ifndef CONFIG_PCI
# error "usb-ohci currently requires PCI-based controllers"
/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
@@ -169,14 +163,14 @@ static int ohci_mem_init (struct ohci_hcd *ohci)
sizeof (struct td),
32 /* byte alignment */,
0 /* no page-crossing issues */,
- GFP_KERNEL | OHCI_MEM_FLAGS);
+ GFP_KERNEL);
if (!ohci->td_cache)
return -ENOMEM;
ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
sizeof (struct ed),
16 /* byte alignment */,
0 /* no page-crossing issues */,
- GFP_KERNEL | OHCI_MEM_FLAGS);
+ GFP_KERNEL);
if (!ohci->ed_cache) {
pci_pool_destroy (ohci->td_cache);
return -ENOMEM;
diff --git a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c
index dd0a2aee0377..36e71896a93d 100644
--- a/drivers/usb/hcd/ohci-q.c
+++ b/drivers/usb/hcd/ohci-q.c
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
- * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
+ * $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
*/
static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
@@ -54,124 +54,81 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
/*
* URB goes back to driver, and isn't reissued.
- * It's completely gone from HC data structures, so no locking
- * is needed ... or desired! (Giveback can call back to hcd.)
+ * It's completely gone from HC data structures.
+ * PRECONDITION: no locks held (Giveback can call into HCD.)
*/
-static inline void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+static void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
{
- if (urb->hcpriv) {
- urb_free_priv (ohci, urb->hcpriv);
- urb->hcpriv = NULL;
- }
- usb_hcd_giveback_urb (&ohci->hcd, urb);
-}
-
-static void td_submit_urb (struct urb *urb);
-
-/*
- * URB is reported to driver, is reissued if it's periodic.
- */
-static int return_urb (struct ohci_hcd *hc, struct urb *urb)
-{
- urb_priv_t *urb_priv = urb->hcpriv;
- struct urb *urbt;
unsigned long flags;
- int i;
#ifdef DEBUG
- if (!urb_priv) {
+ if (!urb->hcpriv) {
err ("already unlinked!");
BUG ();
}
-
- /* just to be sure */
- if (!urb->complete) {
- err ("no completion!");
- BUG ();
- }
#endif
+ urb_free_priv (ohci, urb->hcpriv);
+ urb->hcpriv = NULL;
+
+ spin_lock_irqsave (&urb->lock, flags);
+ if (likely (urb->status == -EINPROGRESS))
+ urb->status = 0;
+ spin_unlock_irqrestore (&urb->lock, flags);
+
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "RET", usb_pipeout (urb->pipe));
#endif
+ usb_hcd_giveback_urb (&ohci->hcd, urb);
+}
+
+static void td_submit_urb (struct urb *urb);
+
+/* Report interrupt transfer completion, maybe reissue */
+static void intr_resub (struct ohci_hcd *hc, struct urb *urb)
+{
+ urb_priv_t *urb_priv = urb->hcpriv;
+ unsigned long flags;
- switch (usb_pipetype (urb->pipe)) {
- case PIPE_INTERRUPT:
#ifdef CONFIG_PCI
// FIXME rewrite this resubmit path. use pci_dma_sync_single()
// and requeue more cheaply, and only if needed.
- pci_unmap_single (hc->hcd.pdev,
- urb_priv->td [0]->data_dma,
- urb->transfer_buffer_length,
- usb_pipeout (urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
+// Better yet ... abolish the notion of automagic resubmission.
+ pci_unmap_single (hc->hcd.pdev,
+ urb_priv->td [0]->data_dma,
+ urb->transfer_buffer_length,
+ usb_pipeout (urb->pipe)
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE);
#endif
- /* FIXME: MP race. If another CPU partially unlinks
- * this URB (urb->status was updated, hasn't yet told
- * us to dequeue) before we call complete() here, an
- * extra "unlinked" completion will be reported...
- */
- urb->complete (urb);
+ /* FIXME: MP race. If another CPU partially unlinks
+ * this URB (urb->status was updated, hasn't yet told
+ * us to dequeue) before we call complete() here, an
+ * extra "unlinked" completion will be reported...
+ */
- /* always requeued, but ED_SKIP if complete() unlinks.
- * removed from periodic table only at SOF intr.
- */
- urb->actual_length = 0;
- if (urb_priv->state != URB_DEL)
- urb->status = -EINPROGRESS;
- spin_lock_irqsave (&hc->lock, flags);
- td_submit_urb (urb);
- spin_unlock_irqrestore (&hc->lock, flags);
- break;
+ spin_lock_irqsave (&urb->lock, flags);
+ if (likely (urb->status == -EINPROGRESS))
+ urb->status = 0;
+ spin_unlock_irqrestore (&urb->lock, flags);
- case PIPE_ISOCHRONOUS:
- for (urbt = urb->next;
- urbt && (urbt != urb);
- urbt = urbt->next)
- continue;
- if (urbt) { /* send the reply and requeue URB */
-#ifdef CONFIG_PCI
-// FIXME rewrite this resubmit path too
- pci_unmap_single (hc->hcd.pdev,
- urb_priv->td [0]->data_dma,
- urb->transfer_buffer_length,
- usb_pipeout (urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
+#ifdef OHCI_VERBOSE_DEBUG
+ urb_print (urb, "INTR", usb_pipeout (urb->pipe));
#endif
- urb->complete (urb);
- spin_lock_irqsave (&hc->lock, flags);
- urb->actual_length = 0;
- urb->status = -EINPROGRESS;
- urb->start_frame = urb_priv->ed->last_iso + 1;
- if (urb_priv->state != URB_DEL) {
- for (i = 0; i < urb->number_of_packets;
- i++) {
- urb->iso_frame_desc [i]
- .actual_length = 0;
- urb->iso_frame_desc [i]
- .status = -EXDEV;
- }
- td_submit_urb (urb);
- }
-// FIXME if not deleted, should have been "finished"
- spin_unlock_irqrestore (&hc->lock, flags);
-
- } else { /* not reissued */
- finish_urb (hc, urb);
- }
- break;
+ urb->complete (urb);
- /*
- * C/B requests that get here are never reissued.
- */
- case PIPE_BULK:
- case PIPE_CONTROL:
- finish_urb (hc, urb);
- break;
- }
- return 0;
+ /* always requeued, but ED_SKIP if complete() unlinks.
+ * EDs are removed from periodic table only at SOF intr.
+ */
+ urb->actual_length = 0;
+ spin_lock_irqsave (&urb->lock, flags);
+ if (urb_priv->state != URB_DEL)
+ urb->status = -EINPROGRESS;
+ spin_unlock (&urb->lock);
+
+ spin_lock (&hc->lock);
+ td_submit_urb (urb);
+ spin_unlock_irqrestore (&hc->lock, flags);
}
@@ -329,6 +286,26 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
/*-------------------------------------------------------------------------*/
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+ struct ohci_hcd *ohci,
+ struct ed *ed,
+ unsigned index,
+ unsigned period
+) {
+ for (; index < NUM_INTS; index += period) {
+ __u32 *ed_p = &ohci->hcca->int_table [index];
+
+ while (*ed_p != 0) {
+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED);
+ }
+ }
+}
+
/* unlink an ed from one of the HC chains.
* just the link to the ed is unlinked.
* the link from the ed still points to another operational ed or 0
@@ -336,11 +313,7 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
*/
static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
{
- int int_branch;
int i;
- int inter;
- int interval;
- __u32 *ed_p;
ed->hwINFO |= ED_SKIP;
@@ -384,22 +357,9 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
break;
case PIPE_INTERRUPT:
- int_branch = ed->int_branch;
- interval = ed->int_interval;
-
- for (i = 0; i < ep_rev (6, interval); i += inter) {
- for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]), inter = 1;
- (*ed_p != 0) && (*ed_p != ed->hwNextED);
- ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED),
- inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {
- if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- for (i = int_branch; i < NUM_INTS; i += interval)
- ohci->ohci_int_load [i] -= ed->int_load;
+ periodic_unlink (ohci, ed, ed->int_branch, ed->int_interval);
+ for (i = ed->int_branch; i < NUM_INTS; i += ed->int_interval)
+ ohci->ohci_int_load [i] -= ed->int_load;
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic (ohci, "UNLINK_INT");
#endif
@@ -412,21 +372,10 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
->ed_prev = ed->ed_prev;
- if (ed->ed_prev != NULL) {
+ if (ed->ed_prev != NULL)
ed->ed_prev->hwNextED = ed->hwNextED;
- } else {
- for (i = 0; i < NUM_INTS; i++) {
- for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
- // inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
- if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- }
+ else
+ periodic_unlink (ohci, ed, 0, 1);
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic (ohci, "UNLINK_ISO");
#endif
@@ -584,6 +533,12 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
return;
}
+#if 0
+ /* no interrupt needed except for URB's last TD */
+ if (index != (urb_priv->length - 1))
+ info |= TD_DI;
+#endif
+
/* use this td as the next dummy */
td_pt = urb_priv->td [index];
td_pt->hwNextTD = 0;
@@ -660,6 +615,9 @@ static void td_submit_urb (struct urb *urb)
} else
data = 0;
+ /* NOTE: TD_CC is set so we can tell which TDs the HC processed by
+ * using TD_CC_GET, as well as by seeing them on the done list.
+ */
switch (usb_pipetype (urb->pipe)) {
case PIPE_BULK:
info = usb_pipeout (urb->pipe)
@@ -726,8 +684,14 @@ static void td_submit_urb (struct urb *urb)
case PIPE_ISOCHRONOUS:
for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
- td_fill (ohci, TD_CC | TD_ISO
- | ((urb->start_frame + cnt) & 0xffff),
+ int frame = urb->start_frame;
+
+ // FIXME scheduling should handle frame counter
+ // roll-around ... exotic case (and OHCI has
+ // a 2^16 iso range, vs other HCs max of 2^10)
+ frame += cnt * urb->interval;
+ frame &= 0xffff;
+ td_fill (ohci, TD_CC | TD_ISO | frame,
data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt);
}
@@ -741,50 +705,77 @@ static void td_submit_urb (struct urb *urb)
* Done List handling functions
*-------------------------------------------------------------------------*/
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length (struct td *td)
+/* calculate transfer length/status and update the urb
+ * PRECONDITION: irqsafe (only for urb->status locking)
+ */
+static void td_done (struct urb *urb, struct td *td)
{
- __u32 tdINFO, tdBE, tdCBP;
- __u16 tdPSW;
- struct urb *urb = td->urb;
- urb_priv_t *urb_priv = urb->hcpriv;
- int dlen = 0;
- int cc = 0;
-
- tdINFO = le32_to_cpup (&td->hwINFO);
- tdBE = le32_to_cpup (&td->hwBE);
- tdCBP = le32_to_cpup (&td->hwCBP);
+ u32 tdINFO = le32_to_cpup (&td->hwINFO);
+ int cc = 0;
+ /* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
- tdPSW = le16_to_cpu (td->hwPSW [0]);
+ u16 tdPSW = le16_to_cpu (td->hwPSW [0]);
+ int dlen = 0;
+
cc = (tdPSW >> 12) & 0xF;
- if (cc < 0xE) {
- if (usb_pipeout (urb->pipe)) {
- dlen = urb->iso_frame_desc [td->index].length;
- } else {
- dlen = tdPSW & 0x3ff;
- }
- urb->actual_length += dlen;
- urb->iso_frame_desc [td->index].actual_length = dlen;
- if (! (urb->transfer_flags & USB_DISABLE_SPD)
- && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- urb->iso_frame_desc [td->index].status
- = cc_to_error [cc];
+ if (! ((urb->transfer_flags & USB_DISABLE_SPD)
+ && (cc == TD_DATAUNDERRUN)))
+ cc = TD_CC_NOERROR;
+
+ if (usb_pipeout (urb->pipe))
+ dlen = urb->iso_frame_desc [td->index].length;
+ else
+ dlen = tdPSW & 0x3ff;
+ urb->actual_length += dlen;
+ urb->iso_frame_desc [td->index].actual_length = dlen;
+ urb->iso_frame_desc [td->index].status = cc_to_error [cc];
+
+ if (cc != 0)
+ dbg (" urb %p iso TD %d len %d CC %d",
+ urb, td->index, dlen, cc);
+
+ /* BULK, INT, CONTROL ... drivers see aggregate length/status,
+ * except that "setup" bytes aren't counted and "short" transfers
+ * might not be reported as errors.
+ */
+ } else {
+ int type = usb_pipetype (urb->pipe);
+ u32 tdBE = le32_to_cpup (&td->hwBE);
+
+ cc = TD_CC_GET (tdINFO);
+
+ /* control endpoints only have soft stalls */
+ if (type != PIPE_CONTROL && cc == TD_CC_STALL)
+ usb_endpoint_halt (urb->dev,
+ usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe));
+
+ /* update packet status if needed (short may be ok) */
+ if (((urb->transfer_flags & USB_DISABLE_SPD) != 0
+ && cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+ if (cc != TD_CC_NOERROR) {
+ spin_lock (&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = cc_to_error [cc];
+ spin_unlock (&urb->lock);
}
- } else { /* BULK, INT, CONTROL DATA */
- if (! (usb_pipetype (urb->pipe) == PIPE_CONTROL &&
- ((td->index == 0)
- || (td->index == urb_priv->length - 1)))) {
- if (tdBE != 0) {
- urb->actual_length += (td->hwCBP == 0)
- ? (tdBE - td->data_dma + 1)
- : (tdCBP - td->data_dma);
- }
- }
+
+ /* count all non-empty packets except control SETUP packet */
+ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
+ if (td->hwCBP == 0)
+ urb->actual_length += tdBE - td->data_dma + 1;
+ else
+ urb->actual_length +=
+ le32_to_cpup (&td->hwCBP)
+ - td->data_dma;
+ }
+
+ if (cc != 0)
+ dbg (" urb %p TD %d CC %d, len=%d",
+ urb, td->index, cc, urb->actual_length);
}
}
@@ -811,13 +802,16 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
- dbg (" USB-error/status: %x : %p",
- TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
- td_list);
- /* typically the endpoint halted too */
+ /* typically the endpoint halts on error; un-halt,
+ * and maybe dequeue other TDs from this urb
+ */
if (td_list->ed->hwHeadP & ED_H) {
if (urb_priv && ((td_list->index + 1)
< urb_priv->length)) {
+ dbg ("urb %p TD %d of %d, patch ED",
+ td_list->urb,
+ 1 + td_list->index,
+ urb_priv->length);
td_list->ed->hwHeadP =
(urb_priv->td [urb_priv->length - 1]->hwNextTD
& __constant_cpu_to_le32 (TD_MASK))
@@ -870,16 +864,19 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
le32_to_cpup (&td->hwNextTD));
if ((urb_priv->state == URB_DEL)) {
tdINFO = le32_to_cpup (&td->hwINFO);
+ /* HC may have partly processed this TD */
if (TD_CC_GET (tdINFO) < 0xE)
- dl_transfer_length (td);
+ td_done (urb, td);
*td_p = td->hwNextTD | (*td_p
& __constant_cpu_to_le32 (0x3));
/* URB is done; clean up */
- if (++ (urb_priv->td_cnt) == urb_priv->length)
-// FIXME: we shouldn't hold ohci->lock here, else the
-// completion function can't talk to this hcd ...
+ if (++ (urb_priv->td_cnt) == urb_priv->length) {
+ spin_unlock_irqrestore (&ohci->lock,
+ flags);
finish_urb (ohci, urb);
+ spin_lock_irqsave (&ohci->lock, flags);
+ }
} else {
td_p = &td->hwNextTD;
}
@@ -931,71 +928,52 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
/*-------------------------------------------------------------------------*/
/*
- * process normal completions (error or success) and some unlinked eds
- * this is the main path for handing urbs back to drivers
+ * Process normal completions (error or success) and clean the schedules.
+ *
+ * This is the main path for handing urbs back to drivers. The only other
+ * path is dl_del_list(), which unlinks URBs by scanning EDs, instead of
+ * scanning the (re-reversed) donelist as this does.
*/
-static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
+static void dl_done_list (struct ohci_hcd *ohci, struct td *td)
{
- struct td *td_list_next = NULL;
- struct ed *ed;
- int cc = 0;
- struct urb *urb;
- urb_priv_t *urb_priv;
- __u32 tdINFO;
-
- unsigned long flags;
-
- while (td_list) {
- td_list_next = td_list->next_dl_td;
-
- urb = td_list->urb;
- urb_priv = urb->hcpriv;
- tdINFO = le32_to_cpup (&td_list->hwINFO);
-
- ed = td_list->ed;
-
- dl_transfer_length (td_list);
+ unsigned long flags;
- /* error code of transfer */
- cc = TD_CC_GET (tdINFO);
- if (cc == TD_CC_STALL)
- usb_endpoint_halt (urb->dev,
- usb_pipeendpoint (urb->pipe),
- usb_pipeout (urb->pipe));
+ spin_lock_irqsave (&ohci->lock, flags);
+ while (td) {
+ struct td *td_next = td->next_dl_td;
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct ed *ed = td->ed;
+
+ /* update URB's length and status from TD */
+ td_done (urb, td);
+ urb_priv->td_cnt++;
+
+ /* If all this urb's TDs are done, call complete().
+ * Interrupt transfers are the only special case:
+ * they're reissued, until "deleted" by usb_unlink_urb
+ * (real work done in a SOF intr, by dl_del_list).
+ */
+ if (urb_priv->td_cnt == urb_priv->length) {
+ int resubmit;
- if (! (urb->transfer_flags & USB_DISABLE_SPD)
- && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
+ resubmit = usb_pipeint (urb->pipe)
+ && (urb_priv->state != URB_DEL);
- if (++ (urb_priv->td_cnt) == urb_priv->length) {
- /*
- * Except for periodic transfers, both branches do
- * the same thing. Periodic urbs get reissued until
- * they're "deleted" (in SOF intr) by usb_unlink_urb.
- */
- if ((ed->state & (ED_OPER | ED_UNLINK))
- && (urb_priv->state != URB_DEL)) {
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error [cc];
- spin_unlock (&urb->lock);
- return_urb (ohci, urb);
- } else
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ if (resubmit)
+ intr_resub (ohci, urb);
+ else
finish_urb (ohci, urb);
+ spin_lock_irqsave (&ohci->lock, flags);
}
- spin_lock_irqsave (&ohci->lock, flags);
- if (ed->state != ED_NEW) {
- u32 edHeadP = ed->hwHeadP;
-
- /* unlink eds if they are not busy */
- edHeadP &= __constant_cpu_to_le32 (ED_MASK);
- if ((edHeadP == ed->hwTailP) && (ed->state == ED_OPER))
- ep_unlink (ohci, ed);
- }
- spin_unlock_irqrestore (&ohci->lock, flags);
-
- td_list = td_list_next;
+ /* clean schedule: unlink EDs that are no longer busy */
+ if ((ed->hwHeadP & __constant_cpu_to_le32 (TD_MASK))
+ == ed->hwTailP
+ && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ td = td_next;
}
+ spin_unlock_irqrestore (&ohci->lock, flags);
}
-
diff --git a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h
index 0a4ae8e24b05..b191552a7a23 100644
--- a/drivers/usb/hcd/ohci.h
+++ b/drivers/usb/hcd/ohci.h
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
- * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
+ * $Id: ohci.h,v 1.6 2002/03/22 16:04:54 dbrownell Exp $
*/
/*
diff --git a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c
index 0bb17425bc39..245ad1a0b5af 100644
--- a/drivers/usb/hid-core.c
+++ b/drivers/usb/hid-core.c
@@ -46,9 +46,7 @@
#include <linux/usb.h>
#include "hid.h"
-#ifdef CONFIG_USB_HIDDEV
#include <linux/hiddev.h>
-#endif
/*
* Version Information
@@ -1441,10 +1439,8 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
if (!hidinput_connect(hid))
hid->claimed |= HID_CLAIMED_INPUT;
-#ifdef CONFIG_USB_HIDDEV
if (!hiddev_connect(hid))
hid->claimed |= HID_CLAIMED_HIDDEV;
-#endif
if (!hid->claimed) {
hid_free_device(hid);
@@ -1483,13 +1479,10 @@ static void hid_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb(hid->urbout);
usb_unlink_urb(hid->urbctrl);
-
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid);
-#ifdef CONFIG_USB_HIDDEV
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
-#endif
usb_free_urb(hid->urbin);
usb_free_urb(hid->urbctrl);
@@ -1516,9 +1509,7 @@ static struct usb_driver hid_driver = {
static int __init hid_init(void)
{
-#ifdef CONFIG_USB_HIDDEV
hiddev_init();
-#endif
usb_register(&hid_driver);
info(DRIVER_VERSION ":" DRIVER_DESC);
@@ -1527,9 +1518,7 @@ static int __init hid_init(void)
static void __exit hid_exit(void)
{
-#ifdef CONFIG_USB_HIDDEV
hiddev_exit();
-#endif
usb_deregister(&hid_driver);
}
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index ed72dc6acfd1..357e31bd3814 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -389,10 +389,6 @@ struct hid_descriptor {
struct hid_class_descriptor desc[1];
} __attribute__ ((packed));
-void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_connect(struct hid_device *);
-void hidinput_disconnect(struct hid_device *);
-
#ifdef DEBUG
#include "hid-debug.h"
#else
@@ -403,9 +399,19 @@ void hidinput_disconnect(struct hid_device *);
#endif
+#ifdef CONFIG_USB_HIDINPUT
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
+extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+extern int hidinput_connect(struct hid_device *);
+extern void hidinput_disconnect(struct hid_device *);
+#else
+#define IS_INPUT_APPLICATION(a) (0)
+static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
+static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
+static inline void hidinput_disconnect(struct hid_device *hid) { }
+#endif
int hid_open(struct hid_device *);
void hid_close(struct hid_device *);
diff --git a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c
index 5d4029259899..206531c7aef7 100644
--- a/drivers/usb/hiddev.c
+++ b/drivers/usb/hiddev.c
@@ -341,9 +341,6 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
return 0;
}
-#define GET_TIMEOUT 3
-#define SET_TIMEOUT 3
-
/*
* "ioctl" file op
*/
@@ -529,36 +526,12 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
return copy_to_user((void *) arg, &uref, sizeof(uref));
case HIDIOCGUSAGE:
- if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
- return -EFAULT;
-
- if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
- field = hiddev_lookup_usage(hid, &uref);
- if (field == NULL)
- return -EINVAL;
- } else {
- rinfo.report_type = uref.report_type;
- rinfo.report_id = uref.report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
-
- if (uref.field_index >= report->maxfield)
- return -EINVAL;
-
- field = report->field[uref.field_index];
- if (uref.usage_index >= field->maxusage)
- return -EINVAL;
- }
-
- uref.value = field->value[uref.usage_index];
-
- return copy_to_user((void *) arg, &uref, sizeof(uref));
-
case HIDIOCSUSAGE:
if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
return -EFAULT;
- if (uref.report_type == HID_REPORT_TYPE_INPUT)
+ if (cmd == HIDIOCSUSAGE &&
+ uref.report_type != HID_REPORT_TYPE_OUTPUT)
return -EINVAL;
if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
@@ -579,7 +552,12 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
- field->value[uref.usage_index] = uref.value;
+ if (cmd == HIDIOCGUSAGE) {
+ uref.value = field->value[uref.usage_index];
+ return copy_to_user((void *) arg, &uref, sizeof(uref));
+ } else {
+ field->value[uref.usage_index] = uref.value;
+ }
return 0;
diff --git a/drivers/usb/hpusbscsi.c b/drivers/usb/hpusbscsi.c
index d63e21f67dce..c964e487bf82 100644
--- a/drivers/usb/hpusbscsi.c
+++ b/drivers/usb/hpusbscsi.c
@@ -129,6 +129,9 @@ hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
if (scsi_register_host(&new->ctempl))
goto err_out;
+ new->sense_command[0] = REQUEST_SENSE;
+ new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
+
/* adding to list for module unload */
list_add (&hpusbscsi_devices, &new->lh);
@@ -379,6 +382,7 @@ static void handle_usb_error (struct hpusbscsi *hpusbscsi)
static void control_interrupt_callback (struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+ u8 scsi_state;
DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
if(unlikely(u->status < 0)) {
@@ -386,10 +390,23 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
handle_usb_error(hpusbscsi);
return;
}
- hpusbscsi->srb->result &= SCSI_ERR_MASK;
- hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte;
- if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
+ scsi_state = hpusbscsi->scsi_state_byte;
+ if (hpusbscsi->state != HP_STATE_ERROR) {
+ hpusbscsi->srb->result &= SCSI_ERR_MASK;
+ hpusbscsi->srb->result |= scsi_state;
+ }
+
+ if (scsi_state == CHECK_CONDITION << 1) {
+ if (hpusbscsi->state == HP_STATE_WAIT) {
+ issue_request_sense(hpusbscsi);
+ } else {
+ /* we request sense after an eventual data transfer */
+ hpusbscsi->state = HP_STATE_ERROR;
+ }
+ }
+
+ if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
/* we do a callback to the scsi layer if and only if all data has been transfered */
hpusbscsi->scallback(hpusbscsi->srb);
@@ -404,6 +421,8 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
hpusbscsi->state = HP_STATE_PREMATURE;
TRACE_STATE;
break;
+ case HP_STATE_ERROR:
+ break;
default:
printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
TRACE_STATE;
@@ -432,32 +451,6 @@ static void simple_command_callback(struct urb *u)
}
}
-static void request_sense_callback (struct urb *u)
-{
- struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
- if (unlikely(u->status<0)) {
- handle_usb_error(hpusbscsi);
- return;
- }
-
- FILL_BULK_URB(
- u,
- hpusbscsi->dev,
- hpusbscsi->current_data_pipe,
- hpusbscsi->srb->sense_buffer,
- SCSI_SENSE_BUFFERSIZE,
- simple_done,
- hpusbscsi
- );
-
- if (unlikely(0 > usb_submit_urb(u, GFP_ATOMIC))) {
- handle_usb_error(hpusbscsi);
- return;
- }
- hpusbscsi->state = HP_STATE_WORKING;
-}
-
static void scatter_gather_callback(struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
@@ -494,7 +487,7 @@ static void scatter_gather_callback(struct urb *u)
res = usb_submit_urb(u, GFP_ATOMIC);
if (unlikely(res))
- hpusbscsi->state = HP_STATE_ERROR;
+ handle_usb_error(hpusbscsi);
TRACE_STATE;
}
@@ -509,11 +502,15 @@ static void simple_done (struct urb *u)
DEBUG("Data transfer done\n");
TRACE_STATE;
if (hpusbscsi->state != HP_STATE_PREMATURE) {
- if (unlikely(u->status < 0))
- hpusbscsi->state = HP_STATE_ERROR;
- else
- hpusbscsi->state = HP_STATE_WAIT;
- TRACE_STATE;
+ if (unlikely(u->status < 0)) {
+ handle_usb_error(hpusbscsi);
+ } else {
+ if (hpusbscsi->state != HP_STATE_ERROR) {
+ hpusbscsi->state = HP_STATE_WAIT;
+ } else {
+ issue_request_sense(hpusbscsi);
+ }
+ }
} else {
if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
@@ -550,12 +547,52 @@ static void simple_payload_callback (struct urb *u)
if (hpusbscsi->state != HP_STATE_PREMATURE) {
hpusbscsi->state = HP_STATE_WORKING;
TRACE_STATE;
- } else {
- if (likely(hpusbscsi->scallback != NULL))
- hpusbscsi->scallback(hpusbscsi->srb);
- hpusbscsi->state = HP_STATE_FREE;
- TRACE_STATE;
+ }
+}
+
+static void request_sense_callback (struct urb *u)
+{
+ struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+ if (u->status<0) {
+ handle_usb_error(hpusbscsi);
+ return;
+ }
+
+ FILL_BULK_URB(
+ u,
+ hpusbscsi->dev,
+ hpusbscsi->current_data_pipe,
+ hpusbscsi->srb->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ simple_done,
+ hpusbscsi
+ );
+
+ if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
+ handle_usb_error(hpusbscsi);
+ return;
}
+ if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
+ hpusbscsi->state = HP_STATE_WORKING;
}
+static void issue_request_sense (struct hpusbscsi *hpusbscsi)
+{
+ FILL_BULK_URB(
+ hpusbscsi->dataurb,
+ hpusbscsi->dev,
+ usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
+ &hpusbscsi->sense_command,
+ SENSE_COMMAND_SIZE,
+ request_sense_callback,
+ hpusbscsi
+ );
+
+ hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
+
+ if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
+ handle_usb_error(hpusbscsi);
+ }
+}
diff --git a/drivers/usb/hpusbscsi.h b/drivers/usb/hpusbscsi.h
index 2287e56dc2ca..87d1d7efa168 100644
--- a/drivers/usb/hpusbscsi.h
+++ b/drivers/usb/hpusbscsi.h
@@ -4,9 +4,14 @@
/* large parts based on or taken from code by John Fremlin and Matt Dharm */
/* this file is licensed under the GPL */
+/* A big thanks to Jose for untiring testing */
+
typedef void (*usb_urb_callback) (struct urb *);
typedef void (*scsi_callback)(Scsi_Cmnd *);
+#define SENSE_COMMAND_SIZE 6
+#define HPUSBSCSI_SENSE_LENGTH 0x16
+
struct hpusbscsi
{
struct list_head lh;
@@ -19,8 +24,9 @@ struct hpusbscsi
struct Scsi_Host *host;
Scsi_Host_Template ctempl;
int number;
- scsi_callback scallback;
- Scsi_Cmnd *srb;
+ scsi_callback scallback;
+ Scsi_Cmnd *srb;
+ u8 sense_command[SENSE_COMMAND_SIZE];
int use_count;
wait_queue_head_t pending;
@@ -57,6 +63,7 @@ static void simple_done (struct urb *u);
static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
+static void issue_request_sense (struct hpusbscsi *hpusbscsi);
static Scsi_Host_Template hpusbscsi_scsi_host_template = {
name: "hpusbscsi",
@@ -86,3 +93,4 @@ static Scsi_Host_Template hpusbscsi_scsi_host_template = {
#define HP_STATE_PREMATURE 5 /* status prematurely reported */
+
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 91bdb6345587..f598a3cc98e0 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -655,11 +655,11 @@ void usb_hub_port_disable(struct usb_device *hub, int port)
* Not covered by the spec - but easy to deal with.
*
* This implementation uses 400ms minimum debounce timeout and checks
- * every 10ms for transient disconnects to restart the delay.
+ * every 100ms for transient disconnects to restart the delay.
*/
#define HUB_DEBOUNCE_TIMEOUT 400
-#define HUB_DEBOUNCE_STEP 10
+#define HUB_DEBOUNCE_STEP 100
/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_debounce(struct usb_device *hub, int port)
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 329462ed7ee5..73527b766d81 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -64,9 +64,9 @@ static int parse_options(struct super_block *s, char *data)
{
char *curopt = NULL, *value;
- if (data)
- curopt = strtok(data, ",");
- for (; curopt; curopt = strtok(NULL, ",")) {
+ while ((curopt = strsep(&data, ",")) != NULL) {
+ if (!*curopt)
+ continue;
if ((value = strchr(curopt, '=')) != NULL)
*value++ = 0;
if (!strcmp(curopt, "devuid")) {
diff --git a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
index 939aaf7fde05..f9af587bf994 100644
--- a/drivers/usb/kaweth.c
+++ b/drivers/usb/kaweth.c
@@ -124,6 +124,7 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
+ { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
diff --git a/drivers/usb/konicawc.c b/drivers/usb/konicawc.c
index 028c4ebc3380..e34316b7cba7 100644
--- a/drivers/usb/konicawc.c
+++ b/drivers/usb/konicawc.c
@@ -1,5 +1,5 @@
/*
- * $Id: konicawc.c,v 1.12 2002/02/07 23:18:53 spse Exp $
+ * $Id$
*
* konicawc.c - konica webcam driver
*
@@ -18,17 +18,18 @@
#include <linux/module.h>
#include <linux/init.h>
-#define DEBUG
-
#include "usbvideo.h"
#define MAX_BRIGHTNESS 108
#define MAX_CONTRAST 108
#define MAX_SATURATION 108
#define MAX_SHARPNESS 108
-#define MAX_WHITEBAL 363
+#define MAX_WHITEBAL 372
+#define MAX_SPEED 6
+#define MAX_CAMERAS 1
-#define MAX_CAMERAS 1
+#define DRIVER_VERSION "v1.1"
+#define DRIVER_DESC "Konica Webcam driver"
enum ctrl_req {
SetWhitebal = 0x01,
@@ -40,7 +41,7 @@ enum ctrl_req {
enum frame_sizes {
- SIZE_160X130 = 0,
+ SIZE_160X136 = 0,
SIZE_176X144 = 1,
SIZE_320X240 = 2,
};
@@ -53,12 +54,30 @@ static usbvideo_t *cams;
static int debug;
static enum frame_sizes size;
+static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */
static int brightness = MAX_BRIGHTNESS/2;
static int contrast = MAX_CONTRAST/2;
static int saturation = MAX_SATURATION/2;
static int sharpness = MAX_SHARPNESS/2;
static int whitebal = 3*(MAX_WHITEBAL/4);
+static int speed_to_interface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static int speed_to_fps[3][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+ { 18, 30, 36, 45, 54, 60, 75 },
+ { 6, 10, 12, 15, 18, 20, 25 } };
+
+
+static int camera_sizes[][2] = { { 160, 136 },
+ { 176, 144 },
+ { 320, 240 },
+ { } /* List terminator */
+};
struct konicawc {
u8 brightness; /* camera uses 0 - 9, x11 for real value */
@@ -66,12 +85,12 @@ struct konicawc {
u8 saturation; /* as above */
u8 sharpness; /* as above */
u8 white_bal; /* 0 - 33, x11 for real value */
- u8 fps; /* Stored as fps * 3 */
+ u8 speed; /* Stored as 0 - 6, used as index in speed_to_* (above) */
u8 size; /* Frame Size */
int height;
int width;
- struct urb *sts_urb[USBVIDEO_NUMFRAMES];
- u8 sts_buf[USBVIDEO_NUMFRAMES][FRAMES_PER_DESC];
+ struct urb *sts_urb[USBVIDEO_NUMSBUF];
+ u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
struct urb *last_data_urb;
int lastframe;
};
@@ -97,19 +116,19 @@ static int konicawc_setup_on_open(uvd_t *uvd)
konicawc_set_misc(uvd, 0x2, 0, 0x0b);
dbg("setting brightness to %d (%d)", cam->brightness,
- cam->brightness*11);
+ cam->brightness * 11);
konicawc_set_value(uvd, cam->brightness, SetBrightness);
dbg("setting white balance to %d (%d)", cam->white_bal,
- cam->white_bal*11);
+ cam->white_bal * 11);
konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
dbg("setting contrast to %d (%d)", cam->contrast,
- cam->contrast*11);
- konicawc_set_value(uvd, cam->brightness, SetBrightness);
+ cam->contrast * 11);
+ konicawc_set_value(uvd, cam->contrast, SetContrast);
dbg("setting saturation to %d (%d)", cam->saturation,
- cam->saturation*11);
+ cam->saturation * 11);
konicawc_set_value(uvd, cam->saturation, SetSaturation);
dbg("setting sharpness to %d (%d)", cam->sharpness,
- cam->sharpness*11);
+ cam->sharpness * 11);
konicawc_set_value(uvd, cam->sharpness, SetSharpness);
dbg("setting size %d", cam->size);
switch(cam->size) {
@@ -131,6 +150,30 @@ static int konicawc_setup_on_open(uvd_t *uvd)
}
+static void konicawc_adjust_picture(uvd_t *uvd)
+{
+ struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+ dbg("new brightness: %d", uvd->vpic.brightness);
+ uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+ if(cam->brightness != uvd->vpic.brightness / 11) {
+ cam->brightness = uvd->vpic.brightness / 11;
+ dbg("setting brightness to %d (%d)", cam->brightness,
+ cam->brightness * 11);
+ konicawc_set_value(uvd, cam->brightness, SetBrightness);
+ }
+
+ dbg("new contrast: %d", uvd->vpic.contrast);
+ uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+ if(cam->contrast != uvd->vpic.contrast / 11) {
+ cam->contrast = uvd->vpic.contrast / 11;
+ dbg("setting contrast to %d (%d)", cam->contrast,
+ cam->contrast * 11);
+ konicawc_set_value(uvd, cam->contrast, SetContrast);
+ }
+}
+
+
static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb)
{
char *cdata;
@@ -138,7 +181,7 @@ static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *st
unsigned char *status = stsurb->transfer_buffer;
int keep = 0, discard = 0, bad = 0;
static int buttonsts = 0;
-
+
for (i = 0; i < dataurb->number_of_packets; i++) {
int button = buttonsts;
unsigned char sts;
@@ -228,7 +271,7 @@ static void konicawc_isoc_irq(struct urb *urb)
int i, len = 0;
uvd_t *uvd = urb->context;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
+
/* We don't want to do anything if we are about to be removed! */
if (!CAMERA_IS_OPERATIONAL(uvd))
return;
@@ -236,7 +279,6 @@ static void konicawc_isoc_irq(struct urb *urb)
if (urb->actual_length > 32) {
cam->last_data_urb = urb;
return;
-
}
if (!uvd->streaming) {
@@ -244,7 +286,7 @@ static void konicawc_isoc_irq(struct urb *urb)
info("Not streaming, but interrupt!");
return;
}
-
+
uvd->stats.urb_count++;
if (urb->actual_length <= 0)
goto urb_done_with;
@@ -329,7 +371,8 @@ static int konicawc_start_data(uvd_t *uvd)
}
}
-
+ cam->last_data_urb = NULL;
+
/* Link URBs into a ring so that they invoke each other infinitely */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
if ((i+1) < USBVIDEO_NUMSBUF) {
@@ -362,11 +405,14 @@ static int konicawc_start_data(uvd_t *uvd)
static void konicawc_stop_data(uvd_t *uvd)
{
int i, j;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
+ struct konicawc *cam;
if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
return;
+ cam = (struct konicawc *)uvd->user_data;
+ cam->last_data_urb = NULL;
+
/* Unschedule all of the iso td's */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
j = usb_unlink_urb(uvd->sbuf[i].urb);
@@ -476,9 +522,9 @@ static void konicawc_process_isoc(uvd_t *uvd, usbvideo_frame_t *frame)
static int konicawc_calculate_fps(uvd_t *uvd)
{
struct konicawc *t = uvd->user_data;
- dbg("");
+ dbg("fps = %d", speed_to_fps[t->size][t->speed]/3);
- return (t->fps)/3;
+ return speed_to_fps[t->size][t->speed]/3;
}
@@ -515,10 +561,10 @@ static void konicawc_configure_video(uvd_t *uvd)
uvd->vcap.type = VID_TYPE_CAPTURE;
uvd->vcap.channels = 1;
uvd->vcap.audios = 0;
- uvd->vcap.maxwidth = cam->width;
- uvd->vcap.maxheight = cam->height;
- uvd->vcap.minwidth = cam->width;
- uvd->vcap.minheight = cam->height;
+ uvd->vcap.minwidth = camera_sizes[cam->size][0];
+ uvd->vcap.minheight = camera_sizes[cam->size][1];
+ uvd->vcap.maxwidth = camera_sizes[cam->size][0];
+ uvd->vcap.maxheight = camera_sizes[cam->size][1];
memset(&uvd->vchan, 0, sizeof(uvd->vchan));
uvd->vchan.flags = 0 ;
@@ -540,7 +586,7 @@ static void konicawc_configure_video(uvd_t *uvd)
}
-static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
+static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
{
uvd_t *uvd = NULL;
int i, nas;
@@ -555,6 +601,7 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const st
return NULL;
info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
+ RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
/* Validate found interface: must have one ISO endpoint */
nas = dev->actconfig->interface[ifnum].num_altsetting;
@@ -600,56 +647,58 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const st
return NULL;
}
} else {
- if (actInterface < 0) {
+ if (i == speed_to_interface[speed]) {
+ /* This one is the requested one */
actInterface = i;
maxPS = endpoint->wMaxPacketSize;
- if (debug > 0)
- info("Active setting=%d. maxPS=%d.",
+ if (debug > 0) {
+ info("Selecting requested active setting=%d. maxPS=%d.",
i, maxPS);
- } else {
- /* Got another active alt. setting */
- if (maxPS < endpoint->wMaxPacketSize) {
- /* This one is better! */
- actInterface = i;
- maxPS = endpoint->wMaxPacketSize;
- if (debug > 0) {
- info("Even better active setting=%d. maxPS=%d.",
- i, maxPS);
- }
}
}
}
}
+ if(actInterface == -1) {
+ err("Cant find required endpoint");
+ return NULL;
+ }
+
/* Code below may sleep, need to lock module while we are here */
MOD_INC_USE_COUNT;
uvd = usbvideo_AllocateDevice(cams);
if (uvd != NULL) {
- struct konicawc *konicawc_data = (struct konicawc *)(uvd->user_data);
+ struct konicawc *cam = (struct konicawc *)(uvd->user_data);
/* Here uvd is a fully allocated uvd_t object */
-
for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
- konicawc_data->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+ cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+ if(cam->sts_urb[i] == NULL) {
+ while(i--) {
+ usb_free_urb(cam->sts_urb[i]);
+ }
+ err("cant allocate urbs");
+ return NULL;
+ }
}
-
+ cam->speed = speed;
switch(size) {
- case SIZE_160X130:
+ case SIZE_160X136:
default:
- konicawc_data->height = 136;
- konicawc_data->width = 160;
- konicawc_data->size = SIZE_160X130;
+ cam->height = 136;
+ cam->width = 160;
+ cam->size = SIZE_160X136;
break;
case SIZE_176X144:
- konicawc_data->height = 144;
- konicawc_data->width = 176;
- konicawc_data->size = SIZE_176X144;
+ cam->height = 144;
+ cam->width = 176;
+ cam->size = SIZE_176X144;
break;
case SIZE_320X240:
- konicawc_data->height = 240;
- konicawc_data->width = 320;
- konicawc_data->size = SIZE_320X240;
+ cam->height = 240;
+ cam->width = 320;
+ cam->size = SIZE_320X240;
break;
}
@@ -663,14 +712,14 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const st
uvd->iso_packet_len = maxPS;
uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
- uvd->canvas = VIDEOSIZE(konicawc_data->width, konicawc_data->height);
+ uvd->canvas = VIDEOSIZE(cam->width, cam->height);
uvd->videosize = uvd->canvas;
/* Initialize konicawc specific data */
konicawc_configure_video(uvd);
i = usbvideo_RegisterVideoDevice(uvd);
- uvd->max_frame_size = (konicawc_data->width * konicawc_data->height * 3)/2;
+ uvd->max_frame_size = (cam->width * cam->height * 3)/2;
if (i != 0) {
err("usbvideo_RegisterVideoDevice() failed.");
uvd = NULL;
@@ -681,9 +730,28 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const st
}
+static void konicawc_free_uvd(uvd_t *uvd)
+{
+ int i;
+ struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ usb_free_urb(cam->sts_urb[i]);
+ cam->sts_urb[i] = NULL;
+ }
+}
+
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+ { } /* Terminating entry */
+};
+
+
static int __init konicawc_init(void)
{
usbvideo_cb_t cbTbl;
+ info(DRIVER_DESC " " DRIVER_VERSION);
memset(&cbTbl, 0, sizeof(cbTbl));
cbTbl.probe = konicawc_probe;
cbTbl.setupOnOpen = konicawc_setup_on_open;
@@ -691,6 +759,8 @@ static int __init konicawc_init(void)
cbTbl.getFPS = konicawc_calculate_fps;
cbTbl.startDataPump = konicawc_start_data;
cbTbl.stopDataPump = konicawc_stop_data;
+ cbTbl.adjustPicture = konicawc_adjust_picture;
+ cbTbl.userFree = konicawc_free_uvd;
return usbvideo_register(
&cams,
MAX_CAMERAS,
@@ -706,19 +776,14 @@ static void __exit konicawc_cleanup(void)
usbvideo_Deregister(&cams);
}
-#if defined(usb_device_id_ver)
-
-static __devinitdata struct usb_device_id id_table[] = {
- { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
- { } /* Terminating entry */
-};
MODULE_DEVICE_TABLE(usb, id_table);
-#endif /* defined(usb_device_id_ver) */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION("Konica Webcam driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(speed, "i");
+MODULE_PARM_DESC(speed, "FPS speed: 0 (slowest) - 6 (fastest)");
MODULE_PARM(size, "i");
MODULE_PARM_DESC(size, "Frame Size 0: 160x136 1: 176x144 2: 320x240");
MODULE_PARM(brightness, "i");
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 841855aef80b..b88a05e5b19b 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -59,7 +59,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_VERSION "v0.5.2 (2002/03/21)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
@@ -487,10 +487,10 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
pegasus_t *pegasus = dev->priv;
- if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) )
- return 1;
- if ( !(bmsr & 0x20) && !loopback )
- warn( "%s: link NOT established (0x%x) - check the cable.",
+ read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+ read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+ if ( !(bmsr & 4) && !loopback )
+ warn( "%s: link NOT established (%04x) - check the cable.",
dev->name, bmsr );
if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
return 2;
@@ -741,6 +741,7 @@ static int pegasus_open(struct net_device *net)
pegasus_t *pegasus = (pegasus_t *)net->priv;
int res;
+ down(&pegasus->sem);
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
@@ -759,11 +760,15 @@ static int pegasus_open(struct net_device *net)
pegasus->flags |= PEGASUS_RUNNING;
if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
err("can't enable_net_traffic() - %d", res);
- return -EIO;
+ res = -EIO;
+ goto exit;
}
set_carrier(net);
+ res = 0;
+exit:
+ up(&pegasus->sem);
- return 0;
+ return res;
}
@@ -771,6 +776,7 @@ static int pegasus_close( struct net_device *net )
{
pegasus_t *pegasus = net->priv;
+ down(&pegasus->sem);
pegasus->flags &= ~PEGASUS_RUNNING;
netif_stop_queue( net );
if ( !(pegasus->flags & PEGASUS_UNPLUG) )
@@ -782,6 +788,7 @@ static int pegasus_close( struct net_device *net )
#ifdef PEGASUS_USE_INTR
usb_unlink_urb( pegasus->intr_urb );
#endif
+ up(&pegasus->sem);
return 0;
}
@@ -868,23 +875,32 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{
__u16 *data = (__u16 *)&rq->ifr_data;
pegasus_t *pegasus = net->priv;
+ int res;
+ down(&pegasus->sem);
switch(cmd) {
case SIOCETHTOOL:
- return pegasus_ethtool_ioctl(net, rq->ifr_data);
+ res = pegasus_ethtool_ioctl(net, rq->ifr_data);
+ break;
case SIOCDEVPRIVATE:
data[0] = pegasus->phy;
case SIOCDEVPRIVATE+1:
read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
- return 0;
+ res = 0;
+ break;
case SIOCDEVPRIVATE+2:
- if ( !capable(CAP_NET_ADMIN) )
+ if ( !capable(CAP_NET_ADMIN) ) {
+ up(&pegasus->sem);
return -EPERM;
+ }
write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
- return 0;
+ res = 0;
+ break;
default:
- return -EOPNOTSUPP;
+ res = -EOPNOTSUPP;
}
+ up(&pegasus->sem);
+ return res;
}
@@ -953,7 +969,6 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
err("usb_set_configuration() failed");
return NULL;
}
-
if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
err("out of memory allocating device structure");
return NULL;
@@ -997,9 +1012,11 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb);
kfree( pegasus );
- return NULL;
+ return NULL;
}
-
+
+ init_MUTEX(&pegasus->sem);
+ down(&pegasus->sem);
pegasus->usb = dev;
pegasus->net = net;
SET_MODULE_OWNER(net);
@@ -1027,7 +1044,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
- return NULL;
+ goto exit;
}
info( "%s: %s", net->name, usb_dev_id[dev_index].name );
@@ -1044,7 +1061,8 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
warn( "can't locate MII phy, using default" );
pegasus->phy = 1;
}
-
+exit:
+ up(&pegasus->sem);
return pegasus;
}
diff --git a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
index 0e56ce1c41b5..a43894d5fb94 100644
--- a/drivers/usb/pegasus.h
+++ b/drivers/usb/pegasus.h
@@ -101,7 +101,7 @@ typedef struct pegasus {
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
- struct semaphore ctrl_sem;
+ struct semaphore sem;
unsigned char rx_buff[PEGASUS_MAX_MTU];
unsigned char tx_buff[PEGASUS_MAX_MTU];
unsigned char intr_buff[8];
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 00ea80dfca00..c3ac522ea24e 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -193,7 +193,14 @@ static struct quirk_printer_struct quirk_printers[] = {
{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+ { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
+ { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */
+ { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */
+ { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
+ { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
+ { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
+ { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
{ 0, 0 }
};
diff --git a/drivers/usb/rtl8150.c b/drivers/usb/rtl8150.c
new file mode 100644
index 000000000000..6427c5ceee31
--- /dev/null
+++ b/drivers/usb/rtl8150.c
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.5.0 (2002/03/28)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
+#define DRIVER_DESC "rtl8150 based usb-ethernet driver"
+
+
+#define IRD 0x0120
+#define MAR 0x0126
+#define CR 0x012e
+#define TCR 0x012f
+#define RCR 0x0130
+#define TSR 0x0132
+#define RSR 0x0133
+#define CON0 0x0135
+#define CON1 0x0136
+#define MSR 0x0137
+#define PHYADD 0x0138
+#define PHYDAT 0x0139
+#define PHYCNT 0x013b
+#define GPPC 0x013d
+#define BMCR 0x0140
+#define BMSR 0x0142
+#define ANAR 0x0144
+#define ANLP 0x0146
+#define AER 0x0148
+
+#define PHY_READ 0
+#define PHY_WRITE 0x20
+#define PHY_GO 0x40
+
+#define RTL8150_REQT_READ 0xc0
+#define RTL8150_REQT_WRITE 0x40
+#define RTL8150_REQ_GET_REGS 0x05
+#define RTL8150_REQ_SET_REGS 0x05
+
+#define RTL8150_MTU 1500
+#define RTL8150_MAX_MTU 1536
+
+#define RTL8150_TX_TIMEOUT (HZ)
+
+/* rtl8150 flags */
+#define RTL8150_FLAG_HWCRC 0
+#define RX_REG_SET 1
+#define RTL8150_UNPLUG 2
+
+
+/* Define these values to match your device */
+#define VENDOR_ID_REALTEK 0x0bda
+#define PRODUCT_ID_RTL8150 0x8150
+
+/* table of devices that work with this driver */
+static struct usb_device_id rtl8150_table [] = {
+ { USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
+ { }
+};
+
+MODULE_DEVICE_TABLE (usb, rtl8150_table);
+
+
+struct rtl8150 {
+ unsigned int flags;
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ struct semaphore sem;
+ struct net_device_stats stats;
+ struct net_device *netdev;
+ struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+ struct usb_ctrlrequest dr;
+ int intr_interval;
+ u16 rx_creg;
+ u8 rx_buff[RTL8150_MAX_MTU];
+ u8 tx_buff[RTL8150_MAX_MTU];
+ u8 intr_buff[8];
+ u8 phy;
+};
+
+typedef struct rtl8150 rtl8150_t;
+
+
+/* the global usb devfs handle */
+extern devfs_handle_t usb_devfs_handle;
+unsigned long multicast_filter_limit = 32;
+
+
+static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
+static void * rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id);
+
+
+static struct usb_driver rtl8150_driver = {
+ name: "rtl8150",
+ probe: rtl8150_probe,
+ disconnect: rtl8150_disconnect,
+ id_table: rtl8150_table,
+};
+
+
+
+/*
+**
+** device related part of the code
+**
+*/
+static int get_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+ return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev,0),
+ RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+ indx, 0, data, size, HZ/2);
+}
+
+
+static int set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev,0),
+ RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+ indx, 0, data, size, HZ/2);
+}
+
+
+static void ctrl_callback(struct urb *urb)
+{
+ rtl8150_t *dev;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ break;
+ case -ENOENT:
+ break;
+ default:
+ warn("ctrl urb status %d", urb->status);
+ }
+ dev = urb->context;
+ clear_bit(RX_REG_SET, &dev->flags);
+}
+
+
+static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+ int ret;
+
+ if (test_bit(RX_REG_SET, &dev->flags))
+ return -EAGAIN;
+
+ dev->dr.bRequestType = RTL8150_REQT_WRITE;
+ dev->dr.bRequest = RTL8150_REQ_SET_REGS;
+ dev->dr.wValue = cpu_to_le16(indx);
+ dev->dr.wIndex = 0;
+ dev->dr.wLength = cpu_to_le16(size);
+ dev->ctrl_urb->transfer_buffer_length = size;
+ FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
+ (char*)&dev->dr, &dev->rx_creg, size,
+ ctrl_callback, dev);
+ if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+ err("control request submission failed: %d", ret);
+ else
+ set_bit(RX_REG_SET, &dev->flags);
+
+ return ret;
+}
+
+
+static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
+{
+ int i;
+ u8 data[3], tmp;
+
+ data[0] = phy;
+ data[1] = data[2] = 0;
+ tmp = indx | PHY_READ | PHY_GO;
+ i = 0;
+
+ set_registers(dev, PHYADD, sizeof(data), data);
+ set_registers(dev, PHYCNT, 1, &tmp);
+ do {
+ get_registers(dev, PHYCNT, 1, data);
+ } while ((data[0] & PHY_GO) && (i++ < HZ));
+
+ if (i < HZ) {
+ get_registers(dev, PHYDAT, 2, data);
+ *reg = le16_to_cpup(data);
+ return 0;
+ } else
+ return 1;
+}
+
+
+static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
+{
+ int i;
+ u8 data[3], tmp;
+
+ data[0] = phy;
+ *(data + 1) = cpu_to_le16p(&reg);
+ tmp = indx | PHY_WRITE | PHY_GO;
+ i = 0;
+
+ set_registers(dev, PHYADD, sizeof(data), data);
+ set_registers(dev, PHYCNT, 1, &tmp);
+ do {
+ get_registers(dev, PHYCNT, 1, data);
+ } while((data[0] & PHY_GO) && (i++ < HZ));
+
+ if (i < HZ)
+ return 0;
+ else
+ return 1;
+}
+
+
+static inline void set_ethernet_addr(rtl8150_t *dev)
+{
+ u8 node_id[6];
+
+ get_registers(dev, IRD, sizeof(node_id), node_id);
+ memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+}
+
+
+static int rtl8150_reset(rtl8150_t *dev)
+{
+ u8 data=0x10;
+ int i=HZ;
+
+ set_registers(dev, CR, 1, &data);
+ do {
+ get_registers(dev, CR, 1, &data);
+ } while ((data & 0x10) && --i);
+
+ return (i > 0) ? 0 : -1;
+}
+
+
+static int alloc_all_urbs(rtl8150_t *dev)
+{
+ dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->rx_urb)
+ return 0;
+ dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->tx_urb) {
+ usb_free_urb(dev->rx_urb);
+ return 0;
+ }
+ dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->intr_urb) {
+ usb_free_urb(dev->rx_urb);
+ usb_free_urb(dev->tx_urb);
+ return 0;
+ }
+ dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->intr_urb) {
+ usb_free_urb(dev->rx_urb);
+ usb_free_urb(dev->tx_urb);
+ usb_free_urb(dev->intr_urb);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void free_all_urbs(rtl8150_t *dev)
+{
+ usb_free_urb(dev->rx_urb);
+ usb_free_urb(dev->tx_urb);
+ usb_free_urb(dev->intr_urb);
+ usb_free_urb(dev->ctrl_urb);
+}
+
+
+static void unlink_all_urbs(rtl8150_t *dev)
+{
+ usb_unlink_urb(dev->rx_urb);
+ usb_unlink_urb(dev->tx_urb);
+ usb_unlink_urb(dev->intr_urb);
+ usb_unlink_urb(dev->ctrl_urb);
+}
+
+
+static void read_bulk_callback(struct urb *urb)
+{
+ rtl8150_t *dev;
+ unsigned pkt_len, res;
+ struct sk_buff *skb;
+ struct net_device *netdev;
+ u16 rx_stat;
+
+ dev = urb->context;
+ if (!dev) {
+ warn("!dev");
+ return;
+ }
+ netdev = dev->netdev;
+ if (!netif_device_present(netdev)) {
+ warn("netdev is not present");
+ return;
+ }
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ return;
+ case -ETIMEDOUT:
+ warn("reset needed may be?..");
+ goto goon;
+ default:
+ warn("Rx status %d", urb->status);
+ goto goon;
+ }
+
+ res = urb->actual_length;
+ rx_stat = le16_to_cpu(*(short*)(dev->rx_buff + res - 4));
+ pkt_len = res - 4;
+
+ if (!(skb = dev_alloc_skb(pkt_len + 2)))
+ goto goon;
+ skb->dev = netdev;
+ skb_reserve(skb, 2);
+ eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0);
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+goon:
+ FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
+ dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+ if ((res=usb_submit_urb(dev->rx_urb, GFP_ATOMIC)))
+ warn("%s: Rx urb submission failed %d", netdev->name, res);
+}
+
+
+static void write_bulk_callback(struct urb *urb)
+{
+ rtl8150_t *dev;
+
+ dev = urb->context;
+ if (!dev)
+ return;
+ if (!netif_device_present(dev->netdev))
+ return;
+ if (urb->status)
+ info("%s: Tx status %d", dev->netdev->name, urb->status);
+ dev->netdev->trans_start = jiffies;
+ netif_wake_queue(dev->netdev);
+}
+
+
+void intr_callback(struct urb *urb)
+{
+ rtl8150_t *dev;
+
+ dev = urb->context;
+ if (!dev)
+ return;
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ return;
+ default:
+ info("%s: intr status %d", dev->netdev->name,
+ urb->status);
+ }
+}
+
+
+/*
+**
+** network related part of the code
+**
+*/
+
+
+static int enable_net_traffic(rtl8150_t *dev)
+{
+ u8 cr, tcr, rcr, msr;
+
+ if (rtl8150_reset(dev)) {
+ warn("%s - device reset failed", __FUNCTION__);
+ }
+ dev->rx_creg = rcr = 0x9e; /* bit7=1 attach Rx info at the end */
+ tcr = 0xd8; /* bit0=1 no CRC at the end of the frame */
+ cr = 0x0c;
+ set_registers(dev, RCR, 1, &rcr);
+ set_registers(dev, TCR, 1, &tcr);
+ set_registers(dev, CR, 1, &cr);
+ get_registers(dev, MSR, 1, &msr);
+
+ return 0;
+}
+
+
+static void disable_net_traffic(rtl8150_t *dev)
+{
+ u8 cr;
+
+ get_registers(dev, CR, 1, &cr);
+ cr &= 0xf3;
+ set_registers(dev, CR, 1, &cr);
+}
+
+
+static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
+{
+ return &((rtl8150_t *)dev->priv)->stats;
+}
+
+
+static void rtl8150_tx_timeout(struct net_device *netdev)
+{
+ rtl8150_t *dev;
+
+ dev = netdev->priv;
+ if (!dev)
+ return;
+ warn("%s: Tx timeout.", netdev->name);
+ dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb(dev->tx_urb);
+ dev->stats.tx_errors++;
+}
+
+
+static void rtl8150_set_multicast(struct net_device *netdev)
+{
+ rtl8150_t *dev;
+
+ dev = netdev->priv;
+ netif_stop_queue(netdev);
+ if (netdev->flags & IFF_PROMISC) {
+ dev->rx_creg |= 0x0001;
+ info("%s: promiscuous mode", netdev->name);
+ } else if ((netdev->mc_count > multicast_filter_limit) ||
+ (netdev->flags & IFF_ALLMULTI)) {
+ dev->rx_creg &= 0xfffe;
+ dev->rx_creg |= 0x0002;
+ info("%s: allmulti set", netdev->name);
+ } else {
+ /* ~RX_MULTICAST, ~RX_PROMISCUOUS */
+ dev->rx_creg &= 0x00fc;
+ }
+ async_set_registers(dev, RCR, 2, &dev->rx_creg);
+ netif_wake_queue(netdev);
+}
+
+
+static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ rtl8150_t *dev;
+ int count, res;
+
+ netif_stop_queue(netdev);
+ dev = netdev->priv;
+ count = (skb->len < 60) ? 60 : skb->len;
+ count = (count & 0x3f) ? count : count + 1;
+ memcpy(dev->tx_buff, skb->data, skb->len);
+ FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
+ dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
+ dev->tx_urb->transfer_buffer_length = count;
+
+ if ((res = usb_submit_urb(dev->tx_urb, GFP_KERNEL))) {
+ warn("failed tx_urb %d\n", res);
+ dev->stats.tx_errors++;
+ netif_start_queue(netdev);
+ } else {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ netdev->trans_start = jiffies;
+ }
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+
+static int rtl8150_open(struct net_device *netdev)
+{
+ rtl8150_t *dev;
+ int res;
+
+ dev = netdev->priv;
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ down(&dev->sem);
+ FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
+ dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+ if ((res=usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+ warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+ FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
+ dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
+ dev, dev->intr_interval);
+ if ((res=usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+ warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
+ netif_start_queue(netdev);
+ enable_net_traffic(dev);
+ up(&dev->sem);
+
+ return res;
+}
+
+
+static int rtl8150_close(struct net_device *netdev)
+{
+ rtl8150_t *dev;
+ int res = 0;
+
+ dev = netdev->priv;
+ if (!dev)
+ return -ENODEV;
+
+ down(&dev->sem);
+ if (!test_bit(RTL8150_UNPLUG, &dev->flags))
+ disable_net_traffic(dev);
+ unlink_all_urbs(dev);
+ netif_stop_queue(netdev);
+ up(&dev->sem);
+
+
+ return res;
+}
+
+
+static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
+{
+ rtl8150_t *dev;
+ int cmd;
+ char tmp[128];
+
+ dev = netdev->priv;
+ if (get_user(cmd, (int *)uaddr))
+ return -EFAULT;
+
+ switch (cmd) {
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+
+ strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+ strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+ sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
+ dev->udev->devnum);
+ strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+ if (copy_to_user(uaddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd;
+ short lpa, bmcr;
+
+ if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+ return -EFAULT;
+ ecmd.supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP |
+ SUPPORTED_MII);
+ ecmd.port = PORT_TP;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = dev->phy;
+ get_registers(dev, BMCR, 2, &bmcr);
+ get_registers(dev, ANLP, 2, &lpa);
+ if (bmcr & BMCR_ANENABLE) {
+ ecmd.autoneg = AUTONEG_ENABLE;
+ ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
+ SPEED_100 : SPEED_10;
+ if (ecmd.speed == SPEED_100)
+ ecmd.duplex = (lpa & LPA_100FULL) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ else
+ ecmd.duplex = (lpa & LPA_10FULL) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed = (bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10;
+ ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+ }
+ case ETHTOOL_SSET:
+ return -ENOTSUPP;
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+
+ edata.data = netif_carrier_ok(netdev);
+ if (copy_to_user(uaddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ rtl8150_t *dev;
+ u16 *data;
+ int res;
+
+ dev = netdev->priv;
+ data = (u16 *)&rq->ifr_data;
+ res = 0;
+
+ down(&dev->sem);
+ switch (cmd) {
+ case SIOCETHTOOL:
+ res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
+ break;
+ case SIOCDEVPRIVATE:
+ data[0] = dev->phy;
+ case SIOCDEVPRIVATE+1:
+ read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
+ break;
+ case SIOCDEVPRIVATE+2:
+ if (!capable(CAP_NET_ADMIN)) {
+ up(&dev->sem);
+ return -EPERM;
+ }
+ write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
+ break;
+ default:
+ res = -EOPNOTSUPP;
+ }
+ up(&dev->sem);
+ return res;
+}
+
+
+static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ rtl8150_t *dev;
+ struct net_device *netdev;
+
+ udev->config[0].bConfigurationValue = 1;
+ if (usb_set_configuration(udev, udev->config[0].bConfigurationValue)) {
+ err("usb_set_configuration() failed");
+ return NULL;
+ }
+ if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
+ (udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
+ err("Not the one we are interested about");
+ return NULL;
+ }
+ dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
+ if (!dev) {
+ err ("Out of memory");
+ goto exit;
+ } else
+ memset(dev, 0, sizeof(rtl8150_t));
+
+ netdev = init_etherdev(NULL, 0);
+ if (!netdev) {
+ kfree(dev);
+ err("Oh boy, out of memory again?!?");
+ dev = NULL;
+ goto exit;
+ }
+
+ init_MUTEX(&dev->sem);
+ dev->udev = udev;
+ dev->netdev = netdev;
+ SET_MODULE_OWNER(netdev);
+ netdev->priv = dev;
+ netdev->open = rtl8150_open;
+ netdev->stop = rtl8150_close;
+ netdev->do_ioctl = rtl8150_ioctl;
+ netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
+ netdev->tx_timeout = rtl8150_tx_timeout;
+ netdev->hard_start_xmit = rtl8150_start_xmit;
+ netdev->set_multicast_list = rtl8150_set_multicast;
+ netdev->get_stats = rtl8150_netdev_stats;
+ netdev->mtu = RTL8150_MTU;
+ dev->intr_interval = 100; /* 100ms */
+
+ if (rtl8150_reset(dev) || !alloc_all_urbs(dev)) {
+ err("couldn't reset the device");
+ free_all_urbs(dev);
+ unregister_netdev(dev->netdev);
+ kfree(netdev);
+ kfree(dev);
+ dev = NULL;
+ goto exit;
+ }
+
+ set_ethernet_addr(dev);
+ info("%s: rtl8150 is detected", netdev->name);
+exit:
+ return dev;
+}
+
+
+static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
+{
+ rtl8150_t *dev;
+
+ dev = ptr;
+ set_bit(RTL8150_UNPLUG, &dev->flags);
+ unregister_netdev(dev->netdev);
+ unlink_all_urbs(dev);
+ free_all_urbs(dev);
+ kfree(dev->netdev);
+ kfree(dev);
+ dev->netdev = NULL;
+ dev = NULL;
+}
+
+
+
+static int __init usb_rtl8150_init(void)
+{
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ return usb_register(&rtl8150_driver);
+}
+
+
+static void __exit usb_rtl8150_exit(void)
+{
+ usb_deregister(&rtl8150_driver);
+}
+
+
+module_init(usb_rtl8150_init);
+module_exit(usb_rtl8150_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/Config.help b/drivers/usb/serial/Config.help
index 4e314e8104cf..550917a7aa1d 100644
--- a/drivers/usb/serial/Config.help
+++ b/drivers/usb/serial/Config.help
@@ -12,6 +12,26 @@ CONFIG_USB_SERIAL
The module will be called usbserial.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_USB_SERIAL_CONSOLE
+ If you say Y here, it will be possible to use a USB to serial
+ converter port as the system console (the system console is the
+ device which receives all kernel messages and warnings and which
+ allows logins in single user mode). This could be useful if some
+ terminal or printer is connected to that serial port.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyUSB0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+ If you don't have a VGA card installed and you say Y here, the
+ kernel will automatically use the first USB to serial converter
+ port, /dev/ttyUSB0, as system console.
+
+ If unsure, say N.
+
CONFIG_USB_SERIAL_GENERIC
Say Y here if you want to use the generic USB serial driver. Please
read <file:Documentation/usb/usb-serial.txt> for more information on
diff --git a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in
index 9969fc0d72d3..2686c0aac7fb 100644
--- a/drivers/usb/serial/Config.in
+++ b/drivers/usb/serial/Config.in
@@ -7,19 +7,20 @@ comment 'USB Serial Converter support'
dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
if [ "$CONFIG_USB_SERIAL" = "y" ]; then
dep_mbool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
+ dep_mbool ' USB Serial Console device support (EXPERIMENTAL)' CONFIG_USB_SERIAL_CONSOLE $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
fi
dep_mbool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
-dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB Belkin and Peracom Single Port Serial Driver' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
+dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
-dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB Empeg empeg-car Mark I/II Driver' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL
dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
dep_tristate ' USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB Inside Out Edgeport Serial Driver' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL
+dep_tristate ' USB Keyspan PDA Single Port Serial Driver' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
+dep_tristate ' USB Keyspan USA-xxx Serial Driver' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
dep_mbool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN
dep_mbool ' USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X $CONFIG_USB_SERIAL_KEYSPAN
dep_mbool ' USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA $CONFIG_USB_SERIAL_KEYSPAN
@@ -28,11 +29,13 @@ dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SER
dep_mbool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X $CONFIG_USB_SERIAL_KEYSPAN
dep_mbool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
dep_mbool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
-dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
+dep_tristate ' USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
+dep_tristate ' USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+ dep_mbool ' USB Secure Encapsulated Driver - Padded (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE_PADDED $CONFIG_USB_SERIAL_SAFE
dep_tristate ' USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB Xircom / Entregra Single Port Serial Driver' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
endmenu
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 90c3dedcb0db..950472988280 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
+obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
# Objects that export symbols.
export-objs := usbserial.o
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 86683cc20c69..8cf592ba8fd7 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -191,9 +191,6 @@ static void belkin_sa_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- belkin_sa_close (&serial->port[i], NULL);
- }
/* My special items, the standard routines free my urbs */
if (serial->port[i].private)
kfree(serial->port[i].private);
@@ -207,26 +204,22 @@ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__" port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- /*Start reading from the device*/
- /* TODO: Look at possibility of submitting mulitple URBs to device to
- * enhance buffering. Win trace shows 16 initial read URBs.
- */
- port->read_urb->dev = port->serial->dev;
- retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (retval) {
- err("usb_submit_urb(read bulk) failed");
- goto exit;
- }
-
- port->interrupt_in_urb->dev = port->serial->dev;
- retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (retval)
- err(" usb_submit_urb(read int) failed");
+ /*Start reading from the device*/
+ /* TODO: Look at possibility of submitting mulitple URBs to device to
+ * enhance buffering. Win trace shows 16 initial read URBs.
+ */
+ port->read_urb->dev = port->serial->dev;
+ retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (retval) {
+ err("usb_submit_urb(read bulk) failed");
+ goto exit;
}
-
+
+ port->interrupt_in_urb->dev = port->serial->dev;
+ retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (retval)
+ err(" usb_submit_urb(read int) failed");
+
exit:
return retval;
} /* belkin_sa_open */
@@ -245,16 +238,11 @@ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__" port %d", port->number);
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
- }
- port->open_count = 0;
+ if (serial->dev) {
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
}
} /* belkin_sa_close */
@@ -336,12 +324,31 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
{
struct usb_serial *serial = port->serial;
struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
- unsigned int iflag = port->tty->termios->c_iflag;
- unsigned int cflag = port->tty->termios->c_cflag;
- unsigned int old_iflag = old_termios->c_iflag;
- unsigned int old_cflag = old_termios->c_cflag;
+ unsigned int iflag;
+ unsigned int cflag;
+ unsigned int old_iflag = 0;
+ unsigned int old_cflag = 0;
__u16 urb_value = 0; /* Will hold the new flags */
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg ("%s - no tty or termios structure", __FUNCTION__);
+ return;
+ }
+
+ iflag = port->tty->termios->c_iflag;
+ cflag = port->tty->termios->c_cflag;
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s - nothing to change...", __FUNCTION__);
+ return;
+ }
+ old_iflag = old_termios->c_iflag;
+ old_cflag = old_termios->c_cflag;
+ }
+
/* Set the baud rate */
if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
/* reassert DTR and (maybe) RTS on transition from B0 */
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 812726b110fa..e6a633756f76 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -130,11 +130,7 @@ static void cyberjack_shutdown (struct usb_serial *serial)
dbg (__FUNCTION__);
- /* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- cyberjack_close (&serial->port[i], NULL);
- }
/* My special items, the standard routines free my urbs */
if (serial->port[i].private)
kfree(serial->port[i].private);
@@ -151,31 +147,27 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number);
- ++port->open_count;
+ /* force low_latency on so that our tty_push actually forces
+ * the data through, otherwise it is scheduled, and with high
+ * data rates (like with OHCI) data can get lost.
+ */
+ port->tty->low_latency = 1;
- if (port->open_count == 1) {
- /* force low_latency on so that our tty_push actually forces
- * the data through, otherwise it is scheduled, and with high
- * data rates (like with OHCI) data can get lost.
- */
- port->tty->low_latency = 1;
+ priv = (struct cyberjack_private *)port->private;
+ priv->rdtodo = 0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
- priv = (struct cyberjack_private *)port->private;
- priv->rdtodo = 0;
- priv->wrfilled = 0;
- priv->wrsent = 0;
+ /* shutdown any bulk reads that might be going on */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
- /* shutdown any bulk reads that might be going on */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
-
- port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (result)
- err(" usb_submit_urb(read int) failed");
- dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
- }
+ port->interrupt_in_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (result)
+ err(" usb_submit_urb(read int) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
return result;
}
@@ -184,16 +176,11 @@ static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
{
dbg(__FUNCTION__ " - port %d", port->number);
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (port->serial->dev) {
- /* shutdown any bulk reads that might be going on */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
- }
- port->open_count = 0;
+ if (port->serial->dev) {
+ /* shutdown any bulk reads that might be going on */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
}
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index a03c9b4a9a1d..5702d26c5b30 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1490,28 +1490,17 @@ dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_cou
return( -EAGAIN );
}
- /* inc module use count before sleeping to wait for closes */
- ++port->open_count;
-
/* wait for a close in progress to finish */
while( priv->dp_in_close ) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
if( signal_pending(current) ) {
- --port->open_count;
return( -EINTR );
}
spin_lock_irqsave( &priv->dp_port_lock, flags );
}
- /* if port is already open, just return */
- /* be sure exactly one open proceeds */
- if( port->open_count != 1) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( 0 );
- }
-
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
/* read modem signals automatically whenever they change */
@@ -1557,14 +1546,6 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
/* do cleanup only after final close on this port */
spin_lock_irqsave( &priv->dp_port_lock, flags );
- if( port->open_count > 1 ) {
- --port->open_count;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return;
- } else if( port->open_count <= 0 ) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return;
- }
priv->dp_in_close = 1;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
@@ -1637,7 +1618,6 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
spin_lock_irqsave( &priv->dp_port_lock, flags );
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
- --port->open_count;
wake_up_interruptible( &priv->dp_close_wait );
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
@@ -1765,8 +1745,6 @@ static void digi_shutdown( struct usb_serial *serial )
{
int i;
- struct digi_port *priv;
- unsigned long flags;
dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
@@ -1777,16 +1755,6 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
usb_unlink_urb( serial->port[i].write_urb );
}
- /* dec module use count */
- for( i=0; i<serial->type->num_ports; i++ ) {
- priv = serial->port[i].private;
- spin_lock_irqsave( &priv->dp_port_lock, flags );
- while( serial->port[i].open_count > 0 ) {
- --serial->port[i].open_count;
- }
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- }
-
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
for( i=0; i<serial->type->num_ports+1; i++ )
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index fa390d5c32cc..9678076c1cd8 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -157,35 +157,29 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number);
- ++port->open_count;
+ /* Force default termio settings */
+ empeg_set_termios (port, NULL) ;
- if (port->open_count == 1) {
+ bytes_in = 0;
+ bytes_out = 0;
- /* Force default termio settings */
- empeg_set_termios (port, NULL) ;
-
- bytes_in = 0;
- bytes_out = 0;
-
- /* Start reading from the device */
- FILL_BULK_URB(
- port->read_urb,
- serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- empeg_read_bulk_callback,
- port);
-
- port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+ /* Start reading from the device */
+ FILL_BULK_URB(
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ empeg_read_bulk_callback,
+ port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
- if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- }
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
return result;
}
@@ -204,16 +198,10 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp)
if (!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* shutdown our bulk read */
- usb_unlink_urb (port->read_urb);
- }
- port->open_count = 0;
+ if (serial->dev) {
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
}
-
/* Uncomment the following line if you want to see some statistics in your syslog */
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
}
@@ -491,17 +479,7 @@ static int empeg_startup (struct usb_serial *serial)
static void empeg_shutdown (struct usb_serial *serial)
{
- int i;
-
dbg (__FUNCTION__);
-
- /* stop reads and writes on all ports */
- for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- empeg_close (&serial->port[i], NULL);
- }
- }
-
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index fc07f8f67835..01563bff129e 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -294,14 +294,8 @@ static int ftdi_8U232AM_startup (struct usb_serial *serial)
static void ftdi_sio_shutdown (struct usb_serial *serial)
{
-
dbg (__FUNCTION__);
-
- /* stop reads and writes on all ports */
- while (serial->port[0].open_count > 0) {
- ftdi_sio_close (&serial->port[0], NULL);
- }
if (serial->port[0].private){
kfree(serial->port[0].private);
serial->port[0].private = NULL;
@@ -319,45 +313,41 @@ static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__);
- ++port->open_count;
+ /* This will push the characters through immediately rather
+ than queue a task to deliver them */
+ port->tty->low_latency = 1;
- if (port->open_count == 1){
- /* This will push the characters through immediately rather
- than queue a task to deliver them */
- port->tty->low_latency = 1;
+ /* No error checking for this (will get errors later anyway) */
+ /* See ftdi_sio.h for description of what is reset */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
+ 0, buf, 0, WDR_TIMEOUT);
- /* No error checking for this (will get errors later anyway) */
- /* See ftdi_sio.h for description of what is reset */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_SIO,
- 0, buf, 0, WDR_TIMEOUT);
+ /* Setup termios defaults. According to tty_io.c the
+ settings are driver specific */
+ port->tty->termios->c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- /* Setup termios defaults. According to tty_io.c the
- settings are driver specific */
- port->tty->termios->c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ /* ftdi_sio_set_termios will send usb control messages */
+ ftdi_sio_set_termios(port, &tmp_termios);
- /* ftdi_sio_set_termios will send usb control messages */
- ftdi_sio_set_termios(port, &tmp_termios);
-
- /* Turn on RTS and DTR since we are not flow controlling by default */
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
- err(__FUNCTION__ " Error from DTR HIGH urb");
- }
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
- err(__FUNCTION__ " Error from RTS HIGH urb");
- }
-
- /* Start reading from the device */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ftdi_sio_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ /* Turn on RTS and DTR since we are not flow controlling by default */
+ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+ err(__FUNCTION__ " Error from DTR HIGH urb");
}
+ if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+ err(__FUNCTION__ " Error from RTS HIGH urb");
+ }
+
+ /* Start reading from the device */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ftdi_sio_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
return result;
} /* ftdi_sio_open */
@@ -371,41 +361,31 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
dbg( __FUNCTION__);
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- if (c_cflag & HUPCL){
- /* Disable flow control */
- if (usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
- FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, 0, buf, 0, WDR_TIMEOUT) < 0) {
- err("error from flowcontrol urb");
- }
-
- /* drop DTR */
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
- err("Error from DTR LOW urb");
- }
- /* drop RTS */
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
- err("Error from RTS LOW urb");
- }
- } /* Note change no line is hupcl is off */
-
- /* shutdown our bulk reads and writes */
- /* ***CHECK*** behaviour when there is nothing queued */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- }
- port->open_count = 0;
- } else {
- /* Send a HUP if necessary */
- if (!(port->tty->termios->c_cflag & CLOCAL)){
- tty_hangup(port->tty);
- }
+ if (serial->dev) {
+ if (c_cflag & HUPCL){
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0, buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+ }
+
+ /* drop DTR */
+ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+ err("Error from DTR LOW urb");
+ }
+ /* drop RTS */
+ if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+ err("Error from RTS LOW urb");
+ }
+ } /* Note change no line is hupcl is off */
+
+ /* shutdown our bulk reads and writes */
+ /* ***CHECK*** behaviour when there is nothing queued */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
}
} /* ftdi_sio_close */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 393fbafd21e2..e4737b967ce1 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -274,7 +274,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -811,7 +811,8 @@ static void edge_interrupt_callback (struct urb *urb)
dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits);
/* tell the tty driver that something has changed */
- wake_up_interruptible(&edge_port->port->tty->write_wait);
+ if (edge_port->port->tty)
+ wake_up_interruptible(&edge_port->port->tty->write_wait);
// Since we have more credit, check if more data can be sent
send_more_port_data(edge_serial, edge_port);
@@ -898,13 +899,15 @@ static void edge_bulk_out_data_callback (struct urb *urb)
tty = edge_port->port->tty;
- /* let the tty driver wakeup if it has a special write_wakeup function */
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
- (tty->ldisc.write_wakeup)(tty);
- }
+ if (tty) {
+ /* let the tty driver wakeup if it has a special write_wakeup function */
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+ (tty->ldisc.write_wakeup)(tty);
+ }
- /* tell the tty driver that something has changed */
- wake_up_interruptible(&tty->write_wait);
+ /* tell the tty driver that something has changed */
+ wake_up_interruptible(&tty->write_wait);
+ }
// Release the Write URB
edge_port->write_in_progress = FALSE;
@@ -953,7 +956,8 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
tty = edge_port->port->tty;
/* tell the tty driver that something has changed */
- wake_up_interruptible(&tty->write_wait);
+ if (tty)
+ wake_up_interruptible(&tty->write_wait);
/* we have completed the command */
edge_port->commandPending = FALSE;
@@ -987,124 +991,118 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
if (edge_port == NULL)
return -ENODEV;
- ++port->open_count;
-
- if (port->open_count == 1) {
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
+ /* force low_latency on so that our tty_push actually forces the data through,
+ otherwise it is scheduled, and with high data rates (like with OHCI) data
+ can get lost. */
+ if (port->tty)
port->tty->low_latency = 1;
+
+ /* see if we've set up our endpoint info yet (can't set it up in edge_startup
+ as the structures were not set up at that time.) */
+ serial = port->serial;
+ edge_serial = (struct edgeport_serial *)serial->private;
+ if (edge_serial == NULL) {
+ return -ENODEV;
+ }
+ if (edge_serial->interrupt_in_buffer == NULL) {
+ struct usb_serial_port *port0 = &serial->port[0];
+
+ /* not set up yet, so do it now */
+ edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
+ edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
+ edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
+ edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
+ edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
+ edge_serial->read_urb = port0->read_urb;
+ edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
- /* see if we've set up our endpoint info yet (can't set it up in edge_startup
- as the structures were not set up at that time.) */
- serial = port->serial;
- edge_serial = (struct edgeport_serial *)serial->private;
- if (edge_serial == NULL) {
- port->open_count = 0;
- return -ENODEV;
- }
- if (edge_serial->interrupt_in_buffer == NULL) {
- struct usb_serial_port *port0 = &serial->port[0];
-
- /* not set up yet, so do it now */
- edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
- edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
- edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
- edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
- edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
- edge_serial->read_urb = port0->read_urb;
- edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
+ /* set up our interrupt urb */
+ FILL_INT_URB(edge_serial->interrupt_read_urb,
+ serial->dev,
+ usb_rcvintpipe(serial->dev,
+ port0->interrupt_in_endpointAddress),
+ port0->interrupt_in_buffer,
+ edge_serial->interrupt_read_urb->transfer_buffer_length,
+ edge_interrupt_callback, edge_serial,
+ edge_serial->interrupt_read_urb->interval);
- /* set up our interrupt urb */
- FILL_INT_URB(edge_serial->interrupt_read_urb,
- serial->dev,
- usb_rcvintpipe(serial->dev,
- port0->interrupt_in_endpointAddress),
- port0->interrupt_in_buffer,
- edge_serial->interrupt_read_urb->transfer_buffer_length,
- edge_interrupt_callback, edge_serial,
- edge_serial->interrupt_read_urb->interval);
-
- /* set up our bulk in urb */
- FILL_BULK_URB(edge_serial->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer,
- edge_serial->read_urb->transfer_buffer_length,
- edge_bulk_in_callback, edge_serial);
-
- /* start interrupt read for this edgeport
- * this interrupt will continue as long as the edgeport is connected */
- response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
- if (response) {
- err(__FUNCTION__" - Error %d submitting control urb", response);
- }
- }
-
- /* initialize our wait queues */
- init_waitqueue_head(&edge_port->wait_open);
- init_waitqueue_head(&edge_port->wait_chase);
- init_waitqueue_head(&edge_port->delta_msr_wait);
- init_waitqueue_head(&edge_port->wait_command);
-
- /* initialize our icount structure */
- memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
- /* initialize our port settings */
- edge_port->txCredits = 0; /* Can't send any data yet */
- edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */
- edge_port->chaseResponsePending = FALSE;
-
- /* send a open port command */
- edge_port->openPending = TRUE;
- edge_port->open = FALSE;
- response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
-
- if (response < 0) {
- err(__FUNCTION__" - error sending open port command");
- edge_port->openPending = FALSE;
- port->open_count = 0;
- return -ENODEV;
- }
-
- /* now wait for the port to be completly opened */
- timeout = OPEN_TIMEOUT;
- while (timeout && edge_port->openPending == TRUE) {
- timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
+ /* set up our bulk in urb */
+ FILL_BULK_URB(edge_serial->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
+ port0->bulk_in_buffer,
+ edge_serial->read_urb->transfer_buffer_length,
+ edge_bulk_in_callback, edge_serial);
+
+ /* start interrupt read for this edgeport
+ * this interrupt will continue as long as the edgeport is connected */
+ response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
+ if (response) {
+ err(__FUNCTION__" - Error %d submitting control urb", response);
}
+ }
+
+ /* initialize our wait queues */
+ init_waitqueue_head(&edge_port->wait_open);
+ init_waitqueue_head(&edge_port->wait_chase);
+ init_waitqueue_head(&edge_port->delta_msr_wait);
+ init_waitqueue_head(&edge_port->wait_command);
+
+ /* initialize our icount structure */
+ memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+
+ /* initialize our port settings */
+ edge_port->txCredits = 0; /* Can't send any data yet */
+ edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */
+ edge_port->chaseResponsePending = FALSE;
+
+ /* send a open port command */
+ edge_port->openPending = TRUE;
+ edge_port->open = FALSE;
+ response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
+
+ if (response < 0) {
+ err(__FUNCTION__" - error sending open port command");
+ edge_port->openPending = FALSE;
+ return -ENODEV;
+ }
- if (edge_port->open == FALSE) {
- /* open timed out */
- dbg(__FUNCTION__" - open timedout");
- edge_port->openPending = FALSE;
- port->open_count = 0;
- return -ENODEV;
- }
+ /* now wait for the port to be completly opened */
+ timeout = OPEN_TIMEOUT;
+ while (timeout && edge_port->openPending == TRUE) {
+ timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
+ }
- /* create the txfifo */
- edge_port->txfifo.head = 0;
- edge_port->txfifo.tail = 0;
- edge_port->txfifo.count = 0;
- edge_port->txfifo.size = edge_port->maxTxCredits;
- edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
+ if (edge_port->open == FALSE) {
+ /* open timed out */
+ dbg(__FUNCTION__" - open timedout");
+ edge_port->openPending = FALSE;
+ return -ENODEV;
+ }
- if (!edge_port->txfifo.fifo) {
- dbg(__FUNCTION__" - no memory");
- edge_close (port, filp);
- return -ENOMEM;
- }
+ /* create the txfifo */
+ edge_port->txfifo.head = 0;
+ edge_port->txfifo.tail = 0;
+ edge_port->txfifo.count = 0;
+ edge_port->txfifo.size = edge_port->maxTxCredits;
+ edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
- /* Allocate a URB for the write */
- edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+ if (!edge_port->txfifo.fifo) {
+ dbg(__FUNCTION__" - no memory");
+ edge_close (port, filp);
+ return -ENOMEM;
+ }
- if (!edge_port->write_urb) {
- dbg(__FUNCTION__" - no memory");
- edge_close (port, filp);
- return -ENOMEM;
- }
+ /* Allocate a URB for the write */
+ edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
- dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+ if (!edge_port->write_urb) {
+ dbg(__FUNCTION__" - no memory");
+ edge_close (port, filp);
+ return -ENOMEM;
}
+ dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+
dbg(__FUNCTION__" exited");
return 0;
@@ -1234,52 +1232,47 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
if ((edge_serial == NULL) || (edge_port == NULL))
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- // block until tx is empty
- block_until_tx_empty(edge_port);
+ if (serial->dev) {
+ // block until tx is empty
+ block_until_tx_empty(edge_port);
- edge_port->closePending = TRUE;
+ edge_port->closePending = TRUE;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
- dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
- }
+ dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
- /* close the port */
- dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
- send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ /* close the port */
+ dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
- //port->close = TRUE;
- edge_port->closePending = FALSE;
- edge_port->open = FALSE;
- edge_port->openPending = FALSE;
+ //port->close = TRUE;
+ edge_port->closePending = FALSE;
+ edge_port->open = FALSE;
+ edge_port->openPending = FALSE;
- if (edge_port->write_urb) {
- usb_unlink_urb (edge_port->write_urb);
- }
- }
-
if (edge_port->write_urb) {
- /* if this urb had a transfer buffer already (old transfer) free it */
- if (edge_port->write_urb->transfer_buffer != NULL) {
- kfree(edge_port->write_urb->transfer_buffer);
- }
- usb_free_urb (edge_port->write_urb);
+ usb_unlink_urb (edge_port->write_urb);
}
- if (edge_port->txfifo.fifo) {
- kfree(edge_port->txfifo.fifo);
+ }
+
+ if (edge_port->write_urb) {
+ /* if this urb had a transfer buffer already (old transfer) free it */
+ if (edge_port->write_urb->transfer_buffer != NULL) {
+ kfree(edge_port->write_urb->transfer_buffer);
}
- port->open_count = 0;
+ usb_free_urb (edge_port->write_urb);
+ }
+ if (edge_port->txfifo.fifo) {
+ kfree(edge_port->txfifo.fifo);
}
dbg(__FUNCTION__" exited");
@@ -1580,6 +1573,10 @@ static void edge_throttle (struct usb_serial_port *port)
}
tty = port->tty;
+ if (!tty) {
+ dbg ("%s - no tty available", __FUNCTION__);
+ return;
+ }
/* if we are implementing XON/XOFF, send the stop character */
if (I_IXOFF(tty)) {
@@ -1625,6 +1622,10 @@ static void edge_unthrottle (struct usb_serial_port *port)
}
tty = port->tty;
+ if (!tty) {
+ dbg ("%s - no tty available", __FUNCTION__);
+ return;
+ }
/* if we are implementing XON/XOFF, send the start character */
if (I_IXOFF(tty)) {
@@ -1656,15 +1657,14 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
{
struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
struct tty_struct *tty = port->tty;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag;
- dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x",
- tty->termios->c_cflag,
- old_termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag),
- RELEVANT_IFLAG(old_termios->c_iflag)
- );
+ if (!port->tty || !port->tty->termios) {
+ dbg ("%s - no tty or termios", __FUNCTION__);
+ return;
+ }
+ cflag = tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
@@ -1674,6 +1674,15 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
}
}
+ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ tty->termios->c_cflag,
+ RELEVANT_IFLAG(tty->termios->c_iflag));
+ if (old_termios) {
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag,
+ RELEVANT_IFLAG(old_termios->c_iflag));
+ }
+
dbg(__FUNCTION__" - port %d", port->number);
if (edge_port == NULL)
@@ -1721,6 +1730,9 @@ static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int
unsigned int result = 0;
struct tty_struct *tty = edge_port->port->tty;
+ if (!tty)
+ return -ENOIOCTLCMD;
+
result = tty->read_cnt;
dbg(__FUNCTION__"(%d) = %d", edge_port->port->number, result);
@@ -2148,7 +2160,8 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
handle_new_msr (edge_port, byte2);
/* send the current line settings to the port so we are in sync with any further termios calls */
- change_port_settings (edge_port, edge_port->port->tty->termios);
+ if (edge_port->port->tty)
+ change_port_settings (edge_port, edge_port->port->tty->termios);
/* we have completed the open */
edge_port->openPending = FALSE;
@@ -2259,7 +2272,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 l
}
/* Place LSR data byte into Rx buffer */
- if (lsrData) {
+ if (lsrData && edge_port->port->tty) {
tty_insert_flip_char(edge_port->port->tty, data, 0);
tty_flip_buffer_push(edge_port->port->tty);
}
@@ -3027,9 +3040,6 @@ static void edge_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- edge_close (&serial->port[i], NULL);
- }
kfree (serial->port[i].private);
serial->port[i].private = NULL;
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index c3e9c8791fa9..4530a54a1328 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -9,6 +9,10 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
+ * (19/3/2002) ganesh
+ * Don't submit urbs while holding spinlocks. Not strictly necessary
+ * in 2.5.x.
+ *
* (8/3/2002) ganesh
* The ipaq sometimes emits a '\0' before the CLIENT string. At this
* point of time, the ppp ldisc is not yet attached to the tty, so
@@ -65,7 +69,7 @@ static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigne
int count);
static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
int count);
-static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_write_gather(struct usb_serial_port *port);
static void ipaq_read_bulk_callback (struct urb *urb);
static void ipaq_write_bulk_callback(struct urb *urb);
static int ipaq_write_room(struct usb_serial_port *port);
@@ -119,93 +123,89 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- bytes_in = 0;
- bytes_out = 0;
- priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
- if (priv == NULL) {
- err(__FUNCTION__ " - Out of memory");
- return -ENOMEM;
+ bytes_in = 0;
+ bytes_out = 0;
+ priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+ if (priv == NULL) {
+ err(__FUNCTION__ " - Out of memory");
+ return -ENOMEM;
+ }
+ port->private = (void *)priv;
+ priv->active = 0;
+ priv->queue_len = 0;
+ INIT_LIST_HEAD(&priv->queue);
+ INIT_LIST_HEAD(&priv->freelist);
+
+ for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+ pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+ if (pkt == NULL) {
+ goto enomem;
}
- port->private = (void *)priv;
- priv->active = 0;
- priv->queue_len = 0;
- INIT_LIST_HEAD(&priv->queue);
- INIT_LIST_HEAD(&priv->freelist);
-
- for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
- pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
- if (pkt == NULL) {
- goto enomem;
- }
- pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
- if (pkt->data == NULL) {
- kfree(pkt);
- goto enomem;
- }
- pkt->len = 0;
- pkt->written = 0;
- INIT_LIST_HEAD(&pkt->list);
- list_add(&pkt->list, &priv->freelist);
- priv->free_len += PACKET_SIZE;
+ pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+ if (pkt->data == NULL) {
+ kfree(pkt);
+ goto enomem;
}
+ pkt->len = 0;
+ pkt->written = 0;
+ INIT_LIST_HEAD(&pkt->list);
+ list_add(&pkt->list, &priv->freelist);
+ priv->free_len += PACKET_SIZE;
+ }
- /*
- * Force low latency on. This will immediately push data to the line
- * discipline instead of queueing.
- */
+ /*
+ * Force low latency on. This will immediately push data to the line
+ * discipline instead of queueing.
+ */
- port->tty->low_latency = 1;
- port->tty->raw = 1;
- port->tty->real_raw = 1;
+ port->tty->low_latency = 1;
+ port->tty->raw = 1;
+ port->tty->real_raw = 1;
- /*
- * Lose the small buffers usbserial provides. Make larger ones.
- */
+ /*
+ * Lose the small buffers usbserial provides. Make larger ones.
+ */
+ kfree(port->bulk_in_buffer);
+ kfree(port->bulk_out_buffer);
+ port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+ if (port->bulk_in_buffer == NULL) {
+ goto enomem;
+ }
+ port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+ if (port->bulk_out_buffer == NULL) {
kfree(port->bulk_in_buffer);
- kfree(port->bulk_out_buffer);
- port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
- if (port->bulk_in_buffer == NULL) {
- goto enomem;
- }
- port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
- if (port->bulk_out_buffer == NULL) {
- kfree(port->bulk_in_buffer);
- goto enomem;
- }
- port->read_urb->transfer_buffer = port->bulk_in_buffer;
- port->write_urb->transfer_buffer = port->bulk_out_buffer;
- port->read_urb->transfer_buffer_length = URBDATA_SIZE;
- port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
-
- /* Start reading from the device */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ipaq_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
- }
+ goto enomem;
+ }
+ port->read_urb->transfer_buffer = port->bulk_in_buffer;
+ port->write_urb->transfer_buffer = port->bulk_out_buffer;
+ port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+ port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+
+ /* Start reading from the device */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ipaq_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ }
- /*
- * Send out two control messages observed in win98 sniffs. Not sure what
- * they do.
- */
+ /*
+ * Send out two control messages observed in win98 sniffs. Not sure what
+ * they do.
+ */
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
- 0x1, 0, NULL, 0, 5 * HZ);
- if (result < 0) {
- err(__FUNCTION__ " - failed doing control urb, error %d", result);
- }
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
- 0x1, 0, NULL, 0, 5 * HZ);
- if (result < 0) {
- err(__FUNCTION__ " - failed doing control urb, error %d", result);
- }
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+ 0x1, 0, NULL, 0, 5 * HZ);
+ if (result < 0) {
+ err(__FUNCTION__ " - failed doing control urb, error %d", result);
+ }
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+ 0x1, 0, NULL, 0, 5 * HZ);
+ if (result < 0) {
+ err(__FUNCTION__ " - failed doing control urb, error %d", result);
}
return result;
@@ -233,22 +233,16 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
if (!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
+ /*
+ * shut down bulk read and write
+ */
- /*
- * shut down bulk read and write
- */
-
- usb_unlink_urb(port->write_urb);
- usb_unlink_urb(port->read_urb);
- ipaq_destroy_lists(port);
- kfree(priv);
- port->private = NULL;
- port->open_count = 0;
+ usb_unlink_urb(port->write_urb);
+ usb_unlink_urb(port->read_urb);
+ ipaq_destroy_lists(port);
+ kfree(priv);
+ port->private = NULL;
- }
/* Uncomment the following line if you want to see some statistics in your syslog */
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
}
@@ -367,17 +361,23 @@ static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const un
priv->queue_len += count;
if (priv->active == 0) {
priv->active = 1;
- result = ipaq_write_flush(port);
+ ipaq_write_gather(port);
+ spin_unlock_irqrestore(&write_list_lock, flags);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ }
+ } else {
+ spin_unlock_irqrestore(&write_list_lock, flags);
}
- spin_unlock_irqrestore(&write_list_lock, flags);
return result;
}
-static int ipaq_write_flush(struct usb_serial_port *port)
+static void ipaq_write_gather(struct usb_serial_port *port)
{
struct ipaq_private *priv = (struct ipaq_private *)port->private;
struct usb_serial *serial = port->serial;
- int count, room, result;
+ int count, room;
struct ipaq_packet *pkt;
struct urb *urb = port->write_urb;
struct list_head *tmp;
@@ -385,7 +385,7 @@ static int ipaq_write_flush(struct usb_serial_port *port)
if (urb->status == -EINPROGRESS) {
/* Should never happen */
err(__FUNCTION__ " - flushing while urb is active !");
- return -EAGAIN;
+ return;
}
room = URBDATA_SIZE;
for (tmp = priv->queue.next; tmp != &priv->queue;) {
@@ -412,11 +412,7 @@ static int ipaq_write_flush(struct usb_serial_port *port)
usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
port);
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- err(__FUNCTION__ " - failed submitting write urb, error %d", result);
- }
- return result;
+ return;
}
static void ipaq_write_bulk_callback(struct urb *urb)
@@ -424,6 +420,7 @@ static void ipaq_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct ipaq_private *priv = (struct ipaq_private *)port->private;
unsigned long flags;
+ int result;
if (port_paranoia_check (port, __FUNCTION__)) {
return;
@@ -437,11 +434,16 @@ static void ipaq_write_bulk_callback(struct urb *urb)
spin_lock_irqsave(&write_list_lock, flags);
if (!list_empty(&priv->queue)) {
- ipaq_write_flush(port);
+ ipaq_write_gather(port);
+ spin_unlock_irqrestore(&write_list_lock, flags);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ }
} else {
priv->active = 0;
+ spin_unlock_irqrestore(&write_list_lock, flags);
}
- spin_unlock_irqrestore(&write_list_lock, flags);
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
@@ -495,16 +497,7 @@ static int ipaq_startup(struct usb_serial *serial)
static void ipaq_shutdown(struct usb_serial *serial)
{
- int i;
-
dbg (__FUNCTION__);
-
- /* stop reads and writes on all ports */
- for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- ipaq_close(&serial->port[i], NULL);
- }
- }
}
static int __init ipaq_init(void)
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 5a8f68918b67..07b3a6ddc56f 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -283,45 +283,42 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- if (buffer_size) {
- /* override the default buffer sizes */
- buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!buffer) {
- err ("%s - out of memory.", __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->read_urb->transfer_buffer);
- port->read_urb->transfer_buffer = buffer;
- port->read_urb->transfer_buffer_length = buffer_size;
-
- buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!buffer) {
- err ("%s - out of memory.", __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->write_urb->transfer_buffer);
- port->write_urb->transfer_buffer = buffer;
- port->write_urb->transfer_buffer_length = buffer_size;
- port->bulk_out_size = buffer_size;
+ if (buffer_size) {
+ /* override the default buffer sizes */
+ buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!buffer) {
+ err ("%s - out of memory.", __FUNCTION__);
+ return -ENOMEM;
}
-
- /* Start reading from the device */
- usb_fill_bulk_urb (
- port->read_urb,
- serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ir_read_bulk_callback,
- port);
- port->read_urb->transfer_flags = USB_QUEUE_BULK;
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ kfree (port->read_urb->transfer_buffer);
+ port->read_urb->transfer_buffer = buffer;
+ port->read_urb->transfer_buffer_length = buffer_size;
+
+ buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!buffer) {
+ err ("%s - out of memory.", __FUNCTION__);
+ return -ENOMEM;
+ }
+ kfree (port->write_urb->transfer_buffer);
+ port->write_urb->transfer_buffer = buffer;
+ port->write_urb->transfer_buffer_length = buffer_size;
+ port->bulk_out_size = buffer_size;
}
+
+ /* Start reading from the device */
+ usb_fill_bulk_urb (
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ ir_read_bulk_callback,
+ port);
+ port->read_urb->transfer_flags = USB_QUEUE_BULK;
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+
return result;
}
@@ -338,15 +335,9 @@ static void ir_close (struct usb_serial_port *port, struct file * filp)
if (!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* shutdown our bulk read */
- usb_unlink_urb (port->read_urb);
- }
- port->open_count = 0;
-
+ if (serial->dev) {
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
}
}
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 2879204149e1..766eebdc71b7 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -852,7 +852,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
struct keyspan_serial_private *s_priv;
struct usb_serial *serial = port->serial;
const struct keyspan_device_details *d_details;
- int i, already_active, err;
+ int i, err;
struct urb *urb;
s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -861,12 +861,6 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
dbg("keyspan_open called for port%d.\n", port->number);
- already_active = port->open_count;
- ++port->open_count;
-
- if (already_active)
- return 0;
-
p_priv = (struct keyspan_port_private *)(port->private);
/* Set some sane defaults */
@@ -924,19 +918,16 @@ static void keyspan_close(struct usb_serial_port *port, struct file *filp)
p_priv->out_flip = 0;
p_priv->in_flip = 0;
- if (--port->open_count <= 0) {
- if (serial->dev) {
- /* Stop reading/writing urbs */
- stop_urb(p_priv->inack_urb);
- stop_urb(p_priv->outcont_urb);
- for (i = 0; i < 2; i++) {
- stop_urb(p_priv->in_urbs[i]);
- stop_urb(p_priv->out_urbs[i]);
- }
+ if (serial->dev) {
+ /* Stop reading/writing urbs */
+ stop_urb(p_priv->inack_urb);
+ stop_urb(p_priv->outcont_urb);
+ for (i = 0; i < 2; i++) {
+ stop_urb(p_priv->in_urbs[i]);
+ stop_urb(p_priv->out_urbs[i]);
}
- port->open_count = 0;
- port->tty = 0;
}
+ port->tty = 0;
}
@@ -1762,9 +1753,6 @@ static void keyspan_shutdown (struct usb_serial *serial)
/* Now free per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = &serial->port[i];
- while (port->open_count > 0) {
- --port->open_count;
- }
kfree(port->private);
}
}
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 54b09b26e43c..8cfc17921efc 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -662,52 +662,45 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
int rc = 0;
struct keyspan_pda_private *priv;
- ++port->open_count;
-
- if (port->open_count == 1) {
- /* find out how much room is in the Tx ring */
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value */
- 0, /* index */
- &room,
- 1,
- 2*HZ);
- if (rc < 0) {
- dbg(__FUNCTION__" - roomquery failed");
- goto error;
- }
- if (rc == 0) {
- dbg(__FUNCTION__" - roomquery returned 0 bytes");
- rc = -EIO;
- goto error;
- }
- priv = (struct keyspan_pda_private *)(port->private);
- priv->tx_room = room;
- priv->tx_throttled = room ? 0 : 1;
-
- /* the normal serial device seems to always turn on DTR and RTS here,
- so do the same */
- if (port->tty->termios->c_cflag & CBAUD)
- keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
- else
- keyspan_pda_set_modem_info(serial, 0);
-
- /*Start reading from the device*/
- port->interrupt_in_urb->dev = serial->dev;
- rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (rc) {
- dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
- goto error;
- }
+ /* find out how much room is in the Tx ring */
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value */
+ 0, /* index */
+ &room,
+ 1,
+ 2*HZ);
+ if (rc < 0) {
+ dbg(__FUNCTION__" - roomquery failed");
+ goto error;
+ }
+ if (rc == 0) {
+ dbg(__FUNCTION__" - roomquery returned 0 bytes");
+ rc = -EIO;
+ goto error;
+ }
+ priv = (struct keyspan_pda_private *)(port->private);
+ priv->tx_room = room;
+ priv->tx_throttled = room ? 0 : 1;
+ /* the normal serial device seems to always turn on DTR and RTS here,
+ so do the same */
+ if (port->tty->termios->c_cflag & CBAUD)
+ keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+ else
+ keyspan_pda_set_modem_info(serial, 0);
+
+ /*Start reading from the device*/
+ port->interrupt_in_urb->dev = serial->dev;
+ rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (rc) {
+ dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
+ goto error;
}
- return rc;
error:
- --port->open_count;
return rc;
}
@@ -716,19 +709,14 @@ static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* the normal serial device seems to always shut off DTR and RTS now */
- if (port->tty->termios->c_cflag & HUPCL)
- keyspan_pda_set_modem_info(serial, 0);
+ if (serial->dev) {
+ /* the normal serial device seems to always shut off DTR and RTS now */
+ if (port->tty->termios->c_cflag & HUPCL)
+ keyspan_pda_set_modem_info(serial, 0);
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->interrupt_in_urb);
- }
- port->open_count = 0;
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
}
}
@@ -805,9 +793,6 @@ static void keyspan_pda_shutdown (struct usb_serial *serial)
{
dbg (__FUNCTION__);
- while (serial->port[0].open_count > 0) {
- keyspan_pda_close (&serial->port[0], NULL);
- }
kfree(serial->port[0].private);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5b0e1b944dcb..9a42dcc87b37 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -317,9 +317,6 @@ static void klsi_105_shutdown (struct usb_serial *serial)
struct klsi_105_private *priv =
(struct klsi_105_private*) serial->port[i].private;
unsigned long flags;
- while (serial->port[i].open_count > 0) {
- klsi_105_close (&serial->port[i], NULL);
- }
if (priv) {
/* kill our write urb pool */
@@ -355,85 +352,80 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
int retval = 0;
+ int rc;
+ int i;
+ unsigned long line_state;
dbg(__FUNCTION__" port %d", port->number);
- ++port->open_count;
+ /* force low_latency on so that our tty_push actually forces
+ * the data through
+ * port->tty->low_latency = 1; */
- if (port->open_count == 1) {
- int rc;
- int i;
- unsigned long line_state;
-
- /* force low_latency on so that our tty_push actually forces
- * the data through
- * port->tty->low_latency = 1; */
-
- /* Do a defined restart:
- * Set up sane default baud rate and send the 'READ_ON'
- * vendor command.
- * FIXME: set modem line control (how?)
- * Then read the modem line control and store values in
- * priv->line_state.
- */
- priv->cfg.pktlen = 5;
- priv->cfg.baudrate = kl5kusb105a_sio_b9600;
- priv->cfg.databits = kl5kusb105a_dtb_8;
- priv->cfg.unknown1 = 0;
- priv->cfg.unknown2 = 1;
- klsi_105_chg_port_settings(serial, &(priv->cfg));
-
- /* set up termios structure */
- priv->termios.c_iflag = port->tty->termios->c_iflag;
- priv->termios.c_oflag = port->tty->termios->c_oflag;
- priv->termios.c_cflag = port->tty->termios->c_cflag;
- priv->termios.c_lflag = port->tty->termios->c_lflag;
- for (i=0; i<NCCS; i++)
- priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
-
-
- /* READ_ON and urb submission */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- klsi_105_read_bulk_callback,
- port);
- port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+ /* Do a defined restart:
+ * Set up sane default baud rate and send the 'READ_ON'
+ * vendor command.
+ * FIXME: set modem line control (how?)
+ * Then read the modem line control and store values in
+ * priv->line_state.
+ */
+ priv->cfg.pktlen = 5;
+ priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+ priv->cfg.databits = kl5kusb105a_dtb_8;
+ priv->cfg.unknown1 = 0;
+ priv->cfg.unknown2 = 1;
+ klsi_105_chg_port_settings(serial, &(priv->cfg));
+
+ /* set up termios structure */
+ priv->termios.c_iflag = port->tty->termios->c_iflag;
+ priv->termios.c_oflag = port->tty->termios->c_oflag;
+ priv->termios.c_cflag = port->tty->termios->c_cflag;
+ priv->termios.c_lflag = port->tty->termios->c_lflag;
+ for (i=0; i<NCCS; i++)
+ priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
- rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (rc) {
- err(__FUNCTION__
- " - failed submitting read urb, error %d", rc);
- retval = rc;
- goto exit;
- }
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
- KL5KUSB105A_SIO_CONFIGURE_READ_ON,
- 0, /* index */
- NULL,
- 0,
- KLSI_TIMEOUT);
- if (rc < 0) {
- err("Enabling read failed (error = %d)", rc);
- retval = rc;
- } else
- dbg(__FUNCTION__ " - enabled reading");
+ /* READ_ON and urb submission */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ klsi_105_read_bulk_callback,
+ port);
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
- rc = klsi_105_get_line_state(serial, &line_state);
- if (rc >= 0) {
- priv->line_state = line_state;
- dbg(__FUNCTION__
- " - read line state 0x%lx", line_state);
- retval = 0;
- } else
- retval = rc;
+ rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (rc) {
+ err(__FUNCTION__
+ " - failed submitting read urb, error %d", rc);
+ retval = rc;
+ goto exit;
}
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+ KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+ 0, /* index */
+ NULL,
+ 0,
+ KLSI_TIMEOUT);
+ if (rc < 0) {
+ err("Enabling read failed (error = %d)", rc);
+ retval = rc;
+ } else
+ dbg(__FUNCTION__ " - enabled reading");
+
+ rc = klsi_105_get_line_state(serial, &line_state);
+ if (rc >= 0) {
+ priv->line_state = line_state;
+ dbg(__FUNCTION__
+ " - read line state 0x%lx", line_state);
+ retval = 0;
+ } else
+ retval = rc;
+
exit:
return retval;
} /* klsi_105_open */
@@ -444,6 +436,7 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial;
struct klsi_105_private *priv
= (struct klsi_105_private *)port->private;
+ int rc;
dbg(__FUNCTION__" port %d", port->number);
serial = get_usb_serial (port, __FUNCTION__);
@@ -451,31 +444,26 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
if(!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- /* send READ_OFF */
- int rc = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- err("Disabling read failed (error = %d)", rc);
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- /* unlink our write pool */
- /* FIXME */
- /* wgg - do I need this? I think so. */
- usb_unlink_urb (port->interrupt_in_urb);
- port->open_count = 0;
- info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
- }
+ /* send READ_OFF */
+ rc = usb_control_msg (serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ err("Disabling read failed (error = %d)", rc);
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ /* unlink our write pool */
+ /* FIXME */
+ /* wgg - do I need this? I think so. */
+ usb_unlink_urb (port->interrupt_in_urb);
+ info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
} /* klsi_105_close */
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 125c4a647ab3..d8b92b0b5488 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -324,9 +324,6 @@ static void mct_u232_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- mct_u232_close (&serial->port[i], NULL);
- }
/* My special items, the standard routines free my urbs */
if (serial->port[i].private)
kfree(serial->port[i].private);
@@ -341,60 +338,55 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__" port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- /* Compensate for a hardware bug: although the Sitecom U232-P25
- * device reports a maximum output packet size of 32 bytes,
- * it seems to be able to accept only 16 bytes (and that's what
- * SniffUSB says too...)
- */
- if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
- port->bulk_out_size = 16;
-
- /* Do a defined restart: the normal serial device seems to
- * always turn on DTR and RTS here, so do the same. I'm not
- * sure if this is really necessary. But it should not harm
- * either.
- */
- if (port->tty->termios->c_cflag & CBAUD)
- priv->control_state = TIOCM_DTR | TIOCM_RTS;
- else
- priv->control_state = 0;
- mct_u232_set_modem_ctrl(serial, priv->control_state);
-
- priv->last_lcr = (MCT_U232_DATA_BITS_8 |
- MCT_U232_PARITY_NONE |
- MCT_U232_STOP_BITS_1);
- mct_u232_set_line_ctrl(serial, priv->last_lcr);
+ /* Compensate for a hardware bug: although the Sitecom U232-P25
+ * device reports a maximum output packet size of 32 bytes,
+ * it seems to be able to accept only 16 bytes (and that's what
+ * SniffUSB says too...)
+ */
+ if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
+ port->bulk_out_size = 16;
- /* Read modem status and update control state */
- mct_u232_get_modem_stat(serial, &priv->last_msr);
- mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
-
- {
- /* Puh, that's dirty */
- struct usb_serial_port *rport;
- rport = &serial->port[1];
- rport->tty = port->tty;
- rport->private = port->private;
- port->read_urb = rport->interrupt_in_urb;
- }
+ /* Do a defined restart: the normal serial device seems to
+ * always turn on DTR and RTS here, so do the same. I'm not
+ * sure if this is really necessary. But it should not harm
+ * either.
+ */
+ if (port->tty->termios->c_cflag & CBAUD)
+ priv->control_state = TIOCM_DTR | TIOCM_RTS;
+ else
+ priv->control_state = 0;
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+
+ priv->last_lcr = (MCT_U232_DATA_BITS_8 |
+ MCT_U232_PARITY_NONE |
+ MCT_U232_STOP_BITS_1);
+ mct_u232_set_line_ctrl(serial, priv->last_lcr);
- port->read_urb->dev = port->serial->dev;
- retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (retval) {
- err("usb_submit_urb(read bulk) failed");
- goto exit;
- }
+ /* Read modem status and update control state */
+ mct_u232_get_modem_stat(serial, &priv->last_msr);
+ mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
- port->interrupt_in_urb->dev = port->serial->dev;
- retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (retval)
- err(" usb_submit_urb(read int) failed");
+ {
+ /* Puh, that's dirty */
+ struct usb_serial_port *rport;
+ rport = &serial->port[1];
+ rport->tty = port->tty;
+ rport->private = port->private;
+ port->read_urb = rport->interrupt_in_urb;
+ }
+ port->read_urb->dev = port->serial->dev;
+ retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (retval) {
+ err("usb_submit_urb(read bulk) failed");
+ goto exit;
}
+ port->interrupt_in_urb->dev = port->serial->dev;
+ retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (retval)
+ err(" usb_submit_urb(read int) failed");
+
exit:
return 0;
} /* mct_u232_open */
@@ -404,16 +396,11 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
{
dbg(__FUNCTION__" port %d", port->number);
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (port->serial->dev) {
- /* shutdown our urbs */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
- }
- port->open_count = 0;
+ if (port->serial->dev) {
+ /* shutdown our urbs */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
}
} /* mct_u232_close */
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 457984644e9b..8d6e8edb10ab 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -157,30 +157,25 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
if (!serial)
return -ENODEV;
- ++port->open_count;
-
- if (port->open_count == 1) {
- od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
- if( !od ) {
- err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
- port->open_count = 0;
- return -ENOMEM;
- }
-
- port->private = od;
- wport = &serial->port[1];
- wport->tty = port->tty;
-
- /* Start reading from the device */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- omninet_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+ if( !od ) {
+ err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
+ return -ENOMEM;
}
+ port->private = od;
+ wport = &serial->port[1];
+ wport->tty = port->tty;
+
+ /* Start reading from the device */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ omninet_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
return result;
}
@@ -199,20 +194,15 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp)
if (!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- wport = &serial->port[1];
- usb_unlink_urb (wport->write_urb);
- usb_unlink_urb (port->read_urb);
- }
-
- port->open_count = 0;
- od = (struct omninet_data *)port->private;
- if (od)
- kfree(od);
+ if (serial->dev) {
+ wport = &serial->port[1];
+ usb_unlink_urb (wport->write_urb);
+ usb_unlink_urb (port->read_urb);
}
+
+ od = (struct omninet_data *)port->private;
+ if (od)
+ kfree(od);
}
@@ -377,10 +367,6 @@ static void omninet_write_bulk_callback (struct urb *urb)
static void omninet_shutdown (struct usb_serial *serial)
{
dbg (__FUNCTION__);
-
- while (serial->port[0].open_count > 0) {
- omninet_close (&serial->port[0], NULL);
- }
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 23adb9024f46..c37fcbe5d175 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1,7 +1,7 @@
/*
* Prolific PL2303 USB to serial adaptor driver
*
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
*
* Original driver for 2.2.x by anonymous
*
@@ -12,6 +12,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * 2002_Mar_26 gkh
+ * allowed driver to work properly if there is no tty assigned to a port
+ * (this happens for serial console devices.)
+ *
* 2001_Oct_06 gkh
* Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it.
*
@@ -173,11 +177,6 @@ static int pl2303_write (struct usb_serial_port *port, int from_user, const uns
dbg (__FUNCTION__ " - port %d, %d bytes", port->number, count);
- if (!port->tty) {
- err (__FUNCTION__ " - no tty???");
- return 0;
- }
-
if (port->write_urb->status == -EINPROGRESS) {
dbg (__FUNCTION__ " - already writing");
return 0;
@@ -367,56 +366,54 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
dbg (__FUNCTION__ " - port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
-#define FISH(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
- b, a, c, d, buf, 1, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
- b, a, c, d, NULL, 0, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
-
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
-
- /* Setup termios */
+#define FISH(a,b,c,d) \
+ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
+ b, a, c, d, buf, 1, 100); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
+
+#define SOUP(a,b,c,d) \
+ result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
+ b, a, c, d, NULL, 0, 100); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
+
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
+ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
+ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
+
+ /* Setup termios */
+ if (port->tty) {
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
pl2303_set_termios (port, &tmp_termios);
+ }
- //FIXME: need to assert RTS and DTR if CRTSCTS off
+ //FIXME: need to assert RTS and DTR if CRTSCTS off
- dbg (__FUNCTION__ " - submitting read urb");
- port->read_urb->dev = serial->dev;
- result = usb_submit_urb (port->read_urb, GFP_KERNEL);
- if (result) {
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
- pl2303_close (port, NULL);
- return -EPROTO;
- }
+ dbg (__FUNCTION__ " - submitting read urb");
+ port->read_urb->dev = serial->dev;
+ result = usb_submit_urb (port->read_urb, GFP_KERNEL);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ pl2303_close (port, NULL);
+ return -EPROTO;
+ }
- dbg (__FUNCTION__ " - submitting interrupt urb");
- port->interrupt_in_urb->dev = serial->dev;
- result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
- if (result) {
- err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
- pl2303_close (port, NULL);
- return -EPROTO;
- }
+ dbg (__FUNCTION__ " - submitting interrupt urb");
+ port->interrupt_in_urb->dev = serial->dev;
+ result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
+ if (result) {
+ err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
+ pl2303_close (port, NULL);
+ return -EPROTO;
}
return 0;
}
@@ -437,9 +434,8 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
dbg (__FUNCTION__ " - port %d", port->number);
- --port->open_count;
- if (port->open_count <= 0) {
- if (serial->dev) {
+ if (serial->dev) {
+ if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
@@ -448,28 +444,27 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
set_control_lines (port->serial->dev,
priv->line_control);
}
+ }
- /* shutdown our urbs */
- dbg (__FUNCTION__ " - shutting down urbs");
- result = usb_unlink_urb (port->write_urb);
- if (result)
- dbg (__FUNCTION__ " - usb_unlink_urb "
- "(write_urb) failed with reason: %d",
- result);
+ /* shutdown our urbs */
+ dbg (__FUNCTION__ " - shutting down urbs");
+ result = usb_unlink_urb (port->write_urb);
+ if (result)
+ dbg (__FUNCTION__ " - usb_unlink_urb "
+ "(write_urb) failed with reason: %d",
+ result);
- result = usb_unlink_urb (port->read_urb);
- if (result)
- dbg (__FUNCTION__ " - usb_unlink_urb "
- "(read_urb) failed with reason: %d",
- result);
+ result = usb_unlink_urb (port->read_urb);
+ if (result)
+ dbg (__FUNCTION__ " - usb_unlink_urb "
+ "(read_urb) failed with reason: %d",
+ result);
- result = usb_unlink_urb (port->interrupt_in_urb);
- if (result)
- dbg (__FUNCTION__ " - usb_unlink_urb "
- "(interrupt_in_urb) failed with reason: %d",
- result);
- }
- port->open_count = 0;
+ result = usb_unlink_urb (port->interrupt_in_urb);
+ if (result)
+ dbg (__FUNCTION__ " - usb_unlink_urb "
+ "(interrupt_in_urb) failed with reason: %d",
+ result);
}
}
@@ -577,12 +572,8 @@ static void pl2303_shutdown (struct usb_serial *serial)
dbg (__FUNCTION__);
- /* stop everything on all ports */
for (i = 0; i < serial->num_ports; ++i)
- while (serial->port[i].open_count > 0) {
- pl2303_close (&serial->port[i], NULL);
- kfree (serial->port[i].private);
- }
+ kfree (serial->port[i].private);
}
@@ -655,7 +646,7 @@ static void pl2303_read_bulk_callback (struct urb *urb)
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
for (i = 0; i < urb->actual_length; ++i) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
new file mode 100644
index 000000000000..ca80dc61e7d1
--- /dev/null
+++ b/drivers/usb/serial/safe_serial.c
@@ -0,0 +1,449 @@
+/*
+ * Safe Encapsulated USB Serial Driver
+ *
+ * Copyright (c) 2001 Lineo
+ * Copyright (c) 2001 Hewlett-Packard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * By:
+ * Stuart Lynne <sl@lineo.com>, Tom Rushworth <tbr@lineo.com>
+ */
+
+/*
+ * The encapsultaion is designed to overcome difficulties with some USB hardware.
+ *
+ * While the USB protocol has a CRC over the data while in transit, i.e. while
+ * being carried over the bus, there is no end to end protection. If the hardware
+ * has any problems getting the data into or out of the USB transmit and receive
+ * FIFO's then data can be lost.
+ *
+ * This protocol adds a two byte trailer to each USB packet to specify the number
+ * of bytes of valid data and a 10 bit CRC that will allow the receiver to verify
+ * that the entire USB packet was received without error.
+ *
+ * Because in this case the sender and receiver are the class and function drivers
+ * there is now end to end protection.
+ *
+ * There is an additional option that can be used to force all transmitted packets
+ * to be padded to the maximum packet size. This provides a work around for some
+ * devices which have problems with small USB packets.
+ *
+ * Assuming a packetsize of N:
+ *
+ * 0..N-2 data and optional padding
+ *
+ * N-2 bits 7-2 - number of bytes of valid data
+ * bits 1-0 top two bits of 10 bit CRC
+ * N-1 bottom 8 bits of 10 bit CRC
+ *
+ *
+ * | Data Length | 10 bit CRC |
+ * + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 +
+ *
+ * The 10 bit CRC is computed across the sent data, followed by the trailer with
+ * the length set and the CRC set to zero. The CRC is then OR'd into the trailer.
+ *
+ * When received a 10 bit CRC is computed over the entire frame including the trailer
+ * and should be equal to zero.
+ *
+ * Two module parameters are used to control the encapsulation, if both are
+ * turned of the module works as a simple serial device with NO
+ * encapsulation.
+ *
+ * See linux/drivers/usbd/serial_fd for a device function driver
+ * implementation of this.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+
+#ifndef CONFIG_USB_SERIAL_DEBUG
+#define CONFIG_USB_SERIAL_DEBUG 0
+#endif
+#ifndef CONFIG_USB_SAFE_PADDED
+#define CONFIG_USB_SAFE_PADDED 0
+#endif
+
+static int debug = CONFIG_USB_SERIAL_DEBUG;
+#include "usb-serial.h" // must follow the declaration of debug
+
+static int safe = 1;
+static int padded = CONFIG_USB_SAFE_PADDED;
+
+#define DRIVER_VERSION "v0.0b"
+#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
+#define DRIVER_DESC "USB Safe Encapsulated Serial"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
+#abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
+#endif
+
+#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
+static __u16 vendor; // no default
+static __u16 product; // no default
+MODULE_PARM (vendor, "i");
+MODULE_PARM (product, "i");
+MODULE_PARM_DESC (vendor, "User specified USB idVendor (required)");
+MODULE_PARM_DESC (product, "User specified USB idProduct (required)");
+#endif
+
+MODULE_PARM (debug, "i");
+MODULE_PARM (safe, "i");
+MODULE_PARM (padded, "i");
+
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+MODULE_PARM_DESC (safe, "Turn Safe Encapsulation On/Off");
+MODULE_PARM_DESC (padded, "Pad to full wMaxPacketSize On/Off");
+
+#define CDC_DEVICE_CLASS 0x02
+
+#define CDC_INTERFACE_CLASS 0x02
+#define CDC_INTERFACE_SUBCLASS 0x06
+
+#define LINEO_INTERFACE_CLASS 0xff
+
+#define LINEO_INTERFACE_SUBCLASS_SAFENET 0x01
+#define LINEO_SAFENET_CRC 0x01
+#define LINEO_SAFENET_CRC_PADDED 0x02
+
+#define LINEO_INTERFACE_SUBCLASS_SAFESERIAL 0x02
+#define LINEO_SAFESERIAL_CRC 0x01
+#define LINEO_SAFESERIAL_CRC_PADDED 0x02
+
+
+#define MY_USB_DEVICE(vend,prod,dc,ic,isc) \
+ match_flags: USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS | \
+ USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
+ idVendor: (vend), \
+ idProduct: (prod),\
+ bDeviceClass: (dc),\
+ bInterfaceClass: (ic), \
+ bInterfaceSubClass: (isc),
+
+static __devinitdata struct usb_device_id id_table[] = {
+ {MY_USB_DEVICE (0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Itsy
+ {MY_USB_DEVICE (0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Calypso
+ {MY_USB_DEVICE (0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Iris
+ {MY_USB_DEVICE (0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
+ {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
+ {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
+ {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp
+#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
+ {MY_USB_DEVICE
+ (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
+ LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
+#endif
+ // extra null entry for module
+ // vendor/produc parameters
+ {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
+ {} // terminating entry
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+static __u16 crc10_table[256] = {
+ 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
+ 0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce, 0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf,
+ 0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d, 0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c,
+ 0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac, 0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad,
+ 0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b, 0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a,
+ 0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a, 0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b,
+ 0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259, 0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158,
+ 0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268, 0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169,
+ 0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377, 0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076,
+ 0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346, 0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047,
+ 0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315, 0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014,
+ 0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324, 0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025,
+ 0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3, 0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2,
+ 0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382, 0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083,
+ 0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1, 0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0,
+ 0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0, 0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1,
+};
+
+#define CRC10_INITFCS 0x000 // Initial FCS value
+#define CRC10_GOODFCS 0x000 // Good final FCS value
+#define CRC10_FCS(fcs, c) ( (((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c))
+
+/**
+ * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer
+ * @sp: pointer to buffer
+ * @len: number of bytes
+ * @fcs: starting FCS
+ *
+ * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return
+ * new 10 bit FCS.
+ */
+static __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs)
+{
+ for (; len-- > 0; fcs = CRC10_FCS (fcs, *sp++));
+ return fcs;
+}
+
+static void safe_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ unsigned char *data = urb->transfer_buffer;
+ unsigned char length = urb->actual_length;
+ int i;
+ int result;
+
+ dbg ("%s", __FUNCTION__);
+
+ if (!serial) {
+ dbg (__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg (__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ dbg ("safe_read_bulk_callback length: %d", port->read_urb->actual_length);
+#ifdef ECHO_RCV
+ {
+ int i;
+ unsigned char *cp = port->read_urb->transfer_buffer;
+ for (i = 0; i < port->read_urb->actual_length; i++) {
+ if ((i % 32) == 0) {
+ printk ("\nru[%02x] ", i);
+ }
+ printk ("%02x ", *cp++);
+ }
+ printk ("\n");
+ }
+#endif
+ if (safe) {
+ __u16 fcs;
+ if (!(fcs = fcs_compute10 (data, length, CRC10_INITFCS))) {
+
+ int actual_length = data[length - 2] >> 2;
+
+ if (actual_length <= (length - 2)) {
+
+ info (__FUNCTION__ " - actual: %d", actual_length);
+
+ for (i = 0; i < actual_length; i++) {
+ tty_insert_flip_char (port->tty, data[i], 0);
+ }
+ tty_flip_buffer_push (port->tty);
+ } else {
+ err (__FUNCTION__ " - inconsistant lengths %d:%d", actual_length,
+ length);
+ }
+ } else {
+ err (__FUNCTION__ " - bad CRC %x", fcs);
+ }
+ } else {
+ for (i = 0; i < length; i++) {
+ tty_insert_flip_char (port->tty, data[i], 0);
+ }
+ tty_flip_buffer_push (port->tty);
+ }
+
+ /* Continue trying to always read */
+ FILL_BULK_URB (urb, serial->dev,
+ usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress),
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ safe_read_bulk_callback, port);
+
+ if ((result = usb_submit_urb (urb, GFP_ATOMIC))) {
+ err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+ }
+}
+
+static int safe_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned char *data;
+ int result;
+ int i;
+ int packet_length;
+
+ dbg ("safe_write port: %p %d urb: %p count: %d", port, port->number, port->write_urb,
+ count);
+
+ if (!port->write_urb) {
+ dbg (__FUNCTION__ " - write urb NULL");
+ return (0);
+ }
+
+ dbg ("safe_write write_urb: %d transfer_buffer_length",
+ port->write_urb->transfer_buffer_length);
+
+ if (!port->write_urb->transfer_buffer_length) {
+ dbg (__FUNCTION__ " - write urb transfer_buffer_length zero");
+ return (0);
+ }
+ if (count == 0) {
+ dbg (__FUNCTION__ " - write request of 0 bytes");
+ return (0);
+ }
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg (__FUNCTION__ " - already writing");
+ return (0);
+ }
+
+ packet_length = port->bulk_out_size; // get max packetsize
+
+ i = packet_length - (safe ? 2 : 0); // get bytes to send
+ count = (count > i) ? i : count;
+
+
+ // get the data into the transfer buffer
+ data = port->write_urb->transfer_buffer;
+ memset (data, '0', packet_length);
+
+ if (from_user) {
+ copy_from_user (data, buf, count);
+ } else {
+ memcpy (data, buf, count);
+ }
+
+ if (safe) {
+ __u16 fcs;
+
+ // pad if necessary
+ if (!padded) {
+ packet_length = count + 2;
+ }
+ // set count
+ data[packet_length - 2] = count << 2;
+ data[packet_length - 1] = 0;
+
+ // compute fcs and insert into trailer
+ fcs = fcs_compute10 (data, packet_length, CRC10_INITFCS);
+ data[packet_length - 2] |= fcs >> 8;
+ data[packet_length - 1] |= fcs & 0xff;
+
+ // set length to send
+ port->write_urb->transfer_buffer_length = packet_length;
+ } else {
+ port->write_urb->transfer_buffer_length = count;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+#ifdef ECHO_TX
+ {
+ int i;
+ unsigned char *cp = port->write_urb->transfer_buffer;
+ for (i = 0; i < port->write_urb->transfer_buffer_length; i++) {
+ if ((i % 32) == 0) {
+ printk ("\nsu[%02x] ", i);
+ }
+ printk ("%02x ", *cp++);
+ }
+ printk ("\n");
+ }
+#endif
+ port->write_urb->dev = serial->dev;
+ if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+ err (__FUNCTION__ " - failed submitting write urb, error %d", result);
+ return 0;
+ }
+ dbg (__FUNCTION__ " urb: %p submitted", port->write_urb);
+
+ return (count);
+}
+
+static int safe_write_room (struct usb_serial_port *port)
+{
+ int room = 0; // Default: no room
+
+ dbg ("%s", __FUNCTION__);
+
+ if (port->write_urb->status != -EINPROGRESS)
+ room = port->bulk_out_size - (safe ? 2 : 0);
+
+ if (room) {
+ dbg ("safe_write_room returns %d", room);
+ }
+
+ return (room);
+}
+
+static int safe_startup (struct usb_serial *serial)
+{
+ switch (serial->interface->altsetting->bInterfaceProtocol) {
+ case LINEO_SAFESERIAL_CRC:
+ break;
+ case LINEO_SAFESERIAL_CRC_PADDED:
+ padded = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct usb_serial_device_type safe_device = {
+ owner: THIS_MODULE,
+ name: "Safe",
+ id_table: id_table,
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ write: safe_write,
+ write_room: safe_write_room,
+ read_bulk_callback: safe_read_bulk_callback,
+ startup: safe_startup,
+};
+
+static int __init safe_init (void)
+{
+ int i;
+
+ info (DRIVER_VERSION " " DRIVER_AUTHOR);
+ info (DRIVER_DESC);
+ info ("vendor: %x product: %x safe: %d padded: %d\n", vendor, product, safe, padded);
+
+ // if we have vendor / product parameters patch them into id list
+ if (vendor || product) {
+ info ("vendor: %x product: %x\n", vendor, product);
+
+ for (i = 0; i < (sizeof (id_table) / sizeof (struct usb_device_id)); i++) {
+ if (!id_table[i].idVendor && !id_table[i].idProduct) {
+ id_table[i].idVendor = vendor;
+ id_table[i].idProduct = product;
+ break;
+ }
+ }
+ }
+
+ usb_serial_register (&safe_device);
+
+ return 0;
+}
+
+static void __exit safe_exit (void)
+{
+ usb_serial_deregister (&safe_device);
+}
+
+module_init (safe_init);
+module_exit (safe_exit);
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index d51e1d1efed9..f072a3f5da08 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * Copyright (C) 1999 - 2001
+ * Copyright (C) 1999 - 2002
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (03/26/2002) gkh
+ * removed the port->tty check from port_paranoia_check() due to serial
+ * consoles not having a tty device assigned to them.
+ *
* (12/03/2001) gkh
* removed active from the port structure.
* added documentation to the usb_serial_device_type structure
@@ -226,10 +230,6 @@ static inline int port_paranoia_check (struct usb_serial_port *port, const char
dbg("%s - port->serial == NULL", function);
return -1;
}
- if (!port->tty) {
- dbg("%s - port->tty == NULL", function);
- return -1;
- }
return 0;
}
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 6271ade640d6..22cd815ff62b 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -15,6 +15,19 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (03/27/2002) gkh
+ * Got USB serial console code working properly and merged into the main
+ * version of the tree. Thanks to Randy Dunlap for the initial version
+ * of this code, and for pushing me to finish it up.
+ * The USB serial console works with any usb serial driver device.
+ *
+ * (03/21/2002) gkh
+ * Moved all manipulation of port->open_count into the core. Now the
+ * individual driver's open and close functions are called only when the
+ * first open() and last close() is called. Making the drivers a bit
+ * smaller and simpler.
+ * Fixed a bug if a driver didn't have the owner field set.
+ *
* (02/26/2002) gkh
* Moved all locking into the main serial_* functions, instead of having
* the individual drivers have to grab the port semaphore. This should
@@ -307,6 +320,14 @@
#include <linux/smp_lock.h>
#include <linux/usb.h>
+#ifdef MODULE
+#undef CONFIG_USB_SERIAL_CONSOLE
+#endif
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/serial.h>
+#endif
+
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
@@ -395,6 +416,16 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list);
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+struct usbcons_info {
+ int magic;
+ int break_flag;
+ struct usb_serial_port *port;
+};
+
+static struct usbcons_info usbcons_info;
+static struct console usbcons;
+#endif /* CONFIG_USB_SERIAL_CONSOLE */
static struct usb_serial *get_serial_by_minor (unsigned int minor)
{
@@ -500,7 +531,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial *serial;
struct usb_serial_port *port;
unsigned int portNumber;
- int retval;
+ int retval = 0;
dbg(__FUNCTION__);
@@ -525,19 +556,48 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
if (serial->type->owner)
__MOD_INC_USE_COUNT(serial->type->owner);
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->open)
- retval = serial->type->open(port, filp);
- else
- retval = generic_open(port, filp);
+ ++port->open_count;
+ if (port->open_count == 1) {
+ /* only call the device specific open if this
+ * is the first time the port is opened */
+ if (serial->type->open)
+ retval = serial->type->open(port, filp);
+ else
+ retval = generic_open(port, filp);
+ }
- if (retval)
- __MOD_DEC_USE_COUNT(serial->type->owner);
+ if (retval) {
+ port->open_count = 0;
+ if (serial->type->owner)
+ __MOD_DEC_USE_COUNT(serial->type->owner);
+ }
up (&port->sem);
return retval;
}
+static void __serial_close(struct usb_serial_port *port, struct file *filp)
+{
+ if (!port->open_count) {
+ dbg (__FUNCTION__ " - port not opened");
+ return;
+ }
+
+ --port->open_count;
+ if (port->open_count <= 0) {
+ /* only call the device specific close if this
+ * port is being closed by the last owner */
+ if (port->serial->type->close)
+ port->serial->type->close(port, filp);
+ else
+ generic_close(port, filp);
+ port->open_count = 0;
+ }
+
+ if (port->serial->type->owner)
+ __MOD_DEC_USE_COUNT(port->serial->type->owner);
+}
+
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
@@ -550,26 +610,11 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
dbg(__FUNCTION__ " - port %d", port->number);
- if (tty->driver_data == NULL) {
- /* disconnect beat us to the punch here, so handle it gracefully */
- goto exit;
+ /* if disconnect beat us to the punch here, there's nothing to do */
+ if (tty->driver_data) {
+ __serial_close(port, filp);
}
- if (!port->open_count) {
- dbg (__FUNCTION__ " - port not opened");
- goto exit_no_mod_dec;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->close)
- serial->type->close(port, filp);
- else
- generic_close(port, filp);
-
-exit:
- if (serial->type->owner)
- __MOD_DEC_USE_COUNT(serial->type->owner);
-exit_no_mod_dec:
up (&port->sem);
}
@@ -791,6 +836,8 @@ exit:
static void serial_shutdown (struct usb_serial *serial)
{
+ dbg(__FUNCTION__);
+
if (serial->type->shutdown)
serial->type->shutdown(serial);
else
@@ -810,54 +857,52 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
+ /* force low_latency on so that our tty_push actually forces the data through,
+ otherwise it is scheduled, and with high data rates (like with OHCI) data
+ can get lost. */
+ if (port->tty)
port->tty->low_latency = 1;
- /* if we have a bulk interrupt, start reading from it */
- if (serial->num_bulk_in) {
- /* Start reading from the device */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ((serial->type->read_bulk_callback) ?
- serial->type->read_bulk_callback :
- generic_read_bulk_callback),
- port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
- }
+ /* if we have a bulk interrupt, start reading from it */
+ if (serial->num_bulk_in) {
+ /* Start reading from the device */
+ usb_fill_bulk_urb (port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ ((serial->type->read_bulk_callback) ?
+ serial->type->read_bulk_callback :
+ generic_read_bulk_callback),
+ port);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
}
return result;
}
-static void generic_close (struct usb_serial_port *port, struct file * filp)
+static void generic_cleanup (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
dbg(__FUNCTION__ " - port %d", port->number);
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* shutdown any bulk reads that might be going on */
- if (serial->num_bulk_out)
- usb_unlink_urb (port->write_urb);
- if (serial->num_bulk_in)
- usb_unlink_urb (port->read_urb);
- }
- port->open_count = 0;
+ if (serial->dev) {
+ /* shutdown any bulk reads that might be going on */
+ if (serial->num_bulk_out)
+ usb_unlink_urb (port->write_urb);
+ if (serial->num_bulk_in)
+ usb_unlink_urb (port->read_urb);
}
}
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+ dbg(__FUNCTION__ " - port %d", port->number);
+ generic_cleanup (port);
+}
+
static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
struct usb_serial *serial = port->serial;
@@ -968,7 +1013,7 @@ static void generic_read_bulk_callback (struct urb *urb)
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -1025,10 +1070,7 @@ static void generic_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- down (&serial->port[i].sem);
- while (serial->port[i].open_count > 0)
- generic_close (&serial->port[i], NULL);
- up (&serial->port[i].sem);
+ generic_cleanup (&serial->port[i]);
}
}
@@ -1040,11 +1082,13 @@ static void port_softint(void *private)
dbg(__FUNCTION__ " - port %d", port->number);
- if (!serial) {
+ if (!serial)
return;
- }
tty = port->tty;
+ if (!tty)
+ return;
+
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg(__FUNCTION__ " - write wakeup call.");
(tty->ldisc.write_wakeup)(tty);
@@ -1294,6 +1338,26 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
type->name, serial->port[i].number, serial->port[i].number);
}
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+ if (minor == 0) {
+ /*
+ * Call register_console() if this is the first device plugged
+ * in. If we call it earlier, then the callback to
+ * console_setup() will fail, as there is not a device seen by
+ * the USB subsystem yet.
+ */
+ /*
+ * Register console.
+ * NOTES:
+ * console_setup() is called (back) immediately (from register_console).
+ * console_write() is called immediately from register_console iff
+ * CON_PRINTBUFFER is set in flags.
+ */
+ dbg ("registering the USB serial console.");
+ register_console(&usbcons);
+ }
+#endif
+
return serial; /* success */
@@ -1334,13 +1398,19 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
struct usb_serial_port *port;
int i;
+ dbg(__FUNCTION__);
if (serial) {
/* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) {
- down (&serial->port[i].sem);
- if (serial->port[i].tty != NULL)
- serial->port[i].tty->driver_data = NULL;
- up (&serial->port[i].sem);
+ port = &serial->port[i];
+ down (&port->sem);
+ if (port->tty != NULL) {
+ while (port->open_count > 0) {
+ __serial_close(port, NULL);
+ }
+ port->tty->driver_data = NULL;
+ }
+ up (&port->sem);
}
serial->dev = NULL;
@@ -1466,6 +1536,9 @@ static int __init usb_serial_init(void)
static void __exit usb_serial_exit(void)
{
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+ unregister_console(&usbcons);
+#endif
#ifdef CONFIG_USB_SERIAL_GENERIC
/* remove our generic driver */
@@ -1515,7 +1588,7 @@ void usb_serial_deregister(struct usb_serial_device_type *device)
-/* If the usb-serial core is build into the core, the usb-serial drivers
+/* If the usb-serial core is built into the core, the usb-serial drivers
need these symbols to load properly as modules. */
EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
@@ -1525,6 +1598,241 @@ EXPORT_SYMBOL(usb_serial_deregister);
#endif
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+/*
+ * ------------------------------------------------------------
+ * USB Serial console driver
+ *
+ * Much of the code here is copied from drivers/char/serial.c
+ * and implements a phony serial console in the same way that
+ * serial.c does so that in case some software queries it,
+ * it will get the same results.
+ *
+ * Things that are different from the way the serial port code
+ * does things, is that we call the lower level usb-serial
+ * driver code to initialize the device, and we set the initial
+ * console speeds based on the command line arguments.
+ * ------------------------------------------------------------
+ */
+
+#if 0
+static kdev_t usb_console_device(struct console *co)
+{
+ return MKDEV(SERIAL_TTY_MAJOR, co->index); /* TBD */
+}
+#endif
+
+/*
+ * The parsing of the command line works exactly like the
+ * serial.c code, except that the specifier is "ttyUSB" instead
+ * of "ttyS".
+ */
+static int __init usb_console_setup(struct console *co, char *options)
+{
+ struct usbcons_info *info = &usbcons_info;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int doflow = 0;
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ int retval = 0;
+ struct tty_struct *tty;
+ struct termios *termios;
+
+ dbg ("%s", __FUNCTION__);
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s) parity = *s++;
+ if (*s) bits = *s++ - '0';
+ if (*s) doflow = (*s++ == 'r');
+ }
+
+ /* build a cflag setting */
+ switch (baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ case 9600:
+ default:
+ cflag |= B9600;
+ /*
+ * Set this to a sane value to prevent a divide error
+ */
+ baud = 9600;
+ break;
+ }
+ switch (bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
+ }
+ switch (parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
+ }
+ co->cflag = cflag;
+
+ /* grab the first serial port that happens to be connected */
+ serial = get_serial_by_minor (0);
+ if (serial_paranoia_check (serial, __FUNCTION__)) {
+ /* no device is connected yet, sorry :( */
+ err ("No USB device connected to ttyUSB0");
+ return -ENODEV;
+ }
+
+ port = &serial->port[0];
+ down (&port->sem);
+ port->tty = NULL;
+
+ info->port = port;
+
+ ++port->open_count;
+ if (port->open_count == 1) {
+ /* only call the device specific open if this
+ * is the first time the port is opened */
+ if (serial->type->open)
+ retval = serial->type->open(port, NULL);
+ else
+ retval = generic_open(port, NULL);
+ if (retval)
+ port->open_count = 0;
+ }
+
+ up (&port->sem);
+
+ if (retval) {
+ err ("could not open USB console port");
+ return retval;
+ }
+
+ if (serial->type->set_termios) {
+ /* build up a fake tty structure so that the open call has something
+ * to look at to get the cflag value */
+ tty = kmalloc (sizeof (*tty), GFP_KERNEL);
+ if (!tty) {
+ err ("no more memory");
+ return -ENOMEM;
+ }
+ termios = kmalloc (sizeof (*termios), GFP_KERNEL);
+ if (!termios) {
+ err ("no more memory");
+ kfree (tty);
+ return -ENOMEM;
+ }
+ memset (tty, 0x00, sizeof(*tty));
+ memset (termios, 0x00, sizeof(*termios));
+ termios->c_cflag = cflag;
+ tty->termios = termios;
+ port->tty = tty;
+
+ /* set up the initial termios settings */
+ serial->type->set_termios(port, NULL);
+ port->tty = NULL;
+ kfree (termios);
+ kfree (tty);
+ }
+
+ return retval;
+}
+
+static void usb_console_write(struct console *co, const char *buf, unsigned count)
+{
+ static struct usbcons_info *info = &usbcons_info;
+ struct usb_serial_port *port = info->port;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ int retval = -ENODEV;
+
+ if (!serial || !port)
+ return;
+
+ if (count == 0)
+ return;
+
+ down (&port->sem);
+
+ dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+
+ if (!port->open_count) {
+ dbg (__FUNCTION__ " - port not opened");
+ goto exit;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->write)
+ retval = serial->type->write(port, 0, buf, count);
+ else
+ retval = generic_write(port, 0, buf, count);
+
+exit:
+ up (&port->sem);
+ dbg("%s - return value (if we had one): %d", __FUNCTION__, retval);
+}
+
+#if 0
+/*
+ * Receive character from the serial port
+ */
+static int usb_console_wait_key(struct console *co)
+{
+ static struct usbcons_info *info = &usbcons_info;
+ int c = 0;
+
+ dbg("%s", __FUNCTION__);
+
+ /* maybe use generic_read_bulk_callback ??? */
+
+ return c;
+}
+#endif
+
+static struct console usbcons = {
+ name: "ttyUSB", /* only [8] */
+ write: usb_console_write,
+#if 0
+ device: usb_console_device, /* TBD */
+ wait_key: usb_console_wait_key, /* TBD */
+#endif
+ setup: usb_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+#endif /* CONFIG_USB_SERIAL_CONSOLE */
+
+
/* Module information */
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 29415d2e2fb1..92be76036702 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,7 +11,19 @@
* (at your option) any later version.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
- *
+ *
+ * (03/27/2002) gkh
+ * Removed assumptions that port->tty was always valid (is not true
+ * for usb serial console devices.)
+ *
+ * (03/23/2002) gkh
+ * Added support for the Palm i705 device, thanks to Thomas Riemer
+ * <tom@netmech.com> for the information.
+ *
+ * (03/21/2002) gkh
+ * Added support for the Palm m130 device, thanks to Udo Eisenbarth
+ * <udo.eisenbarth@web.de> for the information.
+ *
* (02/27/2002) gkh
* Reworked the urb handling logic. We have no more pool, but dynamically
* allocate the urb and the transfer buffer on the fly. In testing this
@@ -169,6 +181,8 @@ static __devinitdata struct usb_device_id combined_id_table [] = {
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -186,6 +200,8 @@ static __devinitdata struct usb_device_id id_table [] = {
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -262,32 +278,32 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__ " - port %d", port->number);
if (!port->read_urb) {
+ /* this is needed for some brain dead Sony devices */
err ("Device lied about number of ports, please use a lower one.");
return -ENODEV;
}
- ++port->open_count;
-
- if (port->open_count == 1) {
- bytes_in = 0;
- bytes_out = 0;
+ bytes_in = 0;
+ bytes_out = 0;
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
+ /*
+ * Force low_latency on so that our tty_push actually forces the data
+ * through, otherwise it is scheduled, and with high data rates (like
+ * with OHCI) data can get lost.
+ */
+ if (port->tty)
port->tty->low_latency = 1;
-
- /* Start reading from the device */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- visor_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
- }
+
+ /* Start reading from the device */
+ usb_fill_bulk_urb (port->read_urb, serial->dev,
+ usb_rcvbulkpipe (serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ visor_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
return result;
}
@@ -307,28 +323,23 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
if (!serial)
return;
- --port->open_count;
-
- if (port->open_count <= 0) {
- if (serial->dev) {
- /* only send a shutdown message if the
- * device is still here */
- transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- if (!transfer_buffer) {
- err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
- } else {
- /* send a shutdown message to the device */
- usb_control_msg (serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- VISOR_CLOSE_NOTIFICATION, 0xc2,
- 0x0000, 0x0000,
- transfer_buffer, 0x12, 300);
- kfree (transfer_buffer);
- }
- /* shutdown our bulk read */
- usb_unlink_urb (port->read_urb);
+ if (serial->dev) {
+ /* only send a shutdown message if the
+ * device is still here */
+ transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+ if (!transfer_buffer) {
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+ } else {
+ /* send a shutdown message to the device */
+ usb_control_msg (serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ VISOR_CLOSE_NOTIFICATION, 0xc2,
+ 0x0000, 0x0000,
+ transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
}
- port->open_count = 0;
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
}
/* Uncomment the following line if you want to see some statistics in your syslog */
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
@@ -390,7 +401,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig
usb_free_urb (urb);
return count;
-}
+}
static int visor_write_room (struct usb_serial_port *port)
@@ -471,7 +482,7 @@ static void visor_read_bulk_callback (struct urb *urb)
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -481,8 +492,8 @@ static void visor_read_bulk_callback (struct urb *urb)
tty_insert_flip_char(tty, data[i], 0);
}
tty_flip_buffer_push(tty);
- bytes_in += urb->actual_length;
}
+ bytes_in += urb->actual_length;
/* Continue trying to always read */
usb_fill_bulk_urb (port->read_urb, serial->dev,
@@ -649,16 +660,9 @@ static int clie_3_5_startup (struct usb_serial *serial)
static void visor_shutdown (struct usb_serial *serial)
{
- int i;
-
dbg (__FUNCTION__);
-
- /* stop reads and writes on all ports */
- for (i=0; i < serial->num_ports; ++i)
- serial->port[i].open_count = 0;
}
-
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 5e582d67b038..b4a28ad79a16 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -24,7 +24,9 @@
#define PALM_M500_ID 0x0001
#define PALM_M505_ID 0x0002
#define PALM_M515_ID 0x0003
+#define PALM_I705_ID 0x0020
#define PALM_M125_ID 0x0040
+#define PALM_M130_ID 0x0050
#define SONY_VENDOR_ID 0x054C
#define SONY_CLIE_3_5_ID 0x0038
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 3a1dcf663a3a..f6143141b650 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -306,58 +306,49 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
dbg(__FUNCTION__" - port %d", port->number);
- ++port->open_count;
-
- if (port->open_count == 1) {
- /* set up some stuff for our command port */
- command_port = &port->serial->port[COMMAND_PORT];
- if (command_port->private == NULL) {
- info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
- if (info == NULL) {
- err(__FUNCTION__ " - out of memory");
- retval = -ENOMEM;
- goto error_exit;
- }
-
- init_waitqueue_head(&info->wait_command);
- command_port->private = info;
- command_port->write_urb->complete = command_port_write_callback;
- command_port->read_urb->complete = command_port_read_callback;
- command_port->read_urb->dev = port->serial->dev;
- command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */
- retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
- if (retval) {
- err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
- goto error_exit;
- }
+ /* set up some stuff for our command port */
+ command_port = &port->serial->port[COMMAND_PORT];
+ if (command_port->private == NULL) {
+ info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+ if (info == NULL) {
+ err(__FUNCTION__ " - out of memory");
+ retval = -ENOMEM;
+ goto exit;
}
- /* Start reading from the device */
- port->read_urb->dev = port->serial->dev;
- retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ init_waitqueue_head(&info->wait_command);
+ command_port->private = info;
+ command_port->write_urb->complete = command_port_write_callback;
+ command_port->read_urb->complete = command_port_read_callback;
+ command_port->read_urb->dev = port->serial->dev;
+ command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */
+ retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
if (retval) {
err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
- goto error_exit;
+ goto exit;
}
+ }
- /* send an open port command */
- /* firmware uses 1 based port numbering */
- open_command.port = port->number - port->serial->minor + 1;
- retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
- if (retval)
- goto error_exit;
-
- /* Need to do device specific setup here (control lines, baud rate, etc.) */
- /* FIXME!!! */
+ /* Start reading from the device */
+ port->read_urb->dev = port->serial->dev;
+ retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (retval) {
+ err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
+ goto exit;
}
- dbg(__FUNCTION__ " - exit");
- return retval;
+ /* send an open port command */
+ /* firmware uses 1 based port numbering */
+ open_command.port = port->number - port->serial->minor + 1;
+ retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+ if (retval)
+ goto exit;
-error_exit:
- --port->open_count;
+ /* Need to do device specific setup here (control lines, baud rate, etc.) */
+ /* FIXME!!! */
- dbg(__FUNCTION__ " - error_exit");
+exit:
+ dbg(__FUNCTION__ " - exit, retval = %d", retval);
return retval;
}
@@ -368,22 +359,17 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
dbg(__FUNCTION__ " - port %d", port->number);
- --port->open_count;
+ /* send a close command to the port */
+ /* firmware uses 1 based port numbering */
+ close_command.port = port->number - port->serial->minor + 1;
+ whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
- if (port->open_count <= 0) {
- /* send a close command to the port */
- /* firmware uses 1 based port numbering */
- close_command.port = port->number - port->serial->minor + 1;
- whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+ /* Need to change the control lines here */
+ /* FIXME */
- /* Need to change the control lines here */
- /* FIXME */
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->open_count = 0;
- }
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
}
@@ -641,18 +627,10 @@ error_out:
static void whiteheat_real_shutdown (struct usb_serial *serial)
{
- struct usb_serial_port *command_port;
- int i;
+ struct usb_serial_port *command_port;
dbg(__FUNCTION__);
- /* stop reads and writes on all ports */
- for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- whiteheat_close (&serial->port[i], NULL);
- }
- }
-
/* free up our private data for our command port */
command_port = &serial->port[COMMAND_PORT];
if (command_port->private != NULL) {
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index a991bd2d9240..2dc2ac1a3e0a 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -112,7 +112,7 @@ struct bulk_cs_wrap {
#define US_BULK_GET_MAX_LUN 0xfe
/*
- * us_bulk_transfer() return codes
+ * usb_stor_transfer() return codes
*/
#define US_BULK_TRANSFER_GOOD 0 /* good transfer */
#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */
diff --git a/drivers/usb/tiglusb.c b/drivers/usb/tiglusb.c
new file mode 100644
index 000000000000..8e3dcf1c9317
--- /dev/null
+++ b/drivers/usb/tiglusb.c
@@ -0,0 +1,495 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
+ * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2001-2002:
+ * Romain Lievin <roms@lpg.ticalc.org>
+ * Julien BLACHE <jb@technologeek.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Based on dabusb.c, printer.c & scanner.c
+ *
+ * Please see the file: linux/Documentation/usb/SilverLink.txt
+ * and the website at: http://lpg.ticalc.org/prj_usb/
+ * for more info.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/ticable.h>
+#include "tiglusb.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.02"
+#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
+#define DRIVER_DESC "TI-GRAPH LINK USB (aka SilverLink) driver"
+#define DRIVER_LICENSE "GPL"
+
+
+/* ----- global variables --------------------------------------------- */
+
+static tiglusb_t tiglusb[MAXTIGL];
+static int timeout = TIMAXTIME; /* timeout in tenth of seconds */
+
+static devfs_handle_t devfs_handle;
+
+/*---------- misc functions ------------------------------------------- */
+
+/* Unregister device */
+static void usblp_cleanup (tiglusb_t * s)
+{
+ devfs_unregister (s->devfs);
+ //memset(tiglusb[s->minor], 0, sizeof(tiglusb_t));
+ info ("tiglusb%d removed", s->minor);
+}
+
+/* Re-initialize device */
+static int clear_device (struct usb_device *dev)
+{
+ if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+ printk ("tiglusb: clear_device failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Clear input & output pipes (endpoints) */
+static int clear_pipes (struct usb_device *dev)
+{
+ unsigned int pipe;
+
+ pipe = usb_sndbulkpipe (dev, 1);
+ if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+ printk ("tiglusb: clear_pipe (r), request failed\n");
+ return -1;
+ }
+
+ pipe = usb_sndbulkpipe (dev, 2);
+ if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+ printk ("tiglusb: clear_pipe (w), request failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int tiglusb_open (struct inode *inode, struct file *file)
+{
+ int devnum = minor (inode->i_rdev);
+ ptiglusb_t s;
+
+ if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
+ return -EIO;
+
+ s = &tiglusb[devnum - TIUSB_MINOR];
+
+ down (&s->mutex);
+
+ while (!s->dev || s->opened) {
+ up (&s->mutex);
+
+ if (file->f_flags & O_NONBLOCK) {
+ return -EBUSY;
+ }
+ schedule_timeout (HZ / 2);
+
+ if (signal_pending (current)) {
+ return -EAGAIN;
+ }
+ down (&s->mutex);
+ }
+
+ s->opened = 1;
+ up (&s->mutex);
+
+ file->f_pos = 0;
+ file->private_data = s;
+
+ return 0;
+}
+
+static int tiglusb_release (struct inode *inode, struct file *file)
+{
+ ptiglusb_t s = (ptiglusb_t) file->private_data;
+
+ lock_kernel ();
+ down (&s->mutex);
+ s->state = _stopped;
+ up (&s->mutex);
+
+ if (!s->remove_pending)
+ clear_device (s->dev);
+ else
+ wake_up (&s->remove_ok);
+
+ s->opened = 0;
+ unlock_kernel ();
+
+ return 0;
+}
+
+static ssize_t tiglusb_read (struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+ ptiglusb_t s = (ptiglusb_t) file->private_data;
+ ssize_t ret = 0;
+ int bytes_to_read = 0;
+ int bytes_read = 0;
+ int result = 0;
+ char buffer[BULK_RCV_MAX];
+ unsigned int pipe;
+
+ if (*ppos)
+ return -ESPIPE;
+
+ if (s->remove_pending)
+ return -EIO;
+
+ if (!s->dev)
+ return -EIO;
+
+ bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
+
+ pipe = usb_rcvbulkpipe (s->dev, 1);
+ result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
+ &bytes_read, HZ / (timeout / 10));
+ if (result == -ETIMEDOUT) { /* NAK */
+ ret = result;
+ if (!bytes_read) {
+ printk ("quirk !\n");
+ }
+ warn ("tiglusb_read, NAK received.");
+ goto out;
+ } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
+ warn ("CLEAR_FEATURE request to remove STALL condition.\n");
+ if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+ warn ("send_packet, request failed\n");
+ //clear_device(s->dev);
+ ret = result;
+ goto out;
+ } else if (result < 0) { /* We should not get any I/O errors */
+ warn ("funky result: %d. Please notify maintainer.", result);
+ ret = -EIO;
+ goto out;
+ }
+
+ if (copy_to_user (buf, buffer, bytes_read)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ out:
+ return ret ? ret : bytes_read;
+}
+
+static ssize_t tiglusb_write (struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+ ptiglusb_t s = (ptiglusb_t) file->private_data;
+ ssize_t ret = 0;
+ int bytes_to_write = 0;
+ int bytes_written = 0;
+ int result = 0;
+ char buffer[BULK_SND_MAX];
+ unsigned int pipe;
+
+ if (*ppos)
+ return -ESPIPE;
+
+ if (s->remove_pending)
+ return -EIO;
+
+ if (!s->dev)
+ return -EIO;
+
+ bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
+ if (copy_from_user (buffer, buf, bytes_to_write)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ pipe = usb_sndbulkpipe (s->dev, 2);
+ result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
+ &bytes_written, HZ / (timeout / 10));
+
+ if (result == -ETIMEDOUT) { /* NAK */
+ warn ("tiglusb_write, NAK received.");
+ ret = result;
+ goto out;
+ } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
+ warn ("CLEAR_FEATURE request to remove STALL condition.");
+ if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+ warn ("send_packet, request failed\n");
+ //clear_device(s->dev);
+ ret = result;
+ goto out;
+ } else if (result < 0) { /* We should not get any I/O errors */
+ warn ("funky result: %d. Please notify maintainer.", result);
+ ret = -EIO;
+ goto out;
+ }
+
+ if (bytes_written != bytes_to_write) {
+ ret = -EIO;
+ goto out;
+ }
+
+ out:
+ return ret ? ret : bytes_written;
+}
+
+static int tiglusb_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ ptiglusb_t s = (ptiglusb_t) file->private_data;
+ int ret = 0;
+
+ if (s->remove_pending)
+ return -EIO;
+
+ down (&s->mutex);
+
+ if (!s->dev) {
+ up (&s->mutex);
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case IOCTL_TIUSB_TIMEOUT:
+ timeout = arg; // timeout value in tenth of seconds
+ break;
+ case IOCTL_TIUSB_RESET_DEVICE:
+ printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_DEVICE\n");
+ if (clear_device (s->dev))
+ ret = -EIO;
+ break;
+ case IOCTL_TIUSB_RESET_PIPES:
+ printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_PIPES\n");
+ if (clear_pipes (s->dev))
+ ret = -EIO;
+ break;
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ up (&s->mutex);
+
+ return ret;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tiglusb_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: tiglusb_read,
+ write: tiglusb_write,
+ ioctl: tiglusb_ioctl,
+ open: tiglusb_open,
+ release: tiglusb_release,
+};
+
+static int tiglusb_find_struct (void)
+{
+ int u;
+
+ for (u = 0; u < MAXTIGL; u++) {
+ ptiglusb_t s = &tiglusb[u];
+ if (!s->dev)
+ return u;
+ }
+
+ return -1;
+}
+
+/* --- initialisation code ------------------------------------- */
+
+static void *tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ int minor;
+ ptiglusb_t s;
+ char name[8];
+
+ printk ("tiglusb: probing vendor id 0x%x, device id 0x%x ifnum:%d\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+ /*
+ * We don't handle multiple configurations. As of version 0x0103 of
+ * the TIGL hardware, there's only 1 configuration.
+ */
+
+ if (dev->descriptor.bNumConfigurations != 1)
+ return NULL;
+
+ if ((dev->descriptor.idProduct != 0xe001) && (dev->descriptor.idVendor != 0x451))
+ return NULL;
+
+ if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+ printk ("tiglusb_probe: set_configuration failed\n");
+ return NULL;
+ }
+
+ minor = tiglusb_find_struct ();
+ if (minor == -1)
+ return NULL;
+
+ s = &tiglusb[minor];
+
+ down (&s->mutex);
+ s->remove_pending = 0;
+ s->dev = dev;
+ up (&s->mutex);
+ dbg ("bound to interface: %d", ifnum);
+
+ sprintf (name, "%d", s->minor);
+ printk ("tiglusb: registering to devfs : major = %d, minor = %d, node = %s\n", TIUSB_MAJOR,
+ (TIUSB_MINOR + s->minor), name);
+ s->devfs =
+ devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
+ TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO, &tiglusb_fops,
+ NULL);
+
+ /* Display firmware version */
+ printk ("tiglusb: link cable version %i.%02x\n",
+ dev->descriptor.bcdDevice >> 8, dev->descriptor.bcdDevice & 0xff);
+
+ return s;
+}
+
+static void tiglusb_disconnect (struct usb_device *dev, void *drv_context)
+{
+ ptiglusb_t s = (ptiglusb_t) drv_context;
+
+ if (!s || !s->dev)
+ printk ("bogus disconnect");
+
+ s->remove_pending = 1;
+ wake_up (&s->wait);
+ if (s->state == _started)
+ sleep_on (&s->remove_ok);
+ s->dev = NULL;
+ s->opened = 0;
+
+ /* cleanup now or later, on close */
+ if (!s->opened)
+ usblp_cleanup (s);
+ else
+ up (&s->mutex);
+
+ /* unregister device */
+ devfs_unregister (s->devfs);
+ s->devfs = NULL;
+ printk ("tiglusb: device disconnected\n");
+}
+
+static struct usb_device_id tiglusb_ids[] = {
+ {USB_DEVICE (0x0451, 0xe001)},
+ {}
+};
+
+MODULE_DEVICE_TABLE (usb, tiglusb_ids);
+
+static struct usb_driver tiglusb_driver = {
+ owner: THIS_MODULE,
+ name: "tiglusb",
+ probe: tiglusb_probe,
+ disconnect: tiglusb_disconnect,
+ id_table: tiglusb_ids,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/* You must set these - there is no sane way to probe for this cable.
+ * You can use 'tipar=timeout,delay' to set these now. */
+static int __init tiglusb_setup (char *str)
+{
+ int ints[2];
+
+ str = get_options (str, ARRAY_SIZE (ints), ints);
+
+ if (ints[0] > 0) {
+ timeout = ints[1];
+ }
+
+ return 1;
+}
+#endif
+
+static int __init tiglusb_init (void)
+{
+ unsigned u;
+ int result;
+
+ /* initialize struct */
+ for (u = 0; u < MAXTIGL; u++) {
+ ptiglusb_t s = &tiglusb[u];
+ memset (s, 0, sizeof (tiglusb_t));
+ init_MUTEX (&s->mutex);
+ s->dev = NULL;
+ s->minor = u;
+ s->opened = 0;
+ init_waitqueue_head (&s->wait);
+ init_waitqueue_head (&s->remove_ok);
+ }
+
+ /* register device */
+ if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+ printk ("tiglusb: unable to get major %d\n", TIUSB_MAJOR);
+ return -EIO;
+ }
+
+ /* Use devfs, tree: /dev/ticables/usb/[0..3] */
+ devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
+
+ /* register USB module */
+ result = usb_register (&tiglusb_driver);
+ if (result < 0) {
+ devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+ return -1;
+ }
+
+ info (DRIVER_DESC ", " DRIVER_VERSION);
+
+ return 0;
+}
+
+static void __exit tiglusb_cleanup (void)
+{
+ usb_deregister (&tiglusb_driver);
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup ("tipar=", tiglusb_setup);
+module_init (tiglusb_init);
+module_exit (tiglusb_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE (DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM (timeout, "i");
+MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/tiglusb.h b/drivers/usb/tiglusb.h
new file mode 100644
index 000000000000..3f2ee4a6f6fd
--- /dev/null
+++ b/drivers/usb/tiglusb.h
@@ -0,0 +1,55 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb - low level driver for SilverLink cable
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TIGLUSB_H
+#define _TIGLUSB_H
+
+/*
+ * Max. number of devices supported
+ */
+#define MAXTIGL 16
+
+/*
+ * Max. packetsize for IN and OUT pipes
+ */
+#define BULK_RCV_MAX 32
+#define BULK_SND_MAX 32
+
+/*
+ * The driver context...
+ */
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+ struct usb_device *dev; /* USB device handle */
+ struct semaphore mutex; /* locks this struct */
+ struct semaphore sem;
+
+ wait_queue_head_t wait; /* for timed waits */
+ wait_queue_head_t remove_ok;
+
+ int minor; /* which minor dev #? */
+ devfs_handle_t devfs; /* devfs device */
+
+ driver_state_t state; /* started/stopped */
+ int opened; /* tru if open */
+ int remove_pending;
+
+ char rd_buf[BULK_RCV_MAX]; /* read buffer */
+ char wr_buf[BULK_SND_MAX]; /* write buffer */
+
+} tiglusb_t, *ptiglusb_t;
+
+extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
+
+#endif
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 7a5f9a02bcff..27a902aefcb2 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -337,6 +337,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
qh->link = UHCI_PTR_TERM;
qh->dev = dev;
+ qh->urbp = NULL;
INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list);
@@ -411,20 +412,19 @@ static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
-static void uhci_remove_qh(struct uhci *uhci, struct urb *urb)
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
unsigned long flags;
- struct uhci_qh *qh = urbp->qh, *pqh;
+ struct uhci_qh *pqh;
if (!qh)
return;
+ qh->urbp = NULL;
+
/* Only go through the hoops if it's actually linked in */
spin_lock_irqsave(&uhci->frame_list_lock, flags);
if (!list_empty(&qh->list)) {
- qh->urbp = NULL;
-
pqh = list_entry(qh->list.prev, struct uhci_qh, list);
if (pqh->urbp) {
@@ -619,7 +619,7 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
{
struct urb_priv *urbp;
- urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
if (!urbp) {
err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
return NULL;
@@ -1043,7 +1043,7 @@ static int usb_control_retrigger_status(struct urb *urb)
urbp->short_control_packet = 1;
/* Create a new QH to avoid pointer overwriting problems */
- uhci_remove_qh(uhci, urb);
+ uhci_remove_qh(uhci, urbp->qh);
/* Delete all of the TD's except for the status TD at the end */
head = &urbp->td_list;
@@ -1264,20 +1264,29 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
data);
data += pktsze;
- len -= pktsze;
+ len -= maxsze;
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
} while (len > 0);
+ /*
+ * USB_ZERO_PACKET means adding a 0-length packet, if
+ * direction is OUT and the transfer_length was an
+ * exact multiple of maxsze, hence
+ * (len = transfer_length - N * maxsze) == 0
+ * however, if transfer_length == 0, the zero packet
+ * was already prepared above.
+ */
if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
- urb->transfer_buffer_length) {
+ !len && urb->transfer_buffer_length) {
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | UHCI_NULL_DATA_SIZE |
+ uhci_fill_td(td, status, destination |
+ (UHCI_NULL_DATA_SIZE << 21) |
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
data);
@@ -1594,7 +1603,9 @@ out:
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
- uhci_call_completion(urb);
+ /* Only call completion if it was successful */
+ if (!ret)
+ uhci_call_completion(urb);
return ret;
}
@@ -1660,6 +1671,7 @@ static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
/* Interrupts are an exception */
if (urb->interval) {
uhci_add_complete(urb);
+ spin_unlock_irqrestore(&urb->lock, flags);
return; /* <-- note return */
}
@@ -1734,7 +1746,8 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
uhci_delete_queued_urb(uhci, urb);
/* The interrupt loop will reclaim the QH's */
- uhci_remove_qh(uhci, urb);
+ uhci_remove_qh(uhci, urbp->qh);
+ urbp->qh = NULL;
}
static int uhci_unlink_urb(struct urb *urb)
@@ -2357,15 +2370,15 @@ static void uhci_call_completion(struct urb *urb)
urb->dev = NULL;
spin_unlock_irqrestore(&urb->lock, flags);
- if (urb->complete) {
+ if (urb->complete)
urb->complete(urb);
+ if (resubmit_interrupt)
/* Recheck the status. The completion handler may have */
/* unlinked the resubmitting interrupt URB */
killed = (urb->status == -ENOENT ||
urb->status == -ECONNABORTED ||
urb->status == -ECONNRESET);
- }
if (resubmit_interrupt && !killed) {
urb->dev = dev;
@@ -2373,7 +2386,7 @@ static void uhci_call_completion(struct urb *urb)
} else {
if (is_ring && !killed) {
urb->dev = dev;
- uhci_submit_urb(urb, GFP_KERNEL);
+ uhci_submit_urb(urb, GFP_ATOMIC);
} else {
/* We decrement the usage count after we're done */
/* with everything */
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 1359625c81cf..78ee59767ed0 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -2,7 +2,7 @@
* URB OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
@@ -11,6 +11,11 @@
*
*
* History:
+ *
+ * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
+ * load failure (Matthew Frederickson)
+ * 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and
+ * make interrupt unlink-in-completion work (db)
*
* 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
* 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
@@ -489,8 +494,7 @@ static int sohci_return_urb (struct ohci *hc, struct urb * urb)
/* implicitly requeued */
urb->actual_length = 0;
urb->status = -EINPROGRESS;
- if (urb_priv->state != URB_DEL)
- td_submit_urb (urb);
+ td_submit_urb (urb);
break;
case PIPE_ISOCHRONOUS:
@@ -800,6 +804,7 @@ static int sohci_unlink_urb (struct urb * urb)
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
spin_unlock_irqrestore (&usb_ed_lock, flags);
+ return -EINPROGRESS;
}
} else {
urb_rm_priv (urb);
@@ -1083,6 +1088,28 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
/*-------------------------------------------------------------------------*/
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+ struct ohci *ohci,
+ struct ed *ed,
+ unsigned index,
+ unsigned period
+) {
+ for (; index < NUM_INTS; index += period) {
+ __u32 *ed_p = &ohci->hcca->int_table [index];
+
+ /* ED might have been unlinked through another path */
+ while (*ed_p != 0) {
+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ ed_p = & ((dma_to_ed (ohci,
+ le32_to_cpup (ed_p)))->hwNextED);
+ }
+ }
+}
+
/* unlink an ed from one of the HC chains.
* just the link to the ed is unlinked.
* the link from the ed still points to another operational ed or 0
@@ -1090,11 +1117,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
static int ep_unlink (ohci_t * ohci, ed_t * ed)
{
- int int_branch;
int i;
- int inter;
- int interval;
- __u32 * ed_p;
ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
@@ -1134,21 +1157,8 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
break;
case PIPE_INTERRUPT:
- int_branch = ed->int_branch;
- interval = ed->int_interval;
-
- for (i = 0; i < ep_rev (6, interval); i += inter) {
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]), inter = 1;
- (*ed_p != 0) && (*ed_p != ed->hwNextED);
- ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED),
- inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {
- if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- for (i = int_branch; i < 32; i += interval)
+ periodic_unlink (ohci, ed, 0, 1);
+ for (i = ed->int_branch; i < 32; i += ed->int_interval)
ohci->ohci_int_load[i] -= ed->int_load;
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_INT");
@@ -1159,23 +1169,13 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
if (ohci->ed_isotail == ed)
ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
- (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+ ->ed_prev = ed->ed_prev;
- if (ed->ed_prev != NULL) {
+ if (ed->ed_prev != NULL)
ed->ed_prev->hwNextED = ed->hwNextED;
- } else {
- for (i = 0; i < 32; i++) {
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
- // inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
- if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- }
+ else
+ periodic_unlink (ohci, ed, 0, 1);
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_ISO");
#endif
@@ -2363,7 +2363,6 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
{
ohci_t * ohci;
- struct usb_bus * bus;
ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
if (!ohci)
@@ -2392,14 +2391,15 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
INIT_LIST_HEAD (&ohci->timeout_list);
- bus = usb_alloc_bus (&sohci_device_operations);
- if (!bus) {
+ ohci->bus = usb_alloc_bus (&sohci_device_operations);
+ if (!ohci->bus) {
+ pci_set_drvdata (dev, NULL);
+ pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+ ohci->hcca, ohci->hcca_dma);
kfree (ohci);
return NULL;
}
-
- ohci->bus = bus;
- bus->hcpriv = (void *) ohci;
+ ohci->bus->hcpriv = (void *) ohci;
return ohci;
}
@@ -2425,9 +2425,11 @@ static void hc_release_ohci (ohci_t * ohci)
ohci->irq = -1;
}
pci_set_drvdata(ohci->ohci_dev, NULL);
-
- usb_deregister_bus (ohci->bus);
- usb_free_bus (ohci->bus);
+ if (ohci->bus) {
+ if (ohci->bus->busnum)
+ usb_deregister_bus (ohci->bus);
+ usb_free_bus (ohci->bus);
+ }
list_del (&ohci->ohci_hcd_list);
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
@@ -2575,12 +2577,14 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned long mem_resource, mem_len;
void *mem_base;
+ int status;
if (pci_enable_device(dev) < 0)
return -ENODEV;
if (!dev->irq) {
err("found OHCI device with no IRQ assigned. check BIOS settings!");
+ pci_disable_device (dev);
return -ENODEV;
}
@@ -2589,19 +2593,28 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
mem_len = pci_resource_len(dev, 0);
if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
dbg ("controller already in use");
+ pci_disable_device (dev);
return -EBUSY;
}
mem_base = ioremap_nocache (mem_resource, mem_len);
if (!mem_base) {
err("Error mapping OHCI memory");
+ release_mem_region (mem_resource, mem_len);
+ pci_disable_device (dev);
return -EFAULT;
}
/* controller writes into our memory */
pci_set_master (dev);
- return hc_found_ohci (dev, dev->irq, mem_base, id);
+ status = hc_found_ohci (dev, dev->irq, mem_base, id);
+ if (status < 0) {
+ iounmap (mem_base);
+ release_mem_region (mem_resource, mem_len);
+ pci_disable_device (dev);
+ }
+ return status;
}
/*-------------------------------------------------------------------------*/
@@ -2639,6 +2652,7 @@ ohci_pci_remove (struct pci_dev *dev)
hc_release_ohci (ohci);
release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+ pci_disable_device (dev);
}
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index 82457dd5850d..99a20358452d 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -454,7 +454,7 @@ static int rh_init_int_timer(struct urb * urb);
/* Recover a TD/ED using its collision chain */
-static inline void *
+static void *
dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
{
struct hash_t * scan = entry->head;
@@ -465,14 +465,14 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
return scan->virt;
}
-static inline struct ed *
+static struct ed *
dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
{
return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
ed_dma);
}
-static inline struct td *
+static struct td *
dma_to_td (struct ohci * hc, dma_addr_t td_dma)
{
return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
@@ -480,7 +480,7 @@ dma_to_td (struct ohci * hc, dma_addr_t td_dma)
}
/* Add a hash entry for a TD/ED; return true on success */
-static inline int
+static int
hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
{
struct hash_t * scan;
@@ -502,14 +502,14 @@ hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
return 1;
}
-static inline int
+static int
hash_add_ed (struct ohci * hc, struct ed * ed)
{
return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
ed, ed->dma);
}
-static inline int
+static int
hash_add_td (struct ohci * hc, struct td * td)
{
return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
@@ -517,7 +517,7 @@ hash_add_td (struct ohci * hc, struct td * td)
}
-static inline void
+static void
hash_free_ed_td (struct hash_list_t * entry, void * virt)
{
struct hash_t *scan, *prev;
@@ -543,13 +543,13 @@ hash_free_ed_td (struct hash_list_t * entry, void * virt)
}
}
-static inline void
+static void
hash_free_ed (struct ohci * hc, struct ed * ed)
{
hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
}
-static inline void
+static void
hash_free_td (struct ohci * hc, struct td * td)
{
hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
@@ -588,7 +588,7 @@ static void ohci_mem_cleanup (struct ohci *ohci)
}
/* TDs ... */
-static inline struct td *
+static struct td *
td_alloc (struct ohci *hc, int mem_flags)
{
dma_addr_t dma;
@@ -616,7 +616,7 @@ td_free (struct ohci *hc, struct td *td)
/* DEV + EDs ... only the EDs need to be consistent */
-static inline struct ohci_device *
+static struct ohci_device *
dev_alloc (struct ohci *hc, int mem_flags)
{
dma_addr_t dma;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 98fbc9980e8e..1d315581cea9 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -171,7 +171,7 @@ _static void uhci_switch_timer_int(uhci_t *s)
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
_static void enable_desc_loop(uhci_t *s, struct urb *urb)
{
- int flags;
+ unsigned long flags;
if (urb->transfer_flags & USB_NO_FSBR)
return;
@@ -186,7 +186,7 @@ _static void enable_desc_loop(uhci_t *s, struct urb *urb)
/*-------------------------------------------------------------------*/
_static void disable_desc_loop(uhci_t *s, struct urb *urb)
{
- int flags;
+ unsigned long flags;
if (urb->transfer_flags & USB_NO_FSBR)
return;
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index a234a7517576..4d1b89cfccf7 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -791,9 +791,22 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
// usbcore-internal ...
// but usb_dec_dev_use() is #defined to this, and that's public!!
+// FIXME the public call should BUG() whenever count goes to zero,
+// the usbcore-internal one should do so _unless_ it does so...
void usb_free_dev(struct usb_device *dev)
{
if (atomic_dec_and_test(&dev->refcnt)) {
+ /* Normally only goes to zero in usb_disconnect(), from
+ * khubd or from roothub shutdown (rmmod/apmd/... thread).
+ * Abnormally, roothub init errors can happen, so HCDs
+ * call this directly.
+ *
+ * Otherwise this is a nasty device driver bug, often in
+ * disconnect processing.
+ */
+ if (in_interrupt ())
+ BUG ();
+
dev->bus->op->deallocate(dev);
usb_destroy_configuration(dev);
diff --git a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
index 7a3664160a66..d7d837d4c836 100644
--- a/drivers/usb/usbnet.c
+++ b/drivers/usb/usbnet.c
@@ -989,9 +989,8 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
|| skb->len > FRAMED_SIZE (dev->net.mtu)) {
dev->stats.rx_frame_errors++;
dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
- MIN_FRAMED, FRAMED_SIZE (dev->net.mtu),
- dev->net.mtu
- );
+ (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu),
+ dev->net.mtu);
return 0;
}
diff --git a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c
index b0d4eb5e0cde..c04a67e6c45c 100644
--- a/drivers/usb/usbvideo.c
+++ b/drivers/usb/usbvideo.c
@@ -1020,7 +1020,7 @@ static struct file_operations usbvideo_fops = {
release: usbvideo_v4l_close,
read: usbvideo_v4l_read,
mmap: usbvideo_v4l_mmap,
- ioctl: video_generic_ioctl,
+ ioctl: usbvideo_v4l_ioctl,
llseek: no_llseek,
};
static struct video_device usbvideo_template = {
@@ -1028,7 +1028,6 @@ static struct video_device usbvideo_template = {
type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_CPIA,
fops: &usbvideo_fops,
- kernel_ioctl: usbvideo_v4l_ioctl,
};
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
@@ -1349,8 +1348,8 @@ int usbvideo_v4l_close(struct inode *inode, struct file *file)
* History:
* 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
*/
-int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
{
uvd_t *uvd = file->private_data;
@@ -1555,6 +1554,12 @@ int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
return 0;
}
+int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
+}
+
/*
* usbvideo_v4l_read()
*
diff --git a/drivers/usb/usbvideo.h b/drivers/usb/usbvideo.h
index 006fd267a426..211249c340db 100644
--- a/drivers/usb/usbvideo.h
+++ b/drivers/usb/usbvideo.h
@@ -350,7 +350,7 @@ void usbvideo_CameraRelease(uvd_t *uvd);
int usbvideo_v4l_close(struct inode *inode, struct file *file);
int usbvideo_v4l_initialize(struct video_device *dev);
int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
- unsigned int ioctlnr, void *arg);
+ unsigned int cmd, unsigned long arg);
int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
int usbvideo_v4l_open(struct inode *inode, struct file *file);
int usbvideo_v4l_read(struct file *file, char *buf,
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index fadb7f0a8719..30de86c25712 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1132,7 +1132,6 @@ static int flash_cursor(void);
static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static u_long chipalloc(u_long size);
static void chipfree(void);
-static char *strtoke(char *s,const char *ct);
/*
* Hardware routines
@@ -1224,22 +1223,22 @@ int __init amifb_setup(char *options)
* <H*> horizontal freq. in kHz
*/
- if (!(p = strtoke(mcap_spec, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
vmin = simple_strtoul(p, NULL, 10);
if (vmin <= 0)
goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
vmax = simple_strtoul(p, NULL, 10);
if (vmax <= 0 || vmax <= vmin)
goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
hmin = 1000 * simple_strtoul(p, NULL, 10);
if (hmin <= 0)
goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p)
+ if (!(p = strsep(&mcap_spec, "")) || !*p)
goto cap_invalid;
hmax = 1000 * simple_strtoul(p, NULL, 10);
if (hmax <= 0 || hmax <= hmin)
@@ -1915,29 +1914,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
}
}
- /*
- * A strtok which returns empty strings, too
- */
-
-static char __init *strtoke(char *s,const char *ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin)
- return NULL;
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
/* --------------------------- Hardware routines --------------------------- */
/*
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 73339ab4cba0..64e8d4a23931 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2860,28 +2860,6 @@ int __init atafb_init(void)
return 0;
}
-/* a strtok which returns empty strings, too */
-
-static char * strtoke(char * s,const char * ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin) {
- return NULL;
- }
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
int __init atafb_setup( char *options )
{
char *this_opt;
@@ -2956,18 +2934,18 @@ int __init atafb_setup( char *options )
int xres;
char *p;
- if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
+ if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
+ if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
sttt_xres=xres;
tt_yres=st_yres=simple_strtoul(p, NULL, 10);
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
sttt_xres_virtual=simple_strtoul(p, NULL, 10);
}
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
sttt_yres_virtual=simple_strtoul(p, NULL, 0);
}
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
ovsc_offset=simple_strtoul(p, NULL, 0);
}
@@ -2993,20 +2971,20 @@ int __init atafb_setup( char *options )
*
* Even xres_virtual is available, we neither support panning nor hw-scrolling!
*/
- if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
xres_virtual = xres = simple_strtoul(p, NULL, 10);
if (xres <= 0) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
yres = simple_strtoul(p, NULL, 10);
if (yres <= 0) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
depth = simple_strtoul(p, NULL, 10);
if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
depth != 16 && depth != 24) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
if (*p == 'i')
planes = FB_TYPE_INTERLEAVED_PLANES;
else if (*p == 'p')
@@ -3019,19 +2997,19 @@ int __init atafb_setup( char *options )
goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
addr = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) ||!*p)
+ if (!(p = strsep(&ext_str, ";")) || !*p)
len = xres*yres*depth/8;
else
len = simple_strtoul(p, NULL, 0);
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
external_vgaiobase=simple_strtoul(p, NULL, 0);
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
external_bitspercol = simple_strtoul(p, NULL, 0);
if (external_bitspercol > 8)
external_bitspercol = 8;
@@ -3039,14 +3017,14 @@ int __init atafb_setup( char *options )
external_bitspercol = 1;
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
if (!strcmp(p, "vga"))
external_card_type = IS_VGA;
if (!strcmp(p, "mv300"))
external_card_type = IS_MV300;
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
xres_virtual = simple_strtoul(p, NULL, 10);
if (xres_virtual < xres)
xres_virtual = xres;
@@ -3089,16 +3067,16 @@ int __init atafb_setup( char *options )
* <V*> vertical freq. in Hz
* <H*> horizontal freq. in kHz
*/
- if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
vmin = simple_strtoul(p, NULL, 10);
if (vmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
vmax = simple_strtoul(p, NULL, 10);
if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
hmin = 1000 * simple_strtoul(p, NULL, 10);
if (hmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, "")) || !*p) goto cap_invalid;
hmax = 1000 * simple_strtoul(p, NULL, 10);
if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
@@ -3117,11 +3095,11 @@ int __init atafb_setup( char *options )
char *p;
int xres, yres, depth, temp;
- if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
yres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, "")) || !*p) goto user_invalid;
depth = simple_strtoul(p, NULL, 10);
if ((temp=get_video_mode("user0"))) {
default_par=temp;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index da3e1ea3cac9..f18527020c7b 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -178,7 +178,6 @@ static void atyfbcon_blank(int blank, struct fb_info *fb);
static int aty_init(struct fb_info_aty *info, const char *name);
#ifdef CONFIG_ATARI
static int store_video_par(char *videopar, unsigned char m64_num);
-static char *strtoke(char *s, const char *ct);
#endif
static void aty_set_crtc(const struct fb_info_aty *info,
@@ -2595,13 +2594,13 @@ static int __init store_video_par(char *video_str, unsigned char m64_num)
printk("store_video_par() '%s' \n", video_str);
- if (!(p = strtoke(video_str, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
vmembase = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
size = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
guiregbase = simple_strtoul(p, NULL, 0);
@@ -2616,25 +2615,6 @@ mach64_invalid:
phys_vmembase[m64_num] = 0;
return -1;
}
-
-static char __init *strtoke(char *s, const char *ct)
-{
- static char *ssave = NULL;
- char *sbegin, *send;
-
- sbegin = s ? s : ssave;
- if (!sbegin)
- return NULL;
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
#endif /* CONFIG_ATARI */
static int atyfbcon_switch(int con, struct fb_info *fb)