summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/processor.c6
-rw-r--r--drivers/atm/idt77252.c4
-rw-r--r--drivers/block/amiflop.c13
-rw-r--r--drivers/block/cciss.c8
-rw-r--r--drivers/block/floppy.c2
-rw-r--r--drivers/block/nbd.c18
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/cdrom/cdu31a.c2
-rw-r--r--drivers/char/amiserial.c28
-rw-r--r--drivers/char/decserial.c3
-rw-r--r--drivers/char/drm/i830_dma.c8
-rw-r--r--drivers/char/genrtc.c81
-rw-r--r--drivers/char/n_tty.c19
-rw-r--r--drivers/char/raw.c71
-rw-r--r--drivers/char/serial167.c3
-rw-r--r--drivers/char/serial_tx3912.c3
-rw-r--r--drivers/char/sh-sci.c3
-rw-r--r--drivers/char/vme_scc.c3
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c302
-rw-r--r--drivers/i2c/busses/i2c-amd756.c138
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c10
-rw-r--r--drivers/i2c/busses/i2c-i801.c363
-rw-r--r--drivers/i2c/busses/i2c-isa.c62
-rw-r--r--drivers/i2c/busses/i2c-piix4.c203
-rw-r--r--drivers/i2c/chips/adm1021.c4
-rw-r--r--drivers/i2c/chips/lm75.c2
-rw-r--r--drivers/i2c/i2c-algo-pcf.c6
-rw-r--r--drivers/i2c/i2c-core.c22
-rw-r--r--drivers/i2c/i2c-proc.c2
-rw-r--r--drivers/ide/pci/piix.c2
-rw-r--r--drivers/macintosh/adb.c2
-rw-r--r--drivers/md/md.c12
-rw-r--r--drivers/md/raid1.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c2
-rw-r--r--drivers/net/3c509.c44
-rw-r--r--drivers/net/82596.c6
-rw-r--r--drivers/net/8390.h3
-rw-r--r--drivers/net/Kconfig56
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/Makefile.lib1
-rw-r--r--drivers/net/Space.c2
-rw-r--r--drivers/net/apne.c8
-rw-r--r--drivers/net/at1700.c120
-rw-r--r--drivers/net/e100/e100.h15
-rw-r--r--drivers/net/e100/e100_config.c21
-rw-r--r--drivers/net/e100/e100_config.h4
-rw-r--r--drivers/net/e100/e100_eeprom.c2
-rw-r--r--drivers/net/e100/e100_main.c268
-rw-r--r--drivers/net/e100/e100_phy.c38
-rw-r--r--drivers/net/e100/e100_phy.h4
-rw-r--r--drivers/net/e100/e100_test.c5
-rw-r--r--drivers/net/e100/e100_ucode.h2
-rw-r--r--drivers/net/e100/e100_vendor.h311
-rw-r--r--drivers/net/e1000/e1000.h32
-rw-r--r--drivers/net/e1000/e1000_ethtool.c104
-rw-r--r--drivers/net/e1000/e1000_hw.c1742
-rw-r--r--drivers/net/e1000/e1000_hw.h303
-rw-r--r--drivers/net/e1000/e1000_main.c806
-rw-r--r--drivers/net/e1000/e1000_osdep.h24
-rw-r--r--drivers/net/e1000/e1000_param.c85
-rw-r--r--drivers/net/macmace.c4
-rw-r--r--drivers/net/ne2k_cbus.c879
-rw-r--r--drivers/net/ne2k_cbus.h481
-rw-r--r--drivers/net/ppp_generic.c7
-rw-r--r--drivers/net/tg3.c8
-rw-r--r--drivers/pnp/pnpbios/core.c4
-rw-r--r--drivers/scsi/3w-xxxx.c435
-rw-r--r--drivers/scsi/3w-xxxx.h33
-rw-r--r--drivers/scsi/53c7xx.c172
-rw-r--r--drivers/scsi/NCR53C9x.c18
-rw-r--r--drivers/scsi/a2091.c10
-rw-r--r--drivers/scsi/a3000.c2
-rw-r--r--drivers/scsi/amiga7xx.c4
-rw-r--r--drivers/scsi/atari_NCR5380.c133
-rw-r--r--drivers/scsi/atari_scsi.c10
-rw-r--r--drivers/scsi/atari_scsi.h2
-rw-r--r--drivers/scsi/blz1230.c4
-rw-r--r--drivers/scsi/blz2060.c4
-rw-r--r--drivers/scsi/cyberstorm.c4
-rw-r--r--drivers/scsi/cyberstormII.c4
-rw-r--r--drivers/scsi/fastlane.c4
-rw-r--r--drivers/scsi/gvp11.c59
-rw-r--r--drivers/scsi/mac_NCR5380.c23
-rw-r--r--drivers/scsi/sun3_NCR5380.c131
-rw-r--r--drivers/scsi/sun3_scsi.c8
-rw-r--r--drivers/scsi/sun3_scsi.h4
-rw-r--r--drivers/scsi/sun3_scsi_vme.c6
-rw-r--r--drivers/scsi/sun3x_esp.c33
-rw-r--r--drivers/scsi/wd33c93.c5
-rw-r--r--drivers/serial/uart00.c4
-rw-r--r--drivers/usb/core/hub.c27
-rw-r--r--drivers/usb/core/message.c4
-rw-r--r--drivers/usb/host/ehci-dbg.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c15
-rw-r--r--drivers/usb/image/scanner.c5
-rw-r--r--drivers/usb/image/scanner.h13
-rw-r--r--drivers/usb/input/hid-core.c4
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/atmsar.c380
-rw-r--r--drivers/usb/misc/atmsar.h87
-rw-r--r--drivers/usb/misc/speedtch.c (renamed from drivers/usb/misc/speedtouch.c)353
-rw-r--r--drivers/usb/net/cdc-ether.c20
-rw-r--r--drivers/usb/net/pegasus.c6
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/usb-skeleton.c229
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amifb.c1500
-rw-r--r--drivers/video/c2p.c229
-rw-r--r--drivers/video/c2p.h16
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/dnfb.c42
113 files changed, 7315 insertions, 3564 deletions
diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c
index 8f06514adce0..4630bb66434d 100644
--- a/drivers/acpi/processor.c
+++ b/drivers/acpi/processor.c
@@ -1356,7 +1356,8 @@ acpi_processor_write_throttling (
loff_t *data)
{
int result = 0;
- struct acpi_processor *pr = (struct acpi_processor *) data;
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_processor *pr = (struct acpi_processor *)m->private;
char state_string[12] = {'\0'};
ACPI_FUNCTION_TRACE("acpi_processor_write_throttling");
@@ -1418,7 +1419,8 @@ acpi_processor_write_limit (
loff_t *data)
{
int result = 0;
- struct acpi_processor *pr = (struct acpi_processor *) data;
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_processor *pr = (struct acpi_processor *)m->private;
char limit_string[25] = {'\0'};
int px = 0;
int tx = 0;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index e337c9e68ed4..3a59d3d3833c 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -730,7 +730,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
struct atm_vcc *vcc = vc->tx_vcc;
vc->estimator->cells += (skb->len + 47) / 48;
- if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
+ if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) {
u32 cps = vc->estimator->maxcps;
vc->estimator->cps = cps;
@@ -2025,7 +2025,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
atomic_inc(&vcc->stats->tx_err);
return -ENOMEM;
}
- atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+ atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
ATM_SKB(skb)->iovcnt = 0;
memcpy(skb_put(skb, 52), cell, 52);
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 924212464123..b473e3b08ce1 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -353,10 +353,8 @@ static int fd_motor_on(int nr)
unit[nr].motor = 1;
fd_select(nr);
- del_timer(&motor_on_timer);
motor_on_timer.data = nr;
- motor_on_timer.expires = jiffies + HZ/2;
- add_timer(&motor_on_timer);
+ mod_timer(&motor_on_timer, jiffies + HZ/2);
on_attempts = 10;
sleep_on (&motor_wait);
@@ -414,11 +412,9 @@ static void floppy_off (unsigned int nr)
int drive;
drive = nr & 3;
- del_timer(motor_off_timer + drive);
- motor_off_timer[drive].expires = jiffies + 3*HZ;
/* called this way it is always from interrupt */
motor_off_timer[drive].data = nr | 0x80000000;
- add_timer(motor_off_timer + nr);
+ mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
}
static int fd_calibrate(int drive)
@@ -1429,10 +1425,7 @@ static void redo_fd_request(void)
floppy->dirty = 1;
/* reset the timer */
- del_timer (flush_track_timer + drive);
-
- flush_track_timer[drive].expires = jiffies + 1;
- add_timer (flush_track_timer + drive);
+ mod_timer (flush_track_timer + drive, jiffies + 1);
local_irq_restore(flags);
break;
}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 734ae3817430..642920295653 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -2623,12 +2623,8 @@ int __init cciss_init(void)
{
printk(KERN_INFO DRIVER_NAME "\n");
- /* Register for out PCI devices */
- if (pci_register_driver(&cciss_pci_driver) > 0 )
- return 0;
- else
- return -ENODEV;
-
+ /* Register for our PCI devices */
+ return pci_register_driver(&cciss_pci_driver);
}
static int __init init_cciss_module(void)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index d3d20c946e30..c8b909229c5d 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3649,6 +3649,8 @@ static void __init config_types(void)
name = default_drive_params[type].name;
allowed_drive_mask |= 1 << drive;
}
+ else
+ allowed_drive_mask &= ~(1 << drive);
} else {
params = &default_drive_params[0].params;
sprintf(temparea, "unknown type %d (usb?)", type);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 001b2f98267e..08298857a712 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -76,22 +76,15 @@ static void nbd_end_request(struct request *req)
{
int uptodate = (req->errors == 0) ? 1 : 0;
request_queue_t *q = req->q;
- struct bio *bio;
- unsigned nsect;
unsigned long flags;
#ifdef PARANOIA
requests_out++;
#endif
spin_lock_irqsave(q->queue_lock, flags);
- while((bio = req->bio) != NULL) {
- nsect = bio_sectors(bio);
- blk_finished_io(nsect);
- req->bio = bio->bi_next;
- bio->bi_next = NULL;
- bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO);
+ if (!end_that_request_first(req, uptodate, req->nr_sectors)) {
+ end_that_request_last(req);
}
- blk_put_request(req);
spin_unlock_irqrestore(q->queue_lock, flags);
}
@@ -243,7 +236,7 @@ static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
req = list_entry(tmp, struct request, queuelist);
if (req != xreq)
continue;
- list_del(&req->queuelist);
+ list_del_init(&req->queuelist);
spin_unlock(&lo->queue_lock);
return req;
}
@@ -322,7 +315,7 @@ void nbd_clear_que(struct nbd_device *lo)
spin_lock(&lo->queue_lock);
if (!list_empty(&lo->queue_head)) {
req = list_entry(lo->queue_head.next, struct request, queuelist);
- list_del(&req->queuelist);
+ list_del_init(&req->queuelist);
}
spin_unlock(&lo->queue_lock);
if (req) {
@@ -387,7 +380,7 @@ static void do_nbd_request(request_queue_t * q)
if (req->errors) {
printk(KERN_ERR "nbd: nbd_send_req failed\n");
spin_lock(&lo->queue_lock);
- list_del(&req->queuelist);
+ list_del_init(&req->queuelist);
spin_unlock(&lo->queue_lock);
nbd_end_request(req);
spin_lock_irq(q->queue_lock);
@@ -590,6 +583,7 @@ static int __init nbd_init(void)
disk->first_minor = i;
disk->fops = &nbd_fops;
disk->private_data = &nbd_dev[i];
+ disk->queue = &nbd_queue;
sprintf(disk->disk_name, "nbd%d", i);
set_capacity(disk, 0x3ffffe);
add_disk(disk);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index aea2bdce51b5..c2774d5224cc 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1125,7 +1125,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
{
- unsigned char buf[20], *base;
+ unsigned char buf[21], *base;
struct dvd_layer *layer;
struct cdrom_generic_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index f25d9ff0fda2..915afe6dfe71 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -1375,9 +1375,9 @@ read_data_block(char *buffer,
readahead_buffer + (2048 -
readahead_dataleft),
readahead_dataleft);
- readahead_dataleft = 0;
bytesleft -= readahead_dataleft;
offset += readahead_dataleft;
+ readahead_dataleft = 0;
} else {
/* The readahead will fill the whole buffer, get the data
and return. */
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 9978844a3bc4..187b8434fb69 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -102,8 +102,6 @@ static char *serial_version = "4.30";
static char *serial_name = "Amiga-builtin serial driver";
-static DECLARE_TASK_QUEUE(tq_serial);
-
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
@@ -276,8 +274,7 @@ static _INLINE_ void rs_sched_event(struct async_struct *info,
int event)
{
info->event |= 1 << event;
- queue_task(&info->tqueue, &tq_serial);
- mark_bh(SERIAL_BH);
+ tasklet_schedule(&info->tlet);
}
static _INLINE_ void receive_chars(struct async_struct *info)
@@ -560,12 +557,8 @@ static void ser_tx_int(int irq, void *dev_id, struct pt_regs * regs)
* interrupt driver proper are done; the interrupt driver schedules
* them using rs_sched_event(), and they get done here.
*/
-static void do_serial_bh(void)
-{
- run_task_queue(&tq_serial);
-}
-static void do_softint(void *private_)
+static void do_softint(unsigned long private_)
{
struct async_struct *info = (struct async_struct *) private_;
struct tty_struct *tty;
@@ -1878,8 +1871,7 @@ static int get_async_struct(int line, struct async_struct **ret_info)
info->flags = sstate->flags;
info->xmit_fifo_size = sstate->xmit_fifo_size;
info->line = line;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
+ tasklet_init(&info->tlet, do_softint, (unsigned long)info);
info->state = sstate;
if (sstate->info) {
kfree(info);
@@ -2117,8 +2109,6 @@ static int __init rs_init(void)
if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]"))
return -EBUSY;
- init_bh(SERIAL_BH, do_serial_bh);
-
IRQ_ports = NULL;
show_serial_version();
@@ -2234,23 +2224,18 @@ static int __init rs_init(void)
static __exit void rs_exit(void)
{
- unsigned long flags;
int e1, e2;
- struct async_struct *info;
+ struct async_struct *info = rs_table[0].info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- save_flags(flags);
- cli();
- remove_bh(SERIAL_BH);
+ tasklet_kill(&info->tlet);
if ((e1 = tty_unregister_driver(&serial_driver)))
printk("SERIAL: failed to unregister serial driver (%d)\n",
e1);
if ((e2 = tty_unregister_driver(&callout_driver)))
printk("SERIAL: failed to unregister callout driver (%d)\n",
e2);
- restore_flags(flags);
- info = rs_table[0].info;
if (info) {
rs_table[0].info = NULL;
kfree(info);
@@ -2320,9 +2305,10 @@ static struct console sercons = {
/*
* Register console.
*/
-static void __init amiserial_console_init(void)
+static int __init amiserial_console_init(void)
{
register_console(&sercons);
+ return 0;
}
console_initcall(amiserial_console_init);
#endif
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
index cd01044afd9d..aa1440934e95 100644
--- a/drivers/char/decserial.c
+++ b/drivers/char/decserial.c
@@ -75,7 +75,7 @@ __initcall(rs_init);
/* serial_console_init handles the special case of starting
* up the console on the serial port
*/
-static void __init decserial_console_init(void)
+static int __init decserial_console_init(void)
{
#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
if (IOASIC)
@@ -93,6 +93,7 @@ static void __init decserial_console_init(void)
#endif
#endif
+ return 0;
}
console_initcall(decserial_console_init);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index dbffc3ced84a..0f65f959c0dd 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -40,12 +40,6 @@
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
-#ifdef DO_MUNMAP_4_ARGS
-#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1)
-#else
-#define DO_MUNMAP(m, a, l) do_munmap(m, a, l)
-#endif
-
#define I830_BUF_FREE 2
#define I830_BUF_CLIENT 1
#define I830_BUF_HARDWARE 0
@@ -230,7 +224,7 @@ static int i830_unmap_buffer(drm_buf_t *buf)
return -EINVAL;
down_write(&current->mm->mmap_sem);
- retcode = DO_MUNMAP(current->mm,
+ retcode = do_munmap(current->mm,
(unsigned long)buf_priv->virtual,
(size_t) buf->total);
up_write(&current->mm->mmap_sem);
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 6be546513a3c..0de5b2d8e51d 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -1,5 +1,8 @@
/*
- * Real Time Clock interface for q40 and other m68k machines
+ * Real Time Clock interface for
+ * - q40 and other m68k machines,
+ * - HP PARISC machines
+ * - PowerPC machines
* emulate some RTC irq capabilities in software
*
* Copyright (C) 1999 Richard Zidlicky
@@ -13,7 +16,7 @@
* pseudo-file for status information.
*
* The ioctls can be used to set the interrupt behaviour where
- * supported.
+ * supported.
*
* The /dev/rtc interface will block on reads until an interrupt
* has been received. If a RTC interrupt has already happened,
@@ -34,9 +37,10 @@
* 1.04 removed useless timer code rz@linux-m68k.org
* 1.05 portable RTC_UIE emulation rz@linux-m68k.org
* 1.06 set_rtc_time can return an error trini@kernel.crashing.org
+ * 1.07 ported to HP PARISC (hppa) Helge Deller <deller@gmx.de>
*/
-#define RTC_VERSION "1.06"
+#define RTC_VERSION "1.07"
#include <linux/module.h>
#include <linux/config.h>
@@ -63,20 +67,17 @@
static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
-static int gen_rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
/*
* Bits in gen_rtc_status.
*/
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
-unsigned char gen_rtc_status; /* bitmapped status byte. */
-unsigned long gen_rtc_irq_data; /* our output to the world */
+static unsigned char gen_rtc_status; /* bitmapped status byte. */
+static unsigned long gen_rtc_irq_data; /* our output to the world */
/* months start at 0 now */
-unsigned char days_in_mo[] =
+static unsigned char days_in_mo[] =
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static int irq_active;
@@ -89,18 +90,20 @@ static unsigned int oldsecs;
static int lostint;
static int tt_exp;
-void gen_rtc_timer(unsigned long data);
+static void gen_rtc_timer(unsigned long data);
static volatile int stask_active; /* schedule_work */
static volatile int ttask_active; /* timer_task */
static int stop_rtc_timers; /* don't requeue tasks */
static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
+static void gen_rtc_interrupt(unsigned long arg);
+
/*
* Routine to poll RTC seconds field for change as often as possible,
* after first RTC_UIE use timer to reduce polling
*/
-void genrtc_troutine(void *data)
+static void genrtc_troutine(void *data)
{
unsigned int tmp = get_rtc_ss();
@@ -124,7 +127,7 @@ void genrtc_troutine(void *data)
stask_active = 0;
}
-void gen_rtc_timer(unsigned long data)
+static void gen_rtc_timer(unsigned long data)
{
lostint = get_rtc_ss() - oldsecs ;
if (lostint<0)
@@ -145,7 +148,7 @@ void gen_rtc_timer(unsigned long data)
* from some routine that periodically (eg 100HZ) monitors
* whether RTC_SECS changed
*/
-void gen_rtc_interrupt(unsigned long arg)
+static void gen_rtc_interrupt(unsigned long arg)
{
/* We store the status in the low byte and the number of
* interrupts received since the last read in the remainder
@@ -175,7 +178,7 @@ static ssize_t gen_rtc_read(struct file *file, char *buf,
unsigned long data;
ssize_t retval;
- if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
+ if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
return -EINVAL;
if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
@@ -385,24 +388,24 @@ static int gen_rtc_read_proc(char *page, char **start, off_t off,
*/
static struct file_operations gen_rtc_fops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
#ifdef CONFIG_GEN_RTC_X
- .read = gen_rtc_read,
- .poll = gen_rtc_poll,
+ .read = gen_rtc_read,
+ .poll = gen_rtc_poll,
#endif
- .ioctl = gen_rtc_ioctl,
- .open = gen_rtc_open,
- .release = gen_rtc_release
+ .ioctl = gen_rtc_ioctl,
+ .open = gen_rtc_open,
+ .release = gen_rtc_release,
};
static struct miscdevice rtc_gen_dev =
{
- RTC_MINOR,
- "rtc",
- &gen_rtc_fops
+ .minor = RTC_MINOR,
+ .name = "rtc",
+ .fops = &gen_rtc_fops,
};
-int __init rtc_generic_init(void)
+static int __init rtc_generic_init(void)
{
int retval;
@@ -436,16 +439,18 @@ module_exit(rtc_generic_exit);
* Info exported via "/proc/rtc".
*/
-int gen_rtc_proc_output(char *buf)
+#ifdef CONFIG_PROC_FS
+
+static int gen_rtc_proc_output(char *buf)
{
char *p;
struct rtc_time tm;
- unsigned tmp;
+ unsigned int flags;
struct rtc_pll_info pll;
p = buf;
- get_rtc_time(&tm);
+ flags = get_rtc_time(&tm);
p += sprintf(p,
"rtc_time\t: %02d:%02d:%02d\n"
@@ -454,7 +459,7 @@ int gen_rtc_proc_output(char *buf)
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
- tm.tm_hour=0;tm.tm_min=0;tm.tm_sec=0;
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
p += sprintf(p, "alarm\t\t: ");
if (tm.tm_hour <= 24)
@@ -472,7 +477,6 @@ int gen_rtc_proc_output(char *buf)
else
p += sprintf(p, "**\n");
- tmp= RTC_24H ;
p += sprintf(p,
"DST_enable\t: %s\n"
"BCD\t\t: %s\n"
@@ -483,15 +487,15 @@ int gen_rtc_proc_output(char *buf)
"periodic_IRQ\t: %s\n"
"periodic_freq\t: %ld\n"
"batt_status\t: %s\n",
- (tmp & RTC_DST_EN) ? "yes" : "no",
- (tmp & RTC_DM_BINARY) ? "no" : "yes",
- (tmp & RTC_24H) ? "yes" : "no",
- (tmp & RTC_SQWE) ? "yes" : "no",
- (tmp & RTC_AIE) ? "yes" : "no",
+ (flags & RTC_DST_EN) ? "yes" : "no",
+ (flags & RTC_DM_BINARY) ? "no" : "yes",
+ (flags & RTC_24H) ? "yes" : "no",
+ (flags & RTC_SQWE) ? "yes" : "no",
+ (flags & RTC_AIE) ? "yes" : "no",
irq_active ? "yes" : "no",
- (tmp & RTC_PIE) ? "yes" : "no",
+ (flags & RTC_PIE) ? "yes" : "no",
0L /* freq */,
- "okay" );
+ (flags & RTC_BATT_BAD) ? "bad" : "okay");
if (!get_rtc_pll(&pll))
p += sprintf(p,
"PLL adjustment\t: %d\n"
@@ -506,7 +510,7 @@ int gen_rtc_proc_output(char *buf)
pll.pll_posmult,
pll.pll_negmult,
pll.pll_clock);
- return p - buf;
+ return p - buf;
}
static int gen_rtc_read_proc(char *page, char **start, off_t off,
@@ -521,6 +525,9 @@ static int gen_rtc_read_proc(char *page, char **start, off_t off,
return len;
}
+#endif /* CONFIG_PROC_FS */
+
MODULE_AUTHOR("Richard Zidlicky");
MODULE_LICENSE("GPL");
+
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index c80d79a80bd0..d4991bac9437 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1029,7 +1029,10 @@ do_it_again:
break;
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
- put_user(cs, b++);
+ if (put_user(cs, b++)) {
+ retval = -EFAULT;
+ break;
+ }
nr--;
break;
}
@@ -1068,7 +1071,10 @@ do_it_again:
/* Deal with packet mode. */
if (tty->packet && b == buf) {
- put_user(TIOCPKT_DATA, b++);
+ if (put_user(TIOCPKT_DATA, b++)) {
+ retval = -EFAULT;
+ break;
+ }
nr--;
}
@@ -1095,12 +1101,17 @@ do_it_again:
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
- put_user(c, b++);
+ if (put_user(c, b++)) {
+ retval = -EFAULT;
+ break;
+ }
nr--;
}
if (eol)
break;
}
+ if (retval)
+ break;
} else {
int uncopied;
uncopied = copy_from_read_buf(tty, &b, &nr);
@@ -1135,7 +1146,7 @@ do_it_again:
current->state = TASK_RUNNING;
size = b - buf;
- if (size) {
+ if (!retval && size) {
retval = size;
if (nr)
clear_bit(TTY_PUSH, &tty->flags);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index ac5f3c0f6041..08fd00d4fce4 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -50,7 +50,7 @@ static int raw_open(struct inode *inode, struct file *filp)
filp->f_op = &raw_ctl_fops;
return 0;
}
-
+
down(&raw_mutex);
/*
@@ -70,10 +70,10 @@ static int raw_open(struct inode *inode, struct file *filp)
} else {
err = set_blocksize(bdev, bdev_hardsect_size(bdev));
if (err == 0) {
- raw_devices[minor].inuse++;
- filp->f_dentry->d_inode->i_mapping =
- bdev->bd_inode->i_mapping;
filp->f_flags |= O_DIRECT;
+ if (++raw_devices[minor].inuse == 1)
+ filp->f_dentry->d_inode->i_mapping =
+ bdev->bd_inode->i_mapping;
}
}
}
@@ -83,6 +83,10 @@ out:
return err;
}
+/*
+ * When the final fd which refers to this character-special node is closed, we
+ * make its ->mapping point back at its own i_data.
+ */
static int raw_release(struct inode *inode, struct file *filp)
{
const int minor= minor(inode->i_rdev);
@@ -90,13 +94,13 @@ static int raw_release(struct inode *inode, struct file *filp)
down(&raw_mutex);
bdev = raw_devices[minor].binding;
- raw_devices[minor].inuse--;
+ if (--raw_devices[minor].inuse == 0) {
+ /* Here inode->i_mapping == bdev->bd_inode->i_mapping */
+ inode->i_mapping = &inode->i_data;
+ inode->i_mapping->backing_dev_info = &default_backing_dev_info;
+ }
up(&raw_mutex);
- /* Here inode->i_mapping == bdev->bd_inode->i_mapping */
- inode->i_mapping = &inode->i_data;
- inode->i_mapping->backing_dev_info = &default_backing_dev_info;
-
bd_release(bdev);
blkdev_put(bdev, BDEV_RAW);
return 0;
@@ -118,27 +122,28 @@ raw_ioctl(struct inode *inode, struct file *filp,
* Deal with ioctls against the raw-device control interface, to bind
* and unbind other raw devices.
*/
-static int
-raw_ctl_ioctl(struct inode *inode, struct file *filp,
- unsigned int command, unsigned long arg)
+static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
+ unsigned int command, unsigned long arg)
{
struct raw_config_request rq;
struct raw_device_data *rawdev;
- int err;
-
+ int err = 0;
+
switch (command) {
case RAW_SETBIND:
case RAW_GETBIND:
/* First, find out which raw minor we want */
- err = -EFAULT;
- if (copy_from_user(&rq, (void *) arg, sizeof(rq)))
+ if (copy_from_user(&rq, (void *) arg, sizeof(rq))) {
+ err = -EFAULT;
goto out;
-
- err = -EINVAL;
- if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS)
+ }
+
+ if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) {
+ err = -EINVAL;
goto out;
+ }
rawdev = &raw_devices[rq.raw_minor];
if (command == RAW_SETBIND) {
@@ -148,9 +153,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
* This is like making block devices, so demand the
* same capability
*/
- err = -EPERM;
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
goto out;
+ }
/*
* For now, we don't need to check that the underlying
@@ -159,17 +165,18 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
* major/minor numbers make sense.
*/
- err = -EINVAL;
dev = MKDEV(rq.block_major, rq.block_minor);
if ((rq.block_major == 0 && rq.block_minor != 0) ||
- MAJOR(dev) != rq.block_major ||
- MINOR(dev) != rq.block_minor)
+ MAJOR(dev) != rq.block_major ||
+ MINOR(dev) != rq.block_minor) {
+ err = -EINVAL;
goto out;
-
+ }
+
down(&raw_mutex);
- err = -EBUSY;
if (rawdev->inuse) {
up(&raw_mutex);
+ err = -EBUSY;
goto out;
}
if (rawdev->binding) {
@@ -181,7 +188,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
rawdev->binding = NULL;
} else {
rawdev->binding = bdget(dev);
- MOD_INC_USE_COUNT;
+ if (rawdev->binding == NULL)
+ err = -ENOMEM;
+ else
+ try_module_get(THIS_MODULE);
}
up(&raw_mutex);
} else {
@@ -196,13 +206,12 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp,
rq.block_major = rq.block_minor = 0;
}
up(&raw_mutex);
- err = -EFAULT;
- if (copy_to_user((void *)arg, &rq, sizeof(rq)))
+ if (copy_to_user((void *)arg, &rq, sizeof(rq))) {
+ err = -EFAULT;
goto out;
+ }
}
- err = 0;
break;
-
default:
err = -EINVAL;
break;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index dcd2d72c2579..1800ea9984dd 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2836,7 +2836,7 @@ static struct console sercons = {
};
-static void __init serial167_console_init(void)
+static int __init serial167_console_init(void)
{
if (vme_brdtype == VME_TYPE_MVME166 ||
vme_brdtype == VME_TYPE_MVME167 ||
@@ -2844,6 +2844,7 @@ static void __init serial167_console_init(void)
mvme167_serial_console_setup(0);
register_console(&sercons);
}
+ return 0;
}
console_initcall(serial167_console_init);
diff --git a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c
index 394b0564aec9..ded61de976d2 100644
--- a/drivers/char/serial_tx3912.c
+++ b/drivers/char/serial_tx3912.c
@@ -1054,9 +1054,10 @@ static struct console sercons = {
.index = -1
};
-static void __init tx3912_console_init(void)
+static int __init tx3912_console_init(void)
{
register_console(&sercons);
+ return 0;
}
console_initcall(tx3912_console_init);
diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
index 5c2463b13eb6..8126a71d0b0b 100644
--- a/drivers/char/sh-sci.c
+++ b/drivers/char/sh-sci.c
@@ -1275,7 +1275,7 @@ static struct console sercons = {
extern void sh_console_unregister (void);
#endif
-static void __init sci_console_init(void)
+static int __init sci_console_init(void)
{
register_console(&sercons);
#ifdef CONFIG_SH_EARLY_PRINTK
@@ -1284,6 +1284,7 @@ static void __init sci_console_init(void)
*/
sh_console_unregister();
#endif
+ return 0;
}
console_initcall(sci_console_init);
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 3eb52370b48a..95cc54d04ed4 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1091,7 +1091,7 @@ static struct console sercons = {
};
-static void __init vme_scc_console_init(void)
+static int __init vme_scc_console_init(void)
{
if (vme_brdtype == VME_TYPE_MVME147 ||
vme_brdtype == VME_TYPE_MVME162 ||
@@ -1099,5 +1099,6 @@ static void __init vme_scc_console_init(void)
vme_brdtype == VME_TYPE_BVME4000 ||
vme_brdtype == VME_TYPE_BVME6000)
register_console(&sercons);
+ return 0;
}
console_initcall(vme_scc_console_init);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 67abe170a8de..a2c20584f7f9 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -76,6 +76,24 @@ config I2C_I801
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
+config I2C_ISA
+ tristate " ISA Bus support"
+ depends on I2C && I2C_PROC && ISA && EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for i2c
+ interfaces that are on the ISA bus.
+
+ This can also be built as a module which can be inserted and removed
+ while the kernel is running. If you want to compile it as a module,
+ say M here and read <file:Documentation/modules.txt>.
+
+ The module will be called i2c-isa.
+
+ You will also need the latest user-space utilties: you can find them
+ in the lm_sensors package, which you can download at
+ http://www.lm-sensors.nu
+
+
config I2C_PIIX4
tristate " Intel PIIX4"
depends on I2C && I2C_PROC && PCI && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index c8e61d4a6f88..b6b6ace36f1b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_I801) += i2c-i801.o
+obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 8d7f372e109f..cd4569ed952f 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -60,6 +60,8 @@
/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
+/* #define DEBUG 1 */
+
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -71,46 +73,46 @@
#include <asm/io.h>
/* ALI15X3 SMBus address offsets */
-#define SMBHSTSTS (0 + ali15x3_smba)
-#define SMBHSTCNT (1 + ali15x3_smba)
-#define SMBHSTSTART (2 + ali15x3_smba)
-#define SMBHSTCMD (7 + ali15x3_smba)
-#define SMBHSTADD (3 + ali15x3_smba)
-#define SMBHSTDAT0 (4 + ali15x3_smba)
-#define SMBHSTDAT1 (5 + ali15x3_smba)
-#define SMBBLKDAT (6 + ali15x3_smba)
+#define SMBHSTSTS (0 + ali15x3_smba)
+#define SMBHSTCNT (1 + ali15x3_smba)
+#define SMBHSTSTART (2 + ali15x3_smba)
+#define SMBHSTCMD (7 + ali15x3_smba)
+#define SMBHSTADD (3 + ali15x3_smba)
+#define SMBHSTDAT0 (4 + ali15x3_smba)
+#define SMBHSTDAT1 (5 + ali15x3_smba)
+#define SMBBLKDAT (6 + ali15x3_smba)
/* PCI Address Constants */
-#define SMBCOM 0x004
-#define SMBBA 0x014
-#define SMBATPC 0x05B /* used to unlock xxxBA registers */
-#define SMBHSTCFG 0x0E0
-#define SMBSLVC 0x0E1
-#define SMBCLK 0x0E2
-#define SMBREV 0x008
+#define SMBCOM 0x004
+#define SMBBA 0x014
+#define SMBATPC 0x05B /* used to unlock xxxBA registers */
+#define SMBHSTCFG 0x0E0
+#define SMBSLVC 0x0E1
+#define SMBCLK 0x0E2
+#define SMBREV 0x008
/* Other settings */
-#define MAX_TIMEOUT 200 /* times 1/100 sec */
-#define ALI15X3_SMB_IOSIZE 32
+#define MAX_TIMEOUT 200 /* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE 32
/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
We don't use these here. If the bases aren't set to some value we
tell user to upgrade BIOS and we fail.
*/
-#define ALI15X3_SMB_DEFAULTBASE 0xE800
+#define ALI15X3_SMB_DEFAULTBASE 0xE800
/* ALI15X3 address lock bits */
-#define ALI15X3_LOCK 0x06
+#define ALI15X3_LOCK 0x06
/* ALI15X3 command constants */
-#define ALI15X3_ABORT 0x02
-#define ALI15X3_T_OUT 0x04
-#define ALI15X3_QUICK 0x00
-#define ALI15X3_BYTE 0x10
-#define ALI15X3_BYTE_DATA 0x20
-#define ALI15X3_WORD_DATA 0x30
-#define ALI15X3_BLOCK_DATA 0x40
-#define ALI15X3_BLOCK_CLR 0x80
+#define ALI15X3_ABORT 0x02
+#define ALI15X3_T_OUT 0x04
+#define ALI15X3_QUICK 0x00
+#define ALI15X3_BYTE 0x10
+#define ALI15X3_BYTE_DATA 0x20
+#define ALI15X3_WORD_DATA 0x30
+#define ALI15X3_BLOCK_DATA 0x40
+#define ALI15X3_BLOCK_CLR 0x80
/* ALI15X3 status register bits */
#define ALI15X3_STS_IDLE 0x04
@@ -129,55 +131,52 @@ MODULE_PARM(force_addr, "i");
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the i2c controller");
-
-static void ali15x3_do_pause(unsigned int amount);
-static int ali15x3_transaction(void);
-
static unsigned short ali15x3_smba = 0;
-int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
{
u16 a;
unsigned char temp;
-/* Check the following things:
- - SMB I/O address is initialized
- - Device is enabled
- - We can use the addresses
-*/
-
-/* Unlock the register.
- The data sheet says that the address registers are read-only
- if the lock bits are 1, but in fact the address registers
- are zero unless you clear the lock bits.
-*/
+ /* Check the following things:
+ - SMB I/O address is initialized
+ - Device is enabled
+ - We can use the addresses
+ */
+
+ /* Unlock the register.
+ The data sheet says that the address registers are read-only
+ if the lock bits are 1, but in fact the address registers
+ are zero unless you clear the lock bits.
+ */
pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
if (temp & ALI15X3_LOCK) {
temp &= ~ALI15X3_LOCK;
pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
}
-/* Determine the address of the SMBus area */
+ /* Determine the address of the SMBus area */
pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
if (ali15x3_smba == 0 && force_addr == 0) {
- printk
- ("i2c-ali15x3.o: ALI15X3_smb region uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+ dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
+ "- upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
if(force_addr)
ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
- if (check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE)) {
- printk
- ("i2c-ali15x3.o: ALI15X3_smb region 0x%x already in use!\n",
- ali15x3_smba);
+ if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) {
+ dev_err(&ALI15X3_dev->dev,
+ "ALI15X3_smb region 0x%x already in use!\n",
+ ali15x3_smba);
return -ENODEV;
}
if(force_addr) {
- printk("i2c-ali15x3.o: forcing ISA address 0x%04X\n", ali15x3_smba);
+ dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
+ ali15x3_smba);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba))
return -ENODEV;
@@ -186,68 +185,60 @@ int ali15x3_setup(struct pci_dev *ALI15X3_dev)
return -ENODEV;
if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
/* make sure it works */
- printk("i2c-ali15x3.o: force address failed - not supported?\n");
+ dev_err(&ALI15X3_dev->dev,
+ "force address failed - not supported?\n");
return -ENODEV;
}
}
-/* check if whole device is enabled */
+ /* check if whole device is enabled */
pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
if ((temp & 1) == 0) {
- printk("i2c-ali15x3: enabling SMBus device\n");
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
}
-/* Is SMB Host controller enabled? */
+ /* Is SMB Host controller enabled? */
pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
if ((temp & 1) == 0) {
- printk("i2c-ali15x3: enabling SMBus controller\n");
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
}
-/* set SMB clock to 74KHz as recommended in data sheet */
+ /* set SMB clock to 74KHz as recommended in data sheet */
pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
- /* Everything is happy, let's grab the memory and set things up. */
- request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb");
-
-#ifdef DEBUG
-/*
- The interrupt routing for SMB is set up in register 0x77 in the
- 1533 ISA Bridge device, NOT in the 7101 device.
- Don't bother with finding the 1533 device and reading the register.
- if ((....... & 0x0F) == 1)
- printk("i2c-ali15x3.o: ALI15X3 using Interrupt 9 for SMBus.\n");
-*/
+ /*
+ The interrupt routing for SMB is set up in register 0x77 in the
+ 1533 ISA Bridge device, NOT in the 7101 device.
+ Don't bother with finding the 1533 device and reading the register.
+ if ((....... & 0x0F) == 1)
+ dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+ */
pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
- printk("i2c-ali15x3.o: SMBREV = 0x%X\n", temp);
- printk("i2c-ali15x3.o: ALI15X3_smba = 0x%X\n", ali15x3_smba);
-#endif /* DEBUG */
+ dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
return 0;
}
-
/* Internally used pause function */
-void ali15x3_do_pause(unsigned int amount)
+static void ali15x3_do_pause(unsigned int amount)
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(amount);
}
/* Another internally used function */
-int ali15x3_transaction(void)
+static int ali15x3_transaction(struct i2c_adapter *adap)
{
int temp;
int result = 0;
int timeout = 0;
-#ifdef DEBUG
- printk
- ("i2c-ali15x3.o: Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
- "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
- inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
- inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
/* get status */
temp = inb_p(SMBHSTSTS);
@@ -255,43 +246,32 @@ int ali15x3_transaction(void)
/* Make sure the SMBus host is ready to start transmitting */
/* Check the busy bit first */
if (temp & ALI15X3_STS_BUSY) {
-/*
- If the host controller is still busy, it may have timed out in the previous transaction,
- resulting in a "SMBus Timeout" printk.
- I've tried the following to reset a stuck busy bit.
- 1. Reset the controller with an ABORT command.
- (this doesn't seem to clear the controller if an external device is hung)
- 2. Reset the controller and the other SMBus devices with a T_OUT command.
- (this clears the host busy bit if an external device is hung,
- but it comes back upon a new access to a device)
- 3. Disable and reenable the controller in SMBHSTCFG
- Worst case, nothing seems to work except power reset.
-*/
-/* Abort - reset the host controller */
-/*
-#ifdef DEBUG
- printk("i2c-ali15x3.o: Resetting host controller to clear busy condition\n",temp);
-#endif
- outb_p(ALI15X3_ABORT, SMBHSTCNT);
- temp = inb_p(SMBHSTSTS);
- if (temp & ALI15X3_STS_BUSY) {
-*/
-
-/*
- Try resetting entire SMB bus, including other devices -
- This may not work either - it clears the BUSY bit but
- then the BUSY bit may come back on when you try and use the chip again.
- If that's the case you are stuck.
-*/
- printk
- ("i2c-ali15x3.o: Resetting entire SMB Bus to clear busy condition (%02x)\n",
- temp);
+ /*
+ If the host controller is still busy, it may have timed out in the
+ previous transaction, resulting in a "SMBus Timeout" Dev.
+ I've tried the following to reset a stuck busy bit.
+ 1. Reset the controller with an ABORT command.
+ (this doesn't seem to clear the controller if an external
+ device is hung)
+ 2. Reset the controller and the other SMBus devices with a
+ T_OUT command. (this clears the host busy bit if an
+ external device is hung, but it comes back upon a new access
+ to a device)
+ 3. Disable and reenable the controller in SMBHSTCFG
+ Worst case, nothing seems to work except power reset.
+ */
+ /* Abort - reset the host controller */
+ /*
+ Try resetting entire SMB bus, including other devices -
+ This may not work either - it clears the BUSY bit but
+ then the BUSY bit may come back on when you try and use the chip again.
+ If that's the case you are stuck.
+ */
+ dev_info(&adap->dev, "Resetting entire SMB Bus to "
+ "clear busy condition (%02x)\n", temp);
outb_p(ALI15X3_T_OUT, SMBHSTCNT);
temp = inb_p(SMBHSTSTS);
}
-/*
- }
-*/
/* now check the error bits and the busy bit */
if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
@@ -302,9 +282,9 @@ int ali15x3_transaction(void)
/* this is probably going to be correctable only by a power reset
as one of the bits now appears to be stuck */
/* This may be a bus or device with electrical problems. */
- printk
- ("i2c-ali15x3.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n",
- temp);
+ dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+ "controller or device on bus is probably hung\n",
+ temp);
return -1;
}
} else {
@@ -328,48 +308,41 @@ int ali15x3_transaction(void)
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
result = -1;
- printk("i2c-ali15x3.o: SMBus Timeout!\n");
+ dev_err(&adap->dev, "SMBus Timeout!\n");
}
if (temp & ALI15X3_STS_TERM) {
result = -1;
-#ifdef DEBUG
- printk("i2c-ali15x3.o: Error: Failed bus transaction\n");
-#endif
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
}
-/*
- Unfortunately the ALI SMB controller maps "no response" and "bus collision"
- into a single bit. No reponse is the usual case so don't
- do a printk.
- This means that bus collisions go unreported.
-*/
+ /*
+ Unfortunately the ALI SMB controller maps "no response" and "bus
+ collision" into a single bit. No reponse is the usual case so don't
+ do a printk.
+ This means that bus collisions go unreported.
+ */
if (temp & ALI15X3_STS_COLL) {
result = -1;
-#ifdef DEBUG
- printk
- ("i2c-ali15x3.o: Error: no response or bus collision ADD=%02x\n",
- inb_p(SMBHSTADD));
-#endif
+ dev_dbg(&adap->dev,
+ "Error: no response or bus collision ADD=%02x\n",
+ inb_p(SMBHSTADD));
}
-/* haven't ever seen this */
+ /* haven't ever seen this */
if (temp & ALI15X3_STS_DEV) {
result = -1;
- printk("i2c-ali15x3.o: Error: device error\n");
+ dev_err(&adap->dev, "Error: device error\n");
}
-#ifdef DEBUG
- printk
- ("i2c-ali15x3.o: Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, "
- "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
- inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
- inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
return result;
}
/* Return -1 on error. */
-s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data * data)
{
@@ -377,9 +350,9 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
int temp;
int timeout;
-/* clear all the bits (clear-on-write) */
+ /* clear all the bits (clear-on-write) */
outb_p(0xFF, SMBHSTSTS);
-/* make sure SMBus is idle */
+ /* make sure SMBus is idle */
temp = inb_p(SMBHSTSTS);
for (timeout = 0;
(timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
@@ -388,14 +361,12 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
temp = inb_p(SMBHSTSTS);
}
if (timeout >= MAX_TIMEOUT) {
- printk("i2c-ali15x3.o: Idle wait Timeout! STS=0x%02x\n",
- temp);
+ dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
}
switch (size) {
case I2C_SMBUS_PROC_CALL:
- printk
- ("i2c-ali15x3.o: I2C_SMBUS_PROC_CALL not supported!\n");
+ dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
return -1;
case I2C_SMBUS_QUICK:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
@@ -442,7 +413,8 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
data->block[0] = len;
}
outb_p(len, SMBHSTDAT0);
- outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
for (i = 1; i <= len; i++)
outb_p(data->block[i], SMBBLKDAT);
}
@@ -452,7 +424,7 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
outb_p(size, SMBHSTCNT); /* output command */
- if (ali15x3_transaction()) /* Error in transaction */
+ if (ali15x3_transaction(adap)) /* Error in transaction */
return -1;
if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
@@ -474,22 +446,19 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
if (len > 32)
len = 32;
data->block[0] = len;
- outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
for (i = 1; i <= data->block[0]; i++) {
data->block[i] = inb_p(SMBBLKDAT);
-#ifdef DEBUG
- printk
- ("i2c-ali15x3.o: Blk: len=%d, i=%d, data=%02x\n",
- len, i, data->block[i]);
-#endif /* DEBUG */
+ dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+ len, i, data->block[i]);
}
break;
}
return 0;
}
-
-u32 ali15x3_func(struct i2c_adapter *adapter)
+static u32 ali15x3_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
@@ -510,8 +479,6 @@ static struct i2c_adapter ali15x3_adapter = {
.algo = &smbus_algorithm,
};
-
-
static struct pci_device_id ali15x3_ids[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_AL,
@@ -525,9 +492,8 @@ static struct pci_device_id ali15x3_ids[] __devinitdata = {
static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (ali15x3_setup(dev)) {
- printk
- ("i2c-ali15x3.o: ALI15X3 not detected, module not inserted.\n");
-
+ dev_err(&dev->dev,
+ "ALI15X3 not detected, module not inserted.\n");
return -ENODEV;
}
@@ -557,17 +523,15 @@ static int __init i2c_ali15x3_init(void)
return pci_module_init(&ali15x3_driver);
}
-
static void __exit i2c_ali15x3_exit(void)
{
pci_unregister_driver(&ali15x3_driver);
release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
}
-
-
-MODULE_AUTHOR
- ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("ALI15X3 SMBus driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index d4bc60ebac3d..86ae2dce1423 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -35,6 +35,8 @@
Note: we assume there can only be one device, with one SMBus interface.
*/
+/* #define DEBUG 1 */
+
#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -46,44 +48,42 @@
#include <linux/init.h>
#include <asm/io.h>
-#define DRV_NAME "i2c-amd756"
-
/* AMD756 SMBus address offsets */
-#define SMB_ADDR_OFFSET 0xE0
-#define SMB_IOSIZE 16
-#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport)
-#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport)
-#define SMB_HOST_ADDRESS (0x4 + amd756_ioport)
-#define SMB_HOST_DATA (0x6 + amd756_ioport)
-#define SMB_HOST_COMMAND (0x8 + amd756_ioport)
-#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport)
-#define SMB_HAS_DATA (0xA + amd756_ioport)
-#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
-#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport)
-#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport)
+#define SMB_ADDR_OFFSET 0xE0
+#define SMB_IOSIZE 16
+#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS (0x4 + amd756_ioport)
+#define SMB_HOST_DATA (0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND (0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport)
+#define SMB_HAS_DATA (0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport)
/* PCI Address Constants */
/* address of I/O space */
-#define SMBBA 0x058 /* mh */
-#define SMBBANFORCE 0x014
+#define SMBBA 0x058 /* mh */
+#define SMBBANFORCE 0x014
/* general configuration */
-#define SMBGCFG 0x041 /* mh */
+#define SMBGCFG 0x041 /* mh */
/* silicon revision code */
-#define SMBREV 0x008
+#define SMBREV 0x008
/* Other settings */
-#define MAX_TIMEOUT 500
+#define MAX_TIMEOUT 500
/* AMD756 constants */
-#define AMD756_QUICK 0x00
-#define AMD756_BYTE 0x01
-#define AMD756_BYTE_DATA 0x02
-#define AMD756_WORD_DATA 0x03
-#define AMD756_PROCESS_CALL 0x04
-#define AMD756_BLOCK_DATA 0x05
+#define AMD756_QUICK 0x00
+#define AMD756_BYTE 0x01
+#define AMD756_BYTE_DATA 0x02
+#define AMD756_WORD_DATA 0x03
+#define AMD756_PROCESS_CALL 0x04
+#define AMD756_BLOCK_DATA 0x05
static unsigned short amd756_ioport = 0;
@@ -101,36 +101,36 @@ static void amd756_do_pause(unsigned int amount)
schedule_timeout(amount);
}
-#define GS_ABRT_STS (1 << 0)
-#define GS_COL_STS (1 << 1)
-#define GS_PRERR_STS (1 << 2)
-#define GS_HST_STS (1 << 3)
-#define GS_HCYC_STS (1 << 4)
-#define GS_TO_STS (1 << 5)
-#define GS_SMB_STS (1 << 11)
+#define GS_ABRT_STS (1 << 0)
+#define GS_COL_STS (1 << 1)
+#define GS_PRERR_STS (1 << 2)
+#define GS_HST_STS (1 << 3)
+#define GS_HCYC_STS (1 << 4)
+#define GS_TO_STS (1 << 5)
+#define GS_SMB_STS (1 << 11)
-#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
- GS_HCYC_STS | GS_TO_STS )
+#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+ GS_HCYC_STS | GS_TO_STS )
-#define GE_CYC_TYPE_MASK (7)
-#define GE_HOST_STC (1 << 3)
-#define GE_ABORT (1 << 5)
+#define GE_CYC_TYPE_MASK (7)
+#define GE_HOST_STC (1 << 3)
+#define GE_ABORT (1 << 5)
-static int amd756_transaction(void)
+static int amd756_transaction(struct i2c_adapter *adap)
{
int temp;
int result = 0;
int timeout = 0;
- pr_debug(DRV_NAME
- ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
- inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
- inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+ dev_dbg(&adap->dev, ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+ "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
+ inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
+ inb_p(SMB_HOST_DATA));
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
- pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp);
+ dev_dbg(&adap->dev, ": SMBus busy (%04x). Waiting... \n", temp);
do {
amd756_do_pause(1);
temp = inw_p(SMB_GLOBAL_STATUS);
@@ -138,7 +138,7 @@ static int amd756_transaction(void)
(timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
- pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp);
+ dev_dbg(&adap->dev, ": Busy wait timeout (%04x)\n", temp);
goto abort;
}
timeout = 0;
@@ -155,46 +155,46 @@ static int amd756_transaction(void)
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
- pr_debug(DRV_NAME ": Completion timeout!\n");
+ dev_dbg(&adap->dev, ": Completion timeout!\n");
goto abort;
}
if (temp & GS_PRERR_STS) {
result = -1;
- pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n");
+ dev_dbg(&adap->dev, ": SMBus Protocol error (no response)!\n");
}
if (temp & GS_COL_STS) {
result = -1;
- printk(KERN_WARNING DRV_NAME " SMBus collision!\n");
+ dev_warn(&adap->dev, " SMBus collision!\n");
}
if (temp & GS_TO_STS) {
result = -1;
- pr_debug(DRV_NAME ": SMBus protocol timeout!\n");
+ dev_dbg(&adap->dev, ": SMBus protocol timeout!\n");
}
if (temp & GS_HCYC_STS)
- pr_debug(DRV_NAME " SMBus protocol success!\n");
+ dev_dbg(&adap->dev, " SMBus protocol success!\n");
outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
#ifdef DEBUG
if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
- pr_debug(DRV_NAME
- ": Failed reset at end of transaction (%04x)\n", temp);
+ dev_dbg(&adap->dev,
+ ": Failed reset at end of transaction (%04x)\n", temp);
}
-
- pr_debug(DRV_NAME
- ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
- inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
- inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
#endif
+ dev_dbg(&adap->dev,
+ ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+ inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+ inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
return result;
abort:
- printk(KERN_WARNING DRV_NAME ": Sending abort.\n");
+ dev_warn(&adap->dev, ": Sending abort.\n");
outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
amd756_do_pause(100);
outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
@@ -211,7 +211,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
/** TODO: Should I supporte the 10-bit transfers? */
switch (size) {
case I2C_SMBUS_PROC_CALL:
- pr_debug(DRV_NAME ": I2C_SMBUS_PROC_CALL not supported!\n");
+ dev_dbg(&adap->dev, ": I2C_SMBUS_PROC_CALL not supported!\n");
/* TODO: Well... It is supported, I'm just not sure what to do here... */
return -1;
case I2C_SMBUS_QUICK:
@@ -266,7 +266,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
/* How about enabling interrupts... */
outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
- if (amd756_transaction()) /* Error in transaction */
+ if (amd756_transaction(adap)) /* Error in transaction */
return -1;
if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
@@ -334,7 +334,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
u8 temp;
if (amd756_ioport) {
- printk(KERN_ERR DRV_NAME ": Only one device supported. "
+ dev_err(&pdev->dev, ": Only one device supported. "
"(you have a strange motherboard, btw..)\n");
return -ENODEV;
}
@@ -351,8 +351,8 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
pci_read_config_byte(pdev, SMBGCFG, &temp);
if ((temp & 128) == 0) {
- printk(KERN_ERR DRV_NAME
- ": Error: SMBus controller I/O not enabled!\n");
+ dev_err(&pdev->dev,
+ ": Error: SMBus controller I/O not enabled!\n");
return -ENODEV;
}
@@ -364,16 +364,14 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
}
if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
- printk(KERN_ERR DRV_NAME
- ": SMB region 0x%x already in use!\n", amd756_ioport);
+ dev_err(&pdev->dev, ": SMB region 0x%x already in use!\n",
+ amd756_ioport);
return -ENODEV;
}
-#ifdef DEBUG
pci_read_config_byte(pdev, SMBREV, &temp);
- printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp);
- printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport);
-#endif
+ dev_dbg(&pdev->dev, ": SMBREV = 0x%X\n", temp);
+ dev_dbg(&pdev->dev, ": AMD756_smba = 0x%X\n", amd756_ioport);
/* set up the driverfs linkage to our parent device */
amd756_adapter.dev.parent = &pdev->dev;
@@ -383,8 +381,8 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
error = i2c_add_adapter(&amd756_adapter);
if (error) {
- printk(KERN_ERR DRV_NAME
- ": Adapter registration failed, module not inserted.\n");
+ dev_err(&pdev->dev,
+ ": Adapter registration failed, module not inserted.\n");
goto out_err;
}
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 07f22e6e8495..e83bbf9ffd0e 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -74,7 +74,7 @@ unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
udelay(1);
if (!timeout) {
- printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n");
+ dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n");
return -1;
}
@@ -89,7 +89,7 @@ unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
udelay(1);
if (!timeout) {
- printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n");
+ dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n");
return -1;
}
@@ -256,11 +256,11 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BLOCK_DATA_PEC:
case I2C_SMBUS_PROC_CALL_PEC:
case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
- printk(KERN_WARNING "i2c-amd8111.c: Unexpected software PEC transaction %d\n.", size);
+ dev_warn(&adap->dev, "Unexpected software PEC transaction %d\n.", size);
return -1;
default:
- printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size);
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
}
@@ -392,7 +392,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev)
}
static struct pci_driver amd8111_driver = {
- .name = "amd8111 smbus",
+ .name = "amd8111 smbus 2",
.id_table = amd8111_ids,
.probe = amd8111_probe,
.remove = __devexit_p(amd8111_remove),
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index b1556e08ce54..9f70bc88e1c5 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -49,65 +49,48 @@
#include <linux/i2c.h>
#include <asm/io.h>
-MODULE_LICENSE("GPL");
-
#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
#define HAVE_PEC
#endif
-#ifndef PCI_DEVICE_ID_INTEL_82801CA_SMBUS
-#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS 0x2483
-#endif
-
-#ifndef PCI_DEVICE_ID_INTEL_82801DB_SMBUS
-#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS 0x24C3
-#endif
-
-static int supported[] = {PCI_DEVICE_ID_INTEL_82801AA_3,
- PCI_DEVICE_ID_INTEL_82801AB_3,
- PCI_DEVICE_ID_INTEL_82801BA_2,
- PCI_DEVICE_ID_INTEL_82801CA_SMBUS,
- PCI_DEVICE_ID_INTEL_82801DB_SMBUS,
- 0 };
-
/* I801 SMBus address offsets */
-#define SMBHSTSTS (0 + i801_smba)
-#define SMBHSTCNT (2 + i801_smba)
-#define SMBHSTCMD (3 + i801_smba)
-#define SMBHSTADD (4 + i801_smba)
-#define SMBHSTDAT0 (5 + i801_smba)
-#define SMBHSTDAT1 (6 + i801_smba)
-#define SMBBLKDAT (7 + i801_smba)
-#define SMBPEC (8 + i801_smba) /* ICH4 only */
-#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */
-#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */
+#define SMBHSTSTS (0 + i801_smba)
+#define SMBHSTCNT (2 + i801_smba)
+#define SMBHSTCMD (3 + i801_smba)
+#define SMBHSTADD (4 + i801_smba)
+#define SMBHSTDAT0 (5 + i801_smba)
+#define SMBHSTDAT1 (6 + i801_smba)
+#define SMBBLKDAT (7 + i801_smba)
+#define SMBPEC (8 + i801_smba) /* ICH4 only */
+#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */
+#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */
/* PCI Address Constants */
-#define SMBBA 0x020
-#define SMBHSTCFG 0x040
-#define SMBREV 0x008
+#define SMBBA 0x020
+#define SMBHSTCFG 0x040
+#define SMBREV 0x008
/* Host configuration bits for SMBHSTCFG */
-#define SMBHSTCFG_HST_EN 1
-#define SMBHSTCFG_SMB_SMI_EN 2
-#define SMBHSTCFG_I2C_EN 4
+#define SMBHSTCFG_HST_EN 1
+#define SMBHSTCFG_SMB_SMI_EN 2
+#define SMBHSTCFG_I2C_EN 4
/* Other settings */
-#define MAX_TIMEOUT 100
-#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
+#define MAX_TIMEOUT 100
+#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
/* I801 command constants */
-#define I801_QUICK 0x00
-#define I801_BYTE 0x04
-#define I801_BYTE_DATA 0x08
-#define I801_WORD_DATA 0x0C
-#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */
-#define I801_BLOCK_DATA 0x14
-#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */
-#define I801_BLOCK_LAST 0x34
-#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */
-#define I801_START 0x40
-#define I801_PEC_EN 0x80 /* ICH4 only */
+#define I801_QUICK 0x00
+#define I801_BYTE 0x04
+#define I801_BYTE_DATA 0x08
+#define I801_WORD_DATA 0x0C
+#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */
+#define I801_BLOCK_DATA 0x14
+#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */
+#define I801_BLOCK_LAST 0x34
+#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */
+#define I801_START 0x40
+#define I801_PEC_EN 0x80 /* ICH4 only */
/* insmod parameters */
@@ -119,10 +102,6 @@ MODULE_PARM_DESC(force_addr,
"Forcibly enable the I801 at the given address. "
"EXTREMELY DANGEROUS!");
-
-
-
-
static void i801_do_pause(unsigned int amount);
static int i801_transaction(void);
static int i801_block_transaction(union i2c_smbus_data *data,
@@ -135,7 +114,6 @@ static int isich4;
static int i801_setup(struct pci_dev *dev)
{
int error_return = 0;
- int *num = supported;
unsigned char temp;
/* Note: we keep on searching until we have found 'function 3' */
@@ -143,101 +121,90 @@ static int i801_setup(struct pci_dev *dev)
return -ENODEV;
I801_dev = dev;
- isich4 = *num == PCI_DEVICE_ID_INTEL_82801DB_SMBUS;
+ if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3)
+ isich4 = 1;
+ else
+ isich4 = 0;
-/* Determine the address of the SMBus areas */
+ /* Determine the address of the SMBus areas */
if (force_addr) {
i801_smba = force_addr & 0xfff0;
} else {
pci_read_config_word(I801_dev, SMBBA, &i801_smba);
i801_smba &= 0xfff0;
if(i801_smba == 0) {
- printk(KERN_ERR "i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+ dev_err(&dev->dev, "SMB base address uninitialized"
+ "- upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
}
- if (check_region(i801_smba, (isich4 ? 16 : 8))) {
- printk
- (KERN_ERR "i2c-i801.o: I801_smb region 0x%x already in use!\n",
- i801_smba);
- error_return = -ENODEV;
+ if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
+ dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n",
+ i801_smba);
+ error_return = -EBUSY;
goto END;
}
pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
-/* If force_addr is set, we program the new address here. Just to make
- sure, we disable the device first. */
+
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the device first. */
if (force_addr) {
pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
pci_write_config_word(I801_dev, SMBBA, i801_smba);
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
- printk
- (KERN_WARNING "i2c-i801.o: WARNING: I801 SMBus interface set to new "
- "address %04x!\n", i801_smba);
+ dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to "
+ "new address %04x!\n", i801_smba);
} else if ((temp & 1) == 0) {
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
- printk(KERN_WARNING "i2c-i801.o: enabling SMBus device\n");
+ dev_warn(&dev->dev, "enabling SMBus device\n");
}
- request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus");
-
-#ifdef DEBUG
if (temp & 0x02)
- printk
- (KERN_DEBUG "i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n");
+ dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n");
else
- printk
- (KERN_DEBUG "i2c-i801.o: I801 using PCI Interrupt for SMBus.\n");
+ dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n");
pci_read_config_byte(I801_dev, SMBREV, &temp);
- printk(KERN_DEBUG "i2c-i801.o: SMBREV = 0x%X\n", temp);
- printk(KERN_DEBUG "i2c-i801.o: I801_smba = 0x%X\n", i801_smba);
-#endif /* DEBUG */
+ dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba);
- END:
+END:
return error_return;
}
-void i801_do_pause(unsigned int amount)
+static void i801_do_pause(unsigned int amount)
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(amount);
}
-int i801_transaction(void)
+static int i801_transaction(void)
{
int temp;
int result = 0;
int timeout = 0;
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
- "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
- inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
/* Make sure the SMBus host is ready to start transmitting */
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
- temp);
-#endif
+ dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n",
+ temp);
outb_p(temp, SMBHSTSTS);
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: Failed! (%02x)\n", temp);
-#endif
+ dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: Successfull!\n");
-#endif
+ dev_dbg(&I801_dev->dev, "Successfull!\n");
}
}
@@ -251,76 +218,64 @@ int i801_transaction(void)
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
+ dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
result = -1;
-#endif
}
if (temp & 0x10) {
result = -1;
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
-#endif
+ dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
}
if (temp & 0x08) {
result = -1;
- printk
- (KERN_ERR "i2c-i801.o: Bus collision! SMBus may be locked until next hard\n"
- "reset. (sorry!)\n");
+ dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
+ "until next hard reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */
}
if (temp & 0x04) {
result = -1;
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
-#endif
+ dev_dbg(&I801_dev->dev, "Error: no response!\n");
}
if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: Failed reset at end of transaction (%02x)\n",
- temp);
-#endif
+ dev_dbg(&I801_dev->dev, "Failed reset at end of transaction"
+ "(%02x)\n", temp);
}
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
- "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
- inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
return result;
}
/* All-inclusive block transaction function */
-int i801_block_transaction(union i2c_smbus_data *data, char read_write,
- int command)
+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+ int command)
{
int i, len;
int smbcmd;
int temp;
int result = 0;
int timeout;
- unsigned char hostc, errmask;
-
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
- if (read_write == I2C_SMBUS_WRITE) {
- /* set I2C_EN bit in configuration register */
- pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
- pci_write_config_byte(I801_dev, SMBHSTCFG,
- hostc | SMBHSTCFG_I2C_EN);
- } else {
- printk("i2c-i801.o: "
- "I2C_SMBUS_I2C_BLOCK_READ not supported!\n");
- return -1;
- }
- }
+ unsigned char hostc, errmask;
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* set I2C_EN bit in configuration register */
+ pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
+ pci_write_config_byte(I801_dev, SMBHSTCFG,
+ hostc | SMBHSTCFG_I2C_EN);
+ } else {
+ dev_err(&I801_dev->dev,
+ "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+ return -1;
+ }
+ }
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
@@ -343,60 +298,43 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
smbcmd = I801_BLOCK_LAST;
else
smbcmd = I801_BLOCK_DATA;
-#if 0 /* now using HW PEC */
- if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC)
- smbcmd |= I801_PEC_EN;
-#endif
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, "
- "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
- inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
- inb_p(SMBBLKDAT));
-#endif
+ dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
/* Make sure the SMBus host is ready to start transmitting */
temp = inb_p(SMBHSTSTS);
- if (i == 1) {
- /* Erronenous conditions before transaction:
- * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
- errmask=0x9f;
- } else {
- /* Erronenous conditions during transaction:
- * Failed, Bus_Err, Dev_Err, Intr */
- errmask=0x1e;
- }
+ if (i == 1) {
+ /* Erronenous conditions before transaction:
+ * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
+ errmask=0x9f;
+ } else {
+ /* Erronenous conditions during transaction:
+ * Failed, Bus_Err, Dev_Err, Intr */
+ errmask=0x1e;
+ }
if (temp & errmask) {
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
- temp);
-#endif
+ dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
+ "Resetting... \n", temp);
outb_p(temp, SMBHSTSTS);
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
- printk
- (KERN_ERR "i2c-i801.o: Reset failed! (%02x)\n",
- temp);
+ dev_err(&I801_dev->dev,
+ "Reset failed! (%02x)\n", temp);
result = -1;
goto END;
}
if (i != 1) {
- result = -1; /* if die in middle of block transaction, fail */
- goto END;
- }
+ /* if die in middle of block transaction, fail */
+ result = -1;
+ goto END;
+ }
}
- if (i == 1) {
-#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */
- if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
- if(read_write == I2C_SMBUS_WRITE)
- outb_p(data->block[len + 1], SMBPEC);
- }
-#endif
+ if (i == 1)
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
- }
/* We will always wait for a fraction of a second! */
timeout = 0;
@@ -410,25 +348,19 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
result = -1;
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
-#endif
+ dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
}
if (temp & 0x10) {
result = -1;
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
-#endif
+ dev_dbg(&I801_dev->dev,
+ "Error: Failed bus transaction\n");
} else if (temp & 0x08) {
result = -1;
- printk(KERN_ERR "i2c-i801.o: Bus collision!\n");
+ dev_err(&I801_dev->dev, "Bus collision!\n");
} else if (temp & 0x04) {
result = -1;
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
-#endif
+ dev_dbg(&I801_dev->dev, "Error: no response!\n");
}
if (i == 1 && read_write == I2C_SMBUS_READ) {
@@ -440,7 +372,7 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
data->block[0] = len;
}
- /* Retrieve/store value in SMBBLKDAT */
+ /* Retrieve/store value in SMBBLKDAT */
if (read_write == I2C_SMBUS_READ)
data->block[i] = inb_p(SMBBLKDAT);
if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
@@ -448,18 +380,15 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
if ((temp & 0x9e) != 0x00)
outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
-#ifdef DEBUG
if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
- printk
- (KERN_DEBUG "i2c-i801.o: Bad status (%02x) at end of transaction\n",
- temp);
+ dev_dbg(&I801_dev->dev,
+ "Bad status (%02x) at end of transaction\n",
+ temp);
}
- printk
- (KERN_DEBUG "i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, "
- "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
- inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
- inb_p(SMBBLKDAT));
-#endif
+ dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
if (result < 0)
goto END;
@@ -476,29 +405,24 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
&& (timeout++ < MAX_TIMEOUT));
if (timeout >= MAX_TIMEOUT) {
- printk(KERN_DEBUG "i2c-i801.o: PEC Timeout!\n");
- }
-#if 0 /* now using HW PEC */
- if(read_write == I2C_SMBUS_READ) {
- data->block[len + 1] = inb_p(SMBPEC);
+ dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
}
-#endif
outb_p(temp, SMBHSTSTS);
}
#endif
- result = 0;
+ result = 0;
END:
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
- /* restore saved configuration register value */
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ /* restore saved configuration register value */
pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
- }
+ }
return result;
}
/* Return -1 on error. */
-s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data * data)
+static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data * data)
{
int hwpec = 0;
int block = 0;
@@ -554,7 +478,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
break;
case I2C_SMBUS_PROC_CALL:
default:
- printk(KERN_ERR "i2c-i801.o: Unsupported transaction %d\n", size);
+ dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
return -1;
}
@@ -600,7 +524,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
}
-u32 i801_func(struct i2c_adapter *adapter)
+static u32 i801_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
@@ -627,8 +551,6 @@ static struct i2c_adapter i801_adapter = {
.algo = &smbus_algorithm,
};
-
-
static struct pci_device_id i801_ids[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_INTEL,
@@ -650,13 +572,13 @@ static struct pci_device_id i801_ids[] __devinitdata = {
},
{
.vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_82801CA_SMBUS,
+ .device = PCI_DEVICE_ID_INTEL_82801CA_3,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_82801DB_SMBUS,
+ .device = PCI_DEVICE_ID_INTEL_82801DB_3,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
@@ -667,8 +589,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
{
if (i801_setup(dev)) {
- printk
- (KERN_WARNING "i2c-i801.o: I801 not detected, module not inserted.\n");
+ dev_warn(&dev->dev,
+ "I801 not detected, module not inserted.\n");
return -ENODEV;
}
@@ -694,22 +616,21 @@ static struct pci_driver i801_driver = {
static int __init i2c_i801_init(void)
{
- printk(KERN_INFO "i2c-i801.o version %s (%s)\n", I2C_VERSION, I2C_DATE);
+ printk(KERN_INFO "i2c-i801 version %s (%s)\n", I2C_VERSION, I2C_DATE);
return pci_module_init(&i801_driver);
}
-
static void __exit i2c_i801_exit(void)
{
pci_unregister_driver(&i801_driver);
release_region(i801_smba, (isich4 ? 16 : 8));
}
-
-
-MODULE_AUTHOR
- ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
module_init(i2c_i801_init);
module_exit(i2c_i801_exit);
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
new file mode 100644
index 000000000000..73612de6e96c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -0,0 +1,62 @@
+/*
+ i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
+ on first sight very useful; almost no functionality is preserved.
+ Except that it makes writing drivers for chips which can be on both
+ the SMBus and the ISA bus very much easier. See lm78.c for an example
+ of this. */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+
+/* This is the actual algorithm we define */
+static struct i2c_algorithm isa_algorithm = {
+ .name = "ISA bus algorithm",
+ .id = I2C_ALGO_ISA,
+};
+
+/* There can only be one... */
+static struct i2c_adapter isa_adapter = {
+ .owner = THIS_MODULE,
+ .name = "ISA main adapter",
+ .id = I2C_ALGO_ISA | I2C_HW_ISA,
+ .algo = &isa_algorithm,
+};
+
+static int __init i2c_isa_init(void)
+{
+ return i2c_add_adapter(&isa_adapter);
+}
+
+static void __exit i2c_isa_exit(void)
+{
+ i2c_del_adapter(&isa_adapter);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("ISA bus access through i2c");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_isa_init);
+module_exit(i2c_isa_exit);
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 5acd8211b1d6..a1048f7b5cbe 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -28,6 +28,8 @@
Note: we assume there can only be one device, with one SMBus interface.
*/
+/* #define DEBUG 1 */
+
#include <linux/module.h>
#include <linux/config.h>
#include <linux/pci.h>
@@ -49,37 +51,37 @@ struct sd {
};
/* PIIX4 SMBus address offsets */
-#define SMBHSTSTS (0 + piix4_smba)
-#define SMBHSLVSTS (1 + piix4_smba)
-#define SMBHSTCNT (2 + piix4_smba)
-#define SMBHSTCMD (3 + piix4_smba)
-#define SMBHSTADD (4 + piix4_smba)
-#define SMBHSTDAT0 (5 + piix4_smba)
-#define SMBHSTDAT1 (6 + piix4_smba)
-#define SMBBLKDAT (7 + piix4_smba)
-#define SMBSLVCNT (8 + piix4_smba)
-#define SMBSHDWCMD (9 + piix4_smba)
-#define SMBSLVEVT (0xA + piix4_smba)
-#define SMBSLVDAT (0xC + piix4_smba)
+#define SMBHSTSTS (0 + piix4_smba)
+#define SMBHSLVSTS (1 + piix4_smba)
+#define SMBHSTCNT (2 + piix4_smba)
+#define SMBHSTCMD (3 + piix4_smba)
+#define SMBHSTADD (4 + piix4_smba)
+#define SMBHSTDAT0 (5 + piix4_smba)
+#define SMBHSTDAT1 (6 + piix4_smba)
+#define SMBBLKDAT (7 + piix4_smba)
+#define SMBSLVCNT (8 + piix4_smba)
+#define SMBSHDWCMD (9 + piix4_smba)
+#define SMBSLVEVT (0xA + piix4_smba)
+#define SMBSLVDAT (0xC + piix4_smba)
/* PCI Address Constants */
-#define SMBBA 0x090
-#define SMBHSTCFG 0x0D2
-#define SMBSLVC 0x0D3
-#define SMBSHDW1 0x0D4
-#define SMBSHDW2 0x0D5
-#define SMBREV 0x0D6
+#define SMBBA 0x090
+#define SMBHSTCFG 0x0D2
+#define SMBSLVC 0x0D3
+#define SMBSHDW1 0x0D4
+#define SMBSHDW2 0x0D5
+#define SMBREV 0x0D6
/* Other settings */
-#define MAX_TIMEOUT 500
-#define ENABLE_INT9 0
+#define MAX_TIMEOUT 500
+#define ENABLE_INT9 0
/* PIIX4 constants */
-#define PIIX4_QUICK 0x00
-#define PIIX4_BYTE 0x04
-#define PIIX4_BYTE_DATA 0x08
-#define PIIX4_WORD_DATA 0x0C
-#define PIIX4_BLOCK_DATA 0x14
+#define PIIX4_QUICK 0x00
+#define PIIX4_BYTE 0x04
+#define PIIX4_BYTE_DATA 0x08
+#define PIIX4_WORD_DATA 0x0C
+#define PIIX4_BLOCK_DATA 0x14
/* insmod parameters */
@@ -102,6 +104,7 @@ static int piix4_transaction(void);
static unsigned short piix4_smba = 0;
+static struct i2c_adapter piix4_adapter;
/*
* Get DMI information.
@@ -125,18 +128,17 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id
if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
return -ENODEV;
- printk(KERN_INFO "i2c-piix4.o: Found %s device\n", PIIX4_dev->dev.name);
+ dev_info(&PIIX4_dev->dev, "Found %s device\n", PIIX4_dev->dev.name);
if(ibm_dmi_probe()) {
- printk
- (KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module may corrupt\n");
- printk
- (KERN_ERR " your serial eeprom! Refusing to load module!\n");
- error_return = -EPERM;
- goto END;
+ dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module "
+ "may corrupt your serial eeprom! Refusing to load "
+ "module!\n");
+ error_return = -EPERM;
+ goto END;
}
-/* Determine the address of the SMBus areas */
+ /* Determine the address of the SMBus areas */
if (force_addr) {
piix4_smba = force_addr & 0xfff0;
force = 0;
@@ -144,75 +146,68 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id
pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
piix4_smba &= 0xfff0;
if(piix4_smba == 0) {
- printk(KERN_ERR "i2c-piix4.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+ dev_err(&PIIX4_dev->dev, "SMB base address "
+ "uninitialized - upgrade BIOS or use "
+ "force_addr=0xaddr\n");
return -ENODEV;
}
}
- if (check_region(piix4_smba, 8)) {
- printk
- (KERN_ERR "i2c-piix4.o: SMB region 0x%x already in use!\n",
- piix4_smba);
+ if (!request_region(piix4_smba, 8, "piix4-smbus")) {
+ dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n",
+ piix4_smba);
error_return = -ENODEV;
goto END;
}
pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
-/* If force_addr is set, we program the new address here. Just to make
- sure, we disable the PIIX4 first. */
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the PIIX4 first. */
if (force_addr) {
pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
- printk
- (KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to new "
- "address %04x!\n", piix4_smba);
+ dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
+ "new address %04x!\n", piix4_smba);
} else if ((temp & 1) == 0) {
if (force) {
-/* This should never need to be done, but has been noted that
- many Dell machines have the SMBus interface on the PIIX4
- disabled!? NOTE: This assumes I/O space and other allocations WERE
- done by the Bios! Don't complain if your hardware does weird
- things after enabling this. :') Check for Bios updates before
- resorting to this. */
+ /* This should never need to be done, but has been
+ * noted that many Dell machines have the SMBus
+ * interface on the PIIX4 disabled!? NOTE: This assumes
+ * I/O space and other allocations WERE done by the
+ * Bios! Don't complain if your hardware does weird
+ * things after enabling this. :') Check for Bios
+ * updates before resorting to this.
+ */
pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
temp | 1);
- printk
- (KERN_NOTICE "i2c-piix4.o: WARNING: SMBus interface has been FORCEFULLY "
- "ENABLED!\n");
+ dev_printk(KERN_NOTICE, &PIIX4_dev->dev,
+ "WARNING: SMBus interface has been "
+ "FORCEFULLY ENABLED!\n");
} else {
- printk
- (KERN_ERR "i2c-piix4.o: Host SMBus controller not enabled!\n");
+ dev_err(&PIIX4_dev->dev,
+ "Host SMBus controller not enabled!\n");
error_return = -ENODEV;
goto END;
}
}
- /* Everything is happy, let's grab the memory and set things up. */
- request_region(piix4_smba, 8, "piix4-smbus");
-
-#ifdef DEBUG
if ((temp & 0x0E) == 8)
- printk
- (KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for SMBus.\n");
+ dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
- printk
- (KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# for SMBus.\n");
+ dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
else
- printk
- (KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration (or code out "
- "of date)!\n");
+ dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
+ "(or code out of date)!\n");
pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
- printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp);
- printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba);
-#endif /* DEBUG */
+ dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba);
- END:
+END:
return error_return;
}
-
/* Internally used pause function */
static void piix4_do_pause(unsigned int amount)
{
@@ -227,29 +222,21 @@ static int piix4_transaction(void)
int result = 0;
int timeout = 0;
-#ifdef DEBUG
- printk
- (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
- "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
- inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting... \n",
- temp);
-#endif
+ dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+ "Resetting... \n", temp);
outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-#ifdef DEBUG
- printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp);
-#endif
+ dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
return -1;
} else {
-#ifdef DEBUG
- printk(KERN_DEBUG "i2c-piix4.o: Successfull!\n");
-#endif
+ dev_dbg(&piix4_adapter.dev, "Successfull!\n");
}
}
@@ -262,50 +249,40 @@ static int piix4_transaction(void)
temp = inb_p(SMBHSTSTS);
} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
-#ifdef DEBUG
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
- printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n");
+ dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
result = -1;
}
-#endif
if (temp & 0x10) {
result = -1;
-#ifdef DEBUG
- printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n");
-#endif
+ dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
}
if (temp & 0x08) {
result = -1;
- printk
- (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n"
- "reset. (sorry!)\n");
+ dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+ "locked until next hard reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */
}
if (temp & 0x04) {
result = -1;
-#ifdef DEBUG
- printk(KERN_ERR "i2c-piix4.o: Error: no response!\n");
-#endif
+ dev_err(&piix4_adapter.dev, "Error: no response!\n");
}
if (inb_p(SMBHSTSTS) != 0x00)
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-#ifdef DEBUG
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
- printk
- (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n",
- temp);
+ dev_err(&piix4_adapter.dev, "Failed reset at end of "
+ "transaction (%02x)\n", temp);
}
- printk
- (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
- "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
- inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+ dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
return result;
}
@@ -318,8 +295,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
switch (size) {
case I2C_SMBUS_PROC_CALL:
- printk
- (KERN_ERR "i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!\n");
+ dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
return -1;
case I2C_SMBUS_QUICK:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
@@ -402,7 +378,6 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
return 0;
}
-
static u32 piix4_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
@@ -424,8 +399,6 @@ static struct i2c_adapter piix4_adapter = {
.algo = &smbus_algorithm,
};
-
-
static struct pci_device_id piix4_ids[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_INTEL,
@@ -468,7 +441,7 @@ static struct pci_device_id piix4_ids[] __devinitdata = {
static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
-
+
retval = piix4_setup(dev, id);
if (retval)
return retval;
@@ -499,7 +472,7 @@ static struct pci_driver piix4_driver = {
static int __init i2c_piix4_init(void)
{
- printk("i2c-piix4.o version %s (%s)\n", I2C_VERSION, I2C_DATE);
+ printk(KERN_INFO "i2c-piix4 version %s (%s)\n", I2C_VERSION, I2C_DATE);
return pci_module_init(&piix4_driver);
}
@@ -510,8 +483,6 @@ static void __exit i2c_piix4_exit(void)
release_region(piix4_smba, 8);
}
-
-
MODULE_AUTHOR
("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
MODULE_DESCRIPTION("PIIX4 SMBus driver");
diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
index 5c15c7b4be1f..c4370afc01e1 100644
--- a/drivers/i2c/chips/adm1021.c
+++ b/drivers/i2c/chips/adm1021.c
@@ -93,9 +93,9 @@ SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1
/* Initial values */
-/* Note: Eventhough I left the low and high limits named os and hyst,
+/* Note: Even though I left the low and high limits named os and hyst,
they don't quite work like a thermostat the way the LM75 does. I.e.,
-a lower temp than THYST actuall triggers an alarm instead of
+a lower temp than THYST actually triggers an alarm instead of
clearing it. Weird, ey? --Phil */
#define adm1021_INIT_TOS 60
#define adm1021_INIT_THYST 20
diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c
index e625528e7b3a..da1e4d2c2c28 100644
--- a/drivers/i2c/chips/lm75.c
+++ b/drivers/i2c/chips/lm75.c
@@ -25,7 +25,7 @@
#include <linux/i2c-proc.h>
-#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
+#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */
/* Addresses to scan */
static unsigned short normal_i2c[] = { SENSORS_I2C_END };
diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c
index 874d37827954..c7383b281a34 100644
--- a/drivers/i2c/i2c-algo-pcf.c
+++ b/drivers/i2c/i2c-algo-pcf.c
@@ -152,7 +152,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
/* load own address in S0, effective address is (own << 1) */
i2c_outb(adap, get_own(adap));
- /* check it's realy writen */
+ /* check it's really written */
if ((temp = i2c_inb(adap)) != get_own(adap)) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
return -ENXIO;
@@ -168,7 +168,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
/* load clock register S2 */
i2c_outb(adap, get_clock(adap));
- /* check it's realy writen, the only 5 lowest bits does matter */
+ /* check it's really written, the only 5 lowest bits does matter */
if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
return -ENXIO;
@@ -177,7 +177,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
/* Enable serial interface, idle, S0 selected */
set_pcf(adap, 1, I2C_PCF_IDLE);
- /* check to see PCF is realy idled and we can access status register */
+ /* check to see PCF is really idled and we can access status register */
if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
return -ENXIO;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 28cc3ec02277..52355c190120 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -53,6 +53,16 @@ static void i2cproc_remove(int bus);
#endif /* CONFIG_PROC_FS */
+int i2c_device_probe(struct device *dev)
+{
+ return -ENODEV;
+}
+
+int i2c_device_remove(struct device *dev)
+{
+ return 0;
+}
+
/* ---------------------------------------------------
* registering functions
* ---------------------------------------------------
@@ -204,6 +214,16 @@ int i2c_add_driver(struct i2c_driver *driver)
drivers[i] = driver;
DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
+
+ /* add the driver to the list of i2c drivers in the driver core */
+ driver->driver.name = driver->name;
+ driver->driver.bus = &i2c_bus_type;
+ driver->driver.probe = i2c_device_probe;
+ driver->driver.remove = i2c_device_remove;
+
+ res = driver_register(&driver->driver);
+ if (res)
+ goto out_unlock;
/* now look for instances of driver on our adapters
*/
@@ -236,6 +256,8 @@ int i2c_del_driver(struct i2c_driver *driver)
goto out_unlock;
}
+ driver_unregister(&driver->driver);
+
/* Have a look at each adapter, if clients of this driver are still
* attached. If so, detach them to be able to kill the driver
* afterwards.
diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c
index 73bb33815907..313b5b5c4d7c 100644
--- a/drivers/i2c/i2c-proc.c
+++ b/drivers/i2c/i2c-proc.c
@@ -270,7 +270,7 @@ static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen,
}
-/* This funcion reads or writes a 'real' value (encoded by the combination
+/* This function reads or writes a 'real' value (encoded by the combination
of an integer and a magnitude, the last is the power of ten the value
should be divided with) to a /proc/sys directory. To use this function,
you must (before registering the ctl_table) set the extra2 field to the
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index a67b113cbce2..2fe946fce0aa 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -106,6 +106,7 @@
#include "ide_modes.h"
#include "piix.h"
+static int no_piix_dma;
#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
@@ -114,7 +115,6 @@ static u8 piix_proc = 0;
#define PIIX_MAX_DEVS 5
static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
static int n_piix_devs;
-static int no_piix_dma = 0;
/**
* piix_get_info - fill in /proc for PIIX ide
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index a5a983fdbede..0f791c59ee52 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -249,7 +249,7 @@ adb_probe_task(void *x)
strcpy(current->comm, "kadbprobe");
sigfillset(&blocked);
- sicprocmask(SIG_BLOCK, &blocked, NULL);
+ sigprocmask(SIG_BLOCK, &blocked, NULL);
flush_signals(current);
printk(KERN_INFO "adb: starting probe task...\n");
diff --git a/drivers/md/md.c b/drivers/md/md.c
index cefd2423f1c7..3de804ebdfee 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1735,7 +1735,6 @@ static int do_md_run(mddev_t * mddev)
mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
mddev->in_sync = 1;
- md_update_sb(mddev);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
set_capacity(disk, md_size[mdidx(mddev)]<<1);
@@ -1763,7 +1762,6 @@ static int restart_array(mddev_t *mddev)
goto out;
mddev->safemode = 0;
- md_update_sb(mddev);
mddev->ro = 0;
set_disk_ro(disk, 0);
@@ -3247,7 +3245,7 @@ static void md_do_sync(mddev_t *mddev)
{
mddev_t *mddev2;
unsigned int max_sectors, currspeed = 0,
- j, window, err;
+ j, window;
unsigned long mark[SYNC_MARKS];
unsigned long mark_cnt[SYNC_MARKS];
int last_mark,m;
@@ -3283,7 +3281,6 @@ static void md_do_sync(mddev_t *mddev)
if (wait_event_interruptible(resync_wait,
mddev2->curr_resync < mddev->curr_resync)) {
flush_signals(current);
- err = -EINTR;
mddev_put(mddev2);
goto skip;
}
@@ -3335,7 +3332,7 @@ static void md_do_sync(mddev_t *mddev)
sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min);
if (sectors < 0) {
- err = sectors;
+ set_bit(MD_RECOVERY_ERR, &mddev->recovery);
goto out;
}
atomic_add(sectors, &mddev->recovery_active);
@@ -3372,7 +3369,7 @@ static void md_do_sync(mddev_t *mddev)
*/
printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n");
flush_signals(current);
- err = -EINTR;
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto out;
}
@@ -3398,7 +3395,6 @@ static void md_do_sync(mddev_t *mddev)
}
}
printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev));
- err = 0;
/*
* this also signals 'finished resyncing' to md_stop
*/
@@ -3408,8 +3404,6 @@ static void md_do_sync(mddev_t *mddev)
/* tell personality that we are finished */
mddev->pers->sync_request(mddev, max_sectors, 1);
- if (err)
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
mddev->curr_resync > 2 &&
mddev->curr_resync > mddev->recovery_cp) {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 0dd391e3d3b1..4921992134bf 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -840,7 +840,8 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
* we read from here, no need to write
*/
continue;
- if (conf->mirrors[i].rdev->in_sync && mddev->in_sync)
+ if (conf->mirrors[i].rdev->in_sync &&
+ r1_bio->sector + (bio->bi_size>>9) <= mddev->recovery_cp)
/*
* don't need to write this we are just rebuilding
*/
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 29289ef75d1b..d9e2735afddf 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -221,7 +221,7 @@ dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *dvbdmxfeed,
return 0;
neq|=f->maskandnotmode[i]&xor;
}
- if (f->doneq & !neq)
+ if (f->doneq && !neq)
return 0;
return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen,
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index fa7af13f3ed4..2f1d8eda388f 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -56,6 +56,10 @@
v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
- Introduce driver model for EISA cards.
*/
+/*
+ FIXES for PC-9800:
+ Shu Iwanaga: 3c569B(PC-9801 C-bus) support
+*/
#define DRV_NAME "3c509"
#define DRV_VERSION "1.19b"
@@ -257,7 +261,7 @@ static struct mca_driver el3_mca_driver = {
};
#endif /* CONFIG_MCA */
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -350,7 +354,7 @@ static void el3_common_remove (struct net_device *dev)
if (lp->pmdev)
pm_unregister(lp->pmdev);
#endif
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (lp->type == EL3_PNP)
pnp_device_detach(to_pnp_dev(lp->dev));
#endif
@@ -368,12 +372,12 @@ static int __init el3_probe(int card_idx)
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
static int pnp_cards;
struct pnp_dev *idev = NULL;
#endif /* __ISAPNP__ */
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (nopnp == 1)
goto no_pnp;
@@ -421,6 +425,9 @@ static int __init el3_probe(int card_idx)
no_pnp:
#endif /* __ISAPNP__ */
+#ifdef CONFIG_X86_PC9800
+ id_port = 0x71d0;
+#else
/* Select an open I/O location at 0x1*0 to do contention select. */
for ( ; id_port < 0x200; id_port += 0x10) {
if (check_region(id_port, 1))
@@ -435,6 +442,7 @@ no_pnp:
printk(" WARNING: No I/O port available for 3c509 activation.\n");
return -ENODEV;
}
+#endif /* CONFIG_X86_PC9800 */
/* Next check for all ISA bus boards by sending the ID sequence to the
ID_PORT. We find cards past the first by setting the 'current_tag'
on cards as they are found. Cards with their tag set will not
@@ -465,7 +473,7 @@ no_pnp:
phys_addr[i] = htons(id_read_eeprom(i));
}
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (nopnp == 0) {
/* The ISA PnP 3c509 cards respond to the ID sequence.
This check is needed in order not to register them twice. */
@@ -490,9 +498,19 @@ no_pnp:
{
unsigned int iobase = id_read_eeprom(8);
if_port = iobase >> 14;
+#ifdef CONFIG_X86_PC9800
+ ioaddr = 0x40d0 + ((iobase & 0x1f) << 8);
+#else
ioaddr = 0x200 + ((iobase & 0x1f) << 4);
+#endif
}
irq = id_read_eeprom(9) >> 12;
+#ifdef CONFIG_X86_PC9800
+ if (irq == 7)
+ irq = 6;
+ else if (irq == 15)
+ irq = 13;
+#endif
if (!(dev = init_etherdev(NULL, sizeof(struct el3_private))))
return -ENOMEM;
@@ -522,7 +540,11 @@ no_pnp:
outb(0xd0 + ++current_tag, id_port);
/* Activate the adaptor at the EEPROM location. */
+#ifdef CONFIG_X86_PC9800
+ outb((ioaddr >> 8) | 0xe0, id_port);
+#else
outb((ioaddr >> 4) | 0xe0, id_port);
+#endif
EL3WINDOW(0);
if (inw(ioaddr) != 0x6d50) {
@@ -534,7 +556,7 @@ no_pnp:
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
found: /* PNP jumps here... */
#endif /* __ISAPNP__ */
@@ -543,7 +565,7 @@ no_pnp:
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
lp->dev = &idev->dev;
#endif
@@ -1388,6 +1410,12 @@ el3_up(struct net_device *dev)
outw(0x0001, ioaddr + 4);
/* Set the IRQ line. */
+#ifdef CONFIG_X86_PC9800
+ if (dev->irq == 6)
+ dev->irq = 7;
+ else if (dev->irq == 13)
+ dev->irq = 15;
+#endif
outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
/* Set the station address in window 2 each time opened. */
@@ -1550,7 +1578,7 @@ MODULE_PARM_DESC(debug, "debug level (0-6)");
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");
MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
MODULE_PARM(nopnp, "i");
MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 76bf501617bd..28001ae6c1b3 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -646,7 +646,7 @@ static int init_i596_mem(struct net_device *dev)
/* change the scp address */
- MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
+ MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
#elif defined(ENABLE_APRICOT)
@@ -677,8 +677,8 @@ static int init_i596_mem(struct net_device *dev)
lp->scp.sysbus = 0x00440000;
#endif
- lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
- lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
+ lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
+ lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
lp->iscp.stat = ISCP_BUSY;
lp->cmd_backlog = 0;
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 4debea1fd190..b9a61079dc5d 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -123,7 +123,8 @@ struct ei_device {
#define inb_p(port) in_8(port)
#define outb_p(val,port) out_8(port,val)
-#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) || \
+ defined(CONFIG_NET_CBUS)
#define EI_SHIFT(x) (ei_local->reg_offset[x])
#else
#define EI_SHIFT(x) (x)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d770d320577f..7d9ab385a1ab 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -663,7 +663,7 @@ config EL16
as <file:Documentation/networking/net-modules.txt>.
config EL3
- tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
+ tristate "3c509/3c529 (MCA)/3c569B (98)/3c579 \"EtherLink III\" support"
depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
---help---
If you have a network (Ethernet) card belonging to the 3Com
@@ -932,7 +932,7 @@ config NI65
source "drivers/net/tulip/Kconfig"
config AT1700
- tristate "AT1700/1720 support (EXPERIMENTAL)"
+ tristate "AT1700/1720/RE1000Plus(C-Bus) support (EXPERIMENTAL)"
depends on NET_ETHERNET && (ISA || MCA) && EXPERIMENTAL
---help---
If you have a network (Ethernet) card of this type, say Y and read
@@ -978,7 +978,7 @@ config HP100
config NET_ISA
bool "Other ISA cards"
- depends on NET_ETHERNET && ISA
+ depends on NET_ETHERNET && ISA && !X86_PC9800
---help---
If your network (Ethernet) card hasn't been mentioned yet and its
bus system (that's the way the cards talks to the other components
@@ -1176,6 +1176,55 @@ config SK_G16
the Ethernet-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
+config NET_CBUS
+ bool "NEC PC-9800 C-bus cards"
+ depends on NET_ETHERNET && ISA && X86_PC9800
+ ---help---
+ If your network (Ethernet) card hasn't been mentioned yet and its
+ bus system (that's the way the cards talks to the other components
+ of your computer) is NEC PC-9800 C-Bus, say Y.
+
+config NE2K_CBUS
+ tristate "Most NE2000-based Ethernet support"
+ depends on NET_CBUS
+
+config NE2K_CBUS_EGY98
+ bool "Melco EGY-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_LGY98
+ bool "Melco LGY-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_ICM
+ bool "ICM IF-27xxET support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_IOLA98
+ bool "I-O DATA LA-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL
+ bool "Contec C-NET(98)E/L support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL_IO_BASE
+ hex "C-NET(98)E/L I/O base address (0xaaed or 0x55ed)"
+ depends on NE2K_CBUS_CNET98EL
+ default "0xaaed"
+
+config NE2K_CBUS_ATLA98
+ bool "Allied Telesis LA-98 Support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_BDN
+ bool "ELECOM Laneed LD-BDN[123]A Support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_NEC108
+ bool "NEC PC-9801-108 Support"
+ depends on NE2K_CBUS
+
config SKMC
tristate "SKnet MCA support"
depends on NET_ETHERNET && MCA
@@ -1904,6 +1953,7 @@ config E1000
82544 PRO/1000 XF Server Adapter A50484-xxx
82544 PRO/1000 T Desktop Adapter A62947-xxx
82540 PRO/1000 MT Desktop Adapter A78408-xxx
+ 82541 PRO/1000 MT Desktop Adapter C91016-xxx
82545 PRO/1000 MT Server Adapter A92165-xxx
82546 PRO/1000 MT Dual Port Server Adapter A92111-xxx
82545 PRO/1000 MF Server Adapter A91622-xxx
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b0b65d9cdbd8..9ad7798d4b1f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_ARM_ETHERH) += 8390.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390.o
obj-$(CONFIG_NE2000) += ne.o 8390.o
+obj-$(CONFIG_NE2K_CBUS) += ne2k_cbus.o 8390.o
obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
obj-$(CONFIG_HPLAN) += hp.o 8390.o
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
diff --git a/drivers/net/Makefile.lib b/drivers/net/Makefile.lib
index c918d456d1b3..44e3b9b329e9 100644
--- a/drivers/net/Makefile.lib
+++ b/drivers/net/Makefile.lib
@@ -19,6 +19,7 @@ obj-$(CONFIG_MACE) += crc32.o
obj-$(CONFIG_MACMACE) += crc32.o
obj-$(CONFIG_MIPS_AU1000_ENET) += crc32.o
obj-$(CONFIG_NATSEMI) += crc32.o
+obj-$(CONFIG_NE2K_CBUS) += crc32.o
obj-$(CONFIG_PCMCIA_FMVJ18X) += crc32.o
obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o
obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 134b45257a5c..b09a14ceae14 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -233,7 +233,7 @@ static struct devprobe isa_probes[] __initdata = {
#ifdef CONFIG_E2100 /* Cabletron E21xx series. */
{e2100_probe, 0},
#endif
-#ifdef CONFIG_NE2000 /* ISA (use ne2k-pci for PCI cards) */
+#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS) /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
{ne_probe, 0},
#endif
#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index b34302abf92b..7d9f45f7e2d9 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -111,9 +111,6 @@ static int init_pcmcia(void);
#define MANUAL_HWADDR5 0x9a
*/
-#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
-
-
static const char version[] =
"apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
@@ -402,10 +399,9 @@ apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pa
}
outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */
-
- hdr->count = WORDSWAP(hdr->count);
-
ei_status.dmaing &= ~0x01;
+
+ le16_to_cpus(&hdr->count);
}
/* Block input and output, similar to the Crynwr packet driver. If you
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 0c21dc3db762..d98c1e8f55bd 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -34,6 +34,10 @@
only is it difficult to detect, it also moves around in I/O space in
response to inb()s from other device probes!
*/
+/*
+ 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa
+ 99/12/30 port to 2.3.35 by K.Takai
+*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -76,10 +80,17 @@ static int fmv18x_probe_list[] __initdata = {
* ISA
*/
+#ifndef CONFIG_X86_PC9800
static int at1700_probe_list[] __initdata = {
0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
};
+#else /* CONFIG_X86_PC9800 */
+static int at1700_probe_list[] __initdata = {
+ 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0
+};
+
+#endif /* CONFIG_X86_PC9800 */
/*
* MCA
*/
@@ -122,6 +133,7 @@ struct net_local {
/* Offsets from the base address. */
+#ifndef CONFIG_X86_PC9800
#define STATUS 0
#define TX_STATUS 0
#define RX_STATUS 1
@@ -136,6 +148,7 @@ struct net_local {
#define TX_START 10
#define COL16CNTL 11 /* Controll Reg for 16 collisions */
#define MODE13 13
+#define RX_CTRL 14
/* Configuration registers only on the '865A/B chips. */
#define EEPROM_Ctrl 16
#define EEPROM_Data 17
@@ -144,8 +157,39 @@ struct net_local {
#define IOCONFIG 18 /* Either read the jumper, or move the I/O. */
#define IOCONFIG1 19
#define SAPROM 20 /* The station address PROM, if no EEPROM. */
+#define MODE24 24
#define RESET 31 /* Write to reset some parts of the chip. */
#define AT1700_IO_EXTENT 32
+#define PORT_OFFSET(o) (o)
+#else /* CONFIG_X86_PC9800 */
+#define STATUS (0x0000)
+#define TX_STATUS (0x0000)
+#define RX_STATUS (0x0001)
+#define TX_INTR (0x0200)/* Bit-mapped interrupt enable registers. */
+#define RX_INTR (0x0201)
+#define TX_MODE (0x0400)
+#define RX_MODE (0x0401)
+#define CONFIG_0 (0x0600)/* Misc. configuration settings. */
+#define CONFIG_1 (0x0601)
+/* Run-time register bank 2 definitions. */
+#define DATAPORT (0x0800)/* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START (0x0a00)
+#define COL16CNTL (0x0a01)/* Controll Reg for 16 collisions */
+#define MODE13 (0x0c01)
+#define RX_CTRL (0x0e00)
+/* Configuration registers only on the '865A/B chips. */
+#define EEPROM_Ctrl (0x1000)
+#define EEPROM_Data (0x1200)
+#define CARDSTATUS 16 /* FMV-18x Card Status */
+#define CARDSTATUS1 17 /* FMV-18x Card Status */
+#define IOCONFIG (0x1400)/* Either read the jumper, or move the I/O. */
+#define IOCONFIG1 (0x1600)
+#define SAPROM 20 /* The station address PROM, if no EEPROM. */
+#define MODE24 (0x1800)/* The station address PROM, if no EEPROM. */
+#define RESET (0x1e01)/* Write to reset some parts of the chip. */
+#define PORT_OFFSET(o) ({ int _o_ = (o); (_o_ & ~1) * 0x100 + (_o_ & 1); })
+#endif /* CONFIG_X86_PC9800 */
+
#define TX_TIMEOUT 10
@@ -225,8 +269,20 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
int slot, ret = -ENODEV;
struct net_local *lp;
+#ifndef CONFIG_X86_PC9800
if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
return -EBUSY;
+#else
+ for (i = 0; i < 0x2000; i += 0x0200) {
+ if (!request_region(ioaddr + i, 2, dev->name)) {
+ while (i > 0) {
+ i -= 0x0200;
+ release_region(ioaddr + i, 2);
+ }
+ return -EBUSY;
+ }
+ }
+#endif
/* Resetting the chip doesn't reset the ISA interface, so don't bother.
That means we have to be careful with the register values we probe for.
@@ -317,10 +373,17 @@ found:
/* Reset the internal state machines. */
outb(0, ioaddr + RESET);
- if (is_at1700)
+ if (is_at1700) {
+#ifndef CONFIG_X86_PC9800
irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
| (read_eeprom(ioaddr, 0)>>14)];
- else {
+#else
+ {
+ char re1000plus_irqmap[4] = {3, 5, 6, 12};
+ irq = re1000plus_irqmap[inb(ioaddr + IOCONFIG1) >> 6];
+ }
+#endif
+ } else {
/* Check PnP mode for FMV-183/184/183A/184A. */
/* This PnP routine is very poor. IO and IRQ should be known. */
if (inb(ioaddr + CARDSTATUS1) & 0x20) {
@@ -392,18 +455,22 @@ found:
/* Set the station address in bank zero. */
outb(0x00, ioaddr + CONFIG_1);
for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + 8 + i);
+ outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));
/* Switch to bank 1 and set the multicast table to accept none. */
outb(0x04, ioaddr + CONFIG_1);
for (i = 0; i < 8; i++)
- outb(0x00, ioaddr + 8 + i);
+ outb(0x00, ioaddr + PORT_OFFSET(8 + i));
/* Switch to bank 2 */
/* Lock our I/O address, and set manual processing mode for 16 collisions. */
outb(0x08, ioaddr + CONFIG_1);
+#ifndef CONFIG_X86_PC9800
outb(dev->if_port, ioaddr + MODE13);
+#else
+ outb(0, ioaddr + MODE13);
+#endif
outb(0x00, ioaddr + COL16CNTL);
if (net_debug)
@@ -447,7 +514,12 @@ err_out_priv:
kfree(dev->priv);
dev->priv = NULL;
err_out:
+#ifndef CONFIG_X86_PC9800
release_region(ioaddr, AT1700_IO_EXTENT);
+#else
+ for (i = 0; i < 0x2000; i += 0x0200)
+ release_region(ioaddr + i, 2);
+#endif
return ret;
}
@@ -459,7 +531,11 @@ err_out:
#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */
/* Delay between EEPROM clock transitions. */
+#ifndef CONFIG_X86_PC9800
#define eeprom_delay() do { } while (0)
+#else
+#define eeprom_delay() __asm__ ("out%B0 %%al,%0" :: "N"(0x5f))
+#endif
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
@@ -542,12 +618,12 @@ static void net_tx_timeout (struct net_device *dev)
inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
? "IRQ conflict" : "network cable problem");
printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
- dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4),
- inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
- inw (ioaddr + 12), inw (ioaddr + 14));
+ dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
+ inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
+ inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
- outw (0xffff, ioaddr + 24);
+ outw(0xffff, ioaddr + MODE24);
outw (0xffff, ioaddr + TX_STATUS);
outb (0x5a, ioaddr + CONFIG_0);
outb (0xe8, ioaddr + CONFIG_1);
@@ -704,7 +780,7 @@ net_rx(struct net_device *dev)
dev->name, inb(ioaddr + RX_MODE), status);
#ifndef final_version
if (status == 0) {
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
break;
}
#endif
@@ -724,7 +800,7 @@ net_rx(struct net_device *dev)
dev->name, pkt_len);
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
lp->stats.rx_errors++;
break;
}
@@ -734,7 +810,7 @@ net_rx(struct net_device *dev)
dev->name, pkt_len);
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
lp->stats.rx_dropped++;
break;
}
@@ -761,7 +837,7 @@ net_rx(struct net_device *dev)
if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
break;
inw(ioaddr + DATAPORT); /* dummy status read */
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
}
if (net_debug > 5)
@@ -844,24 +920,28 @@ set_rx_mode(struct net_device *dev)
outb(0x02, ioaddr + RX_MODE); /* Use normal mode. */
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave (&lp->lock, flags);
if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
int saved_bank = inw(ioaddr + CONFIG_0);
/* Switch to bank 1 and set the multicast table. */
outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
for (i = 0; i < 8; i++)
- outb(mc_filter[i], ioaddr + 8 + i);
+ outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
outw(saved_bank, ioaddr + CONFIG_0);
}
- restore_flags(flags);
+ spin_unlock_irqrestore (&lp->lock, flags);
return;
}
#ifdef MODULE
static struct net_device dev_at1700;
+#ifndef CONFIG_X86_PC9800
static int io = 0x260;
+#else
+static int io = 0xd0;
+#endif
+
static int irq;
MODULE_PARM(io, "i");
@@ -901,7 +981,15 @@ cleanup_module(void)
/* If we don't do this, we can't re-insmod it later. */
free_irq(dev_at1700.irq, NULL);
+#ifndef CONFIG_X86_PC9800
release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
+#else
+ {
+ int i;
+ for (i = 0; i < 0x2000; i += 0x200)
+ release_region(dev_at1700.base_addr + i, 2);
+ }
+#endif
}
#endif /* MODULE */
MODULE_LICENSE("GPL");
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
index 761628d8b586..aa58407de02d 100644
--- a/drivers/net/e100/e100.h
+++ b/drivers/net/e100/e100.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -57,6 +57,8 @@
#include <linux/if.h>
#include <asm/uaccess.h>
#include <linux/ip.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
#define E100_REGS_LEN 1
/*
@@ -301,6 +303,9 @@ struct driver_stats {
/* EEPROM bit definitions */
/*- EEPROM control register bits */
+#define EEPROM_FLAG_ASF 0x8000
+#define EEPROM_FLAG_GCL 0x4000
+
#define EN_TRNF 0x10 /* Enable turnoff */
#define EEDO 0x08 /* EEPROM data out */
#define EEDI 0x04 /* EEPROM data in (set for writing data) */
@@ -319,6 +324,8 @@ struct driver_stats {
#define EEPROM_COMPATIBILITY_WORD 3
#define EEPROM_PWA_NO 8
#define EEPROM_ID_WORD 0x0A
+#define EEPROM_CONFIG_ASF 0x0D
+#define EEPROM_SMBUS_ADDR 0x90
#define EEPROM_SUM 0xbaba
@@ -358,7 +365,7 @@ struct driver_stats {
#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */
#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */
#define CB_STATUS_OK BIT_13 /* CB OK Bit */
-#define CB_STATUS_UNDERRUN BIT_12 /* CB A Bit */
+#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */
#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */
/*misc command bits */
@@ -851,6 +858,7 @@ struct ethtool_lpbk_data{
};
struct e100_private {
+ struct vlan_group *vlgrp;
u32 flags; /* board management flags */
u32 tx_per_underrun; /* number of good tx frames per underrun */
unsigned int tx_count; /* count of tx frames, so we can request an interrupt */
@@ -886,7 +894,6 @@ struct e100_private {
struct driver_stats drv_stats;
u8 rev_id; /* adapter PCI revision ID */
- unsigned long device_type; /* device type from e100_vendor.h */
unsigned int phy_addr; /* address of PHY component */
unsigned int PhyId; /* ID of PHY component */
@@ -923,8 +930,6 @@ struct e100_private {
struct cfg_params params; /* adapter's command line parameters */
- char *id_string;
-
u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */
/* WOL params for ethtool */
diff --git a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c
index bff330628916..d9df35677a7c 100644
--- a/drivers/net/e100/e100_config.c
+++ b/drivers/net/e100/e100_config.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -521,6 +521,25 @@ e100_config_wol(struct e100_private *bdp)
spin_unlock_bh(&(bdp->config_lock));
}
+void
+e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable)
+{
+ spin_lock_bh(&(bdp->config_lock));
+ if (enable) {
+ if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
+ bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE;
+ E100_CONFIG(bdp, 22);
+ }
+
+ } else {
+ if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
+ bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE;
+ E100_CONFIG(bdp, 22);
+ }
+ }
+ spin_unlock_bh(&(bdp->config_lock));
+}
+
/**
* e100_config_loopback_mode
* @bdp: atapter's private data struct
diff --git a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h
index 5bc88f6849b6..5d1e194ff25b 100644
--- a/drivers/net/e100/e100_config.h
+++ b/drivers/net/e100/e100_config.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -163,5 +163,5 @@ 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);
-
+extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable);
#endif /* _E100_CONFIG_INC_ */
diff --git a/drivers/net/e100/e100_eeprom.c b/drivers/net/e100/e100_eeprom.c
index c5618c1a2ca4..ff843e161b76 100644
--- a/drivers/net/e100/e100_eeprom.c
+++ b/drivers/net/e100/e100_eeprom.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index 1f1f70caca21..d241eaa64e2e 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -45,8 +45,22 @@
**********************************************************************/
/* Change Log
- *
- * 2.1.29 12/20/02
+ *
+ * 2.2.21 02/11/03
+ * o Removed marketing brand strings. Instead, Using generic string
+ * "Intel(R) PRO/100 Network Connection" for all adapters.
+ * o Implemented ethtool -S option
+ * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver
+ * o Bug fix: Read wrong byte in EEPROM when offset is odd number
+ * o Bug fix: PHY loopback test fails on ICH devices
+ * o Bug fix: System panic on e100_close when repeating Hot Remove and
+ * Add in a team
+ * o Bug fix: Linux Bonding driver claims adapter's link loss because of
+ * not updating last_rx field
+ * o Bug fix: e100 does not check validity of MAC address
+ * o New feature: added ICH5 support
+ *
+ * 2.1.27 11/20/02
* o Bug fix: Device command timeout due to SMBus processing during init
* o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
* o Bug fix: Not using EEPROM WoL setting as default in ethtool
@@ -62,15 +76,6 @@
* ifconfig down, rmmod and insmod
*
* 2.1.24 10/7/02
- * o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
- * name is changed
- * o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
- * are executing during stress traffic at shared interrupt system.
- * Removed Rx polling code
- * o Added detailed printk if selftest failed when insmod
- * o Removed misleading printks
- *
- * 2.1.12 8/2/02
*/
#include <linux/config.h>
@@ -81,7 +86,8 @@
#include "e100_ucode.h"
#include "e100_config.h"
#include "e100_phy.h"
-#include "e100_vendor.h"
+
+extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp);
static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
@@ -127,7 +133,6 @@ static char *test_strings[] = {
static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
-#include <linux/mii.h>
static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
@@ -136,11 +141,15 @@ static void e100_free_nontx_list(struct e100_private *);
static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
-char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.29-k4";
+char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
+char e100_driver_version[]="2.2.21-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
+static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
+ *grp);
+static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
+static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
#ifdef CONFIG_PM
static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
@@ -186,7 +195,6 @@ static void e100_print_brd_conf(struct e100_private *);
static void e100_set_multi(struct net_device *);
void e100_set_speed_duplex(struct e100_private *);
-char *e100_get_brand_msg(struct e100_private *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
static u8 e100_sw_init(struct e100_private *);
static void e100_tco_workaround(struct e100_private *);
@@ -220,6 +228,7 @@ static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
char *);
unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
void e100_exec_cmplx(struct e100_private *, u32, u8);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
/**
* e100_get_rx_struct - retrieve cell to hold skb buff from the pool
@@ -607,7 +616,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
}
if (((bdp->pdev->device > 0x1030)
- && (bdp->pdev->device < 0x103F))
+ && (bdp->pdev->device < 0x103F))
+ || ((bdp->pdev->device >= 0x1050)
+ && (bdp->pdev->device <= 0x1057))
|| (bdp->pdev->device == 0x2449)
|| (bdp->pdev->device == 0x2459)
|| (bdp->pdev->device == 0x245D)) {
@@ -646,6 +657,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_pci;
}
+ dev->vlan_rx_register = e100_vlan_rx_register;
+ dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
dev->irq = pcid->irq;
dev->open = &e100_open;
dev->hard_start_xmit = &e100_xmit_frame;
@@ -655,9 +669,11 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
dev->set_multicast_list = &e100_set_multi;
dev->set_mac_address = &e100_set_mac;
dev->do_ioctl = &e100_ioctl;
- if (bdp->flags & USE_IPCB) {
- dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- }
+
+ if (bdp->flags & USE_IPCB)
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
e100nics++;
e100_get_speed_duplex_caps(bdp);
@@ -668,25 +684,24 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
memcpy(bdp->ifname, dev->name, IFNAMSIZ);
bdp->ifname[IFNAMSIZ-1] = 0;
- bdp->device_type = ent->driver_data;
printk(KERN_NOTICE
"e100: %s: %s\n",
- bdp->device->name, e100_get_brand_msg(bdp));
+ bdp->device->name, "Intel(R) PRO/100 Network Connection");
e100_print_brd_conf(bdp);
- bdp->id_string = e100_get_brand_msg(bdp);
bdp->wolsupported = 0;
bdp->wolopts = 0;
/* Check if WoL is enabled on EEPROM */
if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
+ /* Magic Packet WoL is enabled on device by default */
+ /* if EEPROM WoL bit is TRUE */
+ bdp->wolsupported = WAKE_MAGIC;
+ bdp->wolopts = WAKE_MAGIC;
if (bdp->rev_id >= D101A4_REV_ID)
bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
if (bdp->rev_id >= D101MA_REV_ID)
bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
- /* Magic Packet WoL is enabled on device by default */
- /* if EEPROM WoL bit is TRUE */
- bdp->wolopts = WAKE_MAGIC;
}
printk(KERN_NOTICE "\n");
@@ -752,6 +767,34 @@ e100_remove1(struct pci_dev *pcid)
--e100nics;
}
+static struct pci_device_id e100_id_table[] __devinitdata = {
+ {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0,} /* This has to be the last entry*/
+};
MODULE_DEVICE_TABLE(pci, e100_id_table);
static struct pci_driver e100_driver = {
@@ -994,13 +1037,14 @@ e100_close(struct net_device *dev)
{
struct e100_private *bdp = dev->priv;
+ e100_disable_clear_intr(bdp);
+ free_irq(dev->irq, dev);
bdp->intr_mask = SCB_INT_MASK;
e100_isolate_driver(bdp);
netif_carrier_off(bdp->device);
bdp->cur_line_speed = 0;
bdp->cur_dplx_mode = 0;
- free_irq(dev->irq, dev);
e100_clear_pools(bdp);
return 0;
@@ -1097,6 +1141,8 @@ e100_set_mac(struct net_device *dev, void *addr)
int rc = -1;
struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+ if (!is_valid_ether_addr(p_sockaddr->sa_data))
+ return -EADDRNOTAVAIL;
bdp = dev->priv;
if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
@@ -1231,6 +1277,10 @@ e100_init(struct e100_private *bdp)
/* read the MAC address from the eprom */
e100_rd_eaddr(bdp);
+ if (!is_valid_ether_addr(bdp->device->dev_addr)) {
+ printk(KERN_ERR "e100: Invalid Ethernet address\n");
+ return false;
+ }
/* read NIC's part number */
e100_rd_pwa_no(bdp);
@@ -1670,6 +1720,11 @@ e100_watchdog(struct net_device *dev)
} else {
if (netif_running(dev))
netif_stop_queue(dev);
+ /* When changing to non-autoneg, device may lose */
+ /* link with some switches. e100 will try to */
+ /* revover link by sending command to PHY layer */
+ if (bdp->params.e100_speed_duplex != E100_AUTONEG)
+ e100_force_speed_duplex_to_phy(bdp);
}
rmb();
@@ -1793,7 +1848,8 @@ e100intr(int irq, void *dev_inst, struct pt_regs *regs)
bdp = dev->priv;
intr_status = readw(&bdp->scb->scb_status);
- if (!intr_status || (intr_status == 0xffff)) {
+ /* If not my interrupt, just return */
+ if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) {
return;
}
@@ -1993,17 +2049,15 @@ e100_rx_srv(struct e100_private *bdp)
} else {
skb->ip_summed = CHECKSUM_NONE;
}
- switch (netif_rx(skb)) {
- case NET_RX_BAD:
- case NET_RX_DROP:
- case NET_RX_CN_MOD:
- case NET_RX_CN_HIGH:
- break;
- default:
- bdp->drv_stats.net_stats.rx_bytes += skb->len;
- break;
- }
+ if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
+ vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
+ } else {
+ netif_rx(skb);
+ }
+ dev->last_rx = jiffies;
+ bdp->drv_stats.net_stats.rx_bytes += skb->len;
+
rfd_cnt++;
} /* end of rfd loop */
@@ -2096,6 +2150,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
}
+ if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
+ (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
+ (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
+ }
+
tcb->tcb_hdr.cb_status = 0;
tcb->tcb_thrshld = bdp->tx_thld;
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
@@ -2114,7 +2173,8 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
if ((ip->protocol == IPPROTO_TCP) ||
(ip->protocol == IPPROTO_UDP)) {
- tcb->tcbu.ipcb.ip_activation_high =
+
+ tcb->tcbu.ipcb.ip_activation_high |=
IPCB_HARDWAREPARSING_ENABLE;
tcb->tcbu.ipcb.ip_schedule |=
IPCB_TCPUDP_CHECKSUM_ENABLE;
@@ -2682,13 +2742,12 @@ e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
udelay(20);
}
- /* Mask off our interrupt line -- its unmasked after reset */
+ /* Mask off our interrupt line -- it is unmasked after reset */
e100_disable_clear_intr(bdp);
#ifdef E100_CU_DEBUG
bdp->last_cmd = 0;
bdp->last_sub_cmd = 0;
#endif
-
}
/**
@@ -2901,27 +2960,6 @@ e100_print_brd_conf(struct e100_private *bdp)
}
/**
- * e100_get_brand_msg
- * @bdp: atapter's private data struct
- *
- * This routine checks if there is specified branding message for a given board
- * type and returns a pointer to the string containing the branding message.
- */
-char *
-e100_get_brand_msg(struct e100_private *bdp)
-{
- int i;
-
- for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
- if (e100_vendor_info_array[i].device_type == bdp->device_type) {
- return e100_vendor_info_array[i].idstr;
- }
- }
-
- return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
-}
-
-/**
* e100_pci_setup - setup the adapter's PCI information
* @pcid: adapter's pci_dev struct
* @bdp: atapter's private data struct
@@ -3004,12 +3042,17 @@ e100_isolate_driver(struct e100_private *bdp)
void
e100_set_speed_duplex(struct e100_private *bdp)
{
- if (netif_carrier_ok(bdp->device))
+ int carrier_ok;
+ /* Device may lose link with some siwtches when */
+ /* changing speed/duplex to non-autoneg. e100 */
+ /* needs to remember carrier state in order to */
+ /* start watchdog timer for recovering link */
+ if ((carrier_ok = netif_carrier_ok(bdp->device)))
e100_isolate_driver(bdp);
e100_phy_set_speed_duplex(bdp, true);
e100_config_fc(bdp); /* re-config flow-control if necessary */
e100_config(bdp);
- if (netif_carrier_ok(bdp->device))
+ if (carrier_ok)
e100_deisolate_driver(bdp, false);
}
@@ -3426,6 +3469,7 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
u16 first_word, last_word;
int i, max_len;
void *ptr;
+ u8 *eeprom_data_bytes = (u8 *)eeprom_data;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -3461,7 +3505,9 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
return -EFAULT;
- if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
+ if(ecmd.offset & 1)
+ eeprom_data_bytes++;
+ if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len))
return -EFAULT;
} else {
if (ecmd.magic != E100_EEPROM_MAGIC)
@@ -3754,7 +3800,8 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
return -EFAULT;
switch (info.string_set) {
- case ETH_SS_TEST:
+ case ETH_SS_TEST: {
+ int ret = 0;
if (info.len > E100_MAX_TEST_RES)
info.len = E100_MAX_TEST_RES;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
@@ -3766,7 +3813,13 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
test_strings[i]);
}
- break;
+ if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+ ret = -EFAULT;
+ if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+ ret = -EFAULT;
+ kfree(strings);
+ return ret;
+ }
case ETH_SS_STATS: {
char *strings = NULL;
void *addr = ifr->ifr_data;
@@ -3783,19 +3836,6 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
default:
return -EOPNOTSUPP;
}
-
- if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) {
- kfree(strings);
- return -EFAULT;
- }
-
- if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) {
- kfree(strings);
- return -EFAULT;
- }
-
- kfree(strings);
- return 0;
}
static int
@@ -4022,6 +4062,45 @@ exit:
spin_unlock_bh(&(bdp->bd_non_tx_lock));
}
+static void
+e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct e100_private *bdp = netdev->priv;
+
+ e100_disable_clear_intr(bdp);
+ bdp->vlgrp = grp;
+
+ if(grp) {
+ /* enable VLAN tag insert/strip */
+ e100_config_vlan_drop(bdp, true);
+
+ } else {
+ /* disable VLAN tag insert/strip */
+ e100_config_vlan_drop(bdp, false);
+ }
+
+ e100_config(bdp);
+ e100_set_intr_mask(bdp);
+}
+
+static void
+e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ /* We don't do Vlan filtering */
+ return;
+}
+
+static void
+e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct e100_private *bdp = netdev->priv;
+
+ if(bdp->vlgrp)
+ bdp->vlgrp->vlan_devices[vid] = NULL;
+ /* We don't do Vlan filtering */
+ return;
+}
+
#ifdef CONFIG_PM
static int
e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
@@ -4057,7 +4136,7 @@ e100_suspend(struct pci_dev *pcid, u32 state)
e100_do_wol(pcid, bdp);
/* If wol is enabled */
- if (bdp->wolopts) {
+ if (bdp->wolopts || e100_asf_enabled(bdp)) {
pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */
pci_set_power_state(pcid, 3); /* Set power state to D3. */
} else {
@@ -4085,6 +4164,31 @@ e100_resume(struct pci_dev *pcid)
}
#endif /* CONFIG_PM */
+/**
+ * e100_asf_enabled - checks if ASF is configured on the current adaper
+ * by reading registers 0xD and 0x90 in the EEPROM
+ * @bdp: atapter's private data struct
+ *
+ * Returns: true if ASF is enabled
+ */
+static unsigned char
+e100_asf_enabled(struct e100_private *bdp)
+{
+ u16 asf_reg;
+ u16 smbus_addr_reg;
+ if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) {
+ asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF);
+ if ((asf_reg & EEPROM_FLAG_ASF)
+ && !(asf_reg & EEPROM_FLAG_GCL)) {
+ smbus_addr_reg =
+ e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR);
+ if ((smbus_addr_reg & 0xFF) != 0xFE)
+ return true;
+ }
+ }
+ return false;
+}
+
#ifdef E100_CU_DEBUG
unsigned char
e100_cu_unknown_state(struct e100_private *bdp)
diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c
index c8f9053992e1..08782934bdf6 100644
--- a/drivers/net/e100/e100_phy.c
+++ b/drivers/net/e100/e100_phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -636,7 +636,6 @@ e100_force_speed_duplex(struct e100_private *bdp)
control &= ~BMCR_ANENABLE;
control &= ~BMCR_LOOPBACK;
- /* Check e100.c values */
switch (bdp->params.e100_speed_duplex) {
case E100_SPEED_10_HALF:
control &= ~BMCR_SPEED100;
@@ -682,6 +681,41 @@ e100_force_speed_duplex(struct e100_private *bdp)
} while (true);
}
+void
+e100_force_speed_duplex_to_phy(struct e100_private *bdp)
+{
+ u16 control;
+
+ e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
+ control &= ~BMCR_ANENABLE;
+ control &= ~BMCR_LOOPBACK;
+
+ switch (bdp->params.e100_speed_duplex) {
+ case E100_SPEED_10_HALF:
+ control &= ~BMCR_SPEED100;
+ control &= ~BMCR_FULLDPLX;
+ break;
+
+ case E100_SPEED_10_FULL:
+ control &= ~BMCR_SPEED100;
+ control |= BMCR_FULLDPLX;
+ break;
+
+ case E100_SPEED_100_HALF:
+ control |= BMCR_SPEED100;
+ control &= ~BMCR_FULLDPLX;
+ break;
+
+ case E100_SPEED_100_FULL:
+ control |= BMCR_SPEED100;
+ control |= BMCR_FULLDPLX;
+ break;
+ }
+
+ /* Send speed/duplex command to PHY layer. */
+ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+}
+
/*
* Procedure: e100_set_fc
*
diff --git a/drivers/net/e100/e100_phy.h b/drivers/net/e100/e100_phy.h
index 51d5ff192700..df2d483e67f8 100644
--- a/drivers/net/e100/e100_phy.h
+++ b/drivers/net/e100/e100_phy.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -30,8 +30,6 @@
#include "e100.h"
-#include <linux/mii.h>
-
/*
* Auto-polarity enable/disable
* e100_autopolarity = 0 => disable auto-polarity
diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
index 27ff5af00bfd..0ff7266ef8e2 100644
--- a/drivers/net/e100/e100_test.c
+++ b/drivers/net/e100/e100_test.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -242,6 +242,9 @@ e100_diag_config_loopback(struct e100_private* bdp,
*dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
if (set_loopback) {
+ /* ICH PHY loopback is broken */
+ if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK)
+ loopback_mode = MAC_LOOPBACK;
/* Configure loopback on MAC */
e100_config_loopback_mode(bdp,loopback_mode);
} else {
diff --git a/drivers/net/e100/e100_ucode.h b/drivers/net/e100/e100_ucode.h
index 1c6b88c7fac3..ccbcd05583aa 100644
--- a/drivers/net/e100/e100_ucode.h
+++ b/drivers/net/e100/e100_ucode.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/e100/e100_vendor.h b/drivers/net/e100/e100_vendor.h
deleted file mode 100644
index 01be2d41b9cd..000000000000
--- a/drivers/net/e100/e100_vendor.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/*******************************************************************************
-
-
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
-
- 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.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef E100_VENDOR_ID_INFO
-#define E100_VENDOR_ID_INFO
-/* ====================================================================== */
-/* vendor_info */
-/* ====================================================================== */
-
-struct e100_vendor_info {
- unsigned long device_type;
- char *idstr;
-};
-
-enum e100_device_type {
- E100_BRD_100TX = 1,
- E100_BRD_100T4,
- E100_BRD_10T,
- E100_BRD_100WFM,
- E100_BRD_82557,
- E100_BRD_82557_WOL,
- E100_BRD_82558,
- E100_BRD_82558_WOL,
- E100_BRD_100,
- E100_BRD_100M,
- E100_BRD_AOL2,
- E100_BRD_AOL,
- E100_PROS_M,
- E100_PROS_AM,
- E100_PROS_AM_AOL,
- E100_PROS_DT,
- E100_PRO_DT,
- E100_PROM_DT,
- E100_PRO_SRV,
- E100_PRO_SRVP,
- E100_PROS_SRV,
- E100_PRO_DUAL,
- E100_PROS_DUAL,
- E100_PROP_DUAL,
- E100_PROP_WOL,
- E100_PROS_MOB,
- E100_PRO_CB,
- E100_PRO_CB_M,
- E100_PROSR_MOB,
- E100_PROS_MC,
- E100_PROSR_MC,
- E100_PROP_MC,
- E100_PROSP_MC,
- E100_PROP_MOB,
- E100_PROSP_MOB,
- E100_PRO_MINI,
- E100_PRO_NET,
- E100_PROS_NET,
- E100_PROVM_NET,
- E100_PROVE_D,
- E100_82559_LOM,
- E100_82559_LOM_AOL,
- E100_82559_LOM_AOL2,
- E100_82559_LOM_DELL,
- E100_IBM_MDS,
- E100_CMPQ_S,
- E100_PROVE_DA,
- E100_PROVM_DA,
- E100_PROVE_LOM,
- E100_PROVE_NET,
- E100_82562,
- E100_82551QM,
- E100_ALL_BOARDS
-};
-
-struct e100_vendor_info e100_vendor_info_array[] = {
- { E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"},
- { E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"},
- { E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"},
- { E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"},
- { E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"},
- { E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"},
- { E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"},
- { E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"},
- { E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
- { E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
- { E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
- { E100_82559_LOM_DELL, "Intel(R) 8255x Based Network Connection"},
- { E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
- { E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
- { E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
- { E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"},
- { E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"},
- { E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"},
- { E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"},
- { E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"},
- { E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"},
- { E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"},
- { E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"},
- { E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"},
- { E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"},
- { E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"},
- { E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"},
- { E100_PRO_CB, "Intel(R) PRO/100 CardBus II"},
- { E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"},
- { E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"},
- { E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"},
- { E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"},
- { E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"},
- { E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"},
- { E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"},
- { E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"},
- { E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"},
- { E100_PRO_NET, "Intel(R) PRO/100 Network Connection" },
- { E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" },
- { E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"},
- { E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"},
- { E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"},
- { E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" },
- { E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" },
- { E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"},
- { E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" },
- { E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"},
- { E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"},
- { E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
- { E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
- { E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
- { E100_82551QM, "Intel(R) PRO/100 M Mobile Connection"},
- { E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
- {0,NULL}
-};
-
-static struct pci_device_id e100_id_table[] __devinitdata = {
- {0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX},
- {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
- {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
- {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
- {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
- {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
- {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
- {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
- {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
- {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
- {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
- {0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558},
- {0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL},
- {0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100},
- {0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M},
- {0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100},
- {0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M},
- {0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2},
- {0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL},
- {0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M},
- {0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M},
- {0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM},
- {0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM},
- {0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL},
- {0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT},
- {0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT},
- {0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT},
- {0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT},
- {0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT},
- {0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV},
- {0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP},
- {0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV},
- {0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV},
- {0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL},
- {0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL},
- {0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL},
- {0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL},
- {0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL},
- {0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV},
- {0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV},
- {0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV},
- {0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV},
- {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL},
- {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL},
- {0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB},
- {0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB},
- {0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M},
- {0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB},
- {0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC},
- {0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC},
- {0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB},
- {0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC},
- {0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB},
- {0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC},
- {0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB},
- {0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC},
- {0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC},
- {0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC},
- {0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI},
- {0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI},
- {0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC},
- {0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC},
- {0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC},
- {0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC},
- {0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI},
- {0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI},
- {0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI},
- {0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM},
- {0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM},
- {0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL},
- {0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2},
- {0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET},
- {0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET},
- {0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET},
- {0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET},
- {0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS},
- {0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET},
- {0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
- {0x8086, 0x1229, 0x1028, PCI_ANY_ID, 0, 0, E100_82559_LOM_DELL},
- {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-
- {0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
- {0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D},
- {0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D},
- {0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA},
- {0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA},
- {0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET},
- {0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET},
- {0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC},
- {0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB},
- {0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET},
- {0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},
- {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-
- {0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM},
- {0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM},
- {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM},
-
- {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
- {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
- {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
- {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
- {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
- {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
- {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
- {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
- {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
- {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
- {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
- {0,} /* This has to be the last entry*/
-};
-
-#endif /* E100_VENDOR_ID_INFO */
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 18d0c2b5e471..2b81e45e641f 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -65,6 +65,7 @@
#include <linux/reboot.h>
#include <net/checksum.h>
#include <linux/workqueue.h>
+#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -95,6 +96,15 @@ struct e1000_adapter;
#define E1000_RXBUFFER_8192 8192
#define E1000_RXBUFFER_16384 16384
+/* SmartSpeed delimiters */
+#define E1000_SMARTSPEED_DOWNSHIFT 3
+#define E1000_SMARTSPEED_MAX 15
+
+/* Packet Buffer allocations */
+#define E1000_TX_FIFO_SIZE_SHIFT 0xA
+#define E1000_TX_HEAD_ADDR_SHIFT 7
+#define E1000_PBA_TX_MASK 0xFFFF0000
+
/* Flow Control High-Watermark: 43464 bytes */
#define E1000_FC_HIGH_THRESH 0xA9C8
@@ -107,10 +117,7 @@ struct e1000_adapter;
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#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
+#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_APME 4
@@ -145,7 +152,8 @@ struct e1000_desc_ring {
};
#define E1000_DESC_UNUSED(R) \
-((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
#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)
@@ -155,6 +163,7 @@ struct e1000_desc_ring {
/* board specific private data structure */
struct e1000_adapter {
+ struct timer_list tx_fifo_stall_timer;
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
@@ -163,6 +172,7 @@ struct e1000_adapter {
uint32_t rx_buffer_len;
uint32_t part_num;
uint32_t wol;
+ uint32_t smartspeed;
uint16_t link_speed;
uint16_t link_duplex;
spinlock_t stats_lock;
@@ -177,7 +187,11 @@ struct e1000_adapter {
uint32_t txd_cmd;
uint32_t tx_int_delay;
uint32_t tx_abs_int_delay;
- int max_data_per_txd;
+ uint32_t gotcl;
+ uint32_t tx_fifo_head;
+ uint32_t tx_head_addr;
+ uint32_t tx_fifo_size;
+ atomic_t tx_fifo_stall;
/* RX */
struct e1000_desc_ring rx_ring;
@@ -186,6 +200,10 @@ struct e1000_adapter {
uint32_t rx_int_delay;
uint32_t rx_abs_int_delay;
boolean_t rx_csum;
+ uint32_t gorcl;
+
+ /* Interrupt Throttle Rate */
+ uint32_t itr;
/* OS defined structs */
struct net_device *netdev;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index d06ef79c6e29..c64530107467 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -38,6 +38,7 @@ extern char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
@@ -129,30 +130,9 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
hw->autoneg = 1;
hw->autoneg_advertised = 0x002F;
ecmd->advertising = 0x002F;
- } else {
- hw->autoneg = 0;
- switch(ecmd->speed + ecmd->duplex) {
- case SPEED_10 + DUPLEX_HALF:
- hw->forced_speed_duplex = e1000_10_half;
- break;
- case SPEED_10 + DUPLEX_FULL:
- hw->forced_speed_duplex = e1000_10_full;
- break;
- case SPEED_100 + DUPLEX_HALF:
- hw->forced_speed_duplex = e1000_100_half;
- break;
- case SPEED_100 + DUPLEX_FULL:
- hw->forced_speed_duplex = e1000_100_full;
- break;
- case SPEED_1000 + DUPLEX_FULL:
- hw->autoneg = 1;
- hw->autoneg_advertised = ADVERTISE_1000_FULL;
- break;
- case SPEED_1000 + DUPLEX_HALF: /* not supported */
- default:
+ } else
+ if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
return -EINVAL;
- }
- }
/* reset the link */
@@ -165,16 +145,6 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
return 0;
}
-static inline int
-e1000_eeprom_size(struct e1000_hw *hw)
-{
- if((hw->mac_type > e1000_82544) &&
- (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
- return 512;
- else
- return 128;
-}
-
static void
e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
struct ethtool_drvinfo *drvinfo)
@@ -186,7 +156,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
drvinfo->n_stats = E1000_STATS_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
- drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
+ drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
}
static void
@@ -220,9 +190,8 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
{
struct e1000_hw *hw = &adapter->hw;
- int max_len, first_word, last_word;
+ int first_word, last_word;
int ret_val = 0;
- int i;
if(eeprom->len == 0) {
ret_val = -EINVAL;
@@ -231,22 +200,28 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
eeprom->magic = hw->vendor_id | (hw->device_id << 16);
- max_len = e1000_eeprom_size(hw);
-
if(eeprom->offset > eeprom->offset + eeprom->len) {
ret_val = -EINVAL;
goto geeprom_error;
}
- if((eeprom->offset + eeprom->len) > max_len)
- eeprom->len = (max_len - eeprom->offset);
+ if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2))
+ eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset);
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
- for(i = 0; i <= (last_word - first_word); i++)
- e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
-
+ if(hw->eeprom.type == e1000_eeprom_spi)
+ ret_val = e1000_read_eeprom(hw, first_word,
+ last_word - first_word + 1,
+ eeprom_buff);
+ else {
+ uint16_t i;
+ for (i = 0; i < last_word - first_word + 1; i++)
+ if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
+ &eeprom_buff[i])))
+ break;
+ }
geeprom_error:
return ret_val;
}
@@ -257,9 +232,8 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
{
struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
- int max_len, first_word, last_word;
void *ptr;
- int i;
+ int max_len, first_word, last_word, ret_val = 0;
if(eeprom->len == 0)
return -EOPNOTSUPP;
@@ -267,7 +241,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
return -EFAULT;
- max_len = e1000_eeprom_size(hw);
+ max_len = hw->eeprom.word_size * 2;
if((eeprom->offset + eeprom->len) > max_len)
eeprom->len = (max_len - eeprom->offset);
@@ -283,30 +257,31 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
if(eeprom->offset & 1) {
/* need read/modify/write of first changed EEPROM word */
/* only the second byte of the word is being modified */
- e1000_read_eeprom(hw, first_word, &eeprom_buff[0]);
+ ret_val = e1000_read_eeprom(hw, first_word, 1,
+ &eeprom_buff[0]);
ptr++;
}
- if((eeprom->offset + eeprom->len) & 1) {
+ if(((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
/* need read/modify/write of last changed EEPROM word */
/* only the first byte of the word is being modified */
- e1000_read_eeprom(hw, last_word,
+ ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
}
- if(copy_from_user(ptr, user_data, eeprom->len)) {
- kfree(eeprom_buff);
- return -EFAULT;
+ if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) {
+ ret_val = -EFAULT;
+ goto seeprom_error;
}
- for(i = 0; i <= (last_word - first_word); i++)
- e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
+ ret_val = e1000_write_eeprom(hw, first_word,
+ last_word - first_word + 1, eeprom_buff);
/* Update the checksum over the first part of the EEPROM if needed */
- if(first_word <= EEPROM_CHECKSUM_REG)
+ if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
e1000_update_eeprom_checksum(hw);
+seeprom_error:
kfree(eeprom_buff);
-
- return 0;
+ return ret_val;
}
static void
@@ -333,8 +308,8 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
/* Fall Through */
default:
- wol->supported = WAKE_UCAST | WAKE_MCAST
- | WAKE_BCAST | WAKE_MAGIC;
+ wol->supported = WAKE_UCAST | WAKE_MCAST |
+ WAKE_BCAST | WAKE_MAGIC;
wol->wolopts = 0;
if(adapter->wol & E1000_WUFC_EX)
@@ -368,7 +343,7 @@ e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
/* Fall Through */
default:
- if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY))
+ if(wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
adapter->wol = 0;
@@ -542,13 +517,12 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
}
case ETHTOOL_GEEPROM: {
struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
+ struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
void *ptr;
- int max_len, err = 0;
-
- max_len = e1000_eeprom_size(&adapter->hw);
+ int err = 0;
- eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+ eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
if(eeprom_buff == NULL)
return -ENOMEM;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 8ead5c6544c8..3527e7794635 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -32,6 +32,8 @@
#include "e1000_hw.h"
+static int32_t e1000_set_phy_type(struct e1000_hw *hw);
+static void e1000_phy_init_script(struct e1000_hw *hw);
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);
@@ -42,19 +44,103 @@ 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 int32_t e1000_write_eeprom_spi(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static int32_t e1000_write_eeprom_microwire(struct e1000_hw *hw,
+ uint16_t offset, uint16_t words,
+ uint16_t *data);
+static int32_t e1000_spi_eeprom_ready(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_clock_eeprom(struct e1000_hw *hw);
-static void e1000_cleanup_eeprom(struct e1000_hw *hw);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count);
+static int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
+static void e1000_release_eeprom(struct e1000_hw *hw);
static void e1000_standby_eeprom(struct e1000_hw *hw);
static int32_t e1000_id_led_init(struct e1000_hw * hw);
+
+
+/******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_phy_type(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_set_phy_type");
+
+ switch(hw->phy_id) {
+ case M88E1000_E_PHY_ID:
+ case M88E1000_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ hw->phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID:
+ hw->phy_type = e1000_phy_igp;
+ break;
+ default:
+ /* Should never have loaded on this device */
+ hw->phy_type = e1000_phy_undefined;
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_phy_init_script");
+
+ if(hw->phy_init_script) {
+ msec_delay(10);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+ e1000_write_phy_reg(hw,0x0000,0x0140);
+
+ msec_delay(5);
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95);
+ e1000_write_phy_reg(hw,0x0015,0x0001);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71);
+ e1000_write_phy_reg(hw,0x0011,0xBD21);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79);
+ e1000_write_phy_reg(hw,0x0019,0x0018);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30);
+ e1000_write_phy_reg(hw,0x0010,0x1600);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31);
+ e1000_write_phy_reg(hw,0x0011,0x0014);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32);
+ e1000_write_phy_reg(hw,0x0012,0x161C);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94);
+ e1000_write_phy_reg(hw,0x0014,0x0003);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96);
+ e1000_write_phy_reg(hw,0x0016,0x003F);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010);
+ e1000_write_phy_reg(hw,0x0010,0x0008);
+
+ e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+ e1000_write_phy_reg(hw,0x0000,0x3300);
+ }
+}
+
/******************************************************************************
* Set the mac type member in the hw struct.
- *
+ *
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
int32_t
@@ -101,10 +187,19 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82546EB_FIBER:
hw->mac_type = e1000_82546;
break;
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EP:
+ hw->mac_type = e1000_82541;
+ break;
+ case E1000_DEV_ID_82547EI:
+ hw->mac_type = e1000_82547;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
}
+
+
return E1000_SUCCESS;
}
/******************************************************************************
@@ -119,9 +214,10 @@ e1000_reset_hw(struct e1000_hw *hw)
uint32_t ctrl_ext;
uint32_t icr;
uint32_t manc;
+ uint32_t led_ctrl;
DEBUGFUNC("e1000_reset_hw");
-
+
/* For 82542 (rev 2.0), disable MWI before issuing a device reset */
if(hw->mac_type == e1000_82542_rev2_0) {
DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
@@ -145,7 +241,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* 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
@@ -156,6 +252,12 @@ e1000_reset_hw(struct e1000_hw *hw)
DEBUGOUT("Issuing a global reset to MAC\n");
ctrl = E1000_READ_REG(hw, CTRL);
+ /* Must reset the PHY before resetting the MAC */
+ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+ msec_delay(5);
+ }
+
if(hw->mac_type > e1000_82543)
E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
else
@@ -173,13 +275,25 @@ e1000_reset_hw(struct e1000_hw *hw)
msec_delay(2);
} else {
/* Wait for EEPROM reload (it happens automatically) */
- msec_delay(4);
+ msec_delay(5);
/* Dissable HW ARPs on ASF enabled adapters */
manc = E1000_READ_REG(hw, MANC);
manc &= ~(E1000_MANC_ARP_EN);
E1000_WRITE_REG(hw, MANC, manc);
}
-
+
+ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ e1000_phy_init_script(hw);
+
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+ if(hw->mac_type == e1000_82547)
+ led_ctrl |= IGP_LED3_MODE;
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
/* Clear interrupt mask to stop board from generating interrupts */
DEBUGOUT("Masking off all interrupts\n");
E1000_WRITE_REG(hw, IMC, 0xffffffff);
@@ -198,8 +312,8 @@ e1000_reset_hw(struct e1000_hw *hw)
* 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
+ *
+ * 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
@@ -224,7 +338,7 @@ e1000_init_hw(struct e1000_hw *hw)
DEBUGOUT("Error Initializing Identification LED\n");
return ret_val;
}
-
+
/* 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 */
@@ -327,13 +441,13 @@ e1000_init_hw(struct e1000_hw *hw)
/******************************************************************************
* 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
+ * established. Assumes the hardware has previously been reset and the
* transmitter and receiver are not enabled.
*****************************************************************************/
int32_t
@@ -353,7 +467,7 @@ e1000_setup_link(struct e1000_hw *hw)
* 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) {
+ if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -361,7 +475,7 @@ e1000_setup_link(struct e1000_hw *hw)
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) ==
+ else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
EEPROM_WORD0F_ASM_DIR)
hw->fc = e1000_fc_tx_pause;
else
@@ -390,7 +504,7 @@ e1000_setup_link(struct e1000_hw *hw)
* or e1000_phy_setup() is called.
*/
if(hw->mac_type == e1000_82543) {
- ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
SWDPIO__EXT_SHIFT);
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
}
@@ -416,7 +530,7 @@ e1000_setup_link(struct e1000_hw *hw)
* 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.
+ * registers will be set to 0.
*/
if(!(hw->fc & e1000_fc_tx_pause)) {
E1000_WRITE_REG(hw, FCRTL, 0);
@@ -445,7 +559,7 @@ e1000_setup_link(struct e1000_hw *hw)
* link. Assumes the hardware has been previously reset and the transmitter
* and receiver are not enabled.
*****************************************************************************/
-static int32_t
+static int32_t
e1000_setup_fiber_link(struct e1000_hw *hw)
{
uint32_t ctrl;
@@ -457,29 +571,29 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
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
+ /* 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
+ * 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
+ * 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).
@@ -491,8 +605,8 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
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
+ /* 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.
@@ -500,7 +614,7 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
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
+ /* 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);
@@ -531,8 +645,8 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
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
+ * 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) {
@@ -543,7 +657,7 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
if(status & E1000_STATUS_LU) break;
}
if(i == (LINK_UP_TIMEOUT / 10)) {
- /* AutoNeg failed to achieve a link, so we'll call
+ /* 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.
@@ -571,10 +685,10 @@ e1000_setup_fiber_link(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int32_t
+static int32_t
e1000_setup_copper_link(struct e1000_hw *hw)
{
- uint32_t ctrl;
+ uint32_t ctrl, led_ctrl;
int32_t ret_val;
uint16_t i;
uint16_t phy_data;
@@ -604,80 +718,148 @@ e1000_setup_copper_link(struct e1000_hw *hw)
}
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;
+ if (hw->phy_type == e1000_phy_igp) {
- /* 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;
+ ret_val = e1000_phy_reset(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
- 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;
- }
+ /* Wait 10ms for MAC to configure PHY from eeprom settings */
+ msec_delay(15);
- /* 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;
- }
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 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 activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+ if(hw->mac_type == e1000_82547)
+ led_ctrl |= IGP_LED3_MODE;
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+
+ if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ /* Set auto Master/Slave resolution process */
+ if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ }
- if (hw->phy_revision < M88E1011_I_REV_4) {
- /* 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) {
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Force MDI for IGP PHY */
+ phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
+ IGP01E1000_PSCR_FORCE_MDI_MDIX);
+
+ hw->mdix = 1;
+
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_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;
+ } else {
+ /* 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;
+
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+ /* 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
@@ -736,6 +918,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
return ret_val;
}
}
+ hw->get_link_status = TRUE;
} else {
DEBUGOUT("Forcing speed and duplex\n");
ret_val = e1000_phy_force_speed_duplex(hw);
@@ -1014,23 +1197,41 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
/* Write the configured values back to the Device Control Reg. */
E1000_WRITE_REG(hw, CTRL, ctrl);
- if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
- DEBUGOUT("PHY Read Error\n");
- return -E1000_ERR_PHY;
- }
+ if (hw->phy_type == e1000_phy_m88) {
+ 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);
+ /* 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;
+ /* Need to reset the PHY or these changes will be ignored */
+ mii_ctrl_reg |= MII_CR_RESET;
+ } else {
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed or duplex are forced.
+ */
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ }
/* Write back the modified PHY MII control register. */
if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
@@ -1069,7 +1270,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
}
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");
@@ -1093,32 +1294,34 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
}
}
}
-
- /* 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;
+ if (hw->phy_type == e1000_phy_m88) {
+ /* 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;
}
@@ -1136,6 +1339,8 @@ e1000_config_collision_dist(struct e1000_hw *hw)
{
uint32_t tctl;
+ DEBUGFUNC("e1000_config_collision_dist");
+
tctl = E1000_READ_REG(hw, TCTL);
tctl &= ~E1000_TCTL_COLD;
@@ -1172,22 +1377,43 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
/* 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;
+ if (hw->phy_type == e1000_phy_igp) {
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
+ else ctrl &= ~E1000_CTRL_FD;
- e1000_config_collision_dist(hw);
+ 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;
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_100MBPS)
+ ctrl |= E1000_CTRL_SPD_100;
+ } else {
+ 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;
@@ -1195,7 +1421,7 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
/******************************************************************************
* 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
@@ -1262,7 +1488,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
/******************************************************************************
* 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.
@@ -1484,9 +1710,9 @@ e1000_check_for_link(struct e1000_hw *hw)
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
+
+ /* 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;
@@ -1519,6 +1745,10 @@ e1000_check_for_link(struct e1000_hw *hw)
if(phy_data & MII_SR_LINK_STATUS) {
hw->get_link_status = FALSE;
+ /* Check if there was DownShift, must be checked immediately after
+ * link-up */
+ e1000_check_downshift(hw);
+
} else {
/* No link detected */
return 0;
@@ -1547,7 +1777,7 @@ e1000_check_for_link(struct e1000_hw *hw)
}
}
- /* Configure Flow Control now that Auto-Neg has completed. First, we
+ /* 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.
*/
@@ -1576,7 +1806,7 @@ e1000_check_for_link(struct e1000_hw *hw)
NWAY_LPAR_100TX_HD_CAPS |
NWAY_LPAR_100TX_FD_CAPS |
NWAY_LPAR_100T4_CAPS)) {
- /* If our link partner advertises anything in addition to
+ /* If our link partner advertises anything in addition to
* gigabit, we do not need to enable TBI compatibility.
*/
if(hw->tbi_compatibility_on) {
@@ -1780,7 +2010,7 @@ e1000_shift_out_mdi_bits(struct e1000_hw *hw,
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
+ * 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;
@@ -1817,7 +2047,7 @@ e1000_shift_out_mdi_bits(struct e1000_hw *hw,
*
* hw - Struct containing variables accessed by shared code
*
-* Bits are shifted in in MSB to LSB order.
+* Bits are shifted in in MSB to LSB order.
******************************************************************************/
static uint16_t
e1000_shift_in_mdi_bits(struct e1000_hw *hw)
@@ -1832,7 +2062,7 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw)
* 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. */
@@ -1892,7 +2122,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
* PHY to retrieve the desired data.
*/
mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
- (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_READ));
E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1930,7 +2160,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
* 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) |
+ mdic = ((reg_addr) | (phy_addr << 5) |
(PHY_OP_READ << 10) | (PHY_SOF << 12));
e1000_shift_out_mdi_bits(hw, mdic, 14);
@@ -1974,7 +2204,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
*/
mdic = (((uint32_t) phy_data) |
(reg_addr << E1000_MDIC_REG_SHIFT) |
- (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_WRITE));
E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1992,12 +2222,12 @@ e1000_write_phy_reg(struct e1000_hw *hw,
} 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
+ * 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
+ /* 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:
@@ -2010,6 +2240,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
e1000_shift_out_mdi_bits(hw, mdic, 32);
}
+
return 0;
}
@@ -2021,8 +2252,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
void
e1000_phy_hw_reset(struct e1000_hw *hw)
{
- uint32_t ctrl;
- uint32_t ctrl_ext;
+ uint32_t ctrl, ctrl_ext, led_ctrl;
DEBUGFUNC("e1000_phy_hw_reset");
@@ -2053,6 +2283,21 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
}
udelay(150);
+
+ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return;
+ }
+
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+ if(hw->mac_type == e1000_82547)
+ led_ctrl |= IGP_LED3_MODE;
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
}
/******************************************************************************
@@ -2079,6 +2324,9 @@ e1000_phy_reset(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
udelay(1);
+ if (hw->phy_type == e1000_phy_igp) {
+ e1000_phy_init_script(hw);
+ }
return 0;
}
@@ -2092,6 +2340,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
{
uint16_t phy_id_high, phy_id_low;
boolean_t match = FALSE;
+ int32_t phy_init_status;
DEBUGFUNC("e1000_detect_gig_phy");
@@ -2101,7 +2350,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
hw->phy_id = (uint32_t) (phy_id_high << 16);
- udelay(2);
+ udelay(20);
if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
DEBUGOUT("PHY Read Error\n");
return -E1000_ERR_PHY;
@@ -2121,11 +2370,17 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
case e1000_82546:
if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
break;
+ case e1000_82541:
+ case e1000_82547:
+ if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+ break;
default:
DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
}
- if(match) {
+ phy_init_status = e1000_set_phy_type(hw);
+
+ if ((match) && (phy_init_status == E1000_SUCCESS)) {
DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
return 0;
}
@@ -2143,7 +2398,7 @@ 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, 0x001d) < 0) break;
if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
@@ -2156,6 +2411,133 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
}
/******************************************************************************
+* Get PHY information from various PHY registers for igp PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+{
+ uint16_t phy_data, polarity, min_length, max_length, average;
+
+ DEBUGFUNC("e1000_phy_igp_get_info");
+
+ /* The downshift status is checked only once, after link is established,
+ * and it stored in the hw->speed_downgraded parameter. */
+ phy_info->downshift = hw->speed_downgraded;
+
+ /* IGP01E1000 does not need to support it. */
+ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
+
+ /* IGP01E1000 always correct polarity reversal */
+ phy_info->polarity_correction = e1000_polarity_reversal_enabled;
+
+ /* Check polarity status */
+ if(e1000_check_polarity(hw, &polarity) < 0)
+ return -E1000_ERR_PHY;
+
+ phy_info->cable_polarity = polarity;
+
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+ IGP01E1000_PSSR_MDIX_SHIFT;
+
+ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+ if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ 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;
+
+ /* Get cable length */
+ if(e1000_get_cable_length(hw, &min_length, &max_length) < 0)
+ return -E1000_ERR_PHY;
+
+ /* transalte to old method */
+ average = (max_length + min_length) / 2;
+
+ if(average <= e1000_igp_cable_length_50)
+ phy_info->cable_length = e1000_cable_length_50;
+ else if(average <= e1000_igp_cable_length_80)
+ phy_info->cable_length = e1000_cable_length_50_80;
+ else if(average <= e1000_igp_cable_length_110)
+ phy_info->cable_length = e1000_cable_length_80_110;
+ else if(average <= e1000_igp_cable_length_140)
+ phy_info->cable_length = e1000_cable_length_110_140;
+ else
+ phy_info->cable_length = e1000_cable_length_140;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers fot m88 PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+{
+ uint16_t phy_data, polarity;
+
+ DEBUGFUNC("e1000_phy_m88_get_info");
+
+ /* The downshift status is checked only once, after link is established,
+ * and it stored in the hw->speed_downgraded parameter. */
+ phy_info->downshift = hw->speed_downgraded;
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ 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;
+
+ /* Check polarity status */
+ if(e1000_check_polarity(hw, &polarity) < 0)
+ return -E1000_ERR_PHY;
+
+ phy_info->cable_polarity = polarity;
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ 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)
+ return -E1000_ERR_PHY;
+
+ 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;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Get PHY information from various PHY registers
*
* hw - Struct containing variables accessed by shared code
@@ -2165,7 +2547,6 @@ 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");
@@ -2173,6 +2554,7 @@ e1000_phy_get_info(struct e1000_hw *hw,
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->downshift = e1000_downshift_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;
@@ -2183,47 +2565,23 @@ e1000_phy_get_info(struct e1000_hw *hw,
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(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) != MII_SR_LINK_STATUS) {
+ DEBUGOUT("PHY info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
- if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
- return ret_val;
+ if (hw->phy_type == e1000_phy_igp)
+ return e1000_phy_igp_get_info(hw, phy_info);
+ else
+ return e1000_phy_m88_get_info(hw, phy_info);
}
int32_t
@@ -2239,6 +2597,109 @@ e1000_validate_mdi_setting(struct e1000_hw *hw)
return 0;
}
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct. Must be called after mac_type
+ * is configured.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_init_eeprom_params(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+ uint16_t eeprom_size;
+
+ DEBUGFUNC("e1000_init_eeprom_params");
+
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+ case e1000_82544:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->word_size = 64;
+ eeprom->opcode_bits = 3;
+ eeprom->address_bits = 6;
+ eeprom->delay_usec = 50;
+ break;
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82546:
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if(eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ break;
+ case e1000_82541:
+ case e1000_82547:
+ default:
+ if (eecd & E1000_EECD_TYPE) {
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ } else {
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ }
+ break;
+ }
+
+ if (eeprom->type == e1000_eeprom_spi) {
+ eeprom->word_size = 64;
+ if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) {
+ eeprom_size &= EEPROM_SIZE_MASK;
+
+ switch (eeprom_size) {
+ case EEPROM_SIZE_16KB:
+ eeprom->word_size = 8192;
+ break;
+ case EEPROM_SIZE_8KB:
+ eeprom->word_size = 4096;
+ break;
+ case EEPROM_SIZE_4KB:
+ eeprom->word_size = 2048;
+ break;
+ case EEPROM_SIZE_2KB:
+ eeprom->word_size = 1024;
+ break;
+ case EEPROM_SIZE_1KB:
+ eeprom->word_size = 512;
+ break;
+ case EEPROM_SIZE_512B:
+ eeprom->word_size = 256;
+ break;
+ case EEPROM_SIZE_128B:
+ default:
+ eeprom->word_size = 64;
+ break;
+ }
+ }
+ }
+}
+
/******************************************************************************
* Raises the EEPROM's clock input.
*
@@ -2255,26 +2716,26 @@ e1000_raise_ee_clk(struct e1000_hw *hw,
*eecd = *eecd | E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, *eecd);
E1000_WRITE_FLUSH(hw);
- udelay(50);
+ udelay(hw->eeprom.delay_usec);
}
/******************************************************************************
* Lowers the EEPROM's clock input.
*
- * hw - Struct containing variables accessed by shared code
+ * 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.
+ /* 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);
E1000_WRITE_FLUSH(hw);
- udelay(50);
+ udelay(hw->eeprom.delay_usec);
}
/******************************************************************************
@@ -2289,16 +2750,21 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw,
uint16_t data,
uint16_t count)
{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
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.
+ * 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);
+ if (eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~E1000_EECD_DO;
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_DO;
+ }
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
@@ -2313,7 +2779,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw,
E1000_WRITE_REG(hw, EECD, eecd);
E1000_WRITE_FLUSH(hw);
- udelay(50);
+ udelay(eeprom->delay_usec);
e1000_raise_ee_clk(hw, &eecd);
e1000_lower_ee_clk(hw, &eecd);
@@ -2333,7 +2799,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw,
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw)
+e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
{
uint32_t eecd;
uint32_t i;
@@ -2351,7 +2817,7 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
data = 0;
- for(i = 0; i < 16; i++) {
+ for(i = 0; i < count; i++) {
data = data << 1;
e1000_raise_ee_clk(hw, &eecd);
@@ -2372,104 +2838,196 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * 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)
+static int32_t
+e1000_acquire_eeprom(struct e1000_hw *hw)
{
- uint32_t eecd;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd, i=0;
+
+ DEBUGFUNC("e1000_acquire_eeprom");
eecd = E1000_READ_REG(hw, EECD);
- /* Clear SK and DI */
- eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
- E1000_WRITE_REG(hw, EECD, eecd);
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(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;
+ }
+ }
- /* Set CS */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
+ /* Setup EEPROM for Read/Write */
+
+ if (eeprom->type == e1000_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(1);
+ }
+
+ return E1000_SUCCESS;
}
/******************************************************************************
* Returns EEPROM to a "standby" state
- *
+ *
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
static void
e1000_standby_eeprom(struct e1000_hw *hw)
{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
uint32_t eecd;
eecd = E1000_READ_REG(hw, EECD);
- /* Deselct EEPROM */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ if(eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
- /* Clock high */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
- /* Select EEPROM */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
- /* Clock low */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ } else if(eeprom->type == e1000_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ }
}
/******************************************************************************
- * Raises then lowers the EEPROM's clock pin
+ * Terminates a command by inverting the EEPROM's chip select pin
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
static void
-e1000_clock_eeprom(struct e1000_hw *hw)
+e1000_release_eeprom(struct e1000_hw *hw)
{
uint32_t eecd;
+ DEBUGFUNC("e1000_release_eeprom");
+
eecd = E1000_READ_REG(hw, EECD);
- /* Rising edge of clock */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ if (hw->eeprom.type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
- /* Falling edge of clock */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(50);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ udelay(hw->eeprom.delay_usec);
+ } else if(hw->eeprom.type == e1000_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+ }
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > e1000_82544) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
}
/******************************************************************************
- * Terminates a command by lowering the EEPROM's chip select pin
+ * Reads a 16 bit word from the EEPROM.
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-static void
-e1000_cleanup_eeprom(struct e1000_hw *hw)
+int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
{
- uint32_t eecd;
+ uint16_t retry_count = 0;
+ uint8_t spi_stat_reg;
- eecd = E1000_READ_REG(hw, EECD);
+ DEBUGFUNC("e1000_spi_eeprom_ready");
+
+ /* Read "Status Register" repeatedly until the LSB is cleared. The
+ * EEPROM will signal that the command has been completed by clearing
+ * bit 0 of the internal status register. If it's not cleared within
+ * 5 milliseconds, then error out.
+ */
+ retry_count = 0;
+ do {
+ e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+ hw->eeprom.opcode_bits);
+ spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+ if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+ break;
- eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+ udelay(5);
+ retry_count += 5;
- E1000_WRITE_REG(hw, EECD, eecd);
+ } while(retry_count < EEPROM_MAX_RETRY_SPI);
- e1000_clock_eeprom(hw);
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+ if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
}
/******************************************************************************
@@ -2477,71 +3035,76 @@ e1000_cleanup_eeprom(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
* offset - offset of word in the EEPROM to read
- * data - word read from the EEPROM
+ * data - word read from the EEPROM
+ * words - number of words to read
*****************************************************************************/
int32_t
e1000_read_eeprom(struct e1000_hw *hw,
uint16_t offset,
+ uint16_t words,
uint16_t *data)
{
- uint32_t eecd;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
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++;
- udelay(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;
- }
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+ if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
}
- /* Prepare the EEPROM for reading */
- e1000_setup_eeprom(hw);
+ /* Prepare the EEPROM for reading */
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
- /* 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);
- }
+ if(eeprom->type == e1000_eeprom_spi) {
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
- /* Read the data */
- *data = e1000_shift_in_ee_bits(hw);
+ if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
- /* End this read operation */
- e1000_standby_eeprom(hw);
+ 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);
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ if((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+ }
+ else if(eeprom->type == e1000_eeprom_microwire) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, offset, eeprom->address_bits);
}
+ /* Read the data. The address of the eeprom internally increments with
+ * each word (microwire) or byte (spi) being read, saving on the overhead
+ * of eeprom setup and tear-down. The address counter will roll over if
+ * reading beyond the size of the eeprom, thus allowing the entire memory
+ * to be read starting from any offset. */
+ for (i = 0; i < words; i++) {
+ uint16_t word_in = e1000_shift_in_ee_bits(hw, 16);
+ if (eeprom->type == e1000_eeprom_spi)
+ word_in = (word_in >> 8) | (word_in << 8);
+ data[i] = word_in;
+ }
+
+ /* End this read operation */
+ e1000_release_eeprom(hw);
+
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.
@@ -2557,7 +3120,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
DEBUGFUNC("e1000_validate_eeprom_checksum");
for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
- if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+ if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -2567,7 +3130,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
if(checksum == (uint16_t) EEPROM_SUM) {
return 0;
} else {
- DEBUGOUT("EEPROM Checksum Invalid\n");
+ DEBUGOUT("EEPROM Checksum Invalid\n");
return -E1000_ERR_EEPROM;
}
}
@@ -2589,14 +3152,14 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw)
DEBUGFUNC("e1000_update_eeprom_checksum");
for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
- if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+ if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
checksum += eeprom_data;
}
checksum = (uint16_t) EEPROM_SUM - checksum;
- if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+ if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
DEBUGOUT("EEPROM Write Error\n");
return -E1000_ERR_EEPROM;
}
@@ -2604,118 +3167,201 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw)
}
/******************************************************************************
- * Writes a 16 bit word to a given offset in the EEPROM.
+ * Parent function for writing words to the different EEPROM types.
*
* hw - Struct containing variables accessed by shared code
* offset - offset within the EEPROM to be written to
- * data - 16 bit word to be writen to the EEPROM
+ * words - number of words to write
+ * data - 16 bit word to be written to the EEPROM
*
- * If e1000_update_eeprom_checksum is not called after this function, the
+ * If e1000_update_eeprom_checksum is not called after this function, the
* EEPROM will most likely contain an invalid checksum.
*****************************************************************************/
int32_t
e1000_write_eeprom(struct e1000_hw *hw,
uint16_t offset,
- uint16_t data)
+ uint16_t words,
+ uint16_t *data)
{
- uint32_t eecd;
- uint32_t i = 0;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
int32_t status = 0;
- boolean_t large_eeprom = FALSE;
DEBUGFUNC("e1000_write_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++;
- udelay(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;
- }
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+ if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
}
/* Prepare the EEPROM for writing */
- e1000_setup_eeprom(hw);
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
- /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
- * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
- * into write/erase mode.
- */
- e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
- if(large_eeprom)
- e1000_shift_out_ee_bits(hw, 0, 6);
+ if(eeprom->type == e1000_eeprom_microwire)
+ status = e1000_write_eeprom_microwire(hw, offset, words, data);
else
- e1000_shift_out_ee_bits(hw, 0, 4);
+ status = e1000_write_eeprom_spi(hw, offset, words, data);
- /* Prepare the EEPROM */
- e1000_standby_eeprom(hw);
+ /* Done with writing */
+ e1000_release_eeprom(hw);
- /* Send the Write command (3-bit opcode + addr) */
- e1000_shift_out_ee_bits(hw, EEPROM_WRITE_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);
+ return status;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in an SPI EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_spi(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint16_t widx = 0;
- /* Send the data */
- e1000_shift_out_ee_bits(hw, data, 16);
+ DEBUGFUNC("e1000_write_eeprom_spi");
- /* Toggle the CS line. This in effect tells to EEPROM to actually execute
- * the command in question.
- */
- e1000_standby_eeprom(hw);
+ while (widx < words) {
+ uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
- /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will
- * signal that the command has been completed by raising the DO signal.
- * If DO does not go high in 10 milliseconds, then error out.
- */
- for(i = 0; i < 200; i++) {
- eecd = E1000_READ_REG(hw, EECD);
- if(eecd & E1000_EECD_DO) break;
- udelay(50);
- }
- if(i == 200) {
- DEBUGOUT("EEPROM Write did not complete\n");
- status = -E1000_ERR_EEPROM;
+ if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+ e1000_standby_eeprom(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode ) */
+ e1000_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
+ eeprom->opcode_bits);
+
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ if((eeprom->address_bits == 8) && (offset >= 128))
+ write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ e1000_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
+
+ e1000_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2),
+ eeprom->address_bits);
+
+ /* Send the data */
+
+ /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+ while (widx < words) {
+ uint16_t word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ e1000_shift_out_ee_bits(hw, word_out, 16);
+ widx++;
+
+ /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
+ * operation, while the smaller eeproms are capable of an 8-byte
+ * PAGE WRITE operation. Break the inner loop to pass new address
+ */
+ if((((offset + widx)*2) % eeprom->page_size) == 0) {
+ e1000_standby_eeprom(hw);
+ break;
+ }
+ }
}
- /* Recover from write */
- e1000_standby_eeprom(hw);
+ return E1000_SUCCESS;
+}
- /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
- * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
- * out of write/erase mode.
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in a Microwire EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_microwire(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+ uint16_t words_written = 0;
+ uint16_t i = 0;
+
+ DEBUGFUNC("e1000_write_eeprom_microwire");
+
+ /* Send the write enable command to the EEPROM (3-bit opcode plus
+ * 6/8-bit dummy address beginning with 11). It's less work to include
+ * the 11 of the dummy address as part of the opcode than it is to shift
+ * it over the correct number of bits for the address. This puts the
+ * EEPROM into write/erase mode.
*/
- e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
- if(large_eeprom)
- e1000_shift_out_ee_bits(hw, 0, 6);
- else
- e1000_shift_out_ee_bits(hw, 0, 4);
+ e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
+ (uint16_t)(eeprom->opcode_bits + 2));
- /* Done with writing */
- e1000_cleanup_eeprom(hw);
+ e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
- /* 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);
+ /* Prepare the EEPROM */
+ e1000_standby_eeprom(hw);
+
+ while (words_written < words) {
+ /* Send the Write command (3-bit opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset + words_written),
+ eeprom->address_bits);
+
+ /* Send the data */
+ e1000_shift_out_ee_bits(hw, data[words_written], 16);
+
+ /* Toggle the CS line. This in effect tells the EEPROM to execute
+ * the previous command.
+ */
+ e1000_standby_eeprom(hw);
+
+ /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will
+ * signal that the command has been completed by raising the DO signal.
+ * If DO does not go high in 10 milliseconds, then error out.
+ */
+ for(i = 0; i < 200; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_DO) break;
+ udelay(50);
+ }
+ if(i == 200) {
+ DEBUGOUT("EEPROM Write did not complete\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Recover from write */
+ e1000_standby_eeprom(hw);
+
+ words_written++;
}
- return status;
+ /* Send the write disable command to the EEPROM (3-bit opcode plus
+ * 6/8-bit dummy address beginning with 10). It's less work to include
+ * the 10 of the dummy address as part of the opcode than it is to shift
+ * it over the correct number of bits for the address. This takes the
+ * EEPROM out of write/erase mode.
+ */
+ e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
+ (uint16_t)(eeprom->opcode_bits + 2));
+
+ e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+ return 0;
}
/******************************************************************************
@@ -2734,7 +3380,7 @@ e1000_read_part_num(struct e1000_hw *hw,
DEBUGFUNC("e1000_read_part_num");
/* Get word 0 from EEPROM */
- if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -2742,7 +3388,7 @@ e1000_read_part_num(struct e1000_hw *hw,
*part_num = (uint32_t) (eeprom_data << 16);
/* Get word 1 from EEPROM */
- if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+ if(e1000_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -2768,7 +3414,7 @@ e1000_read_mac_addr(struct e1000_hw * hw)
for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
offset = i >> 1;
- if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -2790,7 +3436,7 @@ e1000_read_mac_addr(struct e1000_hw * hw)
/******************************************************************************
* Initializes receive address filters.
*
- * hw - Struct containing variables accessed by shared code
+ * 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
@@ -2835,7 +3481,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
*
* 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
+ * for the first 15 multicast addresses, and hashes the rest into the
* multicast table.
*****************************************************************************/
void
@@ -2884,7 +3530,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
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
+ * else put it in the MTA
*/
if(rar_used_count < E1000_RAR_ENTRIES) {
e1000_rar_set(hw,
@@ -2902,7 +3548,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
* 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
+ * mc_addr - the multicast address to hash
*****************************************************************************/
uint32_t
e1000_hash_mc_addr(struct e1000_hw *hw,
@@ -2911,7 +3557,7 @@ e1000_hash_mc_addr(struct e1000_hw *hw,
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.
+ * determined by the mc_filter_type setting.
*/
switch (hw->mc_filter_type) {
/* [0] [1] [2] [3] [4] [5]
@@ -2954,12 +3600,12 @@ e1000_mta_set(struct e1000_hw *hw,
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
+ /* 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
+ * 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;
@@ -2997,7 +3643,7 @@ e1000_rar_set(struct e1000_hw *hw,
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
+ * from network order (big endian) to little endian
*/
rar_low = ((uint32_t) addr[0] |
((uint32_t) addr[1] << 8) |
@@ -3055,24 +3701,24 @@ e1000_id_led_init(struct e1000_hw * hw)
const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
uint16_t eeprom_data, i, temp;
const uint16_t led_mask = 0x0F;
-
+
DEBUGFUNC("e1000_id_led_init");
-
+
if(hw->mac_type < e1000_82540) {
/* Nothing to do */
return 0;
}
-
+
ledctl = E1000_READ_REG(hw, LEDCTL);
hw->ledctl_default = ledctl;
hw->ledctl_mode1 = hw->ledctl_default;
hw->ledctl_mode2 = hw->ledctl_default;
-
- if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
+
+ if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
- if((eeprom_data== ID_LED_RESERVED_0000) ||
+ if((eeprom_data== ID_LED_RESERVED_0000) ||
(eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
for(i = 0; i < 4; i++) {
temp = (eeprom_data >> (i << 2)) & led_mask;
@@ -3123,9 +3769,9 @@ 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:
@@ -3143,7 +3789,7 @@ e1000_setup_led(struct e1000_hw *hw)
hw->ledctl_default = ledctl;
/* Turn off LED0 */
ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
- E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_LED0_BLINK |
E1000_LEDCTL_LED0_MODE_MASK);
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
@@ -3155,6 +3801,9 @@ e1000_setup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EP:
+ case E1000_DEV_ID_82547EI:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
@@ -3193,6 +3842,9 @@ e1000_cleanup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EP:
+ case E1000_DEV_ID_82547EI:
/* Restore LEDCTL settings */
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
break;
@@ -3202,7 +3854,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
}
return 0;
}
-
+
/******************************************************************************
* Turns on the software controllable LED
*
@@ -3244,6 +3896,9 @@ e1000_led_on(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EP:
+ case E1000_DEV_ID_82547EI:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
break;
default:
@@ -3294,6 +3949,9 @@ e1000_led_off(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EP:
+ case E1000_DEV_ID_82547EI:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
@@ -3304,7 +3962,7 @@ e1000_led_off(struct e1000_hw *hw)
}
/******************************************************************************
- * Clears all hardware statistics counters.
+ * Clears all hardware statistics counters.
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
@@ -3423,7 +4081,7 @@ e1000_update_adaptive(struct e1000_hw *hw)
DEBUGFUNC("e1000_update_adaptive");
if(hw->adaptive_ifs) {
- if((hw->collision_delta * hw->ifs_ratio) >
+ if((hw->collision_delta * hw->ifs_ratio) >
hw->tx_packet_delta) {
if(hw->tx_packet_delta > MIN_NUM_XMITS) {
hw->in_ifs_mode = TRUE;
@@ -3436,7 +4094,7 @@ e1000_update_adaptive(struct e1000_hw *hw)
}
}
} else {
- if((hw->in_ifs_mode == TRUE) &&
+ if((hw->in_ifs_mode == TRUE) &&
(hw->tx_packet_delta <= MIN_NUM_XMITS)) {
hw->current_ifs_val = 0;
hw->in_ifs_mode = FALSE;
@@ -3450,7 +4108,7 @@ e1000_update_adaptive(struct e1000_hw *hw)
/******************************************************************************
* 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
@@ -3478,16 +4136,16 @@ e1000_tbi_adjust_stats(struct e1000_hw *hw,
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,
+ * 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
+ * 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
+ * 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))
@@ -3608,3 +4266,221 @@ e1000_write_reg_io(struct e1000_hw *hw,
e1000_io_write(hw, io_data, value);
}
+
+/******************************************************************************
+ * Estimates the cable length.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * min_length - The estimated minimum length
+ * max_length - The estimated maximum length
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * This function always returns a ranged length (minimum & maximum).
+ * So for M88 phy's, this function interprets the one value returned from the
+ * register to the minimum and maximum range.
+ * For IGP phy's, the function calculates the range by the AGC registers.
+ *****************************************************************************/
+int32_t
+e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length,
+ uint16_t *max_length)
+{
+ uint16_t agc_value = 0;
+ uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+ uint16_t i, phy_data;
+
+ DEBUGFUNC("e1000_get_cable_length");
+
+ *min_length = *max_length = 0;
+
+ /* Use old method for Phy older than IGP */
+ if(hw->phy_type == e1000_phy_m88) {
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ /* Convert the enum value to ranged values */
+ switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
+ case e1000_cable_length_50:
+ *min_length = 0;
+ *max_length = e1000_igp_cable_length_50;
+ break;
+ case e1000_cable_length_50_80:
+ *min_length = e1000_igp_cable_length_50;
+ *max_length = e1000_igp_cable_length_80;
+ break;
+ case e1000_cable_length_80_110:
+ *min_length = e1000_igp_cable_length_80;
+ *max_length = e1000_igp_cable_length_110;
+ break;
+ case e1000_cable_length_110_140:
+ *min_length = e1000_igp_cable_length_110;
+ *max_length = e1000_igp_cable_length_140;
+ break;
+ case e1000_cable_length_140:
+ *min_length = e1000_igp_cable_length_140;
+ *max_length = e1000_igp_cable_length_170;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+ } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+ uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A,
+ IGP01E1000_PHY_AGC_B,
+ IGP01E1000_PHY_AGC_C,
+ IGP01E1000_PHY_AGC_D};
+ /* Read the AGC registers for all channels */
+ for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) {
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ agc_reg_array[i]) != E1000_SUCCESS)
+ return -E1000_ERR_PHY;
+ if(e1000_read_phy_reg(hw, agc_reg_array[i] &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data) !=
+ E1000_SUCCESS)
+ return -E1000_ERR_PHY;
+
+ cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+ /* Array bound check. */
+ if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+ (cur_agc == 0))
+ return -E1000_ERR_PHY;
+
+ agc_value += cur_agc;
+
+ /* Update minimal AGC value. */
+ if(min_agc > cur_agc)
+ min_agc = cur_agc;
+ }
+
+ /* Return to page 0 */
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+ E1000_SUCCESS)
+ return -E1000_ERR_PHY;
+
+ /* Remove the minimal AGC result for length < 50m */
+ if(agc_value < IGP01E1000_PHY_AGC_NUM * e1000_igp_cable_length_50) {
+ agc_value -= min_agc;
+
+ /* Get the average length of the remaining 3 channels */
+ agc_value /= (IGP01E1000_PHY_AGC_NUM - 1);
+ } else {
+ /* Get the average length of all the 4 channels. */
+ agc_value /= IGP01E1000_PHY_AGC_NUM;
+ }
+
+ /* Set the range of the calculated length. */
+ *min_length = ((e1000_igp_cable_length_table[agc_value] -
+ IGP01E1000_AGC_RANGE) > 0) ?
+ (e1000_igp_cable_length_table[agc_value] -
+ IGP01E1000_AGC_RANGE) : 0;
+ *max_length = e1000_igp_cable_length_table[agc_value] +
+ IGP01E1000_AGC_RANGE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check the cable polarity
+ *
+ * hw - Struct containing variables accessed by shared code
+ * polarity - output parameter : 0 - Polarity is not reversed
+ * 1 - Polarity is reversed.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function simply reads the polarity bit in the
+ * Phy Status register. For IGP phy's, this bit is valid only if link speed is
+ * 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will
+ * return 0. If the link speed is 1000 Mbps the polarity status is in the
+ * IGP01E1000_PHY_PCS_INIT_REG.
+ *****************************************************************************/
+int32_t
+e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity)
+{
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_check_polarity");
+
+ if(hw->phy_type == e1000_phy_m88) {
+ /* return the Polarity bit in the Status register. */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+ *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+ M88E1000_PSSR_REV_POLARITY_SHIFT;
+ } else if(hw->phy_type == e1000_phy_igp) {
+ /* Read the Status register to check the speed */
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+ * find the polarity status */
+ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+ /* Read the GIG initialization PCS register (0x00B4) */
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_PCS_INIT_REG) < 0)
+ return -E1000_ERR_PHY;
+
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0)
+ return -E1000_ERR_PHY;
+
+ /* Return to page 0 */
+ if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+ E1000_SUCCESS)
+ return -E1000_ERR_PHY;
+
+ /* Check the polarity bits */
+ *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+ } else {
+ /* For 10 Mbps, read the polarity bit in the status register. (for
+ * 100 Mbps this bit is always 0) */
+ *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check if Downshift occured
+ *
+ * hw - Struct containing variables accessed by shared code
+ * downshift - output parameter : 0 - No Downshift ocured.
+ * 1 - Downshift ocured.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * Specific Status register. For IGP phy's, it reads the Downgrade bit in the
+ * Link Health register. In IGP this bit is latched high, so the driver must
+ * read it immediately after link is established.
+ *****************************************************************************/
+int32_t
+e1000_check_downshift(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_check_downshift");
+
+ if(hw->phy_type == e1000_phy_igp) {
+ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+ }
+ else if(hw->phy_type == e1000_phy_m88) {
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+ M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ }
+ return E1000_SUCCESS;
+}
+
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 812dfd140f35..3fe0febaa7e7 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -33,6 +33,7 @@
#ifndef _E1000_HW_H_
#define _E1000_HW_H_
+
#include "e1000_osdep.h"
/* Forward declarations of structures used by the shared code */
@@ -50,9 +51,18 @@ typedef enum {
e1000_82540,
e1000_82545,
e1000_82546,
+ e1000_82541,
+ e1000_82547,
e1000_num_macs
} e1000_mac_type;
+typedef enum {
+ e1000_eeprom_uninitialized = 0,
+ e1000_eeprom_spi,
+ e1000_eeprom_microwire,
+ e1000_num_eeprom_types
+} e1000_eeprom_type;
+
/* Media Types */
typedef enum {
e1000_media_type_copper = 0,
@@ -111,6 +121,27 @@ typedef enum {
} e1000_cable_length;
typedef enum {
+ e1000_igp_cable_length_10 = 10,
+ e1000_igp_cable_length_20 = 20,
+ e1000_igp_cable_length_30 = 30,
+ e1000_igp_cable_length_40 = 40,
+ e1000_igp_cable_length_50 = 50,
+ e1000_igp_cable_length_60 = 60,
+ e1000_igp_cable_length_70 = 70,
+ e1000_igp_cable_length_80 = 80,
+ e1000_igp_cable_length_90 = 90,
+ e1000_igp_cable_length_100 = 100,
+ e1000_igp_cable_length_110 = 110,
+ e1000_igp_cable_length_120 = 120,
+ e1000_igp_cable_length_130 = 130,
+ e1000_igp_cable_length_140 = 140,
+ e1000_igp_cable_length_150 = 150,
+ e1000_igp_cable_length_160 = 160,
+ e1000_igp_cable_length_170 = 170,
+ e1000_igp_cable_length_180 = 180
+} e1000_igp_cable_length;
+
+typedef enum {
e1000_10bt_ext_dist_enable_normal = 0,
e1000_10bt_ext_dist_enable_lower,
e1000_10bt_ext_dist_enable_undefined = 0xFF
@@ -123,6 +154,12 @@ typedef enum {
} e1000_rev_polarity;
typedef enum {
+ e1000_downshift_normal = 0,
+ e1000_downshift_activated,
+ e1000_downshift_undefined = 0xFF
+} e1000_downshift;
+
+typedef enum {
e1000_polarity_reversal_enabled = 0,
e1000_polarity_reversal_disabled,
e1000_polarity_reversal_undefined = 0xFF
@@ -142,10 +179,17 @@ typedef enum {
e1000_1000t_rx_status_undefined = 0xFF
} e1000_1000t_rx_status;
+typedef enum {
+ e1000_phy_m88 = 0,
+ e1000_phy_igp,
+ e1000_phy_undefined = 0xFF
+} e1000_phy_type;
+
struct e1000_phy_info {
e1000_cable_length cable_length;
e1000_10bt_ext_dist_enable extended_10bt_distance;
e1000_rev_polarity cable_polarity;
+ e1000_downshift downshift;
e1000_polarity_reversal polarity_correction;
e1000_auto_x_mode mdix_mode;
e1000_1000t_rx_status local_rx;
@@ -157,6 +201,15 @@ struct e1000_phy_stats {
uint32_t receive_errors;
};
+struct e1000_eeprom_info {
+ e1000_eeprom_type type;
+ uint16_t word_size;
+ uint16_t opcode_bits;
+ uint16_t address_bits;
+ uint16_t delay_usec;
+ uint16_t page_size;
+};
+
/* Error Codes */
@@ -166,6 +219,7 @@ struct e1000_phy_stats {
#define E1000_ERR_CONFIG 3
#define E1000_ERR_PARAM 4
#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
/* Function prototypes */
/* Initialization */
@@ -189,13 +243,19 @@ 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_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length);
+int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity);
+int32_t e1000_check_downshift(struct e1000_hw *hw);
int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
/* EEPROM Functions */
-int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+void e1000_init_eeprom_params(struct e1000_hw *hw);
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
-int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t data);
+int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
int32_t e1000_read_mac_addr(struct e1000_hw * hw);
@@ -231,6 +291,7 @@ uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port);
uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset);
void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value);
void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+
#define E1000_READ_REG_IO(a, reg) \
e1000_read_reg_io((a), E1000_##reg)
#define E1000_WRITE_REG_IO(a, reg, val) \
@@ -253,7 +314,10 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
-#define NUM_DEV_IDS 16
+#define E1000_DEV_ID_82541EI 0x1013
+#define E1000_DEV_ID_82541EP 0x1018
+#define E1000_DEV_ID_82547EI 0x1019
+#define NUM_DEV_IDS 19
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -298,7 +362,7 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
/* This defines the bits that are set in the Interrupt Mask
* Set/Read Register. Each bit is documented below:
* o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- * o RXSEQ = Receive Sequence Error
+ * o RXSEQ = Receive Sequence Error
*/
#define POLL_IMS_ENABLE_MASK ( \
E1000_IMS_RXDMT0 | \
@@ -322,9 +386,9 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
/* The number of high/low register pairs in the RAR. The RAR (Receive Address
* Registers) holds the directed and multicast addresses that we monitor. We
* reserve one of these spots for our directed address, allowing us room for
- * E1000_RAR_ENTRIES - 1 multicast addresses.
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
*/
-#define E1000_RAR_ENTRIES 16
+#define E1000_RAR_ENTRIES 15
#define MIN_NUMBER_OF_DESCRIPTORS 8
#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -523,7 +587,7 @@ struct e1000_ffvt_entry {
/* Register Set. (82543, 82544)
*
* Registers are defined to be 32 bits and should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the
+ * These registers are physically located on the NIC, but are mapped into the
* host memory address space.
*
* RW - register is both readable and writable
@@ -537,6 +601,7 @@ struct e1000_ffvt_entry {
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_FLA 0x0001C /* Flash Access Register - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
@@ -569,6 +634,11 @@ struct e1000_ffvt_entry {
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
@@ -664,6 +734,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_EECD E1000_EECD
#define E1000_82542_EERD E1000_EERD
#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_FLA E1000_FLA
#define E1000_82542_MDIC E1000_MDIC
#define E1000_82542_FCAL E1000_FCAL
#define E1000_82542_FCAH E1000_FCAH
@@ -705,6 +776,9 @@ struct e1000_ffvt_entry {
#define E1000_82542_RADV E1000_RADV
#define E1000_82542_RSRPD E1000_RSRPD
#define E1000_82542_TXDMAC E1000_TXDMAC
+#define E1000_82542_TDFHS E1000_TDFHS
+#define E1000_82542_TDFTS E1000_TDFTS
+#define E1000_82542_TDFPC E1000_TDFPC
#define E1000_82542_TXDCTL E1000_TXDCTL
#define E1000_82542_TADV E1000_TADV
#define E1000_82542_TSPMT E1000_TSPMT
@@ -777,6 +851,8 @@ struct e1000_ffvt_entry {
#define E1000_82542_WUPL E1000_WUPL
#define E1000_82542_WUPM E1000_WUPM
#define E1000_82542_FFLT E1000_FFLT
+#define E1000_82542_TDFH 0x08010
+#define E1000_82542_TDFT 0x08018
#define E1000_82542_FFMT E1000_FFMT
#define E1000_82542_FFVT E1000_FFVT
@@ -846,12 +922,15 @@ struct e1000_hw_stats {
struct e1000_hw {
uint8_t *hw_addr;
e1000_mac_type mac_type;
+ e1000_phy_type phy_type;
+ uint32_t phy_init_script;
e1000_media_type media_type;
void *back;
e1000_fc_type fc;
e1000_bus_speed bus_speed;
e1000_bus_width bus_width;
e1000_bus_type bus_type;
+ struct e1000_eeprom_info eeprom;
uint32_t io_base;
uint32_t phy_id;
uint32_t phy_revision;
@@ -891,6 +970,7 @@ struct e1000_hw {
uint8_t mac_addr[NODE_ADDRESS_SIZE];
uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
boolean_t disable_polarity_correction;
+ boolean_t speed_downgraded;
boolean_t get_link_status;
boolean_t tbi_compatibility_en;
boolean_t tbi_compatibility_on;
@@ -967,14 +1047,20 @@ struct e1000_hw {
#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */
#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */
#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK 0x00000030
+#define E1000_EECD_FWE_MASK 0x00000030
#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+ * (0-small, 1-large) */
+#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
/* EEPROM Read */
#define E1000_EERD_START 0x00000001 /* Start Read */
@@ -984,8 +1070,15 @@ struct e1000_hw {
#define E1000_EERD_DATA_SHIFT 16
#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI 0x01
+#define EEPROM_STATUS_WEN_SPI 0x02
+#define EEPROM_STATUS_BP0_SPI 0x04
+#define EEPROM_STATUS_BP1_SPI 0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
/* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
@@ -1239,6 +1332,7 @@ struct e1000_hw {
#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_SPM 0x80000000 /* Enable SPM */
/* Wake Up Filter Control */
#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
@@ -1282,7 +1376,7 @@ struct e1000_hw {
#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
+#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
* Filtering */
#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
@@ -1302,18 +1396,40 @@ struct e1000_hw {
#define E1000_MDALIGN 4096
-/* EEPROM Commands */
-#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */
-#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */
-#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */
-#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */
-#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI 0x3 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x2 /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI 0x8 /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI 0x6 /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI 0x4 /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI 0x5 /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI 0x1 /* EEPROM write Status register */
+
+/* EEPROM Size definitions */
+#define EEPROM_SIZE_16KB 0x1800
+#define EEPROM_SIZE_8KB 0x1400
+#define EEPROM_SIZE_4KB 0x1000
+#define EEPROM_SIZE_2KB 0x0C00
+#define EEPROM_SIZE_1KB 0x0800
+#define EEPROM_SIZE_512B 0x0400
+#define EEPROM_SIZE_128B 0x0000
+#define EEPROM_SIZE_MASK 0x1C00
+
/* EEPROM Word Offsets */
#define EEPROM_COMPAT 0x0003
#define EEPROM_ID_LED_SETTINGS 0x0004
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_CFG 0x0012
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
@@ -1334,9 +1450,10 @@ struct e1000_hw {
#define ID_LED_OFF1_ON2 0x8
#define ID_LED_OFF1_OFF2 0x9
-/* Mask bits for fields in Word 0x03 of the EEPROM */
-#define EEPROM_COMPAT_SERVER 0x0400
-#define EEPROM_COMPAT_CLIENT 0x0200
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
/* Mask bits for fields in Word 0x0a of the EEPROM */
#define EEPROM_WORD0A_ILOS 0x0010
@@ -1409,7 +1526,9 @@ struct e1000_hw {
/* PBA constants */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
@@ -1438,26 +1557,26 @@ struct e1000_hw {
/* The number of bits that we need to shift right to move the "pause"
* bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
- * in the TXCW register
+ * in the TXCW register
*/
#define PAUSE_SHIFT 5
/* The number of bits that we need to shift left to move the "SWDPIO"
* bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
- * in the CTRL register
+ * in the CTRL register
*/
#define SWDPIO_SHIFT 17
/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
* bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
* Extended CTRL register.
- * in the CTRL register
+ * in the CTRL register
*/
#define SWDPIO__EXT_SHIFT 4
/* The number of bits that we need to shift left to move the "ILOS"
* bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
- * in the CTRL register
+ * in the CTRL register
*/
#define ILOS_SHIFT 3
@@ -1475,7 +1594,7 @@ struct e1000_hw {
/* TBI_ACCEPT macro definition:
*
* This macro requires:
- * adapter = a pointer to struct e1000_hw
+ * 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
@@ -1484,7 +1603,7 @@ struct e1000_hw {
* max_frame_length = the maximum frame length we want to accept.
* min_frame_length = the minimum frame length we want to accept.
*
- * This macro is a conditional that should be used in the interrupt
+ * This macro is a conditional that should be used in the interrupt
* handler's Rx processing routine when RxErrors have been detected.
*
* Typical use:
@@ -1547,6 +1666,29 @@ struct e1000_hw {
#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A 0x1172
+#define IGP01E1000_PHY_AGC_B 0x1272
+#define IGP01E1000_PHY_AGC_C 0x1472
+#define IGP01E1000_PHY_AGC_D 0x1872
+
+/* Number of AGC registers */
+#define IGP01E1000_PHY_AGC_NUM 4
+
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+
+
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
/* PHY Control Register */
@@ -1608,7 +1750,7 @@ struct e1000_hw {
#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 */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
/* Next Page TX Register */
#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
@@ -1619,7 +1761,7 @@ struct e1000_hw {
* 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
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
* 0 = sending last NP
*/
@@ -1628,13 +1770,13 @@ struct e1000_hw {
#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
* of different NP
*/
-#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+#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
+ * 0 = sending last NP
*/
/* 1000BASE-T Control Register */
@@ -1681,20 +1823,20 @@ struct e1000_hw {
#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,
+#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:
+ * 100BASE-TX/10BASE-T:
* MDI Mode
*/
-#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
- * all speeds.
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
*/
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+#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 */
@@ -1712,6 +1854,7 @@ struct e1000_hw {
/* M88E1000 PHY Specific Status Register */
#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
#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 */
@@ -1725,6 +1868,7 @@ struct e1000_hw {
#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_DOWNSHIFT_SHIFT 5
#define M88E1000_PSSR_MDIX_SHIFT 6
#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
@@ -1733,12 +1877,12 @@ struct e1000_hw {
#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
+ * 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_1X 0x0000
#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
@@ -1753,10 +1897,93 @@ struct e1000_hw {
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
+#define IGP01E1000_PSCFR_PRE_EN 0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000
+
+/* IGP01E1000 Specific Port Status Register - R/O */
+#define IGP01E1000_PSSR_AUTONEG_FAILED 0x0001 /* RO LH SC */
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_CABLE_LENGTH 0x007C
+#define IGP01E1000_PSSR_FULL_DUPLEX 0x0200
+#define IGP01E1000_PSSR_LINK_UP 0x0400
+#define IGP01E1000_PSSR_MDIX 0x0800
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000 /* speed bits mask */
+#define IGP01E1000_PSSR_SPEED_10MBPS 0x4000
+#define IGP01E1000_PSSR_SPEED_100MBPS 0x8000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT 0x0002 /* shift right 2 */
+#define IGP01E1000_PSSR_MDIX_SHIFT 0x000B /* shift right 11 */
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK 0x0001
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP 0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */
+
+/* IGP01E1000 Specific Port Link Health Register */
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR 0x4000
+#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK 0x0800 /* LH */
+#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW 0x0400 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_1 0x0200 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_0 0x0100
+#define IGP01E1000_PLHR_AUTONEG_FAULT 0x0010
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE 0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_D 0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_C 0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_B 0x0001
+#define IGP01E1000_PLHR_VALID_CHANNEL_A 0x0000
+
+/* IGP01E1000 Channel Quality Register */
+#define IGP01E1000_MSE_CHANNEL_D 0x000F
+#define IGP01E1000_MSE_CHANNEL_C 0x00F0
+#define IGP01E1000_MSE_CHANNEL_B 0x0F00
+#define IGP01E1000_MSE_CHANNEL_A 0xF000
+
+/* IGP01E1000 AGC Registers */
+
+#define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */
+
+/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+
+/* The precision of the length is +/- 10 meters */
+#define IGP01E1000_AGC_RANGE 10
+
+/* IGP cable length table */
+static const
+uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+ 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
+
+/* IGP01E1000 PCS Initialization register */
+/* bits 3:6 in the PCS registers stores the channels polarity */
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed
+ * on Link-Up */
+#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */
+
/* 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 IGP01E1000_I_PHY_ID 0x02A80380
#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
#define M88E1011_I_REV_4 0x04
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 1b66efa8a2b0..10a831f3bbbd 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -30,7 +30,22 @@
/* Change Log
*
- * 4.4.19 11/27/02
+ * 5.0.43 3/5/03
+ * o Feature: Added support for 82541 and 82547 hardware.
+ * o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of
+ * eeproms.
+ * o Feature: Added support for TCP Segmentation Offload (TSO).
+ * o Feature: Added MII ioctl.
+ * o Feature: Added support for statistics reporting through ethtool.
+ * o Cleanup: Removed proprietary hooks for ANS.
+ * o Cleanup: Miscellaneous code changes to improve CPU utilization.
+ * - Replaced "%" with conditionals and "+-" operators.
+ * - Implemented dynamic Interrupt Throttle Rate (ITR).
+ * - Reduced expensive PCI reads of ICR in interrupt.
+ * o Bug fix: Request IRQ after descriptor ring setup to avoid panic in
+ * shared interrupt instances.
+ *
+ * 4.4.18 11/27/02
* o Feature: Added user-settable knob for interrupt throttle rate (ITR).
* o Cleanup: removed large static array allocations.
* o Cleanup: C99 struct initializer format.
@@ -42,25 +57,12 @@
* o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
*
* 4.4.12 10/15/02
- * o Clean up: use members of pci_device rather than direct calls to
- * pci_read_config_word.
- * o Bug fix: changed default flow control settings.
- * o Clean up: ethtool file now has an inclusive list for adapters in the
- * Wake-On-LAN capabilities instead of an exclusive list.
- * o Bug fix: miscellaneous WoL bug fixes.
- * o Added software interrupt for clearing rx ring
- * o Bug fix: easier to undo "forcing" of 1000/fd using ethtool.
- * o Now setting netdev->mem_end in e1000_probe.
- * o Clean up: Moved tx_timeout from interrupt context to process context
- * using schedule_task.
- *
- * 4.3.15 8/9/02
*/
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.4.19-k3";
-char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
+char e1000_driver_version[] = "5.0.43-k1";
+char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -104,6 +106,8 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
{0,}
};
@@ -112,7 +116,7 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
static char *e1000_strings[] = {
"Intel(R) PRO/1000 Network Connection",
- "Compaq Gigabit Ethernet Server Adapter",
+ "HP Gigabit Ethernet Server Adapter",
"IBM Mobile, Desktop & Server Adapters"
};
@@ -121,6 +125,7 @@ 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);
+int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
static int e1000_init_module(void);
static void e1000_exit_module(void);
@@ -141,6 +146,7 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter);
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
+static void e1000_82547_tx_fifo_stall(unsigned long data);
static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
@@ -149,14 +155,18 @@ static void e1000_update_stats(struct e1000_adapter *adapter);
static inline void e1000_irq_disable(struct e1000_adapter *adapter);
static inline void e1000_irq_enable(struct e1000_adapter *adapter);
static void e1000_intr(int irq, void *data, struct pt_regs *regs);
-static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
#ifdef CONFIG_E1000_NAPI
-static int e1000_poll(struct net_device *netdev, int *budget);
+static int e1000_clean(struct net_device *netdev, int *budget);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ int *work_done, int work_to_do);
#else
-static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
#endif
+static boolean_t e1000_clean_tx_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 int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+ int cmd);
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,
@@ -164,6 +174,9 @@ static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
struct sk_buff *skb);
static void e1000_tx_timeout(struct net_device *dev);
static void e1000_tx_timeout_task(struct net_device *dev);
+static void e1000_smartspeed(struct e1000_adapter *adapter);
+static inline int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
+ struct sk_buff *skb);
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);
@@ -182,6 +195,7 @@ struct notifier_block e1000_notifier_reboot = {
.priority = 0
};
+
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -249,13 +263,10 @@ e1000_up(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
- netdev->name, netdev))
- return -1;
-
/* hardware has been reset, we need to reload some things */
e1000_set_multi(netdev);
+
e1000_restore_vlan(adapter);
e1000_configure_tx(adapter);
@@ -263,6 +274,14 @@ e1000_up(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
+ if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
+ netdev->name, netdev)) {
+ e1000_reset_hw(&adapter->hw);
+ e1000_free_tx_resources(adapter);
+ e1000_free_rx_resources(adapter);
+ return -1;
+ }
+
mod_timer(&adapter->watchdog_timer, jiffies);
e1000_irq_enable(adapter);
@@ -276,6 +295,7 @@ e1000_down(struct e1000_adapter *adapter)
e1000_irq_disable(adapter);
free_irq(netdev->irq, netdev);
+ del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
adapter->link_speed = 0;
@@ -291,14 +311,28 @@ e1000_down(struct e1000_adapter *adapter)
void
e1000_reset(struct e1000_adapter *adapter)
{
+ uint32_t pba;
/* 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(&adapter->hw, PBA, E1000_JUMBO_PBA);
- else
- E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
+ if(adapter->hw.mac_type < e1000_82547) {
+ if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+ pba = E1000_PBA_40K;
+ else
+ pba = E1000_PBA_48K;
+ } else {
+ if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+ pba = E1000_PBA_22K;
+ else
+ pba = E1000_PBA_30K;
+ adapter->tx_fifo_head = 0;
+ adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
+ adapter->tx_fifo_size =
+ (E1000_PBA_40K - pba) << E1000_TX_FIFO_SIZE_SHIFT;
+ atomic_set(&adapter->tx_fifo_stall, 0);
+ }
+ E1000_WRITE_REG(&adapter->hw, PBA, pba);
adapter->hw.fc = adapter->hw.original_fc;
e1000_reset_hw(&adapter->hw);
@@ -389,9 +423,9 @@ e1000_probe(struct pci_dev *pdev,
netdev->change_mtu = &e1000_change_mtu;
netdev->do_ioctl = &e1000_ioctl;
netdev->tx_timeout = &e1000_tx_timeout;
- netdev->watchdog_timeo = HZ;
+ netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_E1000_NAPI
- netdev->poll = &e1000_poll;
+ netdev->poll = &e1000_clean;
netdev->weight = 64;
#endif
netdev->vlan_rx_register = e1000_vlan_rx_register;
@@ -413,17 +447,18 @@ e1000_probe(struct pci_dev *pdev,
if(adapter->hw.mac_type >= e1000_82543) {
netdev->features = NETIF_F_SG |
- NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
+ 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;
}
- if(adapter->hw.mac_type >= e1000_82544)
+ if((adapter->hw.mac_type >= e1000_82544) &&
+ (adapter->hw.mac_type != e1000_82547))
netdev->features |= NETIF_F_TSO;
-
+
if(pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -446,13 +481,9 @@ e1000_probe(struct pci_dev *pdev,
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->tx_fifo_stall_timer);
+ adapter->tx_fifo_stall_timer.function = &e1000_82547_tx_fifo_stall;
+ adapter->tx_fifo_stall_timer.data = (unsigned long) adapter;
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &e1000_watchdog;
@@ -482,11 +513,12 @@ e1000_probe(struct pci_dev *pdev,
* enable the ACPI Magic Packet filter
*/
- e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data);
+ e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG,1, &eeprom_data);
if((adapter->hw.mac_type >= e1000_82544) &&
(eeprom_data & E1000_EEPROM_APME))
adapter->wol |= E1000_WUFC_MAG;
+
/* reset the hardware with the new settings */
e1000_reset(adapter);
@@ -533,6 +565,7 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);
+
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
@@ -568,7 +601,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
hw->max_frame_size = netdev->mtu +
- ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
/* identify the MAC */
@@ -578,6 +611,10 @@ e1000_sw_init(struct e1000_adapter *adapter)
return -1;
}
+ /* initialize eeprom parameters */
+
+ e1000_init_eeprom_params(hw);
+
/* flow control settings */
hw->fc_high_water = E1000_FC_HIGH_THRESH;
@@ -585,6 +622,9 @@ e1000_sw_init(struct e1000_adapter *adapter)
hw->fc_pause_time = E1000_FC_PAUSE_TIME;
hw->fc_send_xon = 1;
+ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547))
+ hw->phy_init_script = 1;
+
/* Media type - copper or fiber */
if(hw->mac_type >= e1000_82543) {
@@ -782,7 +822,7 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tctl &= ~E1000_TCTL_CT;
tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
- (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
@@ -852,8 +892,8 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
- (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ 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;
@@ -907,12 +947,9 @@ e1000_configure_rx(struct e1000_adapter *adapter)
if(adapter->hw.mac_type >= e1000_82540) {
E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
-
- /* 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);
+ if(adapter->itr > 1)
+ E1000_WRITE_REG(&adapter->hw, ITR,
+ 1000000000 / (adapter->itr * 256));
}
/* Setup the Base and Length of the Rx Descriptor Ring */
@@ -1184,9 +1221,9 @@ e1000_set_multi(struct net_device *netdev)
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
+ /* load the first 14 multicast address into the exact filters 1-14
* RAR 0 is used for the station MAC adddress
- * if there are not 15 addresses, go ahead and clear the filters
+ * if there are not 14 addresses, go ahead and clear the filters
*/
mc_ptr = netdev->mc_list;
@@ -1216,6 +1253,40 @@ e1000_set_multi(struct net_device *netdev)
e1000_leave_82542_rst(adapter);
}
+static void
+e1000_tx_flush(struct e1000_adapter *adapter)
+{
+ uint32_t ctrl, tctl, txcw, icr;
+
+ e1000_irq_disable(adapter);
+
+ if(adapter->hw.mac_type < e1000_82543) {
+ /* Transmit Unit Reset */
+ tctl = E1000_READ_REG(&adapter->hw, TCTL);
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST);
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+ e1000_clean_tx_ring(adapter);
+ e1000_configure_tx(adapter);
+ } else {
+ txcw = E1000_READ_REG(&adapter->hw, TXCW);
+ E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE);
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU |
+ E1000_CTRL_ILOS);
+
+ mdelay(10);
+
+ e1000_clean_tx_irq(adapter);
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ E1000_WRITE_REG(&adapter->hw, TXCW, txcw);
+
+ /* clear the link status change interrupts this caused */
+ icr = E1000_READ_REG(&adapter->hw, ICR);
+ }
+
+ e1000_irq_enable(adapter);
+}
/* need to wait a few seconds after link up to get diagnostic information from the phy */
@@ -1227,6 +1298,48 @@ e1000_update_phy_info(unsigned long data)
}
/**
+ * e1000_82547_tx_fifo_stall - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+
+static void
+e1000_82547_tx_fifo_stall(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ struct net_device *netdev = adapter->netdev;
+ uint32_t tctl;
+
+ if(atomic_read(&adapter->tx_fifo_stall)) {
+ if((E1000_READ_REG(&adapter->hw, TDT) ==
+ E1000_READ_REG(&adapter->hw, TDH)) &&
+ (E1000_READ_REG(&adapter->hw, TDFT) ==
+ E1000_READ_REG(&adapter->hw, TDFH)) &&
+ (E1000_READ_REG(&adapter->hw, TDFTS) ==
+ E1000_READ_REG(&adapter->hw, TDFHS))) {
+ tctl = E1000_READ_REG(&adapter->hw, TCTL);
+ E1000_WRITE_REG(&adapter->hw, TCTL,
+ tctl & ~E1000_TCTL_EN);
+ E1000_WRITE_REG(&adapter->hw, TDFT,
+ adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFH,
+ adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFTS,
+ adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFHS,
+ adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ adapter->tx_fifo_head = 0;
+ atomic_set(&adapter->tx_fifo_stall, 0);
+ netif_wake_queue(netdev);
+ } else {
+ mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
+ }
+ }
+}
+
+/**
* e1000_watchdog - Timer Call-back
* @data: pointer to netdev cast into an unsigned long
**/
@@ -1256,6 +1369,7 @@ e1000_watchdog(unsigned long data)
netif_carrier_on(netdev);
netif_wake_queue(netdev);
mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+ adapter->smartspeed = 0;
}
} else {
if(netif_carrier_ok(netdev)) {
@@ -1268,11 +1382,34 @@ e1000_watchdog(unsigned long data)
netif_stop_queue(netdev);
mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
}
+
+ e1000_smartspeed(adapter);
}
e1000_update_stats(adapter);
e1000_update_adaptive(&adapter->hw);
+ if(!netif_carrier_ok(netdev)) {
+ if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
+ unsigned long flags;
+ spin_lock_irqsave(&netdev->xmit_lock, flags);
+ e1000_tx_flush(adapter);
+ spin_unlock_irqrestore(&netdev->xmit_lock, flags);
+ }
+ }
+
+ /* Dynamic mode for Interrupt Throttle Rate (ITR) */
+ if(adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) {
+ /* Symmetric Tx/Rx gets a reduced ITR=2000; Total
+ * asymmetrical Tx or Rx gets ITR=8000; everyone
+ * else is between 2000-8000. */
+ uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000;
+ uint32_t dif = (adapter->gotcl > adapter->gorcl ?
+ adapter->gotcl - adapter->gorcl :
+ adapter->gorcl - adapter->gotcl) / 10000;
+ uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
+ E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (itr * 256));
+ }
/* Cause software interrupt to ensure rx ring is cleaned */
E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
@@ -1301,7 +1438,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
int i;
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
uint16_t ipcse, tucse, mss;
-
+
if(skb_shinfo(skb)->tso_size) {
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
mss = skb_shinfo(skb)->tso_size;
@@ -1321,7 +1458,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
i = adapter->tx_ring.next_to_use;
context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
-
+
context_desc->lower_setup.ip_fields.ipcss = ipcss;
context_desc->lower_setup.ip_fields.ipcso = ipcso;
context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
@@ -1335,12 +1472,12 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
(skb->len - (hdr_len)));
- i = (i + 1) % adapter->tx_ring.count;
+ if(++i == adapter->tx_ring.count) i = 0;
adapter->tx_ring.next_to_use = i;
return TRUE;
}
-
+
return FALSE;
}
@@ -1365,7 +1502,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->cmd_and_length =
cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
- i = (i + 1) % adapter->tx_ring.count;
+ if(++i == adapter->tx_ring.count) i = 0;
adapter->tx_ring.next_to_use = i;
return TRUE;
@@ -1374,24 +1511,24 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
return FALSE;
}
+#define E1000_MAX_TXD_PWR 12
+#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
+
static inline int
e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
- int len, offset, size, count, i;
+ int len = skb->len, offset = 0, size, count = 0, i;
+
int tso = skb_shinfo(skb)->tso_size;
int nr_frags = skb_shinfo(skb)->nr_frags;
-
int f;
- len = skb->len - skb->data_len;
- i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
- count = 0;
+ len -= skb->data_len;
- offset = 0;
+ i = tx_ring->next_to_use;
while(len) {
- i = (i + 1) % tx_ring->count;
- size = min(len, adapter->max_data_per_txd);
+ size = min(len, E1000_MAX_DATA_PER_TXD);
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if(tso && !nr_frags && size == len && size > 4)
@@ -1407,6 +1544,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
len -= size;
offset += size;
count++;
+ if(++i == tx_ring->count) i = 0;
}
for(f = 0; f < nr_frags; f++) {
@@ -1417,8 +1555,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
offset = 0;
while(len) {
- i = (i + 1) % tx_ring->count;
- size = min(len, adapter->max_data_per_txd);
+ size = min(len, E1000_MAX_DATA_PER_TXD);
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if(tso && f == (nr_frags-1) && size == len && size > 4)
@@ -1435,8 +1572,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
len -= size;
offset += size;
count++;
+ if(++i == tx_ring->count) i = 0;
}
}
+ if(--i < 0) i = tx_ring->count - 1;
tx_ring->buffer_info[i].skb = skb;
return count;
@@ -1477,7 +1616,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
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;
+ if(++i == tx_ring->count) i = 0;
}
tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
@@ -1492,34 +1631,74 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
E1000_WRITE_REG(&adapter->hw, TDT, i);
}
-#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
+/**
+ * 82547 workaround to avoid controller hang in half-duplex environment.
+ * The workaround is to avoid queuing a large packet that would span
+ * the internal Tx FIFO ring boundary by notifying the stack to resend
+ * the packet at a later time. This gives the Tx FIFO an opportunity to
+ * flush all packets. When that occurs, we reset the Tx FIFO pointers
+ * to the beginning of the Tx FIFO.
+ **/
+
+#define E1000_FIFO_HDR 0x10
+#define E1000_82547_PAD_LEN 0x3E0
+
+static inline int
+e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+ uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
+ uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
+
+ E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+
+ if(adapter->link_duplex != HALF_DUPLEX)
+ goto no_fifo_stall_required;
+
+ if(atomic_read(&adapter->tx_fifo_stall))
+ return 1;
+
+ if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) {
+ atomic_set(&adapter->tx_fifo_stall, 1);
+ return 1;
+ }
+
+no_fifo_stall_required:
+ adapter->tx_fifo_head += skb_fifo_len;
+ if(adapter->tx_fifo_head >= adapter->tx_fifo_size)
+ adapter->tx_fifo_head -= adapter->tx_fifo_size;
+ return 0;
+}
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> E1000_MAX_TXD_PWR) + \
+ (((S) & (E1000_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED TXD_USE_COUNT(MAX_JUMBO_FRAME_SIZE) + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1
static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
- int tx_flags = 0, count;
- int f;
-
- count = TXD_USE_COUNT(skb->len - skb->data_len,
- adapter->max_data_per_txd);
+ int tx_flags = 0;
- if(count == 0) {
+ if(skb->len <= 0) {
dev_kfree_skb_any(skb);
return 0;
}
- 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_shinfo(skb)->tso_size) || (skb->ip_summed == CHECKSUM_HW))
- count++;
-
- if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+ if(E1000_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED) {
netif_stop_queue(netdev);
return 1;
}
+ if(adapter->hw.mac_type == e1000_82547) {
+ if(e1000_82547_fifo_workaround(adapter, skb)) {
+ netif_stop_queue(netdev);
+ mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
+ return 1;
+ }
+ }
+
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);
@@ -1530,9 +1709,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
else if(e1000_tx_csum(adapter, skb))
tx_flags |= E1000_TX_FLAGS_CSUM;
- count = e1000_tx_map(adapter, skb);
-
- e1000_tx_queue(adapter, count, tx_flags);
+ e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags);
netdev->trans_start = jiffies;
@@ -1653,7 +1830,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
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->gorcl = E1000_READ_REG(hw, GORCL);
+ adapter->stats.gorcl += adapter->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);
@@ -1684,7 +1862,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
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->gotcl = E1000_READ_REG(hw, GOTCL);
+ adapter->stats.gotcl += adapter->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);
@@ -1807,60 +1986,57 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev->priv;
-
-#ifdef CONFIG_E1000_NAPI
- if (netif_rx_schedule_prep(netdev)) {
- /* Disable interrupts and enable polling */
- atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(&adapter->hw, IMC, ~0);
- E1000_WRITE_FLUSH(&adapter->hw);
- __netif_rx_schedule(netdev);
- }
-#else
- uint32_t icr;
- int i = E1000_MAX_INTR;
+ uint32_t icr = E1000_READ_REG(&adapter->hw, ICR);
+#ifndef CONFIG_E1000_NAPI
+ int i;
+#endif
- while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
-
- if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- adapter->hw.get_link_status = 1;
- mod_timer(&adapter->watchdog_timer, jiffies);
- }
-
- e1000_clean_rx_irq(adapter);
- e1000_clean_tx_irq(adapter);
- i--;
+ if(!icr)
+ return; /* Not our interrupt */
+ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ adapter->hw.get_link_status = 1;
+ mod_timer(&adapter->watchdog_timer, jiffies);
}
+
+#ifdef CONFIG_E1000_NAPI
+ /* Don't disable interrupts - rely on h/w interrupt
+ * moderation to keep interrupts low. netif_rx_schedule
+ * is NOP if already polling. */
+ netif_rx_schedule(netdev);
+#else
+ for(i = 0; i < E1000_MAX_INTR; i++)
+ if(!e1000_clean_rx_irq(adapter) &&
+ !e1000_clean_tx_irq(adapter))
+ break;
#endif
}
#ifdef CONFIG_E1000_NAPI
+/**
+ * e1000_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+
static int
-e1000_process_intr(struct net_device *netdev)
+e1000_clean(struct net_device *netdev, int *budget)
{
struct e1000_adapter *adapter = netdev->priv;
- uint32_t icr;
- int i = E1000_MAX_INTR;
- int hasReceived = 0;
-
- while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
- if (icr & E1000_ICR_RXT0)
- hasReceived = 1;
-
- if (!(icr & ~(E1000_ICR_RXT0)))
+ int work_to_do = min(*budget, netdev->quota);
+ int work_done = 0;
+
+ while(work_done < work_to_do)
+ if(!e1000_clean_rx_irq(adapter, &work_done, work_to_do) &&
+ !e1000_clean_tx_irq(adapter))
break;
-
- if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- adapter->hw.get_link_status = 1;
- mod_timer(&adapter->watchdog_timer, jiffies);
- }
-
- e1000_clean_tx_irq(adapter);
- i--;
- }
- return hasReceived;
+ *budget -= work_done;
+ netdev->quota -= work_done;
+
+ if(work_done < work_to_do)
+ netif_rx_complete(netdev);
+
+ return (work_done >= work_to_do);
}
#endif
@@ -1869,20 +2045,22 @@ e1000_process_intr(struct net_device *netdev)
* @adapter: board private structure
**/
-static void
+static boolean_t
e1000_clean_tx_irq(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_tx_desc *tx_desc;
- int i;
+ int i, cleaned = FALSE;
i = tx_ring->next_to_clean;
tx_desc = E1000_TX_DESC(*tx_ring, i);
while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ cleaned = TRUE;
+
if(tx_ring->buffer_info[i].dma) {
pci_unmap_page(pdev,
@@ -1900,158 +2078,34 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->buffer_info[i].skb = NULL;
}
+ tx_desc->buffer_addr = 0;
+ tx_desc->lower.data = 0;
tx_desc->upper.data = 0;
- i = (i + 1) % tx_ring->count;
+ if(++i == tx_ring->count) i = 0;
tx_desc = E1000_TX_DESC(*tx_ring, i);
}
tx_ring->next_to_clean = i;
- if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
- (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
-
+ if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
netif_wake_queue(netdev);
- }
-}
-
-#ifdef CONFIG_E1000_NAPI
-static int
-e1000_poll(struct net_device *netdev, int *budget)
-{
- struct e1000_adapter *adapter = netdev->priv;
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
- struct pci_dev *pdev = adapter->pdev;
- struct e1000_rx_desc *rx_desc;
- struct sk_buff *skb;
- unsigned long flags;
- uint32_t length;
- uint8_t last_byte;
- int i;
- int received = 0;
- int rx_work_limit = *budget;
-
- if(rx_work_limit > netdev->quota)
- rx_work_limit = netdev->quota;
-
- e1000_process_intr(netdev);
-
- i = rx_ring->next_to_clean;
- rx_desc = E1000_RX_DESC(*rx_ring, i);
-
- while(rx_desc->status & E1000_RXD_STAT_DD) {
- if(--rx_work_limit < 0)
- goto not_done;
-
- pci_unmap_single(pdev,
- rx_ring->buffer_info[i].dma,
- rx_ring->buffer_info[i].length,
- PCI_DMA_FROMDEVICE);
-
- skb = rx_ring->buffer_info[i].skb;
- length = le16_to_cpu(rx_desc->length);
-
- if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
-
- /* All receives must fit into a single buffer */
-
- E1000_DBG("Receive packet consumed multiple buffers\n");
-
- dev_kfree_skb_irq(skb);
- rx_desc->status = 0;
- rx_ring->buffer_info[i].skb = NULL;
-
- i = (i + 1) % rx_ring->count;
-
- rx_desc = E1000_RX_DESC(*rx_ring, i);
- continue;
- }
-
- if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
-
- last_byte = *(skb->data + length - 1);
-
- 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->hw,
- &adapter->stats,
- length, skb->data);
-
- spin_unlock_irqrestore(&adapter->stats_lock,
- flags);
- length--;
- } else {
-
- dev_kfree_skb_irq(skb);
- rx_desc->status = 0;
- rx_ring->buffer_info[i].skb = NULL;
-
- i = (i + 1) % rx_ring->count;
-
- rx_desc = E1000_RX_DESC(*rx_ring, i);
- continue;
- }
- }
-
- /* Good Receive */
- skb_put(skb, length - ETHERNET_FCS_SIZE);
-
- /* Receive Checksum Offload */
- e1000_rx_checksum(adapter, rx_desc, skb);
-
- skb->protocol = eth_type_trans(skb, netdev);
- 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_receive_skb(skb);
- }
- netdev->last_rx = jiffies;
-
- rx_desc->status = 0;
- rx_ring->buffer_info[i].skb = NULL;
-
- i = (i + 1) % rx_ring->count;
-
- rx_desc = E1000_RX_DESC(*rx_ring, i);
- received++;
- }
-
- if(!received)
- received = 1;
-
- e1000_alloc_rx_buffers(adapter);
-
- rx_ring->next_to_clean = i;
- netdev->quota -= received;
- *budget -= received;
-
- netif_rx_complete(netdev);
-
- e1000_irq_enable(adapter);
- return 0;
-
-not_done:
-
- e1000_alloc_rx_buffers(adapter);
-
- rx_ring->next_to_clean = i;
- netdev->quota -= received;
- *budget -= received;
- return 1;
+ return cleaned;
}
-#else
+
/**
* e1000_clean_rx_irq - Send received data up the network stack,
* @adapter: board private structure
**/
-static void
+static boolean_t
+#ifdef CONFIG_E1000_NAPI
+e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done,
+ int work_to_do)
+#else
e1000_clean_rx_irq(struct e1000_adapter *adapter)
+#endif
{
struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
@@ -2061,13 +2115,22 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
unsigned long flags;
uint32_t length;
uint8_t last_byte;
- int i;
+ int i, cleaned = FALSE;
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
while(rx_desc->status & E1000_RXD_STAT_DD) {
+#ifdef CONFIG_E1000_NAPI
+ if(*work_done >= work_to_do)
+ break;
+
+ (*work_done)++;
+#endif
+
+ cleaned = TRUE;
+
pci_unmap_single(pdev,
rx_ring->buffer_info[i].dma,
rx_ring->buffer_info[i].length,
@@ -2086,7 +2149,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
- i = (i + 1) % rx_ring->count;
+ if(++i == rx_ring->count) i = 0;
rx_desc = E1000_RX_DESC(*rx_ring, i);
continue;
@@ -2114,7 +2177,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
- i = (i + 1) % rx_ring->count;
+ if(++i == rx_ring->count) i = 0;
rx_desc = E1000_RX_DESC(*rx_ring, i);
continue;
@@ -2128,18 +2191,28 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
e1000_rx_checksum(adapter, rx_desc, skb);
skb->protocol = eth_type_trans(skb, netdev);
+#ifdef CONFIG_E1000_NAPI
+ if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ (rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+ } else {
+ netif_receive_skb(skb);
+ }
+#else /* CONFIG_E1000_NAPI */
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);
}
+#endif /* CONFIG_E1000_NAPI */
+
netdev->last_rx = jiffies;
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
- i = (i + 1) % rx_ring->count;
+ if(++i == rx_ring->count) i = 0;
rx_desc = E1000_RX_DESC(*rx_ring, i);
}
@@ -2147,8 +2220,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_ring->next_to_clean = i;
e1000_alloc_rx_buffers(adapter);
+
+ return cleaned;
}
-#endif
/**
* e1000_alloc_rx_buffers - Replace used receive buffers
@@ -2163,11 +2237,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
struct sk_buff *skb;
- int reserve_len;
+ int reserve_len = 2;
int i;
- reserve_len = 2;
-
i = rx_ring->next_to_use;
while(!rx_ring->buffer_info[i].skb) {
@@ -2198,7 +2270,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
- if(!(i % E1000_RX_BUFFER_WRITE)) {
+ if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) {
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
@@ -2208,13 +2280,68 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
E1000_WRITE_REG(&adapter->hw, RDT, i);
}
- i = (i + 1) % rx_ring->count;
+ if(++i == rx_ring->count) i = 0;
}
rx_ring->next_to_use = i;
}
/**
+ * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
+ * @adapter:
+ **/
+
+static void
+e1000_smartspeed(struct e1000_adapter *adapter)
+{
+ uint16_t phy_status;
+ uint16_t phy_ctrl;
+
+ if((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg ||
+ !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL))
+ return;
+
+ if(adapter->smartspeed == 0) {
+ /* If Master/Slave config fault is asserted twice,
+ * we assume back-to-back */
+ e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status);
+ if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+ e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status);
+ if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+ e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl);
+ if(phy_ctrl & CR_1000T_MS_ENABLE) {
+ phy_ctrl &= ~CR_1000T_MS_ENABLE;
+ e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL,
+ phy_ctrl);
+ adapter->smartspeed++;
+ if(!e1000_phy_setup_autoneg(&adapter->hw) &&
+ !e1000_read_phy_reg(&adapter->hw, PHY_CTRL,
+ &phy_ctrl)) {
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN |
+ MII_CR_RESTART_AUTO_NEG);
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL,
+ phy_ctrl);
+ }
+ }
+ return;
+ } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) {
+ /* If still no link, perhaps using 2/3 pair cable */
+ e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl);
+ phy_ctrl |= CR_1000T_MS_ENABLE;
+ e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl);
+ if(!e1000_phy_setup_autoneg(&adapter->hw) &&
+ !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) {
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN |
+ MII_CR_RESTART_AUTO_NEG);
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl);
+ }
+ }
+ /* Restart process after E1000_SMARTSPEED_MAX iterations */
+ if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX)
+ adapter->smartspeed = 0;
+}
+
+/**
* e1000_ioctl -
* @netdev:
* @ifreq:
@@ -2225,6 +2352,10 @@ static int
e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return e1000_mii_ioctl(netdev, ifr, cmd);
case SIOCETHTOOL:
return e1000_ethtool_ioctl(netdev, ifr);
default:
@@ -2233,6 +2364,86 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
/**
+ * e1000_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+
+static int
+e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+ int retval;
+ uint16_t mii_reg;
+ uint16_t spddplx;
+
+ if(adapter->hw.media_type == e1000_media_type_fiber)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = adapter->hw.phy_addr;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out))
+ return -EIO;
+ break;
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (data->reg_num & ~(0x1F))
+ return -EFAULT;
+ mii_reg = data->val_in;
+ if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
+ data->val_in))
+ return -EIO;
+ if (adapter->hw.phy_type == e1000_phy_m88) {
+ switch (data->reg_num) {
+ case PHY_CTRL:
+ if(data->val_in & MII_CR_AUTO_NEG_EN) {
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = 0x2F;
+ } else {
+ if (data->val_in & 0x40)
+ spddplx = SPEED_1000;
+ else if (data->val_in & 0x2000)
+ spddplx = SPEED_100;
+ else
+ spddplx = SPEED_10;
+ spddplx += (data->val_in & 0x100)
+ ? FULL_DUPLEX :
+ HALF_DUPLEX;
+ retval = e1000_set_spd_dplx(adapter,
+ spddplx);
+ if(retval)
+ return retval;
+ }
+ if(netif_running(adapter->netdev)) {
+ e1000_down(adapter);
+ e1000_up(adapter);
+ } else
+ e1000_reset(adapter);
+ break;
+ case M88E1000_PHY_SPEC_CTRL:
+ case M88E1000_EXT_PHY_SPEC_CTRL:
+ if (e1000_phy_reset(&adapter->hw))
+ return -EIO;
+ break;
+ }
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return E1000_SUCCESS;
+}
+
+/**
* e1000_rx_checksum - Receive Checksum Offload for 82543
* @adapter: board private structure
* @rx_desc: receive descriptor
@@ -2402,6 +2613,35 @@ e1000_restore_vlan(struct e1000_adapter *adapter)
}
}
+int
+e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
+{
+ adapter->hw.autoneg = 0;
+
+ switch(spddplx) {
+ case SPEED_10 + DUPLEX_HALF:
+ adapter->hw.forced_speed_duplex = e1000_10_half;
+ break;
+ case SPEED_10 + DUPLEX_FULL:
+ adapter->hw.forced_speed_duplex = e1000_10_full;
+ break;
+ case SPEED_100 + DUPLEX_HALF:
+ adapter->hw.forced_speed_duplex = e1000_100_half;
+ break;
+ case SPEED_100 + DUPLEX_FULL:
+ adapter->hw.forced_speed_duplex = e1000_100_full;
+ break;
+ case SPEED_1000 + DUPLEX_FULL:
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+ break;
+ case SPEED_1000 + DUPLEX_HALF: /* not supported */
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int
e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
@@ -2419,6 +2659,7 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
return NOTIFY_DONE;
}
+
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
@@ -2483,7 +2724,8 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state)
if(manc & E1000_MANC_SMBUS_EN) {
manc |= E1000_MANC_ARP_EN;
E1000_WRITE_REG(&adapter->hw, MANC, manc);
- state = 0;
+ pci_enable_wake(pdev, 3, 1);
+ pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
}
}
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 0d68940f9b98..fe351959ed47 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -77,24 +77,22 @@ typedef enum {
#define E1000_WRITE_REG(a, reg, value) ( \
- ((a)->mac_type >= e1000_82543) ? \
- (writel((value), ((a)->hw_addr + E1000_##reg))) : \
- (writel((value), ((a)->hw_addr + E1000_82542_##reg))))
+ writel((value), ((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))))
#define E1000_READ_REG(a, reg) ( \
- ((a)->mac_type >= e1000_82543) ? \
- readl((a)->hw_addr + E1000_##reg) : \
- readl((a)->hw_addr + E1000_82542_##reg))
+ readl((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
- ((a)->mac_type >= e1000_82543) ? \
- writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \
- writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))
+ writel((value), ((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+ ((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
- ((a)->mac_type >= e1000_82543) ? \
- readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
- readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
+ readl((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+ ((offset) << 2)))
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index a11941f3f213..75a50ff6f42e 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
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
@@ -169,7 +169,7 @@ E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
*
* Valid Range: 0-65535
*
- * Default Value: 0/128
+ * Default Value: 0
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
@@ -183,6 +183,15 @@ E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 100-100000 (0=off, 1=dynamic)
+ *
+ * Default Value: 1
+ */
+
+E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -213,6 +222,10 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
#define MAX_TXABSDELAY 0xFFFF
#define MIN_TXABSDELAY 0
+#define DEFAULT_ITR 1
+#define MAX_ITR 100000
+#define MIN_ITR 100
+
struct e1000_option {
enum { enable_option, range_option, list_option } type;
char *name;
@@ -309,7 +322,7 @@ e1000_check_options(struct e1000_adapter *adapter)
.name = "Transmit Descriptors",
.err = "using default of " __MODULE_STRING(DEFAULT_TXD),
.def = DEFAULT_TXD,
- .arg = { .r = { .min = MIN_TXD }}
+ .arg = { .r { .min = MIN_TXD }}
};
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
e1000_mac_type mac_type = adapter->hw.mac_type;
@@ -362,7 +375,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = e1000_fc_default,
- .arg = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }}
+ .arg = { .l = { .nr = ARRAY_SIZE(fc_list),
+ .p = fc_list }}
};
int fc = FlowControl[bd];
@@ -370,58 +384,78 @@ e1000_check_options(struct e1000_adapter *adapter)
adapter->hw.fc = adapter->hw.original_fc = fc;
}
{ /* Transmit Interrupt Delay */
- char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
struct e1000_option opt = {
.type = range_option,
.name = "Transmit Interrupt Delay",
- .arg = { .r = { .min = MIN_TXDELAY, .max = MAX_TXDELAY }}
+ .err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
+ .def = DEFAULT_TIDV,
+ .arg = { .r = { .min = MIN_TXDELAY,
+ .max = MAX_TXDELAY }}
};
- opt.def = DEFAULT_TIDV;
- opt.err = tidv;
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt);
}
{ /* Transmit Absolute Interrupt Delay */
- char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
struct e1000_option opt = {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
- .arg = { .r = { .min = MIN_TXABSDELAY, .max = MAX_TXABSDELAY }}
+ .err = "using default of " __MODULE_STRING(DEFAULT_TADV),
+ .def = DEFAULT_TADV,
+ .arg = { .r = { .min = MIN_TXABSDELAY,
+ .max = MAX_TXABSDELAY }}
};
- opt.def = DEFAULT_TADV;
- opt.err = tadv;
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt);
}
{ /* Receive Interrupt Delay */
- char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
struct e1000_option opt = {
.type = range_option,
.name = "Receive Interrupt Delay",
- .arg = { .r = { .min = MIN_RXDELAY, .max = MAX_RXDELAY }}
+ .err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
+ .def = DEFAULT_RDTR,
+ .arg = { .r = { .min = MIN_RXDELAY,
+ .max = MAX_RXDELAY }}
};
- opt.def = DEFAULT_RDTR;
- opt.err = rdtr;
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt);
}
{ /* Receive Absolute Interrupt Delay */
- char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
struct e1000_option opt = {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
- .arg = { .r = { .min = MIN_RXABSDELAY, .max = MAX_RXABSDELAY }}
+ .err = "using default of " __MODULE_STRING(DEFAULT_RADV),
+ .def = DEFAULT_RADV,
+ .arg = { .r = { .min = MIN_RXABSDELAY,
+ .max = MAX_RXABSDELAY }}
};
- opt.def = DEFAULT_RADV;
- opt.err = radv;
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt);
}
-
+ { /* Interrupt Throttling Rate */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Interrupt Throttling Rate (ints/sec)",
+ .err = "using default of " __MODULE_STRING(DEFAULT_ITR),
+ .def = DEFAULT_ITR,
+ .arg = { .r = { .min = MIN_ITR,
+ .max = MAX_ITR }}
+ };
+
+ adapter->itr = InterruptThrottleRate[bd];
+ if(adapter->itr == 0) {
+ printk(KERN_INFO "%s turned off\n", opt.name);
+ } else if(adapter->itr == 1 || adapter->itr == -1) {
+ /* Dynamic mode */
+ adapter->itr = 1;
+ } else {
+ e1000_validate_option(&adapter->itr, &opt);
+ }
+ }
+
switch(adapter->hw.media_type) {
case e1000_media_type_fiber:
e1000_check_fiber_options(adapter);
@@ -486,7 +520,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.name = "Speed",
.err = "parameter ignored",
.def = 0,
- .arg = { .l = { .nr = ARRAY_SIZE(speed_list), .p = speed_list }}
+ .arg = { .l = { .nr = ARRAY_SIZE(speed_list),
+ .p = speed_list }}
};
speed = Speed[bd];
@@ -502,7 +537,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.name = "Duplex",
.err = "parameter ignored",
.def = 0,
- .arg = { .l = { .nr = ARRAY_SIZE(dplx_list), .p = dplx_list }}
+ .arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
+ .p = dplx_list }}
};
dplx = Duplex[bd];
@@ -554,7 +590,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.name = "AutoNeg",
.err = "parameter ignored",
.def = AUTONEG_ADV_DEFAULT,
- .arg = { .l = { .nr = ARRAY_SIZE(an_list), .p = an_list }}
+ .arg = { .l = { .nr = ARRAY_SIZE(an_list),
+ .p = an_list }}
};
int an = AutoNeg[bd];
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 4e8a08b78804..a99f7d037d0a 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -331,8 +331,8 @@ static int mace_open(struct net_device *dev)
return -ENOMEM;
}
- mp->rx_ring_phys = (unsigned char *) virt_to_bus(mp->rx_ring);
- mp->tx_ring_phys = (unsigned char *) virt_to_bus(mp->tx_ring);
+ mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
+ mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
/* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
diff --git a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c
new file mode 100644
index 000000000000..861e1086934c
--- /dev/null
+++ b/drivers/net/ne2k_cbus.c
@@ -0,0 +1,879 @@
+/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
+/*
+ Written 1992-94 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ This driver should work with many programmed-I/O 8390-based ethernet
+ boards. Currently it supports the NE1000, NE2000, many clones,
+ and some Cabletron products.
+
+ Changelog:
+
+ Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made
+ sanity checks and bad clone support optional.
+ Paul Gortmaker : new reset code, reset card after probe at boot.
+ Paul Gortmaker : multiple card support for module users.
+ Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
+ Paul Gortmaker : Allow users with bad cards to avoid full probe.
+ Paul Gortmaker : PCI probe changes, more PCI cards supported.
+ rjohnson@analogic.com : Changed init order so an interrupt will only
+ occur after memory is allocated for dev->priv. Deallocated memory
+ last in cleanup_modue()
+ Richard Guenther : Added support for ISAPnP cards
+ Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead.
+ Osamu Tomita : Separate driver for NEC PC-9800.
+
+*/
+
+/* Routines for the NatSemi-based designs (NE[12]000). */
+
+static const char version1[] =
+"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
+static const char version2[] =
+"Last modified Nov 1, 2000 by Paul Gortmaker\n";
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "8390.h"
+
+/* Some defines that people can play with if so inclined. */
+
+/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
+#define SUPPORT_NE_BAD_CLONES
+
+/* Do we perform extra sanity checks on stuff ? */
+/* #define NE_SANITY_CHECK */
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE 0x40 */
+
+#ifdef SUPPORT_NE_BAD_CLONES
+/* A list of bad clones that we none-the-less recognize. */
+static struct { const char *name8, *name16; unsigned char SAprefix[4];}
+bad_clone_list[] __initdata = {
+ {"LA/T-98?", "LA/T-98", {0x00, 0xa0, 0xb0}}, /* I/O Data */
+ {"EGY-98?", "EGY-98", {0x00, 0x40, 0x26}}, /* Melco EGY98 */
+ {"ICM?", "ICM-27xx-ET", {0x00, 0x80, 0xc8}}, /* ICM IF-27xx-ET */
+ {"CNET-98/EL?", "CNET(98)E/L", {0x00, 0x80, 0x4C}}, /* Contec CNET-98/EL */
+ {0,}
+};
+#endif
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE (dev->base_addr)
+#define NE_CMD EI_SHIFT(0x00)
+#define NE_DATAPORT EI_SHIFT(0x10) /* NatSemi-defined port window offset. */
+#define NE_RESET EI_SHIFT(0x1f) /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT 0x20
+
+#define NE1SM_START_PG 0x20 /* First page of TX buffer */
+#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */
+#define NESM_START_PG 0x40 /* First page of TX buffer */
+#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+#include "ne2k_cbus.h"
+
+int ne_probe(struct net_device *dev);
+static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_open(struct net_device *dev);
+static int ne_close(struct net_device *dev);
+
+static void ne_reset_8390(struct net_device *dev);
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void ne_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+
+
+/* Probe for various non-shared-memory ethercards.
+
+ NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+ buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
+ the SAPROM, while other supposed NE2000 clones must be detected by their
+ SA prefix.
+
+ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+ mode results in doubled values, which can be detected and compensated for.
+
+ The probe is also responsible for initializing the card and filling
+ in the 'dev' and 'ei_status' structures.
+
+ We use the minimum memory size for some ethercard product lines, iff we can't
+ distinguish models. You can increase the packet buffer size by setting
+ PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are:
+ E1010 starts at 0x100 and ends at 0x2000.
+ E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
+ E2010 starts at 0x100 and ends at 0x4000.
+ E2010-x starts at 0x100 and ends at 0xffff. */
+
+int __init ne_probe(struct net_device *dev)
+{
+ unsigned int base_addr = dev->base_addr;
+
+ SET_MODULE_OWNER(dev);
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): entered.\n");
+
+ /* If CONFIG_NET_CBUS,
+ we need dev->priv->reg_offset BEFORE to probe */
+ if (ne2k_cbus_init(dev) != 0)
+ return -ENOMEM;
+
+ /* First check any supplied i/o locations. User knows best. <cough> */
+ if (base_addr > 0) {
+ int result;
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr);
+
+ result = ne_probe_cbus(dev, hw, base_addr);
+ if (result != 0)
+ ne2k_cbus_destroy(dev);
+
+ return result;
+ }
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): base_addr is not specified.\n");
+
+#ifndef MODULE
+ /* Last resort. The semi-risky C-Bus auto-probe. */
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): auto-probe start.\n");
+
+ {
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+ if (hw && hw->hwtype) {
+ const unsigned short *plist;
+ for (plist = hw->portlist; *plist; plist++)
+ if (ne_probe_cbus(dev, hw, *plist) == 0)
+ return 0;
+ } else {
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ const unsigned short *plist;
+ for (plist = hw->portlist; *plist; plist++)
+ if (ne_probe_cbus(dev, hw, *plist) == 0)
+ return 0;
+ }
+ }
+ }
+#endif
+
+ ne2k_cbus_destroy(dev);
+
+ return -ENODEV;
+}
+
+static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n",
+ __builtin_return_address(0));
+
+ if (hw && hw->hwtype) {
+ ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+ return ne_probe1(dev, ioaddr);
+ } else {
+ /* auto detect */
+
+ printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n");
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+ if (ne_probe1(dev, ioaddr) == 0)
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+static int __init ne_probe1(struct net_device *dev, int ioaddr)
+{
+ int i;
+ unsigned char SA_prom[32];
+ int wordlength = 2;
+ const char *name = NULL;
+ int start_page, stop_page;
+ int neX000, bad_card;
+ int reg0, ret;
+ static unsigned version_printed;
+ const struct ne2k_cbus_region *rlist;
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ outb_p(0, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+ /* udelay(5000); */
+ outb_p(1, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+ /* udelay(5000); */
+ outb_p((ioaddr & 0xf000) >> 8 | 0x08 | 0x01, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE + 2);
+ /* udelay(5000); */
+ }
+#endif
+
+ for (rlist = hw->regionlist; rlist->range; rlist++)
+ if (!request_region(ioaddr + rlist->start,
+ rlist->range, dev->name)) {
+ ret = -EBUSY;
+ goto err_out;
+ }
+
+ reg0 = inb_p(ioaddr + EI_SHIFT(0));
+ if (reg0 == 0xFF) {
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ /* Do a preliminary verification that we have a 8390. */
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype != NE2K_CBUS_HARDWARE_TYPE_CNET98EL)
+#endif
+ {
+ int regd;
+ outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+ regd = inb_p(ioaddr + EI_SHIFT(0x0d));
+ outb_p(0xff, ioaddr + EI_SHIFT(0x0d));
+ outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+ inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+ if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+ outb_p(reg0, ioaddr);
+ outb_p(regd, ioaddr + EI_SHIFT(0x0d)); /* Restore the old values. */
+ ret = -ENODEV;
+ goto err_out;
+ }
+ }
+
+ if (ei_debug && version_printed++ == 0)
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+
+ printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+
+ /* A user with a poor card that fails to ack the reset, or that
+ does not have a valid 0x57,0x57 signature can still use this
+ without having to recompile. Specifying an i/o address along
+ with an otherwise unused dev->mem_end value of "0xBAD" will
+ cause the driver to skip these parts of the probe. */
+
+ bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+
+ {
+ unsigned long reset_start_time = jiffies;
+
+ /* derived from CNET98EL-patch for bad clones */
+ outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD);
+
+ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+ while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2*HZ/100) {
+ if (bad_card) {
+ printk(" (warning: no reset ack)");
+ break;
+ } else {
+ printk(" not found (no reset ack).\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+ }
+
+ outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
+ }
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ static const char pat[32] ="AbcdeFghijKlmnoPqrstUvwxyZ789012";
+ char buf[32];
+ int maxwait = 200;
+
+ if (ei_debug > 2)
+ printk(" [CNET98EL-specific initialize...");
+ outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */
+ i = inb(ioaddr);
+ if ((i & ~0x2) != (0x20 | 0x01))
+ return -ENODEV;
+ if ((inb(ioaddr + 0x7) & 0x80) != 0x80)
+ return -ENODEV;
+ outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */
+ /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */
+ outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */
+ outb_p(CNET98EL_START_PG, ioaddr + EN0_STARTPG);
+ outb_p(CNET98EL_STOP_PG, ioaddr + EN0_STOPPG);
+ if (ei_debug > 2)
+ printk("memory check");
+ for (i = 0; i < 65536; i += 1024) {
+ if (ei_debug > 2)
+ printk(" %04x", i);
+ ne2k_cbus_writemem(dev, ioaddr, i, pat, 32);
+ while (((inb(ioaddr + EN0_ISR) & ENISR_RDC) != ENISR_RDC) && --maxwait)
+ ;
+ ne2k_cbus_readmem(dev, ioaddr, i, buf, 32);
+ if (memcmp(pat, buf, 32)) {
+ if (ei_debug > 2)
+ printk(" failed.");
+ break;
+ }
+ }
+ if (i != 16384) {
+ if (ei_debug > 2)
+ printk("] ");
+ printk("memory failure at %x\n", i);
+ return -ENODEV;
+ }
+ if (ei_debug > 2)
+ printk(" good...");
+ if (!dev->irq) {
+ if (ei_debug > 2)
+ printk("] ");
+ printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n");
+ return -ENODEV;
+ }
+ outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400));
+ outb(0x7e, ioaddr + (0x4 | 0x400));
+ ne2k_cbus_readmem(dev, ioaddr, 16384, SA_prom, 32);
+ outb(0xff, ioaddr + EN0_ISR);
+ if (ei_debug > 2)
+ printk("done]");
+ } else
+#endif /* CONFIG_NE2K_CBUS_CNET98EL */
+ /* Read the 16 bytes of station address PROM.
+ We must first initialize registers, similar to NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+ struct {unsigned char value; unsigned short offset;} program_seq[] =
+ {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+ /* NEC PC-9800: some board can only handle word-wide access? */
+ {0x48 | ENDCFG_WTS, EN0_DCFG}, /* Set word-wide (0x48) access. */
+ {16384 / 256, EN0_STARTPG},
+ {32768 / 256, EN0_STOPPG},
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_IMR}, /* Mask completion irq. */
+ {0xFF, EN0_ISR},
+ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, EN0_RCNTLO},
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, EN0_RSARHI},
+ {E8390_RREAD+E8390_START, E8390_CMD},
+ };
+
+ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+ insw(ioaddr + NE_DATAPORT, SA_prom, 32 >> 1);
+
+ }
+
+ if (wordlength == 2)
+ {
+ for (i = 0; i < 16; i++)
+ SA_prom[i] = SA_prom[i+i];
+ start_page = NESM_START_PG;
+ stop_page = NESM_STOP_PG;
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ start_page = CNET98EL_START_PG;
+ stop_page = CNET98EL_STOP_PG;
+ }
+#endif
+ } else {
+ start_page = NE1SM_START_PG;
+ stop_page = NE1SM_STOP_PG;
+ }
+
+ neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
+ if (neX000) {
+ name = "C-Bus-NE2K-compat";
+ }
+ else
+ {
+#ifdef SUPPORT_NE_BAD_CLONES
+ /* Ack! Well, there might be a *bad* NE*000 clone there.
+ Check for total bogus addresses. */
+ for (i = 0; bad_clone_list[i].name8; i++)
+ {
+ if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
+ SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
+ SA_prom[2] == bad_clone_list[i].SAprefix[2])
+ {
+ if (wordlength == 2)
+ {
+ name = bad_clone_list[i].name16;
+ } else {
+ name = bad_clone_list[i].name8;
+ }
+ break;
+ }
+ }
+ if (bad_clone_list[i].name8 == NULL)
+ {
+ printk(" not found (invalid signature %2.2x %2.2x).\n",
+ SA_prom[14], SA_prom[15]);
+ ret = -ENXIO;
+ goto err_out;
+ }
+#else
+ printk(" not found.\n");
+ ret = -ENXIO;
+ goto err_out;
+#endif
+ }
+
+ if (dev->irq < 2)
+ {
+ unsigned long cookie = probe_irq_on();
+ outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */
+ outb_p(0x00, ioaddr + EN0_RCNTLO);
+ outb_p(0x00, ioaddr + EN0_RCNTHI);
+ outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
+ mdelay(10); /* wait 10ms for interrupt to propagate */
+ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
+ dev->irq = probe_irq_off(cookie);
+ if (ei_debug > 2)
+ printk(" autoirq is %d\n", dev->irq);
+ } else if (dev->irq == 7)
+ /* Fixup for users that don't know that IRQ 7 is really IRQ 11,
+ or don't know which one to set. */
+ dev->irq = 11;
+
+ if (! dev->irq) {
+ printk(" failed to detect IRQ line.\n");
+ ret = -EAGAIN;
+ goto err_out;
+ }
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev))
+ {
+ printk (" unable to get memory for dev->priv.\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ /* Snarf the interrupt now. There's no point in waiting since we cannot
+ share and the board will usually be enabled. */
+ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+ if (ret) {
+ printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+ goto err_out_kfree;
+ }
+
+ dev->base_addr = ioaddr;
+
+ for(i = 0; i < ETHER_ADDR_LEN; i++) {
+ printk(" %2.2x", SA_prom[i]);
+ dev->dev_addr[i] = SA_prom[i];
+ }
+
+ printk("\n%s: %s found at %#x, hardware type %d(%s), using IRQ %d.\n",
+ dev->name, name, ioaddr, hw->hwtype, hw->hwident, dev->irq);
+
+ ei_status.name = name;
+ ei_status.tx_start_page = start_page;
+ ei_status.stop_page = stop_page;
+ ei_status.word16 = (wordlength == 2);
+
+ ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+ /* Allow the packet buffer size to be overridden by know-it-alls. */
+ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+ ei_status.reset_8390 = &ne_reset_8390;
+ ei_status.block_input = &ne_block_input;
+ ei_status.block_output = &ne_block_output;
+ ei_status.get_8390_hdr = &ne_get_8390_hdr;
+ ei_status.priv = 0;
+ dev->open = &ne_open;
+ dev->stop = &ne_close;
+ NS8390_init(dev, 0);
+ return 0;
+
+err_out_kfree:
+ ne2k_cbus_destroy(dev);
+err_out:
+ while (rlist > hw->regionlist) {
+ rlist --;
+ release_region(ioaddr + rlist->start, rlist->range);
+ }
+ return ret;
+}
+
+static int ne_open(struct net_device *dev)
+{
+ ei_open(dev);
+ return 0;
+}
+
+static int ne_close(struct net_device *dev)
+{
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+ ei_close(dev);
+ return 0;
+}
+
+/* Hard reset the card. This used to pause for the same period that a
+ 8390 reset command required, but that shouldn't be necessary. */
+
+static void ne_reset_8390(struct net_device *dev)
+{
+ unsigned long reset_start_time = jiffies;
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+
+ /* derived from CNET98EL-patch for bad clones... */
+ outb_p(E8390_NODMA | E8390_STOP, NE_BASE + E8390_CMD); /* 0x20 | 0x1 */
+
+ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2*HZ/100) {
+ printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
+ break;
+ }
+ outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ int nic_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+
+ if (ei_status.dmaing)
+ {
+ printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+ outb_p(0, nic_base + EN0_RCNTHI);
+ outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */
+ outb_p(ring_page, nic_base + EN0_RSARHI);
+ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.word16)
+ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+ else
+ insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+
+ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+
+ le16_to_cpus(&hdr->count);
+}
+
+/* Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard, look at the packet driver source for hints.
+ The NEx000 doesn't share the on-board packet memory -- you have to put
+ the packet out through the "remote DMA" dataport using outb. */
+
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+#ifdef NE_SANITY_CHECK
+ int xfer_count = count;
+#endif
+ int nic_base = dev->base_addr;
+ char *buf = skb->data;
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing)
+ {
+ printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+
+ /* round up count to a word (derived from ICM-patch) */
+ count = (count + 1) & ~1;
+
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+ outb_p(count >> 8, nic_base + EN0_RCNTHI);
+ outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+ outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+ if (ei_status.word16)
+ {
+ insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+ if (count & 0x01)
+ {
+ buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+#ifdef NE_SANITY_CHECK
+ xfer_count++;
+#endif
+ }
+ } else {
+ insb(NE_BASE + NE_DATAPORT, buf, count);
+ }
+
+#ifdef NE_SANITY_CHECK
+ /* This was for the ALPHA version only, but enough people have
+ been encountering problems so it is still here. If you see
+ this message you either 1) have a slightly incompatible clone
+ or 2) have noise/speed problems with your bus. */
+
+ if (ei_debug > 1)
+ {
+ /* DMA termination address check... */
+ int addr, tries = 20;
+ do {
+ /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+ -- it's broken for Rx on some cards! */
+ int high = inb_p(nic_base + EN0_RSARHI);
+ int low = inb_p(nic_base + EN0_RSARLO);
+ addr = (high << 8) + low;
+ if (((ring_offset + xfer_count) & 0xff) == low)
+ break;
+ } while (--tries > 0);
+ if (tries <= 0)
+ printk(KERN_WARNING "%s: RX transfer address mismatch,"
+ "%#4.4x (expected) vs. %#4.4x (actual).\n",
+ dev->name, ring_offset + xfer_count, addr);
+ }
+#endif
+ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+static void ne_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, const int start_page)
+{
+ int nic_base = NE_BASE;
+ unsigned long dma_start;
+#ifdef NE_SANITY_CHECK
+ int retries = 0;
+#endif
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+ /* Round the count up for word writes. Do we need to do this?
+ What effect will an odd byte count have on the 8390?
+ I should check someday. */
+
+ if (ei_status.word16 && (count & 0x01))
+ count++;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing)
+ {
+ printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
+ "[DMAstat:%d][irqlock:%d]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ /* We should already be in page 0, but to be safe... */
+ outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE_SANITY_CHECK
+retry:
+#endif
+
+#ifdef NE8390_RW_BUGFIX
+ /* Handle the read-before-write bug the same way as the
+ Crynwr packet driver -- the NatSemi method doesn't work.
+ Actually this doesn't always work either, but if you have
+ problems with your NEx000 this is better than nothing! */
+
+ outb_p(0x42, nic_base + EN0_RCNTLO);
+ outb_p(0x00, nic_base + EN0_RCNTHI);
+ outb_p(0x42, nic_base + EN0_RSARLO);
+ outb_p(0x00, nic_base + EN0_RSARHI);
+ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+ /* Make certain that the dummy read has occurred. */
+ udelay(6);
+#endif
+
+ outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+ /* Now the normal output. */
+ outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+ outb_p(count >> 8, nic_base + EN0_RCNTHI);
+ outb_p(0x00, nic_base + EN0_RSARLO);
+ outb_p(start_page, nic_base + EN0_RSARHI);
+
+ outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+ if (ei_status.word16) {
+ outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+ } else {
+ outsb(NE_BASE + NE_DATAPORT, buf, count);
+ }
+
+ dma_start = jiffies;
+
+#ifdef NE_SANITY_CHECK
+ /* This was for the ALPHA version only, but enough people have
+ been encountering problems so it is still here. */
+
+ if (ei_debug > 1)
+ {
+ /* DMA termination address check... */
+ int addr, tries = 20;
+ do {
+ int high = inb_p(nic_base + EN0_RSARHI);
+ int low = inb_p(nic_base + EN0_RSARLO);
+ addr = (high << 8) + low;
+ if ((start_page << 8) + count == addr)
+ break;
+ } while (--tries > 0);
+
+ if (tries <= 0)
+ {
+ printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
+ "%#4.4x (expected) vs. %#4.4x (actual).\n",
+ dev->name, (start_page << 8) + count, addr);
+ if (retries++ == 0)
+ goto retry;
+ }
+ }
+#endif
+
+ while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+ if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
+ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+ ne_reset_8390(dev);
+ NS8390_init(dev,1);
+ break;
+ }
+
+ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ return;
+}
+
+
+#ifdef MODULE
+#define MAX_NE_CARDS 4 /* Max number of NE cards per module */
+static struct net_device dev_ne[MAX_NE_CARDS];
+static int io[MAX_NE_CARDS];
+static int irq[MAX_NE_CARDS];
+static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */
+static int hwtype[MAX_NE_CARDS] = { 0, }; /* board type */
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(hwtype, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_PARM_DESC(hwtype, "Board type of PC-9800 C-Bus NIC");
+MODULE_DESCRIPTION("NE1000/NE2000 PC-9800 C-bus Ethernet driver");
+MODULE_LICENSE("GPL");
+
+/* This is set up so that no ISA autoprobe takes place. We can't guarantee
+that the ne2k probe is the last 8390 based probe to take place (as it
+is at boot) and so the probe will get confused by any other 8390 cards.
+ISA device autoprobes on a running machine are not recommended anyway. */
+
+int init_module(void)
+{
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+ struct net_device *dev = &dev_ne[this_dev];
+ dev->irq = irq[this_dev];
+ dev->mem_end = bad[this_dev];
+ dev->base_addr = io[this_dev];
+ dev->mem_start = hwtype[this_dev];
+ dev->init = ne_probe;
+ if (register_netdev(dev) == 0) {
+ found++;
+ continue;
+ }
+ if (found != 0) { /* Got at least one. */
+ return 0;
+ }
+ if (io[this_dev] != 0)
+ printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+ else
+ printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int this_dev;
+
+ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+ struct net_device *dev = &dev_ne[this_dev];
+ if (dev->priv != NULL) {
+ const struct ne2k_cbus_region *rlist;
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+ free_irq(dev->irq, dev);
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ release_region(dev->base_addr + rlist->start,
+ rlist->range);
+ }
+ unregister_netdev(dev);
+ ne2k_cbus_destroy(dev);
+ }
+ }
+}
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * End:
+ */
diff --git a/drivers/net/ne2k_cbus.h b/drivers/net/ne2k_cbus.h
new file mode 100644
index 000000000000..e561ef7f6111
--- /dev/null
+++ b/drivers/net/ne2k_cbus.h
@@ -0,0 +1,481 @@
+/* ne2k_cbus.h:
+ vender-specific information definition for NEC PC-9800
+ C-bus Ethernet Cards
+ Used in ne.c
+
+ (C)1998,1999 KITAGWA Takurou & Linux/98 project
+*/
+
+#include <linux/config.h>
+
+#undef NE_RESET
+#define NE_RESET EI_SHIFT(0x11) /* Issue a read to reset, a write to clear. */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef CONFIG_NE2K_CBUS_CNET98EL_IO_BASE
+#warning CONFIG_NE2K_CBUS_CNET98EL_IO_BASE is not defined(config error?)
+#warning use 0xaaed as default
+#define CONFIG_NE2K_CBUS_CNET98EL_IO_BASE 0xaaed /* or 0x55ed */
+#endif
+#define CNET98EL_START_PG 0x00
+#define CNET98EL_STOP_PG 0x40
+#endif
+
+/* Hardware type definition (derived from *BSD) */
+#define NE2K_CBUS_HARDWARE_TYPE_MASK 0xff
+
+/* 0: reserved for auto-detect */
+/* 1: (not tested)
+ Allied Telesis CentreCom LA-98-T */
+#define NE2K_CBUS_HARDWARE_TYPE_ATLA98 1
+/* 2: (not tested)
+ ELECOM Laneed
+ LD-BDN[123]A
+ PLANET SMART COM 98 EN-2298-C
+ MACNICA ME98 */
+#define NE2K_CBUS_HARDWARE_TYPE_BDN 2
+/* 3:
+ Melco EGY-98
+ Contec C-NET(98)E*A/L*A,C-NET(98)P */
+#define NE2K_CBUS_HARDWARE_TYPE_EGY98 3
+/* 4:
+ Melco LGY-98,IND-SP,IND-SS
+ MACNICA NE2098 */
+#define NE2K_CBUS_HARDWARE_TYPE_LGY98 4
+/* 5:
+ ICM DT-ET-25,DT-ET-T5,IF-2766ET,IF-2771ET
+ PLANET SMART COM 98 EN-2298-T,EN-2298P-T
+ D-Link DE-298PT,DE-298PCAT
+ ELECOM Laneed LD-98P */
+#define NE2K_CBUS_HARDWARE_TYPE_ICM 5
+/* 6: (reserved for SIC-98, which is not supported in this driver.) */
+/* 7: (unused in *BSD?)
+ <Original NE2000 compatible>
+ <for PCI/PCMCIA cards>
+*/
+#define NE2K_CBUS_HARDWARE_TYPE_NE2K 7
+/* 8:
+ NEC PC-9801-108 */
+#define NE2K_CBUS_HARDWARE_TYPE_NEC108 8
+/* 9:
+ I-O DATA LA-98,LA/T-98 */
+#define NE2K_CBUS_HARDWARE_TYPE_IOLA98 9
+/* 10: (reserved for C-NET(98), which is not supported in this driver.) */
+/* 11:
+ Contec C-NET(98)E,L */
+#define NE2K_CBUS_HARDWARE_TYPE_CNET98EL 11
+
+#define NE2K_CBUS_HARDWARE_TYPE_MAX 11
+
+/* HARDWARE TYPE ID 12-31: reserved */
+
+struct ne2k_cbus_offsetinfo {
+ unsigned short skip;
+ unsigned short offset8; /* +0x8 - +0xf */
+ unsigned short offset10; /* +0x10 */
+ unsigned short offset1f; /* +0x1f */
+};
+
+struct ne2k_cbus_region {
+ unsigned short start;
+ short range;
+};
+
+struct ne2k_cbus_hwinfo {
+ const unsigned short hwtype;
+ const unsigned char *hwident;
+#ifndef MODULE
+ const unsigned short *portlist;
+#endif
+ const struct ne2k_cbus_offsetinfo *offsetinfo;
+ const struct ne2k_cbus_region *regionlist;
+};
+
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+#ifndef MODULE
+static unsigned short atla98_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+#define atla98_offsetinfo ne2k_offsetinfo
+#define atla98_regionlist ne2k_regionlist
+#endif /* CONFIG_NE2K_CBUS_ATLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_BDN
+#ifndef MODULE
+static unsigned short bdn_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo bdn_offsetinfo __initdata = {
+#if 0
+ /* comes from FreeBSD(98) ed98.h */
+ 0x1000, 0x8000, 0x100, 0xc200 /* ??? */
+#else
+ /* comes from NetBSD/pc98 if_ne_isa.c */
+ 0x1000, 0x8000, 0x100, 0x7f00 /* ??? */
+#endif
+};
+static struct ne2k_cbus_region bdn_regionlist[] __initdata = {
+ {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000,1},
+ {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+ {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+ {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+ {0x100, 1}, {0x7f00, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_BDN */
+
+#ifdef CONFIG_NE2K_CBUS_EGY98
+#ifndef MODULE
+static unsigned short egy98_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo egy98_offsetinfo __initdata = {
+ 0x02, 0x100, 0x200, 0x300
+};
+static struct ne2k_cbus_region egy98_regionlist[] __initdata = {
+ {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+ {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+ {0x100, 1}, {0x102, 1}, {0x104, 1}, {0x106, 1},
+ {0x108, 1}, {0x10a, 1}, {0x10c, 1}, {0x10e, 1},
+ {0x200, 1}, {0x300, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_EGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_LGY98
+#ifndef MODULE
+static unsigned short lgy98_portlist[] __initdata = {
+ 0xd0, 0x10d0, 0x20d0, 0x30d0, 0x40d0, 0x50d0, 0x60d0, 0x70d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo lgy98_offsetinfo __initdata = {
+ 0x01, 0x08, 0x200, 0x300
+};
+static struct ne2k_cbus_region lgy98_regionlist[] __initdata = {
+ {0x0, 16}, {0x200, 1}, {0x300, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_LGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_ICM
+#ifndef MODULE
+static unsigned short icm_portlist[] __initdata = {
+ /* ICM */
+ 0x56d0,
+ /* LD-98PT */
+ 0x46d0, 0x66d0, 0x76d0, 0x86d0, 0x96d0, 0xa6d0, 0xb6d0, 0xc6d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo icm_offsetinfo __initdata = {
+ 0x01, 0x08, 0x100, 0x10f
+};
+static struct ne2k_cbus_region icm_regionlist[] __initdata = {
+ {0x0, 16}, {0x100, 16},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_ICM */
+
+#if defined(CONFIG_NE2K_CBUS_NE2K) && !defined(MODULE)
+static unsigned short ne2k_portlist[] __initdata = {
+ 0xd0, 0x300, 0x280, 0x320, 0x340, 0x360, 0x380,
+ 0
+};
+#endif
+#if defined(CONFIG_NE2K_CBUS_NE2K) || defined(CONFIG_NE2K_CBUS_ATLA98)
+static struct ne2k_cbus_offsetinfo ne2k_offsetinfo __initdata = {
+ 0x01, 0x08, 0x10, 0x1f
+};
+static struct ne2k_cbus_region ne2k_regionlist[] __initdata = {
+ {0x0, 32},
+ {0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_NEC108
+#ifndef MODULE
+static unsigned short nec108_portlist[] __initdata = {
+ 0x770, 0x2770, 0x4770, 0x6770,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo nec108_offsetinfo __initdata = {
+ 0x02, 0x1000, 0x888, 0x88a
+};
+static struct ne2k_cbus_region nec108_regionlist[] __initdata = {
+ {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+ {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+ {0x1000, 1}, {0x1002, 1}, {0x1004, 1}, {0x1006, 1},
+ {0x1008, 1}, {0x100a, 1}, {0x100c, 1}, {0x100e, 1},
+ {0x888, 1}, {0x88a, 1}, {0x88c, 1}, {0x88e, 1},
+ {0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+#ifndef MODULE
+static unsigned short iola98_portlist[] __initdata = {
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo iola98_offsetinfo __initdata = {
+ 0x1000, 0x8000, 0x100, 0xf100
+};
+static struct ne2k_cbus_region iola98_regionlist[] __initdata = {
+ {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000, 1},
+ {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+ {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+ {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+ {0x100, 1}, {0xf100, 1},
+ {0x0,0}
+};
+#endif /* CONFIG_NE2K_CBUS_IOLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef MODULE
+static unsigned short cnet98el_portlist[] __initdata = {
+ 0x3d0, 0x13d0, 0x23d0, 0x33d0, 0x43d0, 0x53d0, 0x60d0, 0x70d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo cnet98el_offsetinfo __initdata = {
+ 0x01, 0x08, 0x40e, 0x400
+};
+static struct ne2k_cbus_region cnet98el_regionlist[] __initdata = {
+ {0x0, 16}, {0x400, 16},
+ {0x0, 0}
+};
+#endif
+
+
+/* port information table (for ne.c initialize/probe process) */
+
+static struct ne2k_cbus_hwinfo ne2k_cbus_hwinfo_list[] __initdata = {
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+/* NOT TESTED */
+ {
+ NE2K_CBUS_HARDWARE_TYPE_ATLA98,
+ "LA-98-T",
+#ifndef MODULE
+ atla98_portlist,
+#endif
+ &atla98_offsetinfo, atla98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_BDN
+/* NOT TESTED */
+ {
+ NE2K_CBUS_HARDWARE_TYPE_BDN,
+ "LD-BDN[123]A",
+#ifndef MODULE
+ bdn_portlist,
+#endif
+ &bdn_offsetinfo, bdn_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_ICM
+ {
+ NE2K_CBUS_HARDWARE_TYPE_ICM,
+ "IF-27xxET",
+#ifndef MODULE
+ icm_portlist,
+#endif
+ &icm_offsetinfo, icm_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_NE2K
+ {
+ NE2K_CBUS_HARDWARE_TYPE_NE2K,
+ "NE2000 compat.",
+#ifndef MODULE
+ ne2k_portlist,
+#endif
+ &ne2k_offsetinfo, ne2k_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ {
+ NE2K_CBUS_HARDWARE_TYPE_NEC108,
+ "PC-9801-108",
+#ifndef MODULE
+ nec108_portlist,
+#endif
+ &nec108_offsetinfo, nec108_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_IOLA98,
+ "LA-98",
+#ifndef MODULE
+ iola98_portlist,
+#endif
+ &iola98_offsetinfo, iola98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ {
+ NE2K_CBUS_HARDWARE_TYPE_CNET98EL,
+ "C-NET(98)E/L",
+#ifndef MODULE
+ cnet98el_portlist,
+#endif
+ &cnet98el_offsetinfo, cnet98el_regionlist
+ },
+#endif
+/* NOTE: LGY98 must be probed before EGY98, or system stalled!? */
+#ifdef CONFIG_NE2K_CBUS_LGY98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_LGY98,
+ "LGY-98",
+#ifndef MODULE
+ lgy98_portlist,
+#endif
+ &lgy98_offsetinfo, lgy98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_EGY98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_EGY98,
+ "EGY-98",
+#ifndef MODULE
+ egy98_portlist,
+#endif
+ &egy98_offsetinfo, egy98_regionlist
+ },
+#endif
+ {
+ 0,
+ "unsupported hardware",
+#ifndef MODULE
+ NULL,
+#endif
+ NULL, NULL
+ }
+};
+
+static int __init ne2k_cbus_init(struct net_device *dev)
+{
+ struct ei_device *ei_local;
+ if (dev->priv == NULL) {
+ ei_local = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+ if (ei_local == NULL)
+ return -ENOMEM;
+ memset(ei_local, 0, sizeof(struct ei_device));
+ ei_local->reg_offset = kmalloc(sizeof(typeof(*ei_local->reg_offset))*18, GFP_KERNEL);
+ if (ei_local->reg_offset == NULL) {
+ kfree(ei_local);
+ return -ENOMEM;
+ }
+ spin_lock_init(&ei_local->page_lock);
+ dev->priv = ei_local;
+ }
+ return 0;
+}
+
+static void ne2k_cbus_destroy(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ if (ei_local != NULL) {
+ if (ei_local->reg_offset)
+ kfree(ei_local->reg_offset);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
+}
+
+static const struct ne2k_cbus_hwinfo * __init ne2k_cbus_get_hwinfo(int hwtype)
+{
+ const struct ne2k_cbus_hwinfo *hw;
+
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ if (hw->hwtype == hwtype) break;
+ }
+ return hw;
+}
+
+static void __init ne2k_cbus_set_hwtype(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ int i;
+ int hwtype_old = dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+ if (!ei_local)
+ panic("Gieee! ei_local == NULL!! (from %p)",
+ __builtin_return_address(0));
+
+ dev->mem_start &= ~NE2K_CBUS_HARDWARE_TYPE_MASK;
+ dev->mem_start |= hw->hwtype & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+ if (ei_debug > 2) {
+ printk(KERN_DEBUG "hwtype changed: %d -> %d\n",hwtype_old,(int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+ }
+
+ if (hw->offsetinfo) {
+ for (i = 0; i < 8; i++) {
+ ei_local->reg_offset[i] = hw->offsetinfo->skip * i;
+ }
+ for (i = 8; i < 16; i++) {
+ ei_local->reg_offset[i] =
+ hw->offsetinfo->skip*(i-8) + hw->offsetinfo->offset8;
+ }
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_NEC108) {
+ int adj = (ioaddr & 0xf000) /2;
+ ei_local->reg_offset[16] =
+ (hw->offsetinfo->offset10 | adj) - ioaddr;
+ ei_local->reg_offset[17] =
+ (hw->offsetinfo->offset1f | adj) - ioaddr;
+ } else {
+#endif /* CONFIG_NE2K_CBUS_NEC108 */
+ ei_local->reg_offset[16] = hw->offsetinfo->offset10;
+ ei_local->reg_offset[17] = hw->offsetinfo->offset1f;
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ }
+#endif
+ } else {
+ /* make dummmy offset list */
+ for (i = 0; i < 16; i++) {
+ ei_local->reg_offset[i] = i;
+ }
+ ei_local->reg_offset[16] = 0x10;
+ ei_local->reg_offset[17] = 0x1f;
+ }
+}
+
+#if defined(CONFIG_NE2K_CBUS_ICM) || defined(CONFIG_NE2K_CBUS_CNET98EL)
+static void __init ne2k_cbus_readmem(struct net_device *dev, int ioaddr, unsigned short memaddr, char *buf, unsigned short len)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+ outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+ outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+ outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+ outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+ outb_p(E8390_RREAD | E8390_START, ioaddr+E8390_CMD);
+ insw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+static void __init ne2k_cbus_writemem(struct net_device *dev, int ioaddr, unsigned short memaddr, const char *buf, unsigned short len)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+ outb_p(ENISR_RDC, ioaddr+EN0_ISR);
+ outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+ outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+ outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+ outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+ outb_p(E8390_RWRITE | E8390_START, ioaddr+E8390_CMD);
+ outsw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+#endif
+
+static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr);
+/* End of ne2k_cbus.h */
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index e5f5670201e1..e78c6e1006ae 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2214,6 +2214,11 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
* and for initialization.
*/
+static void ppp_device_destructor(struct net_device *dev)
+{
+ kfree(dev);
+}
+
/*
* Create a new ppp interface unit. Fails if it can't allocate memory
* or if there is already a unit with the requested number.
@@ -2262,7 +2267,7 @@ ppp_create_interface(int unit, int *retp)
dev->init = ppp_net_init;
sprintf(dev->name, "ppp%d", unit);
dev->priv = ppp;
- dev->features |= NETIF_F_DYNALLOC;
+ dev->destructor = ppp_device_destructor;
rtnl_lock();
ret = register_netdevice(dev);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 8f48359a3496..ea4082646fde 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -55,8 +55,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.4c"
-#define DRV_MODULE_RELDATE "Feb 18, 2003"
+#define DRV_MODULE_VERSION "1.5"
+#define DRV_MODULE_RELDATE "March 21, 2003"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -6581,11 +6581,11 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ ret = 0;
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;
+ goto out;
- ret = 0;
while (1) {
u32 *p, i;
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 69176c1ef875..2e33b62d2d3f 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -322,7 +322,7 @@ static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node
u16 status;
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- if ( !boot & pnpbios_dont_use_current_config )
+ if ( !boot && pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
nodenum, sizeof(char), data, 65536);
@@ -350,7 +350,7 @@ static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *
u16 status;
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- if ( !boot & pnpbios_dont_use_current_config )
+ if ( !boot && pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
data, 65536, 0, 0);
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 2652645219fb..c90651671cae 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -6,7 +6,7 @@
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Brad Strand <linux@3ware.com>
- Copyright (C) 1999-2002 3ware Inc.
+ Copyright (C) 1999-2003 3ware Inc.
Kernel compatiblity By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
@@ -164,6 +164,11 @@
Add support for mode sense opcode.
Add support for cache mode page.
Add support for synchronize cache opcode.
+ 1.02.00.032 - Fix small multicard rollcall bug.
+ Make driver stay loaded with no units for hot add/swap.
+ Add support for "twe" character device for ioctls.
+ Clean up request_id queueing code.
+ Fix tw_scsi_queue() spinlocks.
*/
#include <linux/module.h>
@@ -203,6 +208,9 @@ MODULE_LICENSE("GPL");
#include "3w-xxxx.h"
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int tw_chrdev_open(struct inode *inode, struct file *file);
+static int tw_chrdev_release(struct inode *inode, struct file *file);
static int tw_copy_info(TW_Info *info, char *fmt, ...);
static void tw_copy_mem_info(TW_Info *info, char *data, int len);
static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -216,10 +224,19 @@ static struct notifier_block tw_notifier = {
tw_halt, NULL, 0
};
+/* File operations struct for character device */
+static struct file_operations tw_fops = {
+ owner: THIS_MODULE,
+ ioctl: tw_chrdev_ioctl,
+ open: tw_chrdev_open,
+ release: tw_chrdev_release
+};
+
/* Globals */
-char *tw_driver_version="1.02.00.031";
+char *tw_driver_version="1.02.00.032";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
+static int twe_major = -1;
/* Functions */
@@ -599,6 +616,209 @@ int tw_check_errors(TW_Device_Extension *tw_dev)
return 0;
} /* End tw_check_errors() */
+/* This function handles ioctl for the character device */
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int error, request_id;
+ dma_addr_t dma_handle;
+ unsigned short tw_aen_code;
+ struct timeval before, timeout;
+ unsigned long flags = 0x0;
+ unsigned int data_buffer_length = 0;
+ unsigned long data_buffer_length_adjusted = 0;
+ unsigned long *cpu_addr;
+ TW_New_Ioctl *tw_ioctl;
+ TW_Passthru *passthru;
+ TW_Device_Extension *tw_dev = tw_device_extension_list[minor(inode->i_rdev)];
+
+ dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
+
+ /* Only let one of these through at a time */
+ if (test_and_set_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags)) {
+ return -EBUSY;
+ }
+
+ /* First copy down the buffer length */
+ error = copy_from_user(&data_buffer_length, (void *)arg, sizeof(unsigned int));
+ if (error) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying buffer length from userspace.\n");
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ return -EFAULT;
+ }
+
+ /* Check size */
+ if (data_buffer_length > TW_MAX_SECTORS * 512) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Invalid buffer size (%d).\n", data_buffer_length);
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ return -EFAULT;
+ }
+
+ /* Hardware can only do multiple of 512 byte transfers */
+ if (data_buffer_length % 512)
+ data_buffer_length_adjusted = data_buffer_length + 512 - (data_buffer_length % 512);
+ else
+ data_buffer_length_adjusted = data_buffer_length;
+
+ /* Now allocate ioctl buf memory */
+ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle);
+ if (cpu_addr == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error allocating memory.\n");
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ return -ENOMEM;
+ }
+
+ tw_ioctl = (TW_New_Ioctl *)cpu_addr;
+
+ /* Now copy down the entire ioctl */
+ error = copy_from_user(tw_ioctl, (void *)arg, data_buffer_length + sizeof(TW_New_Ioctl) - 1);
+ if (error) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data from userspace.\n");
+ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ return -EFAULT;
+ }
+
+ passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
+
+ /* See which ioctl we are doing */
+ switch (cmd) {
+ case TW_OP_NOP:
+ dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");
+ break;
+ case TW_OP_AEN_LISTEN:
+ dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");
+ memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length);
+ if (tw_dev->aen_head == tw_dev->aen_tail) {
+ tw_aen_code = TW_AEN_QUEUE_EMPTY;
+ } else {
+ tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
+ if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+ tw_dev->aen_head = TW_Q_START;
+ } else {
+ tw_dev->aen_head = tw_dev->aen_head + 1;
+ }
+ }
+ memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));
+ break;
+ case TW_CMD_PACKET_WITH_DATA:
+ dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+ spin_lock_irqsave(&tw_dev->tw_lock, flags);
+
+ tw_state_request_start(tw_dev, &request_id);
+
+ /* Flag internal command */
+ tw_dev->srb[request_id] = 0;
+
+ /* Flag chrdev ioctl */
+ tw_dev->chrdev_request_id = request_id;
+
+ tw_ioctl->firmware_command.request_id = request_id;
+
+ /* Load the sg list */
+ switch (tw_ioctl->firmware_command.byte0.sgl_offset) {
+ case 2:
+ tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+ tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
+ break;
+ case 3:
+ tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+ tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;
+ break;
+ case 5:
+ passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+ passthru->sg_list[0].length = data_buffer_length_adjusted;
+ break;
+ }
+
+ memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));
+
+ /* Now post the command packet to the controller */
+ tw_post_command_packet(tw_dev, request_id);
+ spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+
+ /* Now wait for the command to complete */
+ do_gettimeofday(&before);
+
+ tw_ioctl_chrdev_retry:
+
+ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+ interruptible_sleep_on_timeout(&tw_dev->ioctl_wqueue, 1);
+ do_gettimeofday(&timeout);
+ if (before.tv_sec + TW_IOCTL_CHRDEV_TIMEOUT < timeout.tv_sec) {
+ /* Now we need to reset the board */
+ printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
+ spin_lock_irqsave(&tw_dev->tw_lock, flags);
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ tw_state_request_finish(tw_dev, request_id);
+ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+ tw_dev->posted_request_count--;
+ if (tw_reset_device_extension(tw_dev)) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
+ }
+ spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ if (signal_pending(current))
+ return -EINTR;
+ else
+ return -EIO;
+ } else {
+ goto tw_ioctl_chrdev_retry;
+ }
+ }
+
+ /* Now copy in the command packet response */
+ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
+
+ /* Now complete the io */
+ spin_lock_irqsave(&tw_dev->tw_lock, flags);
+ tw_dev->posted_request_count--;
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ tw_state_request_finish(tw_dev, request_id);
+ spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+ break;
+ default:
+ printk(KERN_WARNING "3w-xxxx: Unknown chrdev ioctl 0x%x.\n", cmd);
+ }
+
+ /* Now copy the response to userspace */
+ error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + tw_ioctl->data_buffer_length - 1);
+ if (error) {
+ printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data to userspace.\n");
+ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+ return -EFAULT;
+ }
+
+ /* Now free ioctl buf memory */
+ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+
+ clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+
+ return 0;
+} /* End tw_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int tw_chrdev_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor_number;
+
+ dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
+
+ minor_number = minor(inode->i_rdev);
+ if (minor_number >= tw_device_extension_count)
+ return -ENODEV;
+
+ return 0;
+} /* End tw_chrdev_open() */
+
+/* This function handles close for the character device */
+static int tw_chrdev_release(struct inode *inode, struct file *file)
+{
+ dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n");
+
+ return 0;
+} /* End tw_chrdev_release() */
+
/* This function will clear all interrupts on the controller */
void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
{
@@ -867,7 +1087,9 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Disable interrupts on the card */
tw_disable_interrupts(tw_dev);
-
+
+ tries = 0;
+
while (tries < TW_MAX_RESET_TRIES) {
/* Do soft reset */
tw_soft_reset(tw_dev);
@@ -897,8 +1119,8 @@ int tw_findcards(Scsi_Host_Template *tw_host)
continue;
}
- /* Make sure that io region isn't already taken */
- if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) {
+ /* Reserve the io address space */
+ if (!request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME)) {
printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n",
(tw_dev->tw_pci_dev->resource[0].start),
(tw_dev->tw_pci_dev->resource[0].start) +
@@ -907,16 +1129,10 @@ int tw_findcards(Scsi_Host_Template *tw_host)
kfree(tw_dev);
continue;
}
-
- /* Reserve the io address space */
- 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: No valid units for for card %d.\n", j);
- release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
- tw_free_device_extension(tw_dev);
- kfree(tw_dev);
- continue;
}
error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
@@ -935,7 +1151,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
if (tw_dev->num_units > 0) {
/* Use SHT cmd_per_lun here */
tw_dev->free_head = TW_Q_START;
- tw_dev->free_tail = TW_Q_LENGTH - 1;
+ tw_dev->free_tail = TW_Q_START;
tw_dev->free_wrap = TW_Q_LENGTH - 1;
}
@@ -992,13 +1208,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Tell the firmware we support shutdown notification*/
error = tw_setfeature(tw_dev2, 2, 1, &c);
if (error) {
- printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j);
- scsi_unregister(host);
- release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
- tw_free_device_extension(tw_dev);
- kfree(tw_dev);
- numcards--;
- continue;
+ printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j);
}
/* Now setup the interrupt handler */
@@ -1023,10 +1233,14 @@ int tw_findcards(Scsi_Host_Template *tw_host)
}
}
- if (numcards == 0)
- printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n");
- else
- register_reboot_notifier(&tw_notifier);
+ if (numcards == 0) {
+ printk(KERN_WARNING "3w-xxxx: No cards found.\n");
+ } else {
+ register_reboot_notifier(&tw_notifier);
+ if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) {
+ printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major);
+ }
+ }
return numcards;
} /* End tw_findcards() */
@@ -1153,6 +1367,8 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
tw_dev->pending_head = TW_Q_START;
tw_dev->pending_tail = TW_Q_START;
spin_lock_init(&tw_dev->tw_lock);
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+ init_waitqueue_head(&tw_dev->ioctl_wqueue);
return 0;
} /* End tw_initialize_device_extension() */
@@ -1395,9 +1611,14 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Check for internal command completion */
if (tw_dev->srb[request_id] == 0) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
- 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);
+ /* Check for chrdev ioctl completion */
+ if (request_id != tw_dev->chrdev_request_id) {
+ 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);
+ }
+ } else {
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
}
} else {
switch (tw_dev->srb[request_id]->cmnd[0]) {
@@ -1409,6 +1630,10 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
case WRITE_6:
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
break;
+ case TEST_UNIT_READY:
+ dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+ error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+ break;
case INQUIRY:
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
error = tw_scsiop_inquiry_complete(tw_dev, request_id);
@@ -2070,12 +2295,13 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
tw_dev->state[i] = TW_S_INITIAL;
}
tw_dev->free_head = TW_Q_START;
- tw_dev->free_tail = TW_Q_LENGTH - 1;
+ tw_dev->free_tail = TW_Q_START;
tw_dev->posted_request_count = 0;
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;
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
return 0;
} /* End tw_reset_device_extension() */
@@ -2357,7 +2583,6 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
unsigned char *command = SCpnt->cmnd;
int request_id = 0;
int error = 0;
- unsigned long flags = 0;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
if (tw_dev == NULL) {
@@ -2367,14 +2592,14 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
return 0;
}
- spin_lock_irqsave(&tw_dev->tw_lock, flags);
+ spin_lock(&tw_dev->tw_lock);
dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
/* Skip scsi command if it isn't for us */
- if ((tw_dev->is_unit_present[SCpnt->device->id] == FALSE) || (SCpnt->device->lun != 0)) {
+ if ((SCpnt->device->channel != 0) || (SCpnt->device->lun != 0)) {
SCpnt->result = (DID_BAD_TARGET << 16);
done(SCpnt);
- spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+ spin_unlock(&tw_dev->tw_lock);
return 0;
}
@@ -2387,6 +2612,9 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
/* Save the scsi command for use by the ISR */
tw_dev->srb[request_id] = SCpnt;
+ /* Initialize phase to zero */
+ SCpnt->SCp.phase = 0;
+
switch (*command) {
case READ_10:
case READ_6:
@@ -2436,7 +2664,7 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->result = (DID_ERROR << 16);
done(SCpnt);
}
- spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+ spin_unlock(&tw_dev->tw_lock);
return 0;
} /* End tw_scsi_queue() */
@@ -2460,6 +2688,12 @@ int tw_scsi_release(struct Scsi_Host *tw_host)
/* Free up the IRQ */
free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+ /* Unregister character device */
+ if (twe_major >= 0) {
+ unregister_chrdev(twe_major, "twe");
+ twe_major = -1;
+ }
+
/* Free up device extension resources */
tw_free_device_extension(tw_dev);
@@ -2533,7 +2767,6 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
{
unsigned char *is_unit_present;
unsigned char *request_buffer;
- int i;
TW_Param *param;
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
@@ -2545,12 +2778,12 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
}
request_buffer = tw_dev->srb[request_id]->request_buffer;
memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
- request_buffer[0] = TYPE_DISK; /* Peripheral device type */
- request_buffer[1] = 0; /* Device type modifier */
- request_buffer[2] = 0; /* No ansi/iso compliance */
- request_buffer[4] = 31; /* Additional length */
+ request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+ request_buffer[1] = 0; /* Device type modifier */
+ request_buffer[2] = 0; /* No ansi/iso compliance */
+ request_buffer[4] = 31; /* Additional length */
memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */
- memcpy(&request_buffer[16], "3w-xxxx ", 16); /* Product ID */
+ sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
memcpy(&request_buffer[32], tw_driver_version, 3);
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -2560,15 +2793,12 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
}
is_unit_present = &(param->data[0]);
- for (i=0 ; i<TW_MAX_UNITS; i++) {
- if (is_unit_present[i] == 0) {
- tw_dev->is_unit_present[i] = FALSE;
- } else {
- if (is_unit_present[i] & TW_UNIT_ONLINE) {
- tw_dev->is_unit_present[i] = TRUE;
- dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete: Unit %d found.\n", i);
- }
- }
+ if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+ tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
+ } else {
+ tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
+ tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+ return TW_ISR_DONT_RESULT;
}
return 0;
@@ -2946,17 +3176,88 @@ int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
/* This function will handle test unit ready scsi command */
int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
{
+ TW_Param *param;
+ TW_Command *command_packet;
+ unsigned long command_que_value;
+ u32 command_que_addr;
+ unsigned long param_value;
+
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
- /* Tell the scsi layer were done */
- tw_dev->state[request_id] = TW_S_COMPLETED;
- tw_state_request_finish(tw_dev, request_id);
- tw_dev->srb[request_id]->result = (DID_OK << 16);
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+ /* Initialize command packet */
+ command_que_addr = tw_dev->registers.command_que_addr;
+ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+ if (command_packet == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+ return 1;
+ }
+ memset(command_packet, 0, sizeof(TW_Sector));
+ command_packet->byte0.opcode = TW_OP_GET_PARAM;
+ command_packet->byte0.sgl_offset = 2;
+ command_packet->size = 4;
+ command_packet->request_id = request_id;
+ command_packet->byte3.unit = 0;
+ command_packet->byte3.host_id = 0;
+ command_packet->status = 0;
+ command_packet->flags = 0;
+ command_packet->byte6.parameter_count = 1;
+
+ /* Now setup the param */
+ if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
+ return 1;
+ }
+ param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+ memset(param, 0, sizeof(TW_Sector));
+ param->table_id = 3; /* unit summary table */
+ param->parameter_id = 3; /* unitsstatus parameter */
+ param->parameter_size_bytes = TW_MAX_UNITS;
+ param_value = tw_dev->alignment_physical_address[request_id];
+ if (param_value == 0) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
+ return 1;
+ }
+
+ command_packet->byte8.param.sgl[0].address = param_value;
+ command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+ command_que_value = tw_dev->command_packet_physical_address[request_id];
+ if (command_que_value == 0) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+ return 1;
+ }
+
+ /* Now try to post the command packet */
+ tw_post_command_packet(tw_dev, request_id);
return 0;
} /* End tw_scsiop_test_unit_ready() */
+/* This function is called by the isr to complete a testunitready command */
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+ unsigned char *is_unit_present;
+ TW_Param *param;
+
+ dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
+
+ param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+ if (param == NULL) {
+ printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+ return 1;
+ }
+ is_unit_present = &(param->data[0]);
+
+ if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+ tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
+ } else {
+ tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
+ tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+ return TW_ISR_DONT_RESULT;
+ }
+
+ return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
+
/* Set a value in the features table */
int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
unsigned char *val)
@@ -3091,17 +3392,13 @@ int tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id)
{
dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n");
- do {
- if (tw_dev->free_tail == tw_dev->free_wrap) {
- tw_dev->free_tail = TW_Q_START;
- } else {
- tw_dev->free_tail = tw_dev->free_tail + 1;
- }
- } while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_tail]] != TW_S_COMPLETED));
-
tw_dev->free_queue[tw_dev->free_tail] = request_id;
-
tw_dev->state[request_id] = TW_S_FINISHED;
+ if (tw_dev->free_tail == tw_dev->free_wrap)
+ tw_dev->free_tail = TW_Q_START;
+ else
+ tw_dev->free_tail++;
+
dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing request_id %d\n", request_id);
return 0;
@@ -3115,20 +3412,16 @@ int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
/* Obtain next free request_id */
- do {
- if (tw_dev->free_head == tw_dev->free_wrap) {
- tw_dev->free_head = TW_Q_START;
- } else {
- tw_dev->free_head = tw_dev->free_head + 1;
- }
- } while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK);
-
id = tw_dev->free_queue[tw_dev->free_head];
+ if (tw_dev->free_head == tw_dev->free_wrap)
+ tw_dev->free_head = TW_Q_START;
+ else
+ tw_dev->free_head++;
- dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
*request_id = id;
tw_dev->state[id] = TW_S_STARTED;
+ dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
return 0;
} /* End tw_state_request_start() */
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 48a550c4107f..7c1947966d66 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -6,7 +6,7 @@
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Brad Strand <linux@3ware.com>
- Copyright (C) 1999-2002 3ware Inc.
+ Copyright (C) 1999-2003 3ware Inc.
Kernel compatiblity By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
@@ -113,11 +113,11 @@ static unsigned char tw_sense_table[][4] =
{0x84, 0x0b, 0x47, 0x00}, // Data CRC error SCSI parity error
{0xd0, 0x0b, 0x00, 0x00}, // Device busy Aborted command
{0xd1, 0x0b, 0x00, 0x00}, // Device busy Aborted command
+ {0x37, 0x02, 0x04, 0x00}, // Unit offline Not ready
/* Codes for older firmware */
// 3ware Error SCSI Error
{0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error Aborted command
- {0x37, 0x0b, 0x04, 0x00}, // Unit offline Logical unit not ready
{0x51, 0x0b, 0x00, 0x00} // Unspecified Aborted command
};
@@ -219,18 +219,23 @@ 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 255
+#define TW_MAX_CMDS_PER_LUN 254 /* 254 for io, 1 for
+ chrdev ioctl, one for
+ internal aen post */
#define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */
#define TW_IOCTL 0x80
#define TW_UNIT_ONLINE 1
#define TW_IN_INTR 1
#define TW_IN_IOCTL 2
+#define TW_IN_CHRDEV_IOCTL 3
#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
#define TW_IOCTL_TIMEOUT 25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT 25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_FREE -1
/* Macros */
#define TW_STATUS_ERRORS(x) \
@@ -246,6 +251,8 @@ static unsigned char tw_sense_table[][4] =
#define dprintk(msg...) do { } while(0)
#endif
+#pragma pack(1)
+
/* Scatter Gather List Entry */
typedef struct TAG_TW_SG_Entry {
u32 address;
@@ -295,6 +302,8 @@ typedef struct TW_Command {
} byte8;
} TW_Command;
+#pragma pack()
+
typedef struct TAG_TW_Ioctl {
unsigned char opcode;
unsigned short table_id;
@@ -304,6 +313,16 @@ typedef struct TAG_TW_Ioctl {
unsigned char data[1];
} TW_Ioctl;
+#pragma pack(1)
+
+/* Structure for new chardev ioctls */
+typedef struct TAG_TW_New_Ioctl {
+ unsigned int data_buffer_length;
+ unsigned char padding [508];
+ TW_Command firmware_command;
+ char data_buffer[1];
+} TW_New_Ioctl;
+
/* GetParam descriptor */
typedef struct {
unsigned short table_id;
@@ -414,8 +433,12 @@ typedef struct TAG_TW_Device_Extension {
unsigned long *ioctl_data[TW_Q_LENGTH];
int reset_print;
char online;
+ volatile int chrdev_request_id;
+ wait_queue_head_t ioctl_wqueue;
} TW_Device_Extension;
+#pragma pack()
+
/* Function prototypes */
int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
@@ -463,6 +486,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id);
int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
unsigned char *val);
int tw_setup_irq(TW_Device_Extension *tw_dev);
@@ -483,9 +507,10 @@ void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
.eh_abort_handler = tw_scsi_eh_abort, \
.eh_host_reset_handler = tw_scsi_eh_reset, \
.bios_param = tw_scsi_biosparam, \
- .can_queue = TW_Q_LENGTH-1, \
+ .can_queue = TW_Q_LENGTH-2, \
.this_id = -1, \
.sg_tablesize = TW_MAX_SGL_LENGTH, \
+ .max_sectors = TW_MAX_SECTORS, \
.cmd_per_lun = TW_MAX_CMDS_PER_LUN, \
.present = 0, \
.unchecked_isa_dma = 0, \
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 7fd1ccaffd2d..55d7c145d5b3 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -1463,9 +1463,9 @@ NCR53c7x0_init_fixup (struct Scsi_Host *host) {
patch_abs_32 (hostdata->script, 0, test_src,
virt_to_bus(&hostdata->test_source));
patch_abs_32 (hostdata->script, 0, saved_dsa,
- virt_to_bus(&hostdata->saved2_dsa));
+ virt_to_bus((void *)&hostdata->saved2_dsa));
patch_abs_32 (hostdata->script, 0, emulfly,
- virt_to_bus(&hostdata->emulated_intfly));
+ virt_to_bus((void *)&hostdata->emulated_intfly));
patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
(unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
@@ -1759,7 +1759,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
static void
NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->host;
+ struct Scsi_Host *host = c->device->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata[0];
int i;
@@ -1784,18 +1784,18 @@ NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
*/
patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_lun, c->lun);
+ dsa_temp_lun, c->device->lun);
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
Ent_dsa_code_template + A_dsa_next);
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script));
+ dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script));
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710));
+ dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710));
patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_target, 1 << c->target);
+ dsa_temp_target, 1 << c->device->id);
/* XXX - new pointer stuff */
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
@@ -1856,7 +1856,7 @@ run_process_issue_queue(void) {
static void
abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->host;
+ struct Scsi_Host *host = c->device->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata[0];
unsigned long flags;
@@ -1940,7 +1940,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
host->host_no, c->pid);
else if (linux_search) {
*linux_prev = linux_search->next;
- --hostdata->busy[c->target][c->lun];
+ --hostdata->busy[c->device->id][c->device->lun];
}
/* Return the NCR command structure to the free list */
@@ -2287,9 +2287,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
hostdata->dsp_changed = 1;
if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
printk ("scsi%d : target %d rejected SDTR\n", host->host_no,
- c->target);
+ c->device->id);
cmd->flags &= ~CMD_FLAG_SDTR;
- asynchronous (host, c->target);
+ asynchronous (host, c->device->id);
print = 0;
}
break;
@@ -2311,7 +2311,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (print) {
printk ("scsi%d : received message", host->host_no);
if (c)
- printk (" from target %d lun %d ", c->target, c->lun);
+ printk (" from target %d lun %d ", c->device->id, c->device->lun);
print_msg ((unsigned char *) hostdata->msg_buf);
printk("\n");
}
@@ -2331,7 +2331,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (cmd) {
char buf[80];
- sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target,
+ sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id,
(cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
@@ -2346,10 +2346,10 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (cmd->flags & CMD_FLAG_SDTR) {
cmd->flags &= ~CMD_FLAG_SDTR;
if (hostdata->msg_buf[4])
- synchronous (host, c->target, (unsigned char *)
+ synchronous (host, c->device->id, (unsigned char *)
hostdata->msg_buf);
else
- asynchronous (host, c->target);
+ asynchronous (host, c->device->id);
hostdata->dsp = hostdata->script + hostdata->E_accept_message /
sizeof(u32);
hostdata->dsp_changed = 1;
@@ -2357,11 +2357,11 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
} else {
if (hostdata->options & OPTION_SYNCHRONOUS) {
cmd->flags |= CMD_FLAG_DID_SDTR;
- synchronous (host, c->target, (unsigned char *)
+ synchronous (host, c->device->id, (unsigned char *)
hostdata->msg_buf);
} else {
hostdata->msg_buf[4] = 0; /* 0 offset = async */
- asynchronous (host, c->target);
+ asynchronous (host, c->device->id);
}
patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
@@ -2545,9 +2545,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
host->host_no, NCR53c7x0_read8(SXFER_REG));
if (c) {
print_insn (host, (u32 *)
- hostdata->sync[c->target].script, "", 1);
+ hostdata->sync[c->device->id].script, "", 1);
print_insn (host, (u32 *)
- hostdata->sync[c->target].script + 2, "", 1);
+ hostdata->sync[c->device->id].script + 2, "", 1);
}
}
return SPECIFIC_INT_RESTART;
@@ -2658,7 +2658,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
if (c)
printk("scsi%d : target %d lun %d disconnecting\n",
- host->host_no, c->target, c->lun);
+ host->host_no, c->device->id, c->device->lun);
else
printk("scsi%d : unknown target disconnecting\n",
host->host_no);
@@ -2680,9 +2680,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
#endif
if (c) {
print_insn (host, (u32 *)
- hostdata->sync[c->target].script, "", 1);
+ hostdata->sync[c->device->id].script, "", 1);
print_insn (host, (u32 *)
- hostdata->sync[c->target].script + 2, "", 1);
+ hostdata->sync[c->device->id].script + 2, "", 1);
}
}
return SPECIFIC_INT_RESTART;
@@ -2734,8 +2734,8 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if ((hostdata->chip / 100) == 8) {
scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
if (c) {
- if (sxfer != hostdata->sync[c->target].sxfer_sanity ||
- scntl3 != hostdata->sync[c->target].scntl3_sanity) {
+ if (sxfer != hostdata->sync[c->device->id].sxfer_sanity ||
+ scntl3 != hostdata->sync[c->device->id].scntl3_sanity) {
printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x",
host->host_no, sxfer, scntl3);
NCR53c7x0_write8 (SXFER_REG, sxfer);
@@ -2746,12 +2746,12 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
host->host_no, (int) sxfer, (int) scntl3);
} else {
if (c) {
- if (sxfer != hostdata->sync[c->target].sxfer_sanity) {
+ if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) {
printk ("scsi%d : sync sanity check failed sxfer=0x%x",
host->host_no, sxfer);
NCR53c7x0_write8 (SXFER_REG, sxfer);
NCR53c7x0_write8 (SBCL_REG,
- hostdata->sync[c->target].sscf_710);
+ hostdata->sync[c->device->id].sscf_710);
}
} else
printk ("scsi%d : unknown command sxfer=0x%x\n",
@@ -2807,9 +2807,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
(DCMD_REG)) == hostdata->script +
Ent_select_check_dsa / sizeof(u32) ?
"selection" : "reselection";
- if (c && sdid != c->target) {
+ if (c && sdid != c->device->id) {
printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
- host->host_no, sdid, c->target, where);
+ host->host_no, sdid, c->device->id, where);
print_lots(host);
dump_events (host, 20);
return SPECIFIC_INT_PANIC;
@@ -2855,7 +2855,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (event->event == EVENT_RESELECT)
event->lun = hostdata->reselected_identify & 0xf;
else if (c)
- event->lun = c->lun;
+ event->lun = c->device->lun;
else
event->lun = 255;
do_gettimeofday(&(event->time));
@@ -3049,7 +3049,7 @@ my_free_page (void *addr, int dummy)
static struct NCR53c7x0_cmd *
allocate_cmd (Scsi_Cmnd *cmd) {
- struct Scsi_Host *host = cmd->host;
+ struct Scsi_Host *host = cmd->device->host;
struct NCR53c7x0_hostdata *hostdata =
(struct NCR53c7x0_hostdata *) host->hostdata[0];
u32 real; /* Real address */
@@ -3061,8 +3061,8 @@ allocate_cmd (Scsi_Cmnd *cmd) {
printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
" target = %d, lun = %d, %s\n",
host->host_no, hostdata->num_cmds, host->can_queue,
- cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] &
- (1 << cmd->lun)) ? "already allocated" : "not allocated");
+ cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
+ (1 << cmd->device->lun)) ? "already allocated" : "not allocated");
/*
* If we have not yet reserved commands for this I_T_L nexus, and
@@ -3070,11 +3070,11 @@ allocate_cmd (Scsi_Cmnd *cmd) {
* being allocated under 1.3.x, or being outside of scan_scsis in
* 1.2.x), do so now.
*/
- if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) &&
+ if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
cmd->device && cmd->device->has_cmdblocks) {
if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
hostdata->extra_allocate += host->cmd_per_lun;
- hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun);
+ hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
}
for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
@@ -3130,7 +3130,7 @@ allocate_cmd (Scsi_Cmnd *cmd) {
local_irq_restore(flags);
if (!tmp)
printk ("scsi%d : can't allocate command for target %d lun %d\n",
- host->host_no, cmd->target, cmd->lun);
+ host->host_no, cmd->device->id, cmd->device->lun);
return tmp;
}
@@ -3150,7 +3150,7 @@ allocate_cmd (Scsi_Cmnd *cmd) {
static struct NCR53c7x0_cmd *
create_cmd (Scsi_Cmnd *cmd) {
NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->host;
+ struct Scsi_Host *host = cmd->device->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata[0];
struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
@@ -3166,7 +3166,7 @@ create_cmd (Scsi_Cmnd *cmd) {
#endif
unsigned long flags;
u32 exp_select_indirect; /* Used in sanity check */
- NCR53c7x0_local_setup(cmd->host);
+ NCR53c7x0_local_setup(cmd->device->host);
if (!(tmp = allocate_cmd (cmd)))
return NULL;
@@ -3322,45 +3322,45 @@ create_cmd (Scsi_Cmnd *cmd) {
if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
- exp_select_indirect = ((1 << cmd->target) << 16) |
- (hostdata->sync[cmd->target].sxfer_sanity << 8);
+ exp_select_indirect = ((1 << cmd->device->id) << 16) |
+ (hostdata->sync[cmd->device->id].sxfer_sanity << 8);
- if (hostdata->sync[cmd->target].select_indirect !=
+ if (hostdata->sync[cmd->device->id].select_indirect !=
exp_select_indirect) {
printk ("scsi%d : sanity check failed select_indirect=0x%x\n",
- host->host_no, hostdata->sync[cmd->target].select_indirect);
+ host->host_no, hostdata->sync[cmd->device->id].select_indirect);
FATAL(host);
}
}
patch_dsa_32(tmp->dsa, dsa_select, 0,
- hostdata->sync[cmd->target].select_indirect);
+ hostdata->sync[cmd->device->id].select_indirect);
/*
* Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
* different commands; although it should be trivial to do them
* both at the same time.
*/
- if (hostdata->initiate_wdtr & (1 << cmd->target)) {
+ if (hostdata->initiate_wdtr & (1 << cmd->device->id)) {
memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
sizeof(wdtr_message));
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
local_irq_save(flags);
- hostdata->initiate_wdtr &= ~(1 << cmd->target);
+ hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
local_irq_restore(flags);
- } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
+ } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
sizeof(sdtr_message));
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
tmp->flags |= CMD_FLAG_SDTR;
local_irq_save(flags);
- hostdata->initiate_sdtr &= ~(1 << cmd->target);
+ hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
local_irq_restore(flags);
}
#if 1
- else if (!(hostdata->talked_to & (1 << cmd->target)) &&
+ else if (!(hostdata->talked_to & (1 << cmd->device->id)) &&
!(hostdata->options & OPTION_NO_ASYNC)) {
memcpy ((void *) (tmp->select + 1), (void *) async_message,
@@ -3372,9 +3372,9 @@ create_cmd (Scsi_Cmnd *cmd) {
else
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
- hostdata->talked_to |= (1 << cmd->target);
+ hostdata->talked_to |= (1 << cmd->device->id);
tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
- IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
+ IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun);
patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
@@ -3591,7 +3591,7 @@ create_cmd (Scsi_Cmnd *cmd) {
int
NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
- struct Scsi_Host *host = cmd->host;
+ struct Scsi_Host *host = cmd->device->host;
struct NCR53c7x0_hostdata *hostdata =
(struct NCR53c7x0_hostdata *) host->hostdata[0];
unsigned long flags;
@@ -3604,9 +3604,9 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
#ifdef VALID_IDS
/* Ignore commands on invalid IDs */
- if (!hostdata->valid_ids[cmd->target]) {
+ if (!hostdata->valid_ids[cmd->device->id]) {
printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
return 0;
@@ -3616,16 +3616,16 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
local_irq_save(flags);
if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
|| ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
- !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun)))
+ !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
#ifdef LINUX_1_2
- || cmd->target > 7
+ || cmd->device->id > 7
#else
- || cmd->target > host->max_id
+ || cmd->device->id > host->max_id
#endif
- || cmd->target == host->this_id
+ || cmd->device->id == host->this_id
|| hostdata->state == STATE_DISABLED) {
printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
local_irq_restore(flags);
@@ -3738,7 +3738,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
--i, ncrcurrent += 2 /* JUMP instructions are two words */);
if (i > 0) {
- ++hostdata->busy[tmp->target][tmp->lun];
+ ++hostdata->busy[tmp->device->id][tmp->device->lun];
cmd->next = hostdata->running_list;
hostdata->running_list = cmd;
@@ -3799,7 +3799,7 @@ busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
/* FIXME : in the future, this needs to accommodate SCSI-II tagged
queuing, and we may be able to play with fairness here a bit.
*/
- return hostdata->busy[cmd->target][cmd->lun];
+ return hostdata->busy[cmd->device->id][cmd->device->lun];
}
/*
@@ -3873,7 +3873,7 @@ process_issue_queue (unsigned long flags) {
if (tmp->host_scribble) {
if (hostdata->options & OPTION_DEBUG_QUEUES)
printk ("scsi%d : moving command for target %d lun %d to start list\n",
- host->host_no, tmp->target, tmp->lun);
+ host->host_no, tmp->device->id, tmp->device->lun);
to_schedule_list (host, hostdata,
@@ -3937,7 +3937,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
printk ("scsi%d : Selection Timeout\n", host->host_no);
if (cmd) {
printk("scsi%d : target %d, lun %d, command ",
- host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
print_command (cmd->cmd->cmnd);
printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
NCR53c7x0_read32(DSP_REG),
@@ -3975,7 +3975,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
fatal = 1;
if (cmd) {
printk("scsi%d : target %d lun %d unexpected disconnect\n",
- host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
print_lots (host);
abnormal_finished(cmd, DID_ERROR << 16);
} else
@@ -3991,7 +3991,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
fatal = 1;
if (cmd && cmd->cmd) {
printk("scsi%d : target %d lun %d parity error.\n",
- host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
abnormal_finished (cmd, DID_PARITY << 16);
} else
printk("scsi%d : parity error\n", host->host_no);
@@ -4199,7 +4199,7 @@ restart:
if (cmd_prev_ptr)
*cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
- --hostdata->busy[tmp->target][tmp->lun];
+ --hostdata->busy[tmp->device->id][tmp->device->lun];
cmd->next = hostdata->free;
hostdata->free = cmd;
@@ -4207,7 +4207,7 @@ restart:
if (hostdata->options & OPTION_DEBUG_INTR) {
printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ",
- host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result);
+ host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
print_command (tmp->cmnd);
}
@@ -4292,8 +4292,8 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
if (hostdata->options & OPTION_DEBUG_INTR) {
if (cmd) {
printk("scsi%d : interrupt for pid %lu, id %d, lun %d ",
- host->host_no, cmd->cmd->pid, (int) cmd->cmd->target,
- (int) cmd->cmd->lun);
+ host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
+ (int) cmd->cmd->device->lun);
print_command (cmd->cmd->cmnd);
} else {
printk("scsi%d : no active command\n", host->host_no);
@@ -4671,7 +4671,7 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
hostdata->dsp = dsp + 2 /* two _words_ */;
hostdata->dsp_changed = 1;
printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n",
- host->host_no, cmd->cmd->target);
+ host->host_no, cmd->cmd->device->id);
cmd->flags &= ~CMD_FLAG_SDTR;
action = ACTION_CONTINUE;
break;
@@ -5136,7 +5136,7 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
int
NCR53c7xx_abort (Scsi_Cmnd *cmd) {
NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->host;
+ struct Scsi_Host *host = cmd->device->host;
struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
host->hostdata[0] : NULL;
unsigned long flags;
@@ -5242,7 +5242,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
return SCSI_ABORT_NOT_RUNNING;
} else {
printk ("scsi%d : DANGER : command running, can not abort.\n",
- cmd->host->host_no);
+ cmd->device->host->host_no);
local_irq_restore(flags);
return SCSI_ABORT_BUSY;
}
@@ -5273,7 +5273,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
* command was ever counted as BUSY, so if we end up here we can
* decrement the busy count if and only if it is necessary.
*/
- --hostdata->busy[cmd->target][cmd->lun];
+ --hostdata->busy[cmd->device->id][cmd->device->lun];
}
local_irq_restore(flags);
cmd->scsi_done(cmd);
@@ -5318,7 +5318,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
* each command.
*/
Scsi_Cmnd *nuke_list = NULL;
- struct Scsi_Host *host = cmd->host;
+ struct Scsi_Host *host = cmd->device->host;
struct NCR53c7x0_hostdata *hostdata =
(struct NCR53c7x0_hostdata *) host->hostdata[0];
@@ -5388,7 +5388,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
static int
insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) cmd->host->hostdata[0];
+ (struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
struct NCR53c7x0_cmd *ncmd =
(struct NCR53c7x0_cmd *) cmd->host_scribble;
int offset = 0, buffers;
@@ -5418,7 +5418,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
--buffers, offset += segment->length, ++segment)
#if 0
printk("scsi%d: comparing 0x%p to 0x%p\n",
- cmd->host->host_no, saved, page_address(segment->page+segment->offset);
+ cmd->device->host->host_no, saved, page_address(segment->page+segment->offset);
#else
;
#endif
@@ -5456,7 +5456,7 @@ print_progress (Scsi_Cmnd *cmd) {
int offset, i;
char *where;
u32 *ptr;
- NCR53c7x0_local_setup (cmd->host);
+ NCR53c7x0_local_setup (cmd->device->host);
if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
{
@@ -5484,15 +5484,15 @@ print_progress (Scsi_Cmnd *cmd) {
if (offset != -1)
printk ("scsi%d : %s data pointer at offset %d\n",
- cmd->host->host_no, where, offset);
+ cmd->device->host->host_no, where, offset);
else {
int size;
printk ("scsi%d : can't determine %s data pointer offset\n",
- cmd->host->host_no, where);
+ cmd->device->host->host_no, where);
if (ncmd) {
- size = print_insn (cmd->host,
+ size = print_insn (cmd->device->host,
bus_to_virt(ncmd->saved_data_pointer), "", 1);
- print_insn (cmd->host,
+ print_insn (cmd->device->host,
bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
"", 1);
}
@@ -5549,7 +5549,7 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
/* XXX Maybe we should access cmd->host_scribble->result here. RGH */
if (cmd) {
printk(" result = 0x%x, target = %d, lun = %d, cmd = ",
- cmd->result, cmd->target, cmd->lun);
+ cmd->result, cmd->device->id, cmd->device->lun);
print_command(cmd->cmnd);
} else
printk("\n");
@@ -5558,11 +5558,11 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
if (cmd) {
printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
" script : ",
- host->host_no, cmd->target,
- hostdata->sync[cmd->target].sxfer_sanity,
- hostdata->sync[cmd->target].scntl3_sanity);
- for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i)
- printk ("0x%x ", hostdata->sync[cmd->target].script[i]);
+ host->host_no, cmd->device->id,
+ hostdata->sync[cmd->device->id].sxfer_sanity,
+ hostdata->sync[cmd->device->id].scntl3_sanity);
+ for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i)
+ printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]);
printk ("\n");
print_progress (cmd);
}
@@ -5604,7 +5604,7 @@ print_queues (struct Scsi_Host *host) {
-> dsa, "");
} else
printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
- host->host_no, cmd->pid, cmd->target, cmd->lun);
+ host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
local_irq_restore(flags);
}
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index a1f8470c1a5f..340614409b3b 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -1099,7 +1099,7 @@ do_sync_known:
* disconnect.
*/
ESPMISC(("esp: Selecting device for first time. target=%d "
- "lun=%d\n", target, SCptr->lun));
+ "lun=%d\n", target, SCptr->device->lun));
if(!SDptr->borken && !esp_dev->disconnect)
esp_dev->disconnect = 1;
@@ -1173,7 +1173,7 @@ do_sync_known:
if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
- "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
+ "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
esp_dev->disconnect = 0;
*cmdp++ = IDENTIFY(0, lun);
} else {
@@ -1255,8 +1255,8 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
esp->dma_led_on(esp);
/* We use the scratch area. */
- ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
- ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
+ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun));
+ ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun));
esp_get_dmabufs(esp, SCpnt);
esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
@@ -2235,7 +2235,7 @@ static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
* state.
*/
ESPMISC(("esp: Status <%d> for target %d lun %d\n",
- SCptr->SCp.Status, SCptr->target, SCptr->lun));
+ SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
/* But don't do this when spinning up a disk at
* boot time while we poll for completion as it
@@ -2246,14 +2246,14 @@ static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
if(esp_should_clear_sync(SCptr) != 0)
esp_dev->sync = 0;
}
- ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
+ ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
esp_done(esp, ((SCptr->SCp.Status & 0xff) |
((SCptr->SCp.Message & 0xff)<<8) |
(DID_OK << 16)));
} else if(esp->prevmsgin == DISCONNECT) {
/* Normal disconnect. */
esp_cmd(esp, eregs, ESP_CMD_ESEL);
- ESPDISC(("D<%02x,%02x>", SCptr->target, SCptr->lun));
+ ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
append_SC(&esp->disconnected_SC, SCptr);
esp->current_SC = NULL;
if(esp->issue_SC)
@@ -2811,7 +2811,7 @@ static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Else, there really isn't anyone there. */
ESPMISC(("esp: selection failure, maybe nobody there?\n"));
ESPMISC(("esp: target %d lun %d\n",
- SCptr->target, SCptr->lun));
+ SCptr->device->id, SCptr->device->lun));
esp_done(esp, (DID_BAD_TARGET << 16));
}
return do_intr_end;
@@ -3084,7 +3084,7 @@ static int check_multibyte_msg(struct NCR_ESP *esp,
ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
esp_dev->sync_max_offset,
esp_dev->sync_min_period,
- esp->config3[SCptr->target]));
+ esp->config3[SCptr->device->id]));
esp->snip = 0;
} else if(esp_dev->sync_max_offset) {
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index f8b04da74c83..bf82d0b2df1b 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -52,7 +52,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
- struct Scsi_Host *instance = cmd->host;
+ struct Scsi_Host *instance = cmd->device->host;
/* don't allow DMA if the physical address is bad */
if (addr & A2091_XFER_MASK ||
@@ -102,12 +102,12 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
cntr |= CNTR_DDIR;
/* remember direction */
- HDATA(cmd->host)->dma_dir = dir_in;
+ HDATA(cmd->device->host)->dma_dir = dir_in;
- DMA(cmd->host)->CNTR = cntr;
+ DMA(cmd->device->host)->CNTR = cntr;
/* setup DMA *physical* address */
- DMA(cmd->host)->ACR = addr;
+ DMA(cmd->device->host)->ACR = addr;
if (dir_in){
/* invalidate any cache */
@@ -117,7 +117,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
cache_push (addr, cmd->SCp.this_residual);
}
/* start DMA */
- DMA(cmd->host)->ST_DMA = 1;
+ DMA(cmd->device->host)->ST_DMA = 1;
/* return success */
return 0;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 28a393b68c5c..a6a56c9014f2 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -225,7 +225,7 @@ static Scsi_Host_Template driver_template = {
#include "scsi_module.c"
-int __exit a3000_release(struct Scsi_Host *instance)
+int a3000_release(struct Scsi_Host *instance)
{
wd33c93_release();
DMA(instance)->CNTR = 0;
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 715365d8c02c..89c454b2685f 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -86,7 +86,7 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
#ifdef CONFIG_WARPENGINE_SCSI
case ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx:
if (request_mem_region(address+0x40000, 0x1000, "ncr53c710")) {
- address = (unsigned long)ioremap(address, size);
+ address = (unsigned long)z_ioremap(address, size);
options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
OPTION_INTFLY | OPTION_SYNCHRONOUS |
OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
@@ -102,7 +102,7 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
case ZORRO_PROD_CBM_A4091_1:
case ZORRO_PROD_CBM_A4091_2:
if (request_mem_region(address+0x800000, 0x1000, "ncr53c710")) {
- address = (unsigned long)ioremap(address, size);
+ address = (unsigned long)z_ioremap(address, size);
options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
OPTION_INTFLY | OPTION_SYNCHRONOUS |
OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index df9da107d11b..387a14db1fa9 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -266,7 +266,7 @@ static Scsi_Host_Template *the_template = NULL;
#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
#define HOSTNO instance->host_no
-#define H_NO(cmd) (cmd)->host->host_no
+#define H_NO(cmd) (cmd)->device->host->host_no
#ifdef SUPPORT_TAGS
@@ -350,17 +350,17 @@ static void __init init_tags( void )
static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
- if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
return( 1 );
if (!should_be_tagged ||
!setup_use_tagged_queuing || !cmd->device->tagged_supported)
return( 0 );
- if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
- TagAlloc[cmd->target][cmd->lun].queue_size ) {
+ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+ TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->target, cmd->lun );
+ H_NO(cmd), cmd->device->id, cmd->device->lun );
return( 1 );
}
return( 0 );
@@ -374,7 +374,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
/* If we or the target don't support tagged queuing, allocate the LUN for
* an untagged command.
@@ -382,19 +382,19 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
if (!should_be_tagged ||
!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
cmd->tag = TAG_NONE;
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->target, cmd->lun );
+ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
}
else {
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
set_bit( cmd->tag, ta->allocated );
ta->nr_allocated++;
TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
"(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
ta->nr_allocated );
}
}
@@ -406,23 +406,23 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
static void cmd_free_tag( Scsi_Cmnd *cmd )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
if (cmd->tag == TAG_NONE) {
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->target, cmd->lun );
+ H_NO(cmd), cmd->device->id, cmd->device->lun );
}
else if (cmd->tag >= MAX_TAGS) {
printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
H_NO(cmd), cmd->tag );
}
else {
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
clear_bit( cmd->tag, ta->allocated );
ta->nr_allocated--;
TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
}
}
@@ -811,7 +811,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
int i, s;
unsigned char *command;
SPRINTF("scsi%d: destination target %d, lun %d\n",
- H_NO(cmd), cmd->target, cmd->lun);
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
SPRINTF(" command = ");
command = cmd->cmnd;
SPRINTF("%2d (0x%02x)", command[0], command[0]);
@@ -834,7 +834,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
*
*/
-static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
{
int i;
SETUP_HOSTDATA(instance);
@@ -878,6 +878,8 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ return 0;
}
/*
@@ -898,13 +900,10 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
*
*/
-/* Only make static if a wrapper function is used */
-#ifndef NCR5380_queue_command
static
-#endif
int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
Scsi_Cmnd *tmp;
int oldto;
unsigned long flags;
@@ -938,15 +937,15 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
case WRITE:
case WRITE_6:
case WRITE_10:
- hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
hostdata->pendingw++;
break;
case READ:
case READ_6:
case READ_10:
- hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
hostdata->pendingr++;
break;
}
@@ -1014,7 +1013,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
if (in_interrupt() || ((flags >> 8) & 7) >= 6)
queue_main();
else
- NCR5380_main();
+ NCR5380_main(NULL);
return 0;
}
@@ -1030,7 +1029,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* reenable them. This prevents reentrancy and kernel stack overflow.
*/
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
{
Scsi_Cmnd *tmp, *prev;
struct Scsi_Host *instance = first_instance;
@@ -1087,8 +1086,8 @@ static void NCR5380_main (void)
#if (NDEBUG & NDEBUG_LISTS)
if (prev != tmp)
printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
- tmp, tmp->target, hostdata->busy[tmp->target],
- tmp->lun);
+ tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+ tmp->device->lun);
#endif
/* When we find one, remove it from the issue queue. */
/* ++guenther: possible race with Falcon locking */
@@ -1096,7 +1095,7 @@ static void NCR5380_main (void)
#ifdef SUPPORT_TAGS
!is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
#else
- !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
#endif
) {
/* ++guenther: just to be sure, this must be atomic */
@@ -1122,7 +1121,7 @@ static void NCR5380_main (void)
*/
MAIN_PRINTK("scsi%d: main(): command for target %d "
"lun %d removed from issue_queue\n",
- HOSTNO, tmp->target, tmp->lun);
+ HOSTNO, tmp->device->id, tmp->device->lun);
/*
* REQUEST SENSE commands are issued without tagged
* queueing, even on SCSI-II devices because the
@@ -1356,15 +1355,15 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
case WRITE:
case WRITE_6:
case WRITE_10:
- hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
hostdata->pendingw--;
break;
case READ:
case READ_6:
case READ_10:
- hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
hostdata->pendingr--;
break;
}
@@ -1525,7 +1524,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
/*
* Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1578,7 +1577,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
udelay(1);
- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
/*
* The SCSI specification calls for a 250 ms timeout for the actual
@@ -1629,7 +1628,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->target)) {
+ if (hostdata->targets_present & (1 << cmd->device->id)) {
printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
if (hostdata->restart_select)
printk(KERN_NOTICE "\trestart select\n");
@@ -1651,7 +1650,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
return 0;
}
- hostdata->targets_present |= (1 << cmd->target);
+ hostdata->targets_present |= (1 << cmd->device->id);
/*
* Since we followed the SCSI spec, and raised ATN while SEL
@@ -1672,8 +1671,8 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
while (!(NCR5380_read(STATUS_REG) & SR_REQ));
SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->target);
- tmp[0] = IDENTIFY(1, cmd->lun);
+ HOSTNO, cmd->device->id);
+ tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
if (cmd->tag != TAG_NONE) {
@@ -1695,7 +1694,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
/* XXX need to handle errors here */
hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
#endif
initialize_SCp(cmd);
@@ -2085,7 +2084,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
* polled-IO. */
printk(KERN_NOTICE "scsi%d: switching target %d "
"lun %d to slow handshake\n", HOSTNO,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
cmd->device->borken = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
ICR_ASSERT_ATN);
@@ -2137,7 +2136,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
LNK_PRINTK("scsi%d: target %d lun %d linked command "
- "complete.\n", HOSTNO, cmd->target, cmd->lun);
+ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2150,7 +2149,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
if (!cmd->next_link) {
printk(KERN_NOTICE "scsi%d: target %d lun %d "
"linked command complete, no next_link\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
sink = 1;
do_abort (instance);
return;
@@ -2163,7 +2162,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
LNK_PRINTK("scsi%d: target %d lun %d linked request "
"done, calling scsi_done().\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef NCR5380_STATS
collect_stats(hostdata, cmd);
#endif
@@ -2179,7 +2178,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
falcon_dont_release++;
hostdata->connected = NULL;
QU_PRINTK("scsi%d: command for target %d, lun %d "
- "completed\n", HOSTNO, cmd->target, cmd->lun);
+ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2191,16 +2190,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
*/
/* ++Andreas: the mid level code knows about
QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
TAG_PRINTK("scsi%d: target %d lun %d returned "
"QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->target, cmd->lun,
+ HOSTNO, cmd->device->id, cmd->device->lun,
ta->nr_allocated);
if (ta->queue_size > ta->nr_allocated)
ta->nr_allocated = ta->queue_size;
}
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2296,12 +2295,12 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
* the command is treated as untagged further on.
*/
cmd->device->tagged_supported = 0;
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
cmd->tag = TAG_NONE;
TAG_PRINTK("scsi%d: target %d lun %d rejected "
"QUEUE_TAG message; tagged queuing "
"disabled\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
break;
}
break;
@@ -2318,7 +2317,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
@@ -2417,13 +2416,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
} else if (tmp != EXTENDED_MESSAGE)
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"message %02x from target %d, lun %d\n",
- HOSTNO, tmp, cmd->target, cmd->lun);
+ HOSTNO, tmp, cmd->device->id, cmd->device->lun);
else
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"extended message "
"code %02x, length %d from target %d, lun %d\n",
HOSTNO, extended_msg[1], extended_msg[0],
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
msgout = MESSAGE_REJECT;
@@ -2441,7 +2440,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
@@ -2577,7 +2576,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
tmp; prev = tmp, tmp = NEXT(tmp) ) {
- if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
&& (tag == tmp->tag)
#endif
@@ -2620,7 +2619,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
hostdata->connected = tmp;
RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
- HOSTNO, tmp->target, tmp->lun, tmp->tag);
+ HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
falcon_dont_release--;
}
@@ -2642,12 +2641,10 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
* called where the loop started in NCR5380_main().
*/
-#ifndef NCR5380_abort
static
-#endif
int NCR5380_abort (Scsi_Cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->host;
+ struct Scsi_Host *instance = cmd->device->host;
SETUP_HOSTDATA(instance);
Scsi_Cmnd *tmp, **prev;
unsigned long flags;
@@ -2701,7 +2698,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
local_irq_restore(flags);
cmd->scsi_done(cmd);
@@ -2808,7 +2805,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#ifdef SUPPORT_TAGS
cmd_free_tag( tmp );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
local_irq_restore(flags);
tmp->scsi_done(tmp);
@@ -2842,7 +2839,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
/*
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2850,9 +2847,9 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
*
*/
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
int i;
unsigned long flags;
#if 1
@@ -2863,7 +2860,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
H_NO(cmd) );
- NCR5380_print_status (cmd->host);
+ NCR5380_print_status (cmd->device->host);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 07c40bd87e67..17dfa0835bfb 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -819,11 +819,11 @@ void __init atari_scsi_setup(char *str, int *ints)
#endif
}
-int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
{
int rv;
struct NCR5380_hostdata *hostdata =
- (struct NCR5380_hostdata *)cmd->host->hostdata;
+ (struct NCR5380_hostdata *)cmd->device->host->hostdata;
/* For doing the reset, SCSI interrupts must be disabled first,
* since the 5380 raises its IRQ line while _RST is active and we
@@ -845,7 +845,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#endif /* REAL_DMA */
}
- rv = NCR5380_reset(cmd, reset_flags);
+ rv = NCR5380_bus_reset(cmd);
/* Re-enable ints */
if (IS_A_TT()) {
@@ -1146,8 +1146,8 @@ static Scsi_Host_Template driver_template = {
.release = atari_scsi_release,
.info = atari_scsi_info,
.queuecommand = atari_scsi_queue_command,
- .abort = atari_scsi_abort,
- .reset = atari_scsi_reset,
+ .eh_abort_handler = atari_scsi_abort,
+ .eh_bus_reset_handler = atari_scsi_bus_reset,
.can_queue = 0, /* initialized at run-time */
.this_id = 0, /* initialized at run-time */
.sg_tablesize = 0, /* initialized at run-time */
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index a6fd05a74d33..b417d6c6880c 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -18,10 +18,8 @@
/* (I_HAVE_OVERRUNS stuff removed) */
#ifndef ASM
-int atari_scsi_abort (Scsi_Cmnd *);
int atari_scsi_detect (Scsi_Host_Template *);
const char *atari_scsi_info (struct Scsi_Host *);
-int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
#ifdef MODULE
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 57296ffd25af..1fb8cd9890cf 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -167,8 +167,8 @@ int __init blz1230_esp_detect(Scsi_Host_Template *tpnt)
esp->eregs = eregs;
/* Set the command buffer */
- esp->esp_command = (volatile unsigned char*) cmd_buffer;
- esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+REAL_BLZ1230_ESP_ADDR;
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index 07a9220816a3..77f77e9cefdb 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -142,8 +142,8 @@ int __init blz2060_esp_detect(Scsi_Host_Template *tpnt)
esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
/* Set the command buffer */
- esp->esp_command = (volatile unsigned char*) cmd_buffer;
- esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index 83a3a0a9e5da..e795eeb78629 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -168,8 +168,8 @@ int __init cyber_esp_detect(Scsi_Host_Template *tpnt)
esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
/* Set the command buffer */
- esp->esp_command = (volatile unsigned char*) cmd_buffer;
- esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index 25eb423ce467..4d0bf3ed1456 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -149,8 +149,8 @@ int __init cyberII_esp_detect(Scsi_Host_Template *tpnt)
esp->eregs = eregs;
/* Set the command buffer */
- esp->esp_command = (volatile unsigned char*) cmd_buffer;
- esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index b58c0289ea14..62a473c3497e 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -191,8 +191,8 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt)
esp->edev = (void *) address;
/* Set the command buffer */
- esp->esp_command = (volatile unsigned char*) cmd_buffer;
- esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+FASTLANE_ESP_ADDR;
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index ad2d6c301d30..f3ec633166a6 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -62,61 +62,62 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
static int scsi_alloc_out_of_range = 0;
/* use bounce buffer if the physical address is bad */
- if (addr & HDATA(cmd->host)->dma_xfer_mask ||
+ if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
{
- HDATA(cmd->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+ HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
if( !scsi_alloc_out_of_range ) {
- HDATA(cmd->host)->dma_bounce_buffer =
- kmalloc (HDATA(cmd->host)->dma_bounce_len, GFP_KERNEL);
- HDATA(cmd->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
+ HDATA(cmd->device->host)->dma_bounce_buffer =
+ kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
+ HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
}
- if ( scsi_alloc_out_of_range || !HDATA(cmd->host)->dma_bounce_buffer) {
- HDATA(cmd->host)->dma_bounce_buffer =
- amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len,
+ if (scsi_alloc_out_of_range ||
+ !HDATA(cmd->device->host)->dma_bounce_buffer) {
+ HDATA(cmd->device->host)->dma_bounce_buffer =
+ amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
"GVP II SCSI Bounce Buffer");
- if(!HDATA(cmd->host)->dma_bounce_buffer)
+ if(!HDATA(cmd->device->host)->dma_bounce_buffer)
{
- HDATA(cmd->host)->dma_bounce_len = 0;
+ HDATA(cmd->device->host)->dma_bounce_len = 0;
return 1;
}
- HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+ HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
}
/* check if the address of the bounce buffer is OK */
- addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer);
+ addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
- if (addr & HDATA(cmd->host)->dma_xfer_mask) {
+ if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
/* fall back to Chip RAM if address out of range */
- if( HDATA(cmd->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
- kfree (HDATA(cmd->host)->dma_bounce_buffer);
+ if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+ kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
scsi_alloc_out_of_range = 1;
} else {
- amiga_chip_free (HDATA(cmd->host)->dma_bounce_buffer);
+ amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
}
- HDATA(cmd->host)->dma_bounce_buffer =
- amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len,
+ HDATA(cmd->device->host)->dma_bounce_buffer =
+ amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
"GVP II SCSI Bounce Buffer");
- if(!HDATA(cmd->host)->dma_bounce_buffer)
+ if(!HDATA(cmd->device->host)->dma_bounce_buffer)
{
- HDATA(cmd->host)->dma_bounce_len = 0;
+ HDATA(cmd->device->host)->dma_bounce_len = 0;
return 1;
}
- addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer);
- HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+ addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
+ HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
}
if (!dir_in) {
/* copy to bounce buffer for a write */
- memcpy (HDATA(cmd->host)->dma_bounce_buffer,
+ memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
cmd->SCp.ptr, cmd->SCp.this_residual);
}
}
@@ -125,11 +126,11 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
if (!dir_in)
cntr |= GVP11_DMAC_DIR_WRITE;
- HDATA(cmd->host)->dma_dir = dir_in;
- DMA(cmd->host)->CNTR = cntr;
+ HDATA(cmd->device->host)->dma_dir = dir_in;
+ DMA(cmd->device->host)->CNTR = cntr;
/* setup DMA *physical* address */
- DMA(cmd->host)->ACR = addr;
+ DMA(cmd->device->host)->ACR = addr;
if (dir_in)
/* invalidate any cache */
@@ -138,11 +139,11 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
/* push any dirty cache */
cache_push (addr, cmd->SCp.this_residual);
- if ((bank_mask = (~HDATA(cmd->host)->dma_xfer_mask >> 18) & 0x01c0))
- DMA(cmd->host)->BANK = bank_mask & (addr >> 18);
+ if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
+ DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
/* start DMA */
- DMA(cmd->host)->ST_DMA = 1;
+ DMA(cmd->device->host)->ST_DMA = 1;
/* return success */
return 0;
diff --git a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c
index b51eda3f8110..81e94a695e5e 100644
--- a/drivers/scsi/mac_NCR5380.c
+++ b/drivers/scsi/mac_NCR5380.c
@@ -850,7 +850,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
/*
- * Function : void NCR5380_init (struct Scsi_Host *instance)
+ * Function : void NCR5380_init (struct Scsi_Host *instance, int flags)
*
* Purpose : initializes *instance and corresponding 5380 chip.
*
@@ -861,7 +861,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
*
*/
-static void NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
{
int i;
SETUP_HOSTDATA(instance);
@@ -905,6 +905,8 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags)
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ return 0;
}
/*
@@ -925,17 +927,13 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags)
*
*/
-/* Only make static if a wrapper function is used */
-#ifndef NCR5380_queue_command
static
-#endif
int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
SETUP_HOSTDATA(cmd->host);
Scsi_Cmnd *tmp;
int oldto;
unsigned long flags;
- extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
@@ -1025,12 +1023,12 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
if (in_interrupt() > 0 || ((flags >> 8) & 7) >= 6)
queue_main();
else
- NCR5380_main();
+ NCR5380_main(NULL);
return 0;
}
/*
- * Function : NCR5380_main (void)
+ * Function : NCR5380_main (void *bl)
*
* Purpose : NCR5380_main is a coroutine that runs as long as more work can
* be done on the NCR5380 host adapters in a system. Both
@@ -1041,7 +1039,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* reenable them. This prevents reentrancy and kernel stack overflow.
*/
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
{
Scsi_Cmnd *tmp, *prev;
struct Scsi_Host *instance = first_instance;
@@ -2790,9 +2788,6 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
* called where the loop started in NCR5380_main().
*/
-#ifndef NCR5380_abort
-static
-#endif
int NCR5380_abort (Scsi_Cmnd *cmd)
{
struct Scsi_Host *instance = cmd->host;
@@ -2982,7 +2977,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
/*
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2990,7 +2985,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
*
*/
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
{
SETUP_HOSTDATA(cmd->host);
int i;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 7ab4086e6f26..89d3b02c8a05 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -268,7 +268,7 @@ static Scsi_Host_Template *the_template = NULL;
#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
#define HOSTNO instance->host_no
-#define H_NO(cmd) (cmd)->host->host_no
+#define H_NO(cmd) (cmd)->device->host->host_no
#define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \
(buffer)->offset)
@@ -360,17 +360,17 @@ static void __init init_tags( void )
static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
- if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
return( 1 );
if (!should_be_tagged ||
!setup_use_tagged_queuing || !cmd->device->tagged_supported)
return( 0 );
- if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
- TagAlloc[cmd->target][cmd->lun].queue_size ) {
+ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+ TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->target, cmd->lun );
+ H_NO(cmd), cmd->device->id, cmd->device->lun );
return( 1 );
}
return( 0 );
@@ -384,7 +384,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
/* If we or the target don't support tagged queuing, allocate the LUN for
* an untagged command.
@@ -392,19 +392,19 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
if (!should_be_tagged ||
!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
cmd->tag = TAG_NONE;
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->target, cmd->lun );
+ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
}
else {
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
set_bit( cmd->tag, &ta->allocated );
ta->nr_allocated++;
TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
"(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
ta->nr_allocated );
}
}
@@ -416,23 +416,23 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
static void cmd_free_tag( Scsi_Cmnd *cmd )
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
if (cmd->tag == TAG_NONE) {
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->target, cmd->lun );
+ H_NO(cmd), cmd->device->id, cmd->device->lun );
}
else if (cmd->tag >= MAX_TAGS) {
printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
H_NO(cmd), cmd->tag );
}
else {
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
clear_bit( cmd->tag, &ta->allocated );
ta->nr_allocated--;
TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
}
}
@@ -616,11 +616,11 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
- printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
else {
for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
(phases[i].value != (status & PHASE_MASK)); ++i);
- printk("scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
}
}
@@ -819,7 +819,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
int i, s;
unsigned char *command;
SPRINTF("scsi%d: destination target %d, lun %d\n",
- H_NO(cmd), cmd->target, cmd->lun);
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
SPRINTF(" command = ");
command = cmd->cmnd;
SPRINTF("%2d (0x%02x)", command[0], command[0]);
@@ -842,7 +842,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
*
*/
-static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
{
int i;
SETUP_HOSTDATA(instance);
@@ -886,6 +886,8 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ return 0;
}
/*
@@ -909,10 +911,9 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
/* Only make static if a wrapper function is used */
static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
Scsi_Cmnd *tmp;
unsigned long flags;
- extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
@@ -942,15 +943,15 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
case WRITE:
case WRITE_6:
case WRITE_10:
- hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
hostdata->pendingw++;
break;
case READ:
case READ_6:
case READ_10:
- hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
hostdata->pendingr++;
break;
}
@@ -1014,7 +1015,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
if (in_interrupt() || ((flags >> 8) & 7) >= 6)
queue_main();
else
- NCR5380_main();
+ NCR5380_main(NULL);
return 0;
}
@@ -1030,7 +1031,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* reenable them. This prevents reentrancy and kernel stack overflow.
*/
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
{
Scsi_Cmnd *tmp, *prev;
struct Scsi_Host *instance = first_instance;
@@ -1065,7 +1066,7 @@ static void NCR5380_main (void)
local_save_flags(flags);
do {
- local_irq_disable(flags); /* Freeze request queues */
+ local_irq_disable(); /* Freeze request queues */
done = 1;
if (!hostdata->connected) {
@@ -1095,7 +1096,7 @@ static void NCR5380_main (void)
#ifdef SUPPORT_TAGS
!is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
#else
- !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
#endif
) {
/* ++guenther: just to be sure, this must be atomic */
@@ -1217,8 +1218,8 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance )
BASR_ACK)) ==
(BASR_PHASE_MATCH | BASR_ACK)) {
printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
- printk("scsi%d: bus stuck in data phase -- probably a
- single byte overrun!\n", HOSTNO);
+ printk("scsi%d: bus stuck in data phase -- probably a single byte "
+ "overrun!\n", HOSTNO);
printk("not prepared for this error!\n");
printk("please e-mail sammy@sammy.net with a description of how this\n");
printk("error was produced.\n");
@@ -1349,15 +1350,15 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
case WRITE:
case WRITE_6:
case WRITE_10:
- hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
hostdata->pendingw--;
break;
case READ:
case READ_6:
case READ_10:
- hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
hostdata->pendingr--;
break;
}
@@ -1518,7 +1519,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
/*
* Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1571,7 +1572,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
udelay(1);
- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
/*
* The SCSI specification calls for a 250 ms timeout for the actual
@@ -1622,7 +1623,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->target)) {
+ if (hostdata->targets_present & (1 << cmd->device->id)) {
printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
if (hostdata->restart_select)
printk(KERN_NOTICE "\trestart select\n");
@@ -1644,7 +1645,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
return 0;
}
- hostdata->targets_present |= (1 << cmd->target);
+ hostdata->targets_present |= (1 << cmd->device->id);
/*
* Since we followed the SCSI spec, and raised ATN while SEL
@@ -1665,8 +1666,8 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
while (!(NCR5380_read(STATUS_REG) & SR_REQ));
SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->target);
- tmp[0] = IDENTIFY(1, cmd->lun);
+ HOSTNO, cmd->device->id);
+ tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
if (cmd->tag != TAG_NONE) {
@@ -1688,7 +1689,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
/* XXX need to handle errors here */
hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
#endif
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
@@ -2103,7 +2104,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
* polled-IO. */
printk(KERN_NOTICE "scsi%d: switching target %d "
"lun %d to slow handshake\n", HOSTNO,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
cmd->device->borken = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
ICR_ASSERT_ATN);
@@ -2161,7 +2162,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
LNK_PRINTK("scsi%d: target %d lun %d linked command "
- "complete.\n", HOSTNO, cmd->target, cmd->lun);
+ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2174,7 +2175,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
if (!cmd->next_link) {
printk(KERN_NOTICE "scsi%d: target %d lun %d "
"linked command complete, no next_link\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
sink = 1;
do_abort (instance);
return;
@@ -2187,7 +2188,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
LNK_PRINTK("scsi%d: target %d lun %d linked request "
"done, calling scsi_done().\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef NCR5380_STATS
collect_stats(hostdata, cmd);
#endif
@@ -2201,7 +2202,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
hostdata->connected = NULL;
QU_PRINTK("scsi%d: command for target %d, lun %d "
- "completed\n", HOSTNO, cmd->target, cmd->lun);
+ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2213,16 +2214,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
*/
/* ++Andreas: the mid level code knows about
QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
TAG_PRINTK("scsi%d: target %d lun %d returned "
"QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->target, cmd->lun,
+ HOSTNO, cmd->device->id, cmd->device->lun,
ta->nr_allocated);
if (ta->queue_size > ta->nr_allocated)
ta->nr_allocated = ta->queue_size;
}
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2312,12 +2313,12 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
* the command is treated as untagged further on.
*/
cmd->device->tagged_supported = 0;
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
cmd->tag = TAG_NONE;
TAG_PRINTK("scsi%d: target %d lun %d rejected "
"QUEUE_TAG message; tagged queuing "
"disabled\n",
- HOSTNO, cmd->target, cmd->lun);
+ HOSTNO, cmd->device->id, cmd->device->lun);
break;
}
break;
@@ -2334,7 +2335,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
@@ -2436,13 +2437,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
} else if (tmp != EXTENDED_MESSAGE)
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"message %02x from target %d, lun %d\n",
- HOSTNO, tmp, cmd->target, cmd->lun);
+ HOSTNO, tmp, cmd->device->id, cmd->device->lun);
else
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"extended message "
"code %02x, length %d from target %d, lun %d\n",
HOSTNO, extended_msg[1], extended_msg[0],
- cmd->target, cmd->lun);
+ cmd->device->id, cmd->device->lun);
msgout = MESSAGE_REJECT;
@@ -2460,7 +2461,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
@@ -2579,7 +2580,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
tmp; prev = tmp, tmp = NEXT(tmp) ) {
- if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
&& (tag == tmp->tag)
#endif
@@ -2686,7 +2687,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
static int NCR5380_abort (Scsi_Cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->host;
+ struct Scsi_Host *instance = cmd->device->host;
SETUP_HOSTDATA(instance);
Scsi_Cmnd *tmp, **prev;
unsigned long flags;
@@ -2736,7 +2737,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
#ifdef SUPPORT_TAGS
cmd_free_tag( cmd );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
local_irq_restore(flags);
cmd->scsi_done(cmd);
@@ -2841,7 +2842,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
#ifdef SUPPORT_TAGS
cmd_free_tag( tmp );
#else
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
local_irq_restore(flags);
tmp->scsi_done(tmp);
@@ -2868,7 +2869,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
/*
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2876,9 +2877,9 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
*
*/
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->host);
+ SETUP_HOSTDATA(cmd->device->host);
int i;
unsigned long flags;
#if 1
@@ -2886,7 +2887,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#endif
- NCR5380_print_status (cmd->host);
+ NCR5380_print_status (cmd->device->host);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 978e81e9e602..e3d27cc486dd 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -79,6 +79,8 @@
#include "sun3_scsi.h"
#include "NCR5380.h"
+static void NCR5380_print(struct Scsi_Host *instance);
+
/* #define OLDDMA */
#define USE_WRAPPER
@@ -312,7 +314,7 @@ int sun3scsi_release (struct Scsi_Host *shpnt)
if (shpnt->irq != IRQ_NONE)
free_irq (shpnt->irq, NULL);
- iounmap(sun3_scsi_regp);
+ iounmap((void *)sun3_scsi_regp);
return 0;
}
@@ -621,8 +623,8 @@ static Scsi_Host_Template driver_template = {
.release = sun3scsi_release,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
- .abort = sun3scsi_abort,
- .reset = sun3scsi_reset,
+ .eh_abort_handler = sun3scsi_abort,
+ .eh_bus_reset_handler = sun3scsi_bus_reset,
.can_queue = CAN_QUEUE,
.this_id = 7,
.sg_tablesize = SG_TABLESIZE,
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index b7a569b3d2bb..23a897d39c87 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -55,7 +55,7 @@
static int sun3scsi_abort (Scsi_Cmnd *);
static int sun3scsi_detect (Scsi_Host_Template *);
static const char *sun3scsi_info (struct Scsi_Host *);
-static int sun3scsi_reset(Scsi_Cmnd *, unsigned int);
+static int sun3scsi_bus_reset(Scsi_Cmnd *);
static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
static int sun3scsi_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout);
@@ -109,7 +109,7 @@ static int sun3scsi_release (struct Scsi_Host *);
#define NCR5380_intr sun3scsi_intr
#define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_reset sun3scsi_reset
+#define NCR5380_bus_reset sun3scsi_bus_reset
#define NCR5380_abort sun3scsi_abort
#define NCR5380_proc_info sun3scsi_proc_info
#define NCR5380_dma_xfer_len(i, cmd, phase) \
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index 056a65cd4551..484500e20395 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -1,4 +1,4 @@
-/*
+ /*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
* Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
@@ -566,8 +566,8 @@ static Scsi_Host_Template driver_template = {
.release = sun3scsi_release,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
- .abort = sun3scsi_abort,
- .reset = sun3scsi_reset,
+ .eh_abort_handler = sun3scsi_abort,
+ .eh_bus_reset_handler = sun3scsi_bus_reset,
.can_queue = CAN_QUEUE,
.this_id = 7,
.sg_tablesize = SG_TABLESIZE,
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index bfbdf74c018b..7c44fc01f784 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -374,11 +374,44 @@ static void dma_advance_sg (Scsi_Cmnd *sp)
sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
}
+
+static int esp_slave_alloc(Scsi_Device *SDptr)
+{
+ struct esp_device *esp_dev =
+ kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+
+ if (!esp_dev)
+ return -ENOMEM;
+ memset(esp_dev, 0, sizeof(struct esp_device));
+ SDptr->hostdata = esp_dev;
+ return 0;
+}
+
+static void esp_slave_destroy(Scsi_Device *SDptr)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata;
+
+ esp->targets_present &= ~(1 << SDptr->id);
+ kfree(SDptr->hostdata);
+ SDptr->hostdata = NULL;
+}
+
+
+static int sun3x_esp_release(struct Scsi_Host *instance)
+{
+ /* this code does not support being compiled as a module */
+ return 1;
+
+}
+
static Scsi_Host_Template driver_template = {
.proc_name = "esp",
.proc_info = &esp_proc_info,
.name = "Sun ESP 100/100a/200",
.detect = sun3x_esp_detect,
+ .release = sun3x_esp_release,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
.info = esp_info,
.command = esp_command,
.queuecommand = esp_queue,
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index f9cb9e3c8d1e..520f1d4f318c 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -1471,7 +1471,7 @@ reset_wd33c93(struct Scsi_Host *instance)
int busycount = 0;
extern void sgiwd93_reset(unsigned long);
/* wait 'til the chip gets some time for us */
- while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100)
+ while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100)
udelay (10);
/*
* there are scsi devices out there, which manage to lock up
@@ -1481,7 +1481,7 @@ reset_wd33c93(struct Scsi_Host *instance)
* does this for the SGI Indy, where this is possible
*/
/* still busy ? */
- if (READ_AUX_STAT() & ASR_BSY)
+ if (read_aux_stat(regs) & ASR_BSY)
sgiwd93_reset(instance->base); /* yeah, give it the hard one */
}
#endif
@@ -2086,3 +2086,4 @@ EXPORT_SYMBOL(wd33c93_release);
EXPORT_SYMBOL(wd33c93_abort);
EXPORT_SYMBOL(wd33c93_queuecommand);
EXPORT_SYMBOL(wd33c93_intr);
+EXPORT_SYMBOL(wd33c93_proc_info);
diff --git a/drivers/serial/uart00.c b/drivers/serial/uart00.c
index c5c4bfc1161c..deba4a10e439 100644
--- a/drivers/serial/uart00.c
+++ b/drivers/serial/uart00.c
@@ -235,8 +235,8 @@ static void uart00_modem_status(struct uart_port *port)
status = UART_GET_MSR(port);
- if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK |
- UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))
+ if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK |
+ UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)))
return;
if (status & UART_MSR_DDCD_MSK)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b8f282d5524a..03696016c495 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1175,7 +1175,7 @@ void usb_hub_cleanup(void)
int usb_reset_device(struct usb_device *dev)
{
struct usb_device *parent = dev->parent;
- struct usb_device_descriptor descriptor;
+ struct usb_device_descriptor *descriptor;
int i, ret, port = -1;
if (!parent) {
@@ -1224,17 +1224,24 @@ int usb_reset_device(struct usb_device *dev)
* If nothing changed, we reprogram the configuration and then
* the alternate settings.
*/
- ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
- sizeof(descriptor));
- if (ret < 0)
+ descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
+ if (!descriptor) {
+ return -ENOMEM;
+ }
+ ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
+ sizeof(*descriptor));
+ if (ret < 0) {
+ kfree(descriptor);
return ret;
+ }
- le16_to_cpus(&descriptor.bcdUSB);
- le16_to_cpus(&descriptor.idVendor);
- le16_to_cpus(&descriptor.idProduct);
- le16_to_cpus(&descriptor.bcdDevice);
+ le16_to_cpus(&descriptor->bcdUSB);
+ le16_to_cpus(&descriptor->idVendor);
+ le16_to_cpus(&descriptor->idProduct);
+ le16_to_cpus(&descriptor->bcdDevice);
- if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+ if (memcmp(&dev->descriptor, descriptor, sizeof(*descriptor))) {
+ kfree(descriptor);
usb_destroy_configuration(dev);
ret = usb_get_device_descriptor(dev);
@@ -1268,6 +1275,8 @@ int usb_reset_device(struct usb_device *dev)
return 1;
}
+ kfree(descriptor);
+
ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue);
if (ret < 0) {
err("failed to set dev %s active configuration (error=%d)",
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 97c986e346d2..793a82b23ac2 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -88,7 +88,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
int retv;
int length;
- urb = usb_alloc_urb(0, GFP_KERNEL);
+ urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
@@ -131,7 +131,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
- struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
int ret;
if (!dr)
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 4e57b88d616d..32478229d4c9 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -117,10 +117,10 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
static void __attribute__((__unused__))
dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
- qh, qh->hw_info1, qh->hw_info2,
+ dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label,
+ qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
qh->hw_current, qh->hw_qtd_next);
- dbg (" alt+errs= %x, token= %x, page0= %x, page1= %x",
+ dbg (" alt+nak+t= %x, token= %x, page0= %x, page1= %x",
qh->hw_alt_next, qh->hw_token,
qh->hw_buf [0], qh->hw_buf [1]);
if (qh->hw_buf [2]) {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d0954475b709..072d70416540 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -576,7 +576,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
int ports;
int i;
- dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
+ ehci_dbg (ehci, "suspend to %d\n", state);
ports = HCS_N_PORTS (ehci->hcs_params);
@@ -593,7 +593,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
if ((temp & PORT_PE) == 0
|| (temp & PORT_OWNER) != 0)
continue;
-dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
+ ehci_dbg (ehci, "suspend port %d", i);
temp |= PORT_SUSPEND;
writel (temp, &ehci->regs->port_status [i]);
}
@@ -615,7 +615,7 @@ static int ehci_resume (struct usb_hcd *hcd)
int ports;
int i;
- dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
+ ehci_dbg (ehci, "resume\n");
ports = HCS_N_PORTS (ehci->hcs_params);
@@ -635,7 +635,7 @@ static int ehci_resume (struct usb_hcd *hcd)
if ((temp & PORT_PE) == 0
|| (temp & PORT_SUSPEND) != 0)
continue;
-dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
+ ehci_dbg (ehci, "resume port %d", i);
temp |= PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
readl (&ehci->regs->command); /* unblock posted writes */
@@ -880,8 +880,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/* ASSERT: no requests/urbs are still linked (so no TDs) */
/* ASSERT: nobody can be submitting urbs for this any more */
- dbg ("%s: free_config devnum %d",
- hcd_to_bus (hcd)->bus_name, udev->devnum);
+ ehci_dbg (ehci, "free_config %s devnum %d\n",
+ udev->devpath, udev->devnum);
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < 32; i++) {
@@ -912,7 +912,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
dev->ep [i] = 0;
if (qh->qh_state == QH_STATE_IDLE)
goto idle;
- dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+ ehci_dbg (ehci, "free_config, async ep 0x%02x qh %p",
+ i, qh);
/* scan_async() empties the ring as it does its work,
* using IAA, but doesn't (yet?) turn it off. if it
diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
index 6fb7c46362d6..284baf47656f 100644
--- a/drivers/usb/image/scanner.c
+++ b/drivers/usb/image/scanner.c
@@ -347,8 +347,9 @@
* - Don't print errors when the device is busy.
*
* 0.4.11 2003-02-25
- * - Added vendor/product ids for Artec, Avision, Brother, Medion, Primax,
- * Prolink, Fujitsu, Plustek, and SYSCAN scanners.
+ * - Added vendor/product ids for Artec, Avision, Brother, Canon, Compaq,
+ * Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek,
+ * Primax, Prolink, Plustek, SYSCAN, Trust and UMAX scanners.
* - Fixed generation of devfs names if dynamic minors are disabled.
* - Used kobject reference counting to free the scn struct when the device
* is closed and disconnected. Avoids crashes when writing to a
diff --git a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
index dc77eb090dec..230f08c307b7 100644
--- a/drivers/usb/image/scanner.h
+++ b/drivers/usb/image/scanner.h
@@ -105,6 +105,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */
/* Benq: see Acer */
/* Brother */
+ { USB_DEVICE(0x04f9, 0x010f) }, /* MFC 5100C */
{ USB_DEVICE(0x04f9, 0x0111) }, /* MFC 6800 */
/* Canon */
{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
@@ -118,9 +119,11 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04a9, 0x220c) }, /* CanoScan D1250U2 */
{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
+ { USB_DEVICE(0x04a9, 0x2213) }, /* LIDE 50 */
{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
/* Colorado -- See Primax/Colorado below */
/* Compaq */
+ { USB_DEVICE(0x049f, 0x001a) }, /* S4 100 */
{ USB_DEVICE(0x049f, 0x0021) }, /* S200 */
/* Epson -- See Seiko/Epson below */
/* Fujitsu */
@@ -152,6 +155,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
// { USB_DEVICE(0x03f0, 0x0801) }, /* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
+ { USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */
+ { USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */
{ USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */
{ USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */
{ USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */
@@ -159,12 +164,16 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
/* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
+ { USB_DEVICE(0x043d, 0x003d) }, /* X83 */
+ /* LG Electronics */
+ { USB_DEVICE(0x0461, 0x0364) }, /* Scanworks 600U (repackaged Primax?) */
/* Medion */
{ USB_DEVICE(0x0461, 0x0377) }, /* MD 5345 - repackaged Primax? */
/* Memorex */
{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
/* Microtek */
{ USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */
+ { USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */
/* The following SCSI-over-USB Microtek devices are supported by the
microtek driver: Enable SCSI and USB Microtek in kernel config */
// { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */
@@ -259,7 +268,11 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* SYSCAN */
{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
+ /* Trust */
+ { USB_DEVICE(0x05cb, 0x1483) }, /* CombiScan 19200 */
+ { USB_DEVICE(0x05d8, 0x4006) }, /* Easy Webscan 19200 (repackaged Artec?) */
/* Umax */
+ { USB_DEVICE(0x05d8, 0x4009) }, /* Astraslim (actually Artec?) */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
{ USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 4da30222593a..9ec19ad566ef 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1334,6 +1334,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_TANGTOP 0x0d3d
#define USB_DEVICE_ID_TANGTOP_USBPS2 0x0001
+#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
@@ -1377,6 +1380,7 @@ struct hid_blacklist {
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ 0, 0 }
};
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index e333dbe6d07b..c24cebd97cba 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -12,5 +12,3 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TIGL) += tiglusb.o
obj-$(CONFIG_USB_USS720) += uss720.o
-
-speedtch-objs := speedtouch.o atmsar.o
diff --git a/drivers/usb/misc/atmsar.c b/drivers/usb/misc/atmsar.c
deleted file mode 100644
index e9afd62768c8..000000000000
--- a/drivers/usb/misc/atmsar.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/******************************************************************************
- * atmsar.c -- General SAR library for ATM devices.
- *
- * Copyright (C) 2000, Johan Verrept
- *
- * 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.
- *
- ******************************************************************************/
-
-/*
- * Written by Johan Verrept (Johan.Verrept@advalvas.be)
- *
- * 0.2.4A: - Version for inclusion in 2.5 series kernel
- * - Modifications by Richard Purdie (rpurdie@rpsys.net)
- * - replaced "sarlib" with "atmsar"
- * - adaptations for inclusion in kernel tree
- *
- * 0.2.4: - Fixed wrong buffer overrun check in atmsar_decode_rawcell()
- * reported by Stephen Robinson <stephen.robinson@zen.co.uk>
- * - Fixed bug when input skb did not contain a multple of 52/53
- * bytes (would happen when the speedtouch device resynced)
- * also reported by Stephen Robinson <stephen.robinson@zen.co.uk>
- *
- * 0.2.3: - Fixed wrong allocation size. caused memory corruption in some
- * cases. Reported by Vladimir Dergachev <volodya@mindspring.com>
- * - Added some comments
- *
- * 0.2.2: - Fixed CRCASM
- * patch from Linus Flannagan <linusf@netservices.eng.net>
- * - Fixed problem when user did NOT use the
- * ATMSAR_USE_53BYTE_CELL flag.
- * reported by Piers Scannell <email@lot105.com>
- * - No more in-buffer rewriting for cloned buffers.
- * - Removed the PII specific CFLAGS in the Makefile.
- *
- * 0.2.1: - removed dependency on alloc_tx. tis presented problems when
- * using this with the br2684 code.
- *
- * 0.2: - added AAL0 reassembly
- * - added alloc_tx support
- * - replaced alloc_skb in decode functions to dev_alloc_skb to
- * allow calling from interrupt
- * - fixed embarassing AAL5 bug. I was setting the pti bit in the
- * wrong byte...
- * - fixed another emabrassing bug.. picked up the wrong crc type
- * and forgot to invert the crc result...
- * - fixed AAL5 length calculations.
- * - removed automatic skb freeing from encode functions.
- * This caused problems because i did kfree_skb it, while it
- * needed to be popped. I cannot determine though whether it
- * needs to be popped or not. Figu'e it out ye'self ;-)
- * - added mru field. This is the buffersize. atmsar_decode_aal0
- * will use when it allocates a receive buffer. A stop gap for
- * real buffer management.
- *
- * 0.1: - library created.
- * - only contains AAL5, AAL0 can be easily added. (actually, only
- * AAL0 reassembly is missing)
- *
- */
-
-#include <linux/crc32.h>
-#include "atmsar.h"
-
-/***********************
- **
- ** things to remember
- **
- ***********************/
-
-/*
- 1. the atmsar_vcc_data list pointer MUST be initialized to NULL
- 2. atmsar_encode_rawcell will drop incomplete cells.
- 3. ownership of the skb goes to the library !
-*/
-
-#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
-
-/***********************
- **
- ** LOCAL STRUCTURES
- **
- ***********************/
-
-/***********************
- **
- ** LOCAL MACROS
- **
- ***********************/
-/*
-#define DEBUG 1
-*/
-#ifdef DEBUG
-#define PDEBUG(arg...) printk(KERN_DEBUG "atmsar: " arg)
-#else
-#define PDEBUG(arg...)
-#endif
-
-#define ADD_HEADER(dest, header) \
- *dest++ = (unsigned char) (header >> 24); \
- *dest++ = (unsigned char) (header >> 16); \
- *dest++ = (unsigned char) (header >> 8); \
- *dest++ = (unsigned char) (header & 0xff);
-
-
-struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
- ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
-{
- struct atmsar_vcc_data *new;
-
- if (!vcc)
- return NULL;
-
- new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
-
- if (!new)
- return NULL;
-
- memset (new, 0, sizeof (struct atmsar_vcc_data));
- new->vcc = vcc;
- new->stats = vcc->stats;
- new->type = type;
- new->next = NULL;
- new->gfc = gfc;
- new->vp = vpi;
- new->vc = vci;
- new->pti = pti;
-
- switch (type) {
- case ATMSAR_TYPE_AAL0:
- new->mtu = ATMSAR_DEF_MTU_AAL0;
- break;
- case ATMSAR_TYPE_AAL1:
- new->mtu = ATMSAR_DEF_MTU_AAL1;
- break;
- case ATMSAR_TYPE_AAL2:
- new->mtu = ATMSAR_DEF_MTU_AAL2;
- break;
- case ATMSAR_TYPE_AAL34:
- /* not supported */
- new->mtu = ATMSAR_DEF_MTU_AAL34;
- break;
- case ATMSAR_TYPE_AAL5:
- new->mtu = ATMSAR_DEF_MTU_AAL5;
- break;
- }
-
- new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
- | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
- | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
- | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
- new->flags = flags;
- new->next = NULL;
- new->reasBuffer = NULL;
-
- new->next = *list;
- *list = new;
-
- PDEBUG ("Allocated new SARLib vcc 0x%p with vp %d vc %d\n", new, vpi, vci);
-
- return new;
-}
-
-void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
-{
- struct atmsar_vcc_data *work;
-
- if (*list == vcc) {
- *list = (*list)->next;
- } else {
- for (work = *list; work && work->next && (work->next != vcc); work = work->next);
-
- /* return if not found */
- if (work->next != vcc)
- return;
-
- work->next = work->next->next;
- }
-
- if (vcc->reasBuffer) {
- dev_kfree_skb (vcc->reasBuffer);
- }
-
- PDEBUG ("Allocated SARLib vcc 0x%p with vp %d vc %d\n", vcc, vcc->vp, vcc->vc);
-
- kfree (vcc);
-}
-
-
-/***********************
- **
- ** DECODE FUNCTIONS
- **
- ***********************/
-
-struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
- struct atmsar_vcc_data **ctx)
-{
- while (skb->len) {
- unsigned char *cell = skb->data;
- unsigned char *cell_payload;
- struct atmsar_vcc_data *vcc = list;
- unsigned long atmHeader =
- ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
- ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
-
- PDEBUG ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called\n", list, skb, ctx);
- PDEBUG ("atmsar_decode_rawcell skb->data %p, skb->tail %p\n", skb->data, skb->tail);
-
- if (!list || !skb || !ctx)
- return NULL;
- if (!skb->data || !skb->tail)
- return NULL;
-
- /* here should the header CRC check be... */
-
- /* look up correct vcc */
- for (;
- vcc
- && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
- vcc = vcc->next);
-
- PDEBUG ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d\n", vcc,
- (int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
- (int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
-
- if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
- cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
-
- switch (vcc->type) {
- case ATMSAR_TYPE_AAL0:
- /* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */
- {
- struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
-
- if (tmp) {
- memcpy (tmp->tail, cell_payload, 48);
- skb_put (tmp, 48);
-
- if (vcc->stats)
- atomic_inc (&vcc->stats->rx);
-
- skb_pull (skb,
- (vcc->
- flags & ATMSAR_USE_53BYTE_CELL ? 53 :
- 52));
- PDEBUG
- ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d\n",
- tmp, tmp->len);
- return tmp;
- };
- }
- break;
- case ATMSAR_TYPE_AAL1:
- case ATMSAR_TYPE_AAL2:
- case ATMSAR_TYPE_AAL34:
- /* not supported */
- break;
- case ATMSAR_TYPE_AAL5:
- if (!vcc->reasBuffer)
- vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
-
- /* if alloc fails, we just drop the cell. it is possible that we can still
- * receive cells on other vcc's
- */
- if (vcc->reasBuffer) {
- /* if (buffer overrun) discard received cells until now */
- if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
- skb_trim (vcc->reasBuffer, 0);
-
- /* copy data */
- memcpy (vcc->reasBuffer->tail, cell_payload, 48);
- skb_put (vcc->reasBuffer, 48);
-
- /* check for end of buffer */
- if (cell[3] & 0x2) {
- struct sk_buff *tmp;
-
- /* the aal5 buffer ends here, cut the buffer. */
- /* buffer will always have at least one whole cell, so */
- /* don't need to check return from skb_pull */
- skb_pull (skb,
- (vcc->
- flags & ATMSAR_USE_53BYTE_CELL ? 53 :
- 52));
- *ctx = vcc;
- tmp = vcc->reasBuffer;
- vcc->reasBuffer = NULL;
-
- PDEBUG
- ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d\n",
- tmp, tmp->len);
- return tmp;
- }
- }
- break;
- };
- /* flush the cell */
- /* buffer will always contain at least one whole cell, so don't */
- /* need to check return value from skb_pull */
- skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
- } else {
- /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
- if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
- NULL)
- return NULL;
- }
- }
-
- return NULL;
-};
-
-struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
-{
- uint crc = 0xffffffff;
- uint length, pdu_crc, pdu_length;
-
- PDEBUG ("atmsar_decode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
-
- if (skb->len && (skb->len % 48))
- return NULL;
-
- length = (skb->tail[-6] << 8) + skb->tail[-5];
- pdu_crc =
- (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
- pdu_length = ((length + 47 + 8) / 48) * 48;
-
- PDEBUG ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d\n",
- skb->len, length, pdu_crc, pdu_length);
-
- /* is skb long enough ? */
- if (skb->len < pdu_length) {
- if (ctx->stats)
- atomic_inc (&ctx->stats->rx_err);
- return NULL;
- }
-
- /* is skb too long ? */
- if (skb->len > pdu_length) {
- PDEBUG ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d\n",
- skb->len, pdu_length);
- /* buffer is too long. we can try to recover
- * if we discard the first part of the skb.
- * the crc will decide whether this was ok
- */
- skb_pull (skb, skb->len - pdu_length);
- }
-
- crc = ~crc32_be (crc, skb->data, pdu_length - 4);
-
- /* check crc */
- if (pdu_crc != crc) {
- PDEBUG ("atmsar_decode_aal5: crc check failed!\n");
- if (ctx->stats)
- atomic_inc (&ctx->stats->rx_err);
- return NULL;
- }
-
- /* pdu is ok */
- skb_trim (skb, length);
-
- /* update stats */
- if (ctx->stats)
- atomic_inc (&ctx->stats->rx);
-
- PDEBUG ("atmsar_decode_aal5 returns pdu 0x%p with length %d\n", skb, skb->len);
- return skb;
-};
diff --git a/drivers/usb/misc/atmsar.h b/drivers/usb/misc/atmsar.h
deleted file mode 100644
index 29727e784b72..000000000000
--- a/drivers/usb/misc/atmsar.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef _ATMSAR_H_
-#define _ATMSAR_H_
-
-/******************************************************************************
- * atmsar.h -- General SAR library for ATM devices.
- *
- * Copyright (C) 2000, Johan Verrept
- *
- * 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.
- *
- ******************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/atmdev.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/atm.h>
-
-#define ATMSAR_USE_53BYTE_CELL 0x1L
-#define ATMSAR_SET_PTI 0x2L
-
-#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-
-/* types */
-#define ATMSAR_TYPE_AAL0 ATM_AAL0
-#define ATMSAR_TYPE_AAL1 ATM_AAL1
-#define ATMSAR_TYPE_AAL2 ATM_AAL2
-#define ATMSAR_TYPE_AAL34 ATM_AAL34
-#define ATMSAR_TYPE_AAL5 ATM_AAL5
-
-
-/* default MTU's */
-#define ATMSAR_DEF_MTU_AAL0 48
-#define ATMSAR_DEF_MTU_AAL1 47
-#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */
-#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */
-#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */
-
-struct atmsar_vcc_data {
- struct atmsar_vcc_data *next;
-
- /* general atmsar flags, per connection */
- int flags;
- int type;
-
- /* connection specific non-atmsar data */
- struct atm_vcc *vcc;
- struct k_atm_aal_stats *stats;
- unsigned short mtu; /* max is actually 65k for AAL5... */
-
- /* cell data */
- unsigned int vp;
- unsigned int vc;
- unsigned char gfc;
- unsigned char pti;
- unsigned int headerFlags;
- unsigned long atmHeader;
-
- /* raw cell reassembly */
- struct sk_buff *reasBuffer;
-};
-
-
-extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc,
- uint type, ushort vpi, ushort vci, unchar pti,
- unchar gfc, uint flags);
-extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc);
-
-struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
- struct atmsar_vcc_data **ctx);
-struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
-
-#endif /* _ATMSAR_H_ */
diff --git a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtch.c
index 58bb47c64e6a..d2006a09c36e 100644
--- a/drivers/usb/misc/speedtouch.c
+++ b/drivers/usb/misc/speedtch.c
@@ -61,7 +61,6 @@
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/crc32.h>
-#include "atmsar.h"
/*
#define DEBUG 1
@@ -102,6 +101,8 @@ static int udsl_print_packet (const unsigned char *data, int len);
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87
+#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
+
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
/* usb_device_id struct */
@@ -147,6 +148,30 @@ struct udsl_control {
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
+struct atmsar_vcc_data {
+ struct atmsar_vcc_data *next;
+
+ /* general atmsar flags, per connection */
+ int flags;
+ int type;
+
+ /* connection specific non-atmsar data */
+ struct atm_vcc *vcc;
+ struct k_atm_aal_stats *stats;
+ unsigned short mtu; /* max is actually 65k for AAL5... */
+
+ /* cell data */
+ unsigned int vp;
+ unsigned int vc;
+ unsigned char gfc;
+ unsigned char pti;
+ unsigned int headerFlags;
+ unsigned long atmHeader;
+
+ /* raw cell reassembly */
+ struct sk_buff *reasBuffer;
+};
+
/*
* UDSL main driver data
*/
@@ -230,6 +255,188 @@ static struct usb_driver udsl_usb_driver = {
/*************
+** decode **
+*************/
+
+#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
+#define ATMSAR_USE_53BYTE_CELL 0x1L
+
+struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
+ struct atmsar_vcc_data **ctx)
+{
+ while (skb->len) {
+ unsigned char *cell = skb->data;
+ unsigned char *cell_payload;
+ struct atmsar_vcc_data *vcc = list;
+ unsigned long atmHeader =
+ ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
+ ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
+
+ dbg ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx);
+ dbg ("atmsar_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
+
+ if (!list || !skb || !ctx)
+ return NULL;
+ if (!skb->data || !skb->tail)
+ return NULL;
+
+ /* here should the header CRC check be... */
+
+ /* look up correct vcc */
+ for (;
+ vcc
+ && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
+ vcc = vcc->next);
+
+ dbg ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d", vcc,
+ (int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
+ (int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
+
+ if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
+ cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
+
+ switch (vcc->type) {
+ case ATM_AAL0:
+ /* case ATM_AAL1: when we have a decode AAL1 function... */
+ {
+ struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
+
+ if (tmp) {
+ memcpy (tmp->tail, cell_payload, 48);
+ skb_put (tmp, 48);
+
+ if (vcc->stats)
+ atomic_inc (&vcc->stats->rx);
+
+ skb_pull (skb,
+ (vcc->
+ flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+ 52));
+ dbg
+ ("atmsar_decode_rawcell returns ATM_AAL0 pdu 0x%p with length %d",
+ tmp, tmp->len);
+ return tmp;
+ };
+ }
+ break;
+ case ATM_AAL1:
+ case ATM_AAL2:
+ case ATM_AAL34:
+ /* not supported */
+ break;
+ case ATM_AAL5:
+ if (!vcc->reasBuffer)
+ vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
+
+ /* if alloc fails, we just drop the cell. it is possible that we can still
+ * receive cells on other vcc's
+ */
+ if (vcc->reasBuffer) {
+ /* if (buffer overrun) discard received cells until now */
+ if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
+ skb_trim (vcc->reasBuffer, 0);
+
+ /* copy data */
+ memcpy (vcc->reasBuffer->tail, cell_payload, 48);
+ skb_put (vcc->reasBuffer, 48);
+
+ /* check for end of buffer */
+ if (cell[3] & 0x2) {
+ struct sk_buff *tmp;
+
+ /* the aal5 buffer ends here, cut the buffer. */
+ /* buffer will always have at least one whole cell, so */
+ /* don't need to check return from skb_pull */
+ skb_pull (skb,
+ (vcc->
+ flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+ 52));
+ *ctx = vcc;
+ tmp = vcc->reasBuffer;
+ vcc->reasBuffer = NULL;
+
+ dbg
+ ("atmsar_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d",
+ tmp, tmp->len);
+ return tmp;
+ }
+ }
+ break;
+ };
+ /* flush the cell */
+ /* buffer will always contain at least one whole cell, so don't */
+ /* need to check return value from skb_pull */
+ skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
+ } else {
+ /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+ if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
+ NULL)
+ return NULL;
+ }
+ }
+
+ return NULL;
+};
+
+struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+ uint crc = 0xffffffff;
+ uint length, pdu_crc, pdu_length;
+
+ dbg ("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+
+ if (skb->len && (skb->len % 48))
+ return NULL;
+
+ length = (skb->tail[-6] << 8) + skb->tail[-5];
+ pdu_crc =
+ (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
+ pdu_length = ((length + 47 + 8) / 48) * 48;
+
+ dbg ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d",
+ skb->len, length, pdu_crc, pdu_length);
+
+ /* is skb long enough ? */
+ if (skb->len < pdu_length) {
+ if (ctx->stats)
+ atomic_inc (&ctx->stats->rx_err);
+ return NULL;
+ }
+
+ /* is skb too long ? */
+ if (skb->len > pdu_length) {
+ dbg ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d",
+ skb->len, pdu_length);
+ /* buffer is too long. we can try to recover
+ * if we discard the first part of the skb.
+ * the crc will decide whether this was ok
+ */
+ skb_pull (skb, skb->len - pdu_length);
+ }
+
+ crc = ~crc32_be (crc, skb->data, pdu_length - 4);
+
+ /* check crc */
+ if (pdu_crc != crc) {
+ dbg ("atmsar_decode_aal5: crc check failed!");
+ if (ctx->stats)
+ atomic_inc (&ctx->stats->rx_err);
+ return NULL;
+ }
+
+ /* pdu is ok */
+ skb_trim (skb, length);
+
+ /* update stats */
+ if (ctx->stats)
+ atomic_inc (&ctx->stats->rx);
+
+ dbg ("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
+ return skb;
+};
+
+
+/*************
** encode **
*************/
@@ -396,7 +603,7 @@ static void udsl_process_receive (unsigned long data)
dbg ("(after cell processing)skb->len = %d", new->len);
switch (atmsar_vcc->type) {
- case ATMSAR_TYPE_AAL5:
+ case ATM_AAL5:
tmp = new;
new = atmsar_decode_aal5 (atmsar_vcc, new);
@@ -690,15 +897,98 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
}
-/************
-** ATM **
-************/
+/**********
+** ATM **
+**********/
+
+#define ATMSAR_DEF_MTU_AAL0 48
+#define ATMSAR_DEF_MTU_AAL1 47
+#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */
+#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */
+#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */
+
+struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
+ ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
+{
+ struct atmsar_vcc_data *new;
+
+ if (!vcc)
+ return NULL;
+
+ new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
+
+ if (!new)
+ return NULL;
+
+ memset (new, 0, sizeof (struct atmsar_vcc_data));
+ new->vcc = vcc;
+ new->stats = vcc->stats;
+ new->type = type;
+ new->next = NULL;
+ new->gfc = gfc;
+ new->vp = vpi;
+ new->vc = vci;
+ new->pti = pti;
+
+ switch (type) {
+ case ATM_AAL0:
+ new->mtu = ATMSAR_DEF_MTU_AAL0;
+ break;
+ case ATM_AAL1:
+ new->mtu = ATMSAR_DEF_MTU_AAL1;
+ break;
+ case ATM_AAL2:
+ new->mtu = ATMSAR_DEF_MTU_AAL2;
+ break;
+ case ATM_AAL34:
+ /* not supported */
+ new->mtu = ATMSAR_DEF_MTU_AAL34;
+ break;
+ case ATM_AAL5:
+ new->mtu = ATMSAR_DEF_MTU_AAL5;
+ break;
+ }
+
+ new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
+ | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
+ | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
+ | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
+ new->flags = flags;
+ new->next = NULL;
+ new->reasBuffer = NULL;
+
+ new->next = *list;
+ *list = new;
+
+ dbg ("Allocated new SARLib vcc 0x%p with vp %d vc %d", new, vpi, vci);
+
+ return new;
+}
+
+void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
+{
+ struct atmsar_vcc_data *work;
+
+ if (*list == vcc) {
+ *list = (*list)->next;
+ } else {
+ for (work = *list; work && work->next && (work->next != vcc); work = work->next);
+
+ /* return if not found */
+ if (work->next != vcc)
+ return;
-/***************************************************************************
-*
-* init functions
-*
-****************************************************************************/
+ work->next = work->next->next;
+ }
+
+ if (vcc->reasBuffer) {
+ dev_kfree_skb (vcc->reasBuffer);
+ }
+
+ dbg ("Allocated SARLib vcc 0x%p with vp %d vc %d", vcc, vcc->vp, vcc->vc);
+
+ kfree (vcc);
+}
static void udsl_atm_dev_close (struct atm_dev *dev)
{
@@ -718,13 +1008,6 @@ static void udsl_atm_dev_close (struct atm_dev *dev)
dev->dev_data = NULL;
}
-
-/***************************************************************************
-*
-* ATM helper functions
-*
-****************************************************************************/
-
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
{
struct udsl_instance_data *instance = atm_dev->dev_data;
@@ -778,12 +1061,7 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
return 0;
}
-
-/***************************************************************************
-*
-* SAR driver entries
-*
-****************************************************************************/
+#define ATMSAR_SET_PTI 0x2L
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
{
@@ -803,7 +1081,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
MOD_INC_USE_COUNT;
vcc->dev_data =
- atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0,
+ atmsar_open (&(instance->atmsar_vcc_list), vcc, ATM_AAL5, vpi, vci, 0, 0,
ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
if (!vcc->dev_data) {
MOD_DEC_USE_COUNT;
@@ -866,9 +1144,9 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
}
-/************
-** USB **
-************/
+/**********
+** USB **
+**********/
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
{
@@ -1180,11 +1458,9 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
}
-/***************************************************************************
-*
-* Driver Init
-*
-****************************************************************************/
+/***********
+** init **
+***********/
static int __init udsl_usb_init (void)
{
@@ -1215,13 +1491,11 @@ MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
-#ifdef DEBUG_PACKET
-/*******************************************************************************
-*
-* Debug
-*
-*******************************************************************************/
+/************
+** debug **
+************/
+#ifdef DEBUG_PACKET
static int udsl_print_packet (const unsigned char *data, int len)
{
unsigned char buffer [256];
@@ -1237,5 +1511,4 @@ static int udsl_print_packet (const unsigned char *data, int len)
}
return i;
}
-
-#endif /* PACKETDEBUG */
+#endif
diff --git a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c
index 2dc8dfe0ba99..e6b530720209 100644
--- a/drivers/usb/net/cdc-ether.c
+++ b/drivers/usb/net/cdc-ether.c
@@ -1064,15 +1064,23 @@ static void set_ethernet_addr( ether_dev_t *ether_dev )
// Used by driver's probe routine ////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-void log_device_info(ether_dev_t *ether_dev)
+static void log_device_info(ether_dev_t *ether_dev)
{
int len;
int string_num;
- unsigned char manu[256];
- unsigned char prod[256];
- unsigned char sern[256];
+ unsigned char *manu = NULL;
+ unsigned char *prod = NULL;
+ unsigned char *sern = NULL;
unsigned char *mac_addr;
+ manu = kmalloc(256, GFP_KERNEL);
+ prod = kmalloc(256, GFP_KERNEL);
+ sern = kmalloc(256, GFP_KERNEL);
+ if (!manu || !prod || !sern) {
+ dbg("no mem for log_device_info");
+ goto fini;
+ }
+
// Default empty strings in case we don't find a real one
manu[0] = 0x00;
prod[0] = 0x00;
@@ -1113,6 +1121,10 @@ void log_device_info(ether_dev_t *ether_dev)
ether_dev->net->name, manu, prod, sern, mac_addr[0],
mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4],
mac_addr[5] );
+fini:
+ kfree(manu);
+ kfree(prod);
+ kfree(sern);
}
/* Forward declaration */
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 138ca704f779..a72a4ce7456e 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -121,7 +121,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char *buffer;
DECLARE_WAITQUEUE(wait, current);
- buffer = kmalloc(size, GFP_DMA);
+ buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
warn("%s: looks like we're out of memory", __FUNCTION__);
return -ENOMEM;
@@ -170,7 +170,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char *buffer;
DECLARE_WAITQUEUE(wait, current);
- buffer = kmalloc(size, GFP_DMA);
+ buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
warn("%s: looks like we're out of memory", __FUNCTION__);
return -ENOMEM;
@@ -218,7 +218,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
char *tmp;
DECLARE_WAITQUEUE(wait, current);
- tmp = kmalloc(1, GFP_DMA);
+ tmp = kmalloc(1, GFP_KERNEL);
if (!tmp) {
warn("%s: looks like we're out of memory", __FUNCTION__);
return -ENOMEM;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 7738a16f5b40..7acdf0580a3f 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -783,7 +783,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un
if (info->mcr & UART_MCR_RTS)
modem_signals |= TIOCM_RTS;
- if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int)));
+ if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int)))
return -EFAULT;
break;
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b89ca760a959..643d71fc64ea 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -1,5 +1,5 @@
/*
- * USB Skeleton driver - 0.9
+ * USB Skeleton driver - 1.0
*
* Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
*
@@ -12,14 +12,17 @@
* USB driver quickly. The design of it is based on the usb-serial and
* dc2xx drivers.
*
- * Thanks to Oliver Neukum and David Brownell for their help in debugging
- * this driver.
+ * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help
+ * in debugging this driver.
*
- * TODO:
- * - fix urb->status race condition in write sequence
*
* History:
*
+ * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and
+ * disconnect. Fix transfer amount in read(). Use
+ * macros instead of magic numbers in probe(). Change
+ * size variables to size_t. Show how to eliminate
+ * DMA bounce buffer.
* 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array.
* 2002_09_26 - 0.8 - changes due to USB core conversion to struct device
* driver.
@@ -33,7 +36,7 @@
* 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
* 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
* 2001_05_01 - 0.1 - first version
- *
+ *
*/
#include <linux/config.h>
@@ -42,8 +45,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
+#include <linux/completion.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
@@ -60,7 +63,7 @@
/* Version Information */
-#define DRIVER_VERSION "v0.4"
+#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
#define DRIVER_DESC "USB Skeleton Driver"
@@ -101,15 +104,16 @@ struct usb_skel {
char num_bulk_out; /* number of bulk out endpoints we have */
unsigned char * bulk_in_buffer; /* the buffer to receive data */
- int bulk_in_size; /* the size of the receive buffer */
+ size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
unsigned char * bulk_out_buffer; /* the buffer to send data */
- int bulk_out_size; /* the size of the send buffer */
+ size_t bulk_out_size; /* the size of the send buffer */
struct urb * write_urb; /* the urb used to send data */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
+ atomic_t write_busy; /* true iff write urb is busy */
+ struct completion write_finished; /* wait for the write to finish */
- struct work_struct work; /* work queue entry for line discipline waking up */
int open; /* if the port is open or not */
struct semaphore sem; /* locks this structure */
};
@@ -118,6 +122,8 @@ struct usb_skel {
/* the global usb devfs handle */
extern devfs_handle_t usb_devfs_handle;
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX (disconnect_sem);
/* local function prototypes */
static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos);
@@ -125,7 +131,7 @@ static ssize_t skel_write (struct file *file, const char *buffer, size_t count,
static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int skel_open (struct inode *inode, struct file *file);
static int skel_release (struct inode *inode, struct file *file);
-
+
static int skel_probe (struct usb_interface *intf, const struct usb_device_id *id);
static void skel_disconnect (struct usb_interface *intf);
@@ -138,7 +144,7 @@ static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
* to have a node in the /dev directory. If the USB
* device were for a network interface then the driver
* would use "struct net_driver" instead, and a serial
- * device would use "struct tty_driver".
+ * device would use "struct tty_driver".
*/
static struct file_operations skel_fops = {
/*
@@ -167,7 +173,7 @@ static struct file_operations skel_fops = {
.ioctl = skel_ioctl,
.open = skel_open,
.release = skel_release,
-};
+};
/* usb specific object needed to register this driver with the usb subsystem */
@@ -188,8 +194,8 @@ static inline void usb_skel_debug_data (const char *function, int size, const un
if (!debug)
return;
-
- printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
+
+ printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
function, size);
for (i = 0; i < size; ++i) {
printk ("%.2x ", data[i]);
@@ -206,7 +212,9 @@ static inline void skel_delete (struct usb_skel *dev)
if (dev->bulk_in_buffer != NULL)
kfree (dev->bulk_in_buffer);
if (dev->bulk_out_buffer != NULL)
- kfree (dev->bulk_out_buffer);
+ usb_buffer_free (dev->udev, dev->bulk_out_size,
+ dev->bulk_out_buffer,
+ dev->write_urb->transfer_dma);
if (dev->write_urb != NULL)
usb_free_urb (dev->write_urb);
kfree (dev);
@@ -222,22 +230,28 @@ static int skel_open (struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor;
int retval = 0;
-
+
dbg("%s", __FUNCTION__);
subminor = minor (inode->i_rdev);
+ /* prevent disconnects */
+ down (&disconnect_sem);
+
interface = usb_find_interface (&skel_driver,
mk_kdev(USB_MAJOR, subminor));
if (!interface) {
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
- return -ENODEV;
+ retval = -ENODEV;
+ goto exit_no_device;
}
-
+
dev = usb_get_intfdata(interface);
- if (!dev)
- return -ENODEV;
+ if (!dev) {
+ retval = -ENODEV;
+ goto exit_no_device;
+ }
/* lock this device */
down (&dev->sem);
@@ -251,6 +265,8 @@ static int skel_open (struct inode *inode, struct file *file)
/* unlock this device */
up (&dev->sem);
+exit_no_device:
+ up (&disconnect_sem);
return retval;
}
@@ -280,6 +296,12 @@ static int skel_release (struct inode *inode, struct file *file)
goto exit_not_opened;
}
+ /* wait for any bulk writes that might be going on to finish up */
+ if (atomic_read (&dev->write_busy))
+ wait_for_completion (&dev->write_finished);
+
+ dev->open = 0;
+
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
up (&dev->sem);
@@ -287,11 +309,6 @@ static int skel_release (struct inode *inode, struct file *file)
return 0;
}
- /* shutdown any bulk writes that might be going on */
- usb_unlink_urb (dev->write_urb);
-
- dev->open = 0;
-
exit_not_opened:
up (&dev->sem);
@@ -308,7 +325,7 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t
int retval = 0;
dev = (struct usb_skel *)file->private_data;
-
+
dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count);
/* lock this object */
@@ -319,12 +336,13 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t
up (&dev->sem);
return -ENODEV;
}
-
- /* do an immediate bulk read to get data from the device */
+
+ /* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg (dev->udev,
- usb_rcvbulkpipe (dev->udev,
+ usb_rcvbulkpipe (dev->udev,
dev->bulk_in_endpointAddr),
- dev->bulk_in_buffer, dev->bulk_in_size,
+ dev->bulk_in_buffer,
+ min (dev->bulk_in_size, count),
&count, HZ*10);
/* if the read was successful, copy the data to userspace */
@@ -334,7 +352,7 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t
else
retval = count;
}
-
+
/* unlock the device */
up (&dev->sem);
return retval;
@@ -343,6 +361,18 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t
/**
* skel_write
+ *
+ * A device driver has to decide how to report I/O errors back to the
+ * user. The safest course is to wait for the transfer to finish before
+ * returning so that any errors will be reported reliably. skel_read()
+ * works like this. But waiting for I/O is slow, so many drivers only
+ * check for errors during I/O initiation and do not report problems
+ * that occur during the actual transfer. That's what we will do here.
+ *
+ * A driver concerned with maximum I/O throughput would use double-
+ * buffering: Two urbs would be devoted to write transfers, so that
+ * one urb could always be active while the other was waiting for the
+ * user to send more data.
*/
static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
@@ -369,37 +399,38 @@ static ssize_t skel_write (struct file *file, const char *buffer, size_t count,
goto exit;
}
- /* see if we are already in the middle of a write */
- if (dev->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
- goto exit;
- }
+ /* wait for a previous write to finish up; we don't use a timeout
+ * and so a nonresponsive device can delay us indefinitely.
+ */
+ if (atomic_read (&dev->write_busy))
+ wait_for_completion (&dev->write_finished);
- /* we can only write as much as 1 urb will hold */
- bytes_written = (count > dev->bulk_out_size) ?
- dev->bulk_out_size : count;
+ /* we can only write as much as our buffer will hold */
+ bytes_written = min (dev->bulk_out_size, count);
- /* copy the data from userspace into our urb */
- if (copy_from_user(dev->write_urb->transfer_buffer, buffer,
+ /* copy the data from userspace into our transfer buffer;
+ * this is the only copy required.
+ */
+ if (copy_from_user(dev->write_urb->transfer_buffer, buffer,
bytes_written)) {
retval = -EFAULT;
goto exit;
}
- usb_skel_debug_data (__FUNCTION__, bytes_written,
+ usb_skel_debug_data (__FUNCTION__, bytes_written,
dev->write_urb->transfer_buffer);
- /* set up our urb */
- usb_fill_bulk_urb(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
- dev->write_urb->transfer_buffer, bytes_written,
- skel_write_bulk_callback, dev);
+ /* this urb was already set up, except for this write size */
+ dev->write_urb->transfer_buffer_length = bytes_written;
/* send the data out the bulk port */
/* a character device write uses GFP_KERNEL,
unless a spinlock is held */
+ init_completion (&dev->write_finished);
+ atomic_set (&dev->write_busy, 1);
retval = usb_submit_urb(dev->write_urb, GFP_KERNEL);
if (retval) {
+ atomic_set (&dev->write_busy, 0);
err("%s - failed submitting write urb, error %d",
__FUNCTION__, retval);
} else {
@@ -435,12 +466,11 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__,
dev->minor, cmd, arg);
-
/* fill in your device specific stuff here */
-
+
/* unlock the device */
up (&dev->sem);
-
+
/* return that we did not understand this ioctl call */
return -ENOTTY;
}
@@ -455,14 +485,16 @@ static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
dbg("%s - minor %d", __FUNCTION__, dev->minor);
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
- return;
}
- return;
+ /* notify anyone waiting that the write has finished */
+ atomic_set (&dev->write_busy, 0);
+ complete (&dev->write_finished);
}
@@ -479,12 +511,12 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int minor;
- int buffer_size;
+ size_t buffer_size;
int i;
int retval;
char name[10];
-
+
/* See if the device offered us matches what we can accept */
if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
(udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
@@ -513,12 +545,15 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
/* set up the endpoint information */
/* check out the endpoints */
+ /* use only the first bulk-in and bulk-out endpoints */
iface_desc = &interface->altsetting[0];
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+ if (!dev->bulk_in_endpointAddr &&
+ (endpoint->bEndpointAddress & USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
@@ -529,9 +564,11 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
goto error;
}
}
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+
+ if (!dev->bulk_out_endpointAddr &&
+ !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk out endpoint */
/* a probe() may sleep and has no restrictions on memory allocations */
dev->write_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -539,40 +576,56 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
err("No free urbs available");
goto error;
}
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+
+ /* on some platforms using this kind of buffer alloc
+ * call eliminates a dma "bounce buffer".
+ *
+ * NOTE: you'd normally want i/o buffers that hold
+ * more than one packet, so that i/o delays between
+ * packets don't hurt throughput.
+ */
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_out_size = buffer_size;
- dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
- dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ dev->write_urb->transfer_flags = (URB_NO_DMA_MAP |
+ URB_ASYNC_UNLINK);
+ dev->bulk_out_buffer = usb_buffer_alloc (udev,
+ buffer_size, GFP_KERNEL,
+ &dev->write_urb->transfer_dma);
if (!dev->bulk_out_buffer) {
err("Couldn't allocate bulk_out_buffer");
goto error;
}
- usb_fill_bulk_urb(dev->write_urb, udev,
- usb_sndbulkpipe(udev,
+ usb_fill_bulk_urb(dev->write_urb, udev,
+ usb_sndbulkpipe(udev,
endpoint->bEndpointAddress),
dev->bulk_out_buffer, buffer_size,
skel_write_bulk_callback, dev);
}
}
+ if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+ err("Couldn't find both bulk-in and bulk-out endpoints");
+ goto error;
+ }
/* initialize the devfs node for this device and register it */
sprintf(name, "skel%d", dev->minor);
-
+
dev->devfs = devfs_register (usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR,
dev->minor,
- S_IFCHR | S_IRUSR | S_IWUSR |
- S_IRGRP | S_IWGRP | S_IROTH,
+ S_IFCHR | S_IRUSR | S_IWUSR |
+ S_IRGRP | S_IWGRP | S_IROTH,
&skel_fops, NULL);
/* let the user know what node this device is now attached to */
- info ("USB Skeleton device now attached to USBSkel%d", dev->minor);
+ info ("USB Skeleton device now attached to USBSkel-%d", dev->minor);
/* add device id so the device works when advertised */
interface->kdev = mk_kdev(USB_MAJOR, dev->minor);
goto exit;
-
+
error:
skel_delete (dev);
dev = NULL;
@@ -593,12 +646,21 @@ exit:
* skel_disconnect
*
* Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->udev. It is also supposed to terminate any currently
+ * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does
+ * not provide any way to do this. But at least we can cancel an active
+ * write.
*/
static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev;
int minor;
+ /* prevent races with open() */
+ down (&disconnect_sem);
+
dev = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
@@ -606,7 +668,7 @@ static void skel_disconnect(struct usb_interface *interface)
return;
down (&dev->sem);
-
+
/* remove device id to disable open() */
interface->kdev = NODEV;
@@ -617,15 +679,21 @@ static void skel_disconnect(struct usb_interface *interface)
/* give back our dynamic minor */
usb_deregister_dev (1, minor);
-
+
+ /* terminate an ongoing write */
+ if (atomic_read (&dev->write_busy)) {
+ usb_unlink_urb (dev->write_urb);
+ wait_for_completion (&dev->write_finished);
+ }
+
+ dev->udev = NULL;
+ up (&dev->sem);
+
/* if the device is not opened, then we clean up right now */
- if (!dev->open) {
- up (&dev->sem);
+ if (!dev->open)
skel_delete (dev);
- } else {
- dev->udev = NULL;
- up (&dev->sem);
- }
+
+ up (&disconnect_sem);
info("USB Skeleton #%d now disconnected", minor);
}
@@ -668,4 +736,3 @@ module_exit (usb_skel_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 227bd6af7e85..03f5dcef1d0a 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_PPC) += macmodes.o
endif
obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_AMIGA) += amifb.o
+obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o
@@ -58,7 +58,7 @@ obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbi
obj-$(CONFIG_FB_MATROX) += matrox/
obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SIS) += sis/
-obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o cfbfillrect.o cfbimgblt.o
+obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 1a5410518e0b..5470149c077f 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
*
- * Copyright (C) 1995 Geert Uytterhoeven
+ * Copyright (C) 1995-2003 Geert Uytterhoeven
*
* with work by Roman Zippel
*
@@ -62,10 +62,7 @@
#include <asm/amigaints.h>
#include <asm/setup.h>
-#include <video/fbcon.h>
-#include <video/fbcon-afb.h>
-#include <video/fbcon-ilbm.h>
-#include <video/fbcon-mfb.h>
+#include "c2p.h"
#define DEBUG
@@ -613,12 +610,11 @@ static u_short maxfmode, chipset;
#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */
#define DUMMYSPRITEMEMSIZE (8)
+static u_long spritememory;
#define CHIPRAM_SAFETY_LIMIT (16384)
-static u_long videomemory, spritememory;
-static u_long videomemorysize;
-static u_long videomemory_phys;
+static u_long videomemory;
/*
* This is the earliest allowed start of fetching display data.
@@ -660,6 +656,47 @@ static struct copdisplay {
static u_short currentcop = 0;
/*
+ * Hardware Cursor API Definitions
+ * These used to be in linux/fb.h, but were preliminary and used by
+ * amifb only anyway
+ */
+
+#define FBIOGET_FCURSORINFO 0x4607
+#define FBIOGET_VCURSORINFO 0x4608
+#define FBIOPUT_VCURSORINFO 0x4609
+#define FBIOGET_CURSORSTATE 0x460A
+#define FBIOPUT_CURSORSTATE 0x460B
+
+
+struct fb_fix_cursorinfo {
+ __u16 crsr_width; /* width and height of the cursor in */
+ __u16 crsr_height; /* pixels (zero if no cursor) */
+ __u16 crsr_xsize; /* cursor size in display pixels */
+ __u16 crsr_ysize;
+ __u16 crsr_color1; /* colormap entry for cursor color1 */
+ __u16 crsr_color2; /* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+ __u16 width;
+ __u16 height;
+ __u16 xspot;
+ __u16 yspot;
+ __u8 data[1]; /* field with [height][width] */
+};
+
+struct fb_cursorstate {
+ __s16 xoffset;
+ __s16 yoffset;
+ __u16 mode;
+};
+
+#define FB_CURSOR_OFF 0
+#define FB_CURSOR_ON 1
+#define FB_CURSOR_FLASH 2
+
+
+ /*
* Hardware Cursor
*/
@@ -738,28 +775,28 @@ static struct amifb_par {
u_short fmode; /* vmode */
} currentpar;
-static struct display disp;
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+ .fix = {
+ .id = "Amiga ",
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .accel = FB_ACCEL_AMIGABLITT
+ }
+};
/*
- * Since we can't read the palette on OCS/ECS, and since reading one
- * single color palette entry requires 5 expensive custom chip bus accesses
- * on AGA, we keep a copy of the current palette.
- * Note that the entries are always 24 bit!
+ * Saved color entry 0 so we can restore it when unblanking
*/
-#if defined(CONFIG_FB_AMIGA_AGA)
-static struct { u_char red, green, blue, pad; } palette[256];
-#else
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif
+static u_char red0, green0, blue0;
+
#if defined(CONFIG_FB_AMIGA_ECS)
static u_short ecs_palette[32];
#endif
+
/*
* Latches for Display Changes during VBlank
*/
@@ -778,15 +815,6 @@ static u_short is_blanked = 0; /* Screen is Blanked */
static u_short is_lace = 0; /* Screen is laced */
/*
- * Frame Buffer Name
- *
- * The rest of the name is filled in during initialization
- */
-
-static char amifb_name[16] = "Amiga ";
-
-
- /*
* Predefined Video Modes
*
*/
@@ -1087,29 +1115,22 @@ static u_short sprfetchmode[3] = {
int amifb_setup(char*);
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
+static int amifb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int amifb_set_par(struct fb_info *info);
+static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info);
static int amifb_blank(int blank, struct fb_info *info);
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
+static int amifb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con, struct fb_info *info);
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *region);
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image);
+static int amifb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ struct fb_info *info);
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var,
- u_char *data, int con);
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var,
- u_char *data, int con);
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
/*
* Interface to the low level console driver
@@ -1117,8 +1138,6 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
int amifb_init(void);
static void amifb_deinit(void);
-static int amifbcon_switch(int con, struct fb_info *info);
-static int amifbcon_updatevar(int con, struct fb_info *info);
/*
* Internal routines
@@ -1133,29 +1152,20 @@ static void chipfree(void);
* Hardware routines
*/
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amifb_par *par);
static int ami_decode_var(struct fb_var_screeninfo *var,
struct amifb_par *par);
static int ami_encode_var(struct fb_var_screeninfo *var,
struct amifb_par *par);
-static void ami_get_par(struct amifb_par *par);
-static void ami_set_var(struct fb_var_screeninfo *var);
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par);
-#endif
static void ami_pan_var(struct fb_var_screeninfo *var);
static int ami_update_par(void);
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
static void ami_update_display(void);
static void ami_init_display(void);
static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_get_cursorstate(struct fb_cursorstate *state);
+static int ami_set_cursorstate(struct fb_cursorstate *state);
static void ami_set_sprite(void);
static void ami_init_copper(void);
static void ami_reinit_copper(void);
@@ -1165,14 +1175,15 @@ static void ami_rebuild_copper(void);
static struct fb_ops amifb_ops = {
.owner = THIS_MODULE,
- .fb_get_fix = amifb_get_fix,
- .fb_get_var = amifb_get_var,
- .fb_set_var = amifb_set_var,
- .fb_get_cmap = amifb_get_cmap,
- .fb_set_cmap = gen_set_cmap,
+ .fb_check_var = amifb_check_var,
+ .fb_set_par = amifb_set_par,
.fb_setcolreg = amifb_setcolreg,
- .fb_pan_display = amifb_pan_display,
.fb_blank = amifb_blank,
+ .fb_pan_display = amifb_pan_display,
+ .fb_fillrect = amifb_fillrect,
+ .fb_copyarea = amifb_copyarea,
+ .fb_imageblit = amifb_imageblit,
+ .fb_cursor = soft_cursor,
.fb_ioctl = amifb_ioctl,
};
@@ -1217,8 +1228,6 @@ int __init amifb_setup(char *options)
{
char *this_opt;
- fb_info.fontname[0] = '\0';
-
if (!options || !*options)
return 0;
@@ -1234,8 +1243,6 @@ int __init amifb_setup(char *options)
amifb_ilbm = 1;
else if (!strncmp(this_opt, "monitorcap:", 11))
amifb_setup_mcap(this_opt+11);
- else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
else if (!strncmp(this_opt, "fstart:", 7))
min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
else
@@ -1248,293 +1255,975 @@ int __init amifb_setup(char *options)
return 0;
}
- /*
- * Get the Fixed Part of the Display
- */
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
+static int amifb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
+ int err;
struct amifb_par par;
- if (con == -1)
- ami_get_par(&par);
- else {
- int err;
+ /* Validate wanted screen parameters */
+ if ((err = ami_decode_var(var, &par)))
+ return err;
- if ((err = ami_decode_var(&fb_display[con].var, &par)))
- return err;
- }
- return ami_encode_fix(fix, &par);
+ /* Encode (possibly rounded) screen parameters */
+ ami_encode_var(var, &par);
+ return 0;
}
- /*
- * Get the User Defined Part of the Display
- */
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static int amifb_set_par(struct fb_info *info)
{
- int err = 0;
-
- if (con == -1) {
- struct amifb_par par;
-
- ami_get_par(&par);
- err = ami_encode_var(var, &par);
- } else
- *var = fb_display[con].var;
- return err;
-}
+ struct amifb_par *par = (struct amifb_par *)info->par;
- /*
- * Set the User Defined Part of the Display
- */
+ do_vmode_pan = 0;
+ do_vmode_full = 0;
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err, activate = var->activate;
- int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
- struct amifb_par par;
+ /* Decode wanted screen parameters */
+ ami_decode_var(&info->var, par);
- struct display *display;
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
+ /* Set new videomode */
+ ami_build_copper();
- /*
- * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
- * as FB_VMODE_SMOOTH_XPAN is only used internally
- */
+ /* Set VBlank trigger */
+ do_vmode_full = 1;
- if (var->vmode & FB_VMODE_CONUPDATE) {
- var->vmode |= FB_VMODE_YWRAP;
- var->xoffset = display->var.xoffset;
- var->yoffset = display->var.yoffset;
+ /* Update fix for new screen parameters */
+ if (par->bpp == 1) {
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ } else if (amifb_ilbm) {
+ info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
+ info->fix.type_aux = par->next_line;
+ } else {
+ info->fix.type = FB_TYPE_PLANES;
+ info->fix.type_aux = 0;
}
- if ((err = ami_decode_var(var, &par)))
- return err;
- ami_encode_var(var, &par);
- if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = display->var.xres;
- oldyres = display->var.yres;
- oldvxres = display->var.xres_virtual;
- oldvyres = display->var.yres_virtual;
- oldbpp = display->var.bits_per_pixel;
- display->var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- struct fb_fix_screeninfo fix;
-
- ami_encode_fix(&fix, &par);
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->can_soft_blank = 1;
- display->inverse = amifb_inverse;
- switch (fix.type) {
-#ifdef FBCON_HAS_ILBM
- case FB_TYPE_INTERLEAVED_PLANES:
- display->dispsw = &fbcon_ilbm;
- break;
-#endif
-#ifdef FBCON_HAS_AFB
- case FB_TYPE_PLANES:
- display->dispsw = &fbcon_afb;
- break;
-#endif
-#ifdef FBCON_HAS_MFB
- case FB_TYPE_PACKED_PIXELS: /* depth == 1 */
- display->dispsw = &fbcon_mfb;
- break;
-#endif
- default:
- display->dispsw = &fbcon_dummy;
- }
- if (fb_info.changevar)
- (*fb_info.changevar)(con);
- }
- if (oldbpp != var->bits_per_pixel) {
- if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
- return err;
- do_install_cmap(con, info);
- }
- if (con == info->currcon)
- ami_set_var(&display->var);
+ info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
+
+ if (par->vmode & FB_VMODE_YWRAP) {
+ info->fix.ywrapstep = 1;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ } else {
+ info->fix.ywrapstep = 0;
+ if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
+ info->fix.xpanstep = 1;
+ else
+ info->fix.xpanstep = 16<<maxfmode;
+ info->fix.ypanstep = 1;
}
return 0;
}
+
/*
* Pan or Wrap the Display
*
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
- if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+ if (var->yoffset < 0 ||
+ var->yoffset >= info->var.yres_virtual || var->xoffset)
return -EINVAL;
} else {
/*
* TODO: There will be problems when xpan!=1, so some columns
* on the right side will never be seen
*/
- if (var->xoffset+fb_display[con].var.xres > upx(16<<maxfmode, fb_display[con].var.xres_virtual) ||
- var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
+ var->yoffset+info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
- if (con == info->currcon)
- ami_pan_var(var);
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
+ ami_pan_var(var);
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
- fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+ info->var.vmode |= FB_VMODE_YWRAP;
else
- fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+ info->var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
- /*
- * Get the Colormap
- */
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG 4
+#define SHIFT_PER_LONG 5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG 8
+#define SHIFT_PER_LONG 6
+#else
+#define Please update me
+#endif
+
+
+ /*
+ * Compose two values, using a bitmask as decision value
+ * This is equivalent to (a & mask) | (b & ~mask)
+ */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+ unsigned long mask)
{
- if (con == info->currcon) /* current console? */
- return fb_get_cmap(cmap, kspc, ami_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
+ return ((a ^ b) & mask) ^ b;
}
-
- /*
- * Amiga Frame Buffer Specific ioctls
- */
-static int amifb_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg, int con, struct fb_info *info)
+
+static inline unsigned long xor(unsigned long a, unsigned long b,
+ unsigned long mask)
{
- int i;
+ return (a & mask) ^ b;
+}
- switch (cmd) {
- case FBIOGET_FCURSORINFO : {
- struct fb_fix_cursorinfo crsrfix;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
- if (!i) {
- i = amifb_get_fix_cursorinfo(&crsrfix, con);
- copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
+
+ /*
+ * Unaligned forward bit copy using 32-bit or 64-bit memory accesses
+ */
+
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+ int src_idx, u32 n)
+{
+ unsigned long first, last;
+ int shift = dst_idx-src_idx, left, right;
+ unsigned long d0, d1;
+ int m;
+
+ if (!n)
+ return;
+
+ shift = dst_idx-src_idx;
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+ if (!shift) {
+ // Same alignment for source and dest
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single word
+ if (last)
+ first &= last;
+ *dst = comp(*src, *dst, first);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ *dst = comp(*src, *dst, first);
+ dst++;
+ src++;
+ n -= BITS_PER_LONG-dst_idx;
}
- return i;
- }
- case FBIOGET_VCURSORINFO : {
- struct fb_var_cursorinfo crsrvar;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
- if (!i) {
- i = amifb_get_var_cursorinfo(&crsrvar,
- ((struct fb_var_cursorinfo *)arg)->data, con);
- copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ n -= 8;
}
- return i;
+ while (n--)
+ *dst++ = *src++;
+
+ // Trailing bits
+ if (last)
+ *dst = comp(*src, *dst, last);
}
- case FBIOPUT_VCURSORINFO : {
- struct fb_var_cursorinfo crsrvar;
-
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
- if (!i) {
- copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
- i = amifb_set_var_cursorinfo(&crsrvar,
- ((struct fb_var_cursorinfo *)arg)->data, con);
+ } else {
+ // Different alignment for source and dest
+
+ right = shift & (BITS_PER_LONG-1);
+ left = -shift & (BITS_PER_LONG-1);
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single destination word
+ if (last)
+ first &= last;
+ if (shift > 0) {
+ // Single source word
+ *dst = comp(*src >> right, *dst, first);
+ } else if (src_idx+n <= BITS_PER_LONG) {
+ // Single source word
+ *dst = comp(*src << left, *dst, first);
+ } else {
+ // 2 source words
+ d0 = *src++;
+ d1 = *src;
+ *dst = comp(d0 << left | d1 >> right, *dst,
+ first);
+ }
+ } else {
+ // Multiple destination words
+ d0 = *src++;
+ // Leading bits
+ if (shift > 0) {
+ // Single source word
+ *dst = comp(d0 >> right, *dst, first);
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ } else {
+ // 2 source words
+ d1 = *src++;
+ *dst = comp(d0 << left | d1 >> right, *dst,
+ first);
+ d0 = d1;
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
+
+ // Main chunk
+ m = n % BITS_PER_LONG;
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ }
+
+ // Trailing bits
+ if (last) {
+ if (m <= right) {
+ // Single source word
+ *dst = comp(d0 << left, *dst, last);
+ } else {
+ // 2 source words
+ d1 = *src;
+ *dst = comp(d0 << left | d1 >> right,
+ *dst, last);
+ }
}
- return i;
}
- case FBIOGET_CURSORSTATE : {
- struct fb_cursorstate crsrstate;
+ }
+}
+
+
+ /*
+ * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
+ */
+
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+ const unsigned long *src, int src_idx, u32 n)
+{
+ unsigned long first, last;
+ int shift = dst_idx-src_idx, left, right;
+ unsigned long d0, d1;
+ int m;
+
+ if (!n)
+ return;
+
+ dst += (n-1)/BITS_PER_LONG;
+ src += (n-1)/BITS_PER_LONG;
+ if ((n-1) % BITS_PER_LONG) {
+ dst_idx += (n-1) % BITS_PER_LONG;
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= BITS_PER_LONG-1;
+ src_idx += (n-1) % BITS_PER_LONG;
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= BITS_PER_LONG-1;
+ }
+
+ shift = dst_idx-src_idx;
+ first = ~0UL << (BITS_PER_LONG-1-dst_idx);
+ last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+
+ if (!shift) {
+ // Same alignment for source and dest
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
- if (!i) {
- i = amifb_get_cursorstate(&crsrstate, con);
- copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
+ if ((unsigned long)dst_idx+1 >= n) {
+ // Single word
+ if (last)
+ first &= last;
+ *dst = comp(*src, *dst, first);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ *dst = comp(*src, *dst, first);
+ dst--;
+ src--;
+ n -= dst_idx+1;
+ }
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ n -= 8;
}
- return i;
+ while (n--)
+ *dst-- = *src--;
+
+ // Trailing bits
+ if (last)
+ *dst = comp(*src, *dst, last);
}
- case FBIOPUT_CURSORSTATE : {
- struct fb_cursorstate crsrstate;
+ } else {
+ // Different alignment for source and dest
+
+ right = shift & (BITS_PER_LONG-1);
+ left = -shift & (BITS_PER_LONG-1);
+
+ if ((unsigned long)dst_idx+1 >= n) {
+ // Single destination word
+ if (last)
+ first &= last;
+ if (shift < 0) {
+ // Single source word
+ *dst = comp(*src << left, *dst, first);
+ } else if (1+(unsigned long)src_idx >= n) {
+ // Single source word
+ *dst = comp(*src >> right, *dst, first);
+ } else {
+ // 2 source words
+ d0 = *src--;
+ d1 = *src;
+ *dst = comp(d0 >> right | d1 << left, *dst,
+ first);
+ }
+ } else {
+ // Multiple destination words
+ d0 = *src--;
+ // Leading bits
+ if (shift < 0) {
+ // Single source word
+ *dst = comp(d0 << left, *dst, first);
+ dst--;
+ n -= dst_idx+1;
+ } else {
+ // 2 source words
+ d1 = *src--;
+ *dst = comp(d0 >> right | d1 << left, *dst,
+ first);
+ d0 = d1;
+ dst--;
+ n -= dst_idx+1;
+ }
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
- if (!i) {
- copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
- i = amifb_set_cursorstate(&crsrstate, con);
+ // Main chunk
+ m = n % BITS_PER_LONG;
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ }
+
+ // Trailing bits
+ if (last) {
+ if (m <= left) {
+ // Single source word
+ *dst = comp(d0 >> right, *dst, last);
+ } else {
+ // 2 source words
+ d1 = *src;
+ *dst = comp(d0 >> right | d1 << left,
+ *dst, last);
+ }
}
- return i;
}
-#ifdef DEBUG
- case FBCMD_GET_CURRENTPAR : {
- struct amifb_par par;
+ }
+}
+
+
+ /*
+ * Unaligned forward inverting bit copy using 32-bit or 64-bit memory
+ * accesses
+ */
+
+static void bitcpy_not(unsigned long *dst, int dst_idx,
+ const unsigned long *src, int src_idx, u32 n)
+{
+ unsigned long first, last;
+ int shift = dst_idx-src_idx, left, right;
+ unsigned long d0, d1;
+ int m;
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par));
- if (!i) {
- ami_get_par(&par);
- copy_to_user((void *)arg, &par, sizeof(struct amifb_par));
+ if (!n)
+ return;
+
+ shift = dst_idx-src_idx;
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+ if (!shift) {
+ // Same alignment for source and dest
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single word
+ if (last)
+ first &= last;
+ *dst = comp(~*src, *dst, first);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ *dst = comp(~*src, *dst, first);
+ dst++;
+ src++;
+ n -= BITS_PER_LONG-dst_idx;
}
- return i;
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ *dst++ = ~*src++;
+ n -= 8;
+ }
+ while (n--)
+ *dst++ = ~*src++;
+
+ // Trailing bits
+ if (last)
+ *dst = comp(~*src, *dst, last);
}
- case FBCMD_SET_CURRENTPAR : {
- struct amifb_par par;
+ } else {
+ // Different alignment for source and dest
+
+ right = shift & (BITS_PER_LONG-1);
+ left = -shift & (BITS_PER_LONG-1);
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single destination word
+ if (last)
+ first &= last;
+ if (shift > 0) {
+ // Single source word
+ *dst = comp(~*src >> right, *dst, first);
+ } else if (src_idx+n <= BITS_PER_LONG) {
+ // Single source word
+ *dst = comp(~*src << left, *dst, first);
+ } else {
+ // 2 source words
+ d0 = ~*src++;
+ d1 = ~*src;
+ *dst = comp(d0 << left | d1 >> right, *dst,
+ first);
+ }
+ } else {
+ // Multiple destination words
+ d0 = ~*src++;
+ // Leading bits
+ if (shift > 0) {
+ // Single source word
+ *dst = comp(d0 >> right, *dst, first);
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ } else {
+ // 2 source words
+ d1 = ~*src++;
+ *dst = comp(d0 << left | d1 >> right, *dst,
+ first);
+ d0 = d1;
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par));
- if (!i) {
- copy_from_user(&par, (void *)arg, sizeof(struct amifb_par));
- ami_set_par(&par);
+ // Main chunk
+ m = n % BITS_PER_LONG;
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ d1 = ~*src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = ~*src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = ~*src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = ~*src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = ~*src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ }
+
+ // Trailing bits
+ if (last) {
+ if (m <= right) {
+ // Single source word
+ *dst = comp(d0 << left, *dst, last);
+ } else {
+ // 2 source words
+ d1 = ~*src;
+ *dst = comp(d0 << left | d1 >> right,
+ *dst, last);
+ }
}
- return i;
}
-#endif /* DEBUG */
}
- return -EINVAL;
}
+
+ /*
+ * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
+ */
+
+static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+{
+ unsigned long val = pat;
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+#if BITS_PER_LONG == 64
+ val |= val << 32;
+#endif
+
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single word
+ if (last)
+ first &= last;
+ *dst = comp(val, *dst, first);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ *dst = comp(val, *dst, first);
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ *dst++ = val;
+ n -= 8;
+ }
+ while (n--)
+ *dst++ = val;
+
+ // Trailing bits
+ if (last)
+ *dst = comp(val, *dst, last);
+ }
+}
+
+
+ /*
+ * Unaligned 32-bit pattern xor using 32/64-bit memory accesses
+ */
+
+static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+{
+ unsigned long val = pat;
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+#if BITS_PER_LONG == 64
+ val |= val << 32;
+#endif
+
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single word
+ if (last)
+ first &= last;
+ *dst = xor(val, *dst, first);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ *dst = xor(val, *dst, first);
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ n -= 4;
+ }
+ while (n--)
+ *dst++ ^= val;
+
+ // Trailing bits
+ if (last)
+ *dst = xor(val, *dst, last);
+ }
+}
+
+static inline void fill_one_line(int bpp, unsigned long next_plane,
+ unsigned long *dst, int dst_idx, u32 n,
+ u32 color)
+{
+ while (1) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BITS_PER_LONG-1);
+ bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+ if (!--bpp)
+ break;
+ color >>= 1;
+ dst_idx += next_plane*8;
+ }
+}
+
+static inline void xor_one_line(int bpp, unsigned long next_plane,
+ unsigned long *dst, int dst_idx, u32 n,
+ u32 color)
+{
+ while (color) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BITS_PER_LONG-1);
+ bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+ if (!--bpp)
+ break;
+ color >>= 1;
+ dst_idx += next_plane*8;
+ }
+}
+
+
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+ struct amifb_par *par = (struct amifb_par *)info->par;
+ int dst_idx, x2, y2;
+ unsigned long *dst;
+
+ if (!rect->width || !rect->height)
+ return;
+
/*
- * Hardware Cursor
- */
+ * We could use hardware clipping but on many cards you get around
+ * hardware clipping by writing to framebuffer directly.
+ * */
+ x2 = rect->dx + rect->width;
+ y2 = rect->dy + rect->height;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ rect->width = x2 - rect->dx;
+ rect->height = y2 - rect->dy;
+
+ dst = (unsigned long *)
+ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+ dst_idx += rect->dy*par->next_line*8+rect->dx;
+ while (rect->height--) {
+ switch (rect->rop) {
+ case ROP_COPY:
+ fill_one_line(info->var.bits_per_pixel,
+ par->next_plane, dst, dst_idx,
+ rect->width, rect->color);
+ break;
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+ case ROP_XOR:
+ xor_one_line(info->var.bits_per_pixel,
+ par->next_plane, dst, dst_idx,
+ rect->width, rect->color);
+ break;
+ }
+ dst_idx += par->next_line*8;
+ }
+}
+
+static inline void copy_one_line(int bpp, unsigned long next_plane,
+ unsigned long *dst, int dst_idx,
+ unsigned long *src, int src_idx, u32 n)
{
- return ami_get_fix_cursorinfo(fix, con);
+ while (1) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BITS_PER_LONG-1);
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= (BITS_PER_LONG-1);
+ bitcpy(dst, dst_idx, src, src_idx, n);
+ if (!--bpp)
+ break;
+ dst_idx += next_plane*8;
+ src_idx += next_plane*8;
+ }
}
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
+ unsigned long *dst, int dst_idx,
+ unsigned long *src, int src_idx, u32 n)
{
- return ami_get_var_cursorinfo(var, data, con);
+ while (1) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BITS_PER_LONG-1);
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= (BITS_PER_LONG-1);
+ bitcpy_rev(dst, dst_idx, src, src_idx, n);
+ if (!--bpp)
+ break;
+ dst_idx += next_plane*8;
+ src_idx += next_plane*8;
+ }
}
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{
- return ami_set_var_cursorinfo(var, data, con);
+ struct amifb_par *par = (struct amifb_par *)info->par;
+ int x2, y2, old_dx, old_dy;
+ unsigned long *dst, *src;
+ int dst_idx, src_idx, height;
+ int rev_copy = 0;
+
+ /* clip the destination */
+ old_dx = area->dx;
+ old_dy = area->dy;
+
+ /*
+ * We could use hardware clipping but on many cards you get around
+ * hardware clipping by writing to framebuffer directly.
+ */
+ x2 = area->dx + area->width;
+ y2 = area->dy + area->height;
+ area->dx = area->dx > 0 ? area->dx : 0;
+ area->dy = area->dy > 0 ? area->dy : 0;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ area->width = x2 - area->dx;
+ area->height = y2 - area->dy;
+
+ /* update sx1,sy1 */
+ area->sx += (area->dx - old_dx);
+ area->sy += (area->dy - old_dy);
+
+ height = area->height;
+
+ /* the source must be completely inside the virtual screen */
+ if (area->sx < 0 || area->sy < 0 ||
+ (area->sx + area->width) > info->var.xres_virtual ||
+ (area->sy + area->height) > info->var.yres_virtual)
+ return;
+
+ if (area->dy > area->sy ||
+ (area->dy == area->sy && area->dx > area->sx)) {
+ area->dy += area->height;
+ area->sy += area->height;
+ rev_copy = 1;
+ }
+ dst = (unsigned long *)
+ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+ src = dst;
+ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+ src_idx = dst_idx;
+ dst_idx += area->dy*par->next_line*8+area->dx;
+ src_idx += area->sy*par->next_line*8+area->sx;
+ if (rev_copy) {
+ while (height--) {
+ dst_idx -= par->next_line*8;
+ src_idx -= par->next_line*8;
+ copy_one_line_rev(info->var.bits_per_pixel,
+ par->next_plane, dst, dst_idx, src,
+ src_idx, area->width);
+ }
+ } else {
+ while (height--) {
+ copy_one_line(info->var.bits_per_pixel,
+ par->next_plane, dst, dst_idx, src,
+ src_idx, area->width);
+ dst_idx += par->next_line*8;
+ src_idx += par->next_line*8;
+ }
+ }
}
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con)
+
+static inline void expand_one_line(int bpp, unsigned long next_plane,
+ unsigned long *dst, int dst_idx, u32 n,
+ const u8 *data, u32 bgcolor, u32 fgcolor)
{
- return ami_get_cursorstate(state, con);
+ const unsigned long *src;
+ int src_idx;
+
+ while (1) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BITS_PER_LONG-1);
+ if ((bgcolor ^ fgcolor) & 1) {
+ src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
+ src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
+ if (fgcolor & 1)
+ bitcpy(dst, dst_idx, src, src_idx, n);
+ else
+ bitcpy_not(dst, dst_idx, src, src_idx, n);
+ /* set or clear */
+ } else
+ bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
+ if (!--bpp)
+ break;
+ bgcolor >>= 1;
+ fgcolor >>= 1;
+ dst_idx += next_plane*8;
+ }
}
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
+
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image)
{
- return ami_set_cursorstate(state, con);
+ struct amifb_par *par = (struct amifb_par *)info->par;
+ int x2, y2;
+ unsigned long *dst;
+ int dst_idx;
+ const char *src;
+ u32 dx, dy, width, height, pitch;
+
+ /*
+ * We could use hardware clipping but on many cards you get around
+ * hardware clipping by writing to framebuffer directly like we are
+ * doing here.
+ */
+ x2 = image->dx + image->width;
+ y2 = image->dy + image->height;
+ dx = image->dx;
+ dy = image->dy;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ width = x2 - dx;
+ height = y2 - dy;
+
+ if (image->depth == 1) {
+ dst = (unsigned long *)
+ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+ dst_idx += dy*par->next_line*8+dx;
+ src = image->data;
+ pitch = (image->width+7)/8;
+ while (height--) {
+ expand_one_line(info->var.bits_per_pixel,
+ par->next_plane, dst, dst_idx, width,
+ src, image->bg_color,
+ image->fg_color);
+ dst_idx += par->next_line*8;
+ src += pitch;
+ }
+ } else {
+ c2p(info->screen_base, image->data, dx, dy, width, height,
+ par->next_line, par->next_plane, image->width,
+ info->var.bits_per_pixel);
+ }
+}
+
+
+ /*
+ * Amiga Frame Buffer Specific ioctls
+ */
+
+static int amifb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ struct fb_info *info)
+{
+ union {
+ struct fb_fix_cursorinfo fix;
+ struct fb_var_cursorinfo var;
+ struct fb_cursorstate state;
+ } crsr;
+ int i;
+
+ switch (cmd) {
+ case FBIOGET_FCURSORINFO:
+ i = ami_get_fix_cursorinfo(&crsr.fix);
+ if (i)
+ return i;
+ return copy_to_user((void *)arg, &crsr.fix,
+ sizeof(crsr.fix)) ? -EFAULT : 0;
+
+ case FBIOGET_VCURSORINFO:
+ i = ami_get_var_cursorinfo(&crsr.var,
+ ((struct fb_var_cursorinfo *)arg)->data);
+ if (i)
+ return i;
+ return copy_to_user((void *)arg, &crsr.var,
+ sizeof(crsr.var)) ? -EFAULT : 0;
+
+ case FBIOPUT_VCURSORINFO:
+ if (copy_from_user(&crsr.var, (void *)arg,
+ sizeof(crsr.var)))
+ return -EFAULT;
+ return ami_set_var_cursorinfo(&crsr.var,
+ ((struct fb_var_cursorinfo *)arg)->data);
+
+ case FBIOGET_CURSORSTATE:
+ i = ami_get_cursorstate(&crsr.state);
+ if (i)
+ return i;
+ return copy_to_user((void *)arg, &crsr.state,
+ sizeof(crsr.state)) ? -EFAULT : 0;
+
+ case FBIOPUT_CURSORSTATE:
+ if (copy_from_user(&crsr.state, (void *)arg,
+ sizeof(crsr.state)))
+ return -EFAULT;
+ return ami_set_cursorstate(&crsr.state);
+ }
+ return -EINVAL;
}
@@ -1570,7 +2259,6 @@ int __init amifb_init(void)
int tag, i, err = 0;
u_long chipptr;
u_int defmode;
- struct fb_var_screeninfo var;
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
return -ENXIO;
@@ -1600,7 +2288,7 @@ int __init amifb_init(void)
switch (amiga_chipset) {
#ifdef CONFIG_FB_AMIGA_OCS
case CS_OCS:
- strcat(amifb_name, "OCS");
+ strcat(fb_info.fix.id, "OCS");
default_chipset:
chipset = TAG_OCS;
maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
@@ -1609,13 +2297,13 @@ default_chipset:
maxfmode = TAG_FMODE_1;
defmode = amiga_vblank == 50 ? DEFMODE_PAL
: DEFMODE_NTSC;
- videomemorysize = VIDEOMEMSIZE_OCS;
+ fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
break;
#endif /* CONFIG_FB_AMIGA_OCS */
#ifdef CONFIG_FB_AMIGA_ECS
case CS_ECS:
- strcat(amifb_name, "ECS");
+ strcat(fb_info.fix.id, "ECS");
chipset = TAG_ECS;
maxdepth[TAG_SHRES] = 2;
maxdepth[TAG_HIRES] = 4;
@@ -1629,15 +2317,15 @@ default_chipset:
: DEFMODE_NTSC;
if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
VIDEOMEMSIZE_ECS_1M)
- videomemorysize = VIDEOMEMSIZE_ECS_2M;
+ fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
else
- videomemorysize = VIDEOMEMSIZE_ECS_1M;
+ fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
break;
#endif /* CONFIG_FB_AMIGA_ECS */
#ifdef CONFIG_FB_AMIGA_AGA
case CS_AGA:
- strcat(amifb_name, "AGA");
+ strcat(fb_info.fix.id, "AGA");
chipset = TAG_AGA;
maxdepth[TAG_SHRES] = 8;
maxdepth[TAG_HIRES] = 8;
@@ -1646,16 +2334,16 @@ default_chipset:
defmode = DEFMODE_AGA;
if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
VIDEOMEMSIZE_AGA_1M)
- videomemorysize = VIDEOMEMSIZE_AGA_2M;
+ fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
else
- videomemorysize = VIDEOMEMSIZE_AGA_1M;
+ fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
break;
#endif /* CONFIG_FB_AMIGA_AGA */
default:
#ifdef CONFIG_FB_AMIGA_OCS
printk("Unknown graphics chipset, defaulting to OCS\n");
- strcat(amifb_name, "Unknown");
+ strcat(fb_info.fix.id, "Unknown");
goto default_chipset;
#else /* CONFIG_FB_AMIGA_OCS */
err = -ENXIO;
@@ -1698,31 +2386,25 @@ default_chipset:
fb_info.monspecs.vfmax = 90;
}
- strcpy(fb_info.modename, amifb_name);
- fb_info.changevar = NULL;
fb_info.node = NODEV;
fb_info.fbops = &amifb_ops;
- fb_info.disp = &disp;
- fb_info.currcon = 1;
- fb_info.switch_con = &amifbcon_switch;
- fb_info.updatevar = &amifbcon_updatevar;
+ fb_info.par = &currentpar;
fb_info.flags = FBINFO_FLAG_DEFAULT;
- memset(&var, 0, sizeof(var));
- if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
+ if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
err = -EINVAL;
goto amifb_error;
}
round_down_bpp = 0;
- chipptr = chipalloc(videomemorysize+
+ chipptr = chipalloc(fb_info.fix.smem_len+
SPRITEMEMSIZE+
DUMMYSPRITEMEMSIZE+
COPINITSIZE+
4*COPLISTSIZE);
- assignchunk(videomemory, u_long, chipptr, videomemorysize);
+ assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
@@ -1734,11 +2416,12 @@ default_chipset:
/*
* access the videomem with writethrough cache
*/
- videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
- videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
+ fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
+ videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
+ fb_info.fix.smem_len);
if (!videomemory) {
printk("amifb: WARNING! unable to map videomem cached writethrough\n");
- videomemory = ZTWO_VADDR(videomemory_phys);
+ videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
}
fb_info.screen_base = (char *)videomemory;
@@ -1757,25 +2440,24 @@ default_chipset:
ami_init_copper();
- if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0,
+ if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
"fb vertb handler", &currentpar)) {
err = -EBUSY;
goto amifb_error;
}
- amifb_set_var(&var, -1, &fb_info);
+ fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
if (register_framebuffer(&fb_info) < 0) {
err = -EINVAL;
goto amifb_error;
}
- printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
- minor(fb_info.node), fb_info.modename,
- videomemorysize>>10);
+ printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ minor(fb_info.node), fb_info.fix.id, fb_info.fix.smem_len>>10);
return 0;
-
+
amifb_error:
amifb_deinit();
return err;
@@ -1783,33 +2465,12 @@ amifb_error:
static void amifb_deinit(void)
{
- chipfree();
+ fb_dealloc_cmap(&fb_info.cmap);
+ chipfree();
release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
-static int amifbcon_switch(int con, struct fb_info *info)
-{
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, ami_getcolreg, info);
-
- info->currcon = con;
- ami_set_var(&fb_display[con].var);
- /* Install new colormap */
- do_install_cmap(con, info);
- return 0;
-}
-
- /*
- * Update the `var' structure (called by fbcon.c)
- */
-
-static int amifbcon_updatevar(int con, struct fb_info *info)
-{
- ami_pan_var(&fb_display[con].var);
- return 0;
-}
/*
* Blank the display.
@@ -1821,6 +2482,10 @@ static int amifb_blank(int blank, struct fb_info *info)
return 0;
}
+ /*
+ * Flash the cursor (called by VBlank interrupt)
+ */
+
static int flash_cursor(void)
{
static int cursorcount = 1;
@@ -1875,50 +2540,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
/* --------------------------- Hardware routines --------------------------- */
/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amifb_par *par)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, amifb_name);
- fix->smem_start = videomemory_phys;
- fix->smem_len = videomemorysize;
-
-#ifdef FBCON_HAS_MFB
- if (par->bpp == 1) {
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- } else
-#endif
- if (amifb_ilbm) {
- fix->type = FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux = par->next_line;
- } else {
- fix->type = FB_TYPE_PLANES;
- fix->type_aux = 0;
- }
- fix->line_length = div8(upx(16<<maxfmode, par->vxres));
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
- if (par->vmode & FB_VMODE_YWRAP) {
- fix->ywrapstep = 1;
- fix->xpanstep = fix->ypanstep = 0;
- } else {
- fix->ywrapstep = 0;
- if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
- fix->xpanstep = 1;
- else
- fix->xpanstep = 16<<maxfmode;
- fix->ypanstep = 1;
- }
- fix->accel = FB_ACCEL_AMIGABLITT;
- return 0;
-}
-
- /*
* Get the video params out of `var'. If a value doesn't fit, round
* it up, if it's too big, return -EINVAL.
*/
@@ -2074,7 +2695,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
if (!IS_OCS) {
par->beamcon0 = BMC0_PAL;
par->bplcon3 |= BPC3_BRDRBLNK;
- } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+ } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
par->beamcon0 = BMC0_PAL;
par->hsstop = 1;
@@ -2104,7 +2725,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
if (!IS_OCS) {
par->beamcon0 = 0;
par->bplcon3 |= BPC3_BRDRBLNK;
- } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+ } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
par->beamcon0 = 0;
par->hsstop = 1;
@@ -2235,14 +2856,14 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
if (amifb_ilbm) {
par->next_plane = div8(upx(16<<maxfmode, par->vxres));
par->next_line = par->bpp*par->next_plane;
- if (par->next_line * par->vyres > videomemorysize) {
+ if (par->next_line * par->vyres > fb_info.fix.smem_len) {
DPRINTK("too few video mem\n");
return -EINVAL;
}
} else {
par->next_line = div8(upx(16<<maxfmode, par->vxres));
par->next_plane = par->vyres*par->next_line;
- if (par->next_plane * par->bpp > videomemorysize) {
+ if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
DPRINTK("too few video mem\n");
return -EINVAL;
}
@@ -2402,38 +3023,6 @@ static int ami_encode_var(struct fb_var_screeninfo *var,
return 0;
}
- /*
- * Get current hardware setting
- */
-
-static void ami_get_par(struct amifb_par *par)
-{
- *par = currentpar;
-}
-
- /*
- * Set new videomode
- */
-
-static void ami_set_var(struct fb_var_screeninfo *var)
-{
- do_vmode_pan = 0;
- do_vmode_full = 0;
- ami_decode_var(var, &currentpar);
- ami_build_copper();
- do_vmode_full = 1;
-}
-
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par)
-{
- do_vmode_pan = 0;
- do_vmode_full = 0;
- currentpar = *par;
- ami_build_copper();
- do_vmode_full = 1;
-}
-#endif
/*
* Pan or Wrap the Display
@@ -2506,16 +3095,16 @@ static int ami_update_par(void)
par->bpl1mod = par->bpl2mod;
if (par->yoffset) {
- par->bplpt0 = videomemory_phys + par->next_line*par->yoffset + move;
+ par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
if (par->vmode & FB_VMODE_YWRAP) {
if (par->yoffset > par->vyres-par->yres) {
- par->bplpt0wrap = videomemory_phys + move;
+ par->bplpt0wrap = fb_info.fix.smem_start + move;
if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
par->bplpt0wrap += par->next_line;
}
}
} else
- par->bplpt0 = videomemory_phys + move;
+ par->bplpt0 = fb_info.fix.smem_start + move;
if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
par->bplpt0 += par->next_line;
@@ -2523,45 +3112,6 @@ static int ami_update_par(void)
return 0;
}
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- int len, tr, tg, tb;
-
- if (IS_AGA) {
- if (regno > 255)
- return 1;
- len = 8;
- } else if (currentpar.bplcon0 & BPC0_SHRES) {
- if (regno > 3)
- return 1;
- len = 2;
- } else {
- if (regno > 31)
- return 1;
- len = 4;
- }
- tr = palette[regno].red>>(8-len);
- tg = palette[regno].green>>(8-len);
- tb = palette[regno].blue>>(8-len);
- while (len < 16) {
- tr |= tr<<len;
- tg |= tg<<len;
- tb |= tb<<len;
- len <<= 1;
- }
- *red = tr;
- *green = tg;
- *blue = tb;
- *transp = 0;
- return 0;
-}
-
/*
* Set a single color register. The values supplied are already
@@ -2585,9 +3135,11 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
red >>= 8;
green >>= 8;
blue >>= 8;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
+ if (!regno) {
+ red0 = red;
+ green0 = green;
+ blue0 = blue;
+ }
/*
* Update the corresponding Hardware Color Register, unless it's Color
@@ -2650,6 +3202,7 @@ static void ami_update_display(void)
static void ami_init_display(void)
{
struct amifb_par *par = &currentpar;
+ int i;
custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
@@ -2685,18 +3238,16 @@ static void ami_init_display(void)
is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
#if 1
if (is_lace) {
- if (custom.vposr & 0x8000)
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
- else
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
+ i = custom.vposr >> 15;
} else {
custom.vposw = custom.vposr | 0x8000;
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+ i = 1;
}
#else
+ i = 1;
custom.vposw = custom.vposr | 0x8000;
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
#endif
+ custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
}
/*
@@ -2744,9 +3295,9 @@ static void ami_do_blank(void)
}
} else {
custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
- red = palette[0].red;
- green = palette[0].green;
- blue = palette[0].blue;
+ red = red0;
+ green = green0;
+ blue = blue0;
if (!IS_OCS) {
custom.hsstrt = hsstrt2hw(par->hsstrt);
custom.hsstop = hsstop2hw(par->hsstop);
@@ -2782,11 +3333,7 @@ static void ami_do_blank(void)
is_blanked = do_blank > 0 ? do_blank : 0;
}
- /*
- * Flash the cursor (called by VBlank interrupt)
- */
-
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
{
struct amifb_par *par = &currentpar;
@@ -2797,7 +3344,7 @@ static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
return 0;
}
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
{
struct amifb_par *par = &currentpar;
register u_short *lspr, *sspr;
@@ -2846,7 +3393,7 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i
"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
: "=d" (color), "=d" (datawords) : "1" (datawords));
#else
- color = (((datawords >> 30) & 2)
+ color = (((datawords >> 30) & 2)
| ((datawords >> 15) & 1));
datawords <<= 1;
#endif
@@ -2872,7 +3419,7 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i
return 0;
}
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
{
struct amifb_par *par = &currentpar;
register u_short *lspr, *sspr;
@@ -2991,7 +3538,7 @@ static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i
return 0;
}
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_get_cursorstate(struct fb_cursorstate *state)
{
struct amifb_par *par = &currentpar;
@@ -3001,7 +3548,7 @@ static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
return 0;
}
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_set_cursorstate(struct fb_cursorstate *state)
{
struct amifb_par *par = &currentpar;
@@ -3062,6 +3609,7 @@ static void ami_set_sprite(void)
}
}
+
/*
* Initialise the Copper Initialisation List
*/
diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c
new file mode 100644
index 000000000000..5c30bbd33054
--- /dev/null
+++ b/drivers/video/c2p.c
@@ -0,0 +1,229 @@
+/*
+ * Fast C2P (Chunky-to-Planar) Conversion
+ *
+ * Copyright (C) 2003 Geert Uytterhoeven
+ *
+ * NOTES:
+ * - This code was inspired by Scout's C2P tutorial
+ * - It assumes to run on a big endian system
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/string.h>
+#include "c2p.h"
+
+
+ /*
+ * Basic transpose step
+ */
+
+#define _transp(d, i1, i2, shift, mask) \
+ do { \
+ u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; \
+ d[i1] ^= t; \
+ d[i2] ^= t << shift; \
+ } while (0)
+
+static inline u32 get_mask(int n)
+{
+ switch (n) {
+ case 1:
+ return 0x55555555;
+ break;
+
+ case 2:
+ return 0x33333333;
+ break;
+
+ case 4:
+ return 0x0f0f0f0f;
+ break;
+
+ case 8:
+ return 0x00ff00ff;
+ break;
+
+ case 16:
+ return 0x0000ffff;
+ break;
+ }
+ return 0;
+}
+
+#define transp_nx1(d, n) \
+ do { \
+ u32 mask = get_mask(n); \
+ /* First block */ \
+ _transp(d, 0, 1, n, mask); \
+ /* Second block */ \
+ _transp(d, 2, 3, n, mask); \
+ /* Third block */ \
+ _transp(d, 4, 5, n, mask); \
+ /* Fourth block */ \
+ _transp(d, 6, 7, n, mask); \
+ } while (0)
+
+#define transp_nx2(d, n) \
+ do { \
+ u32 mask = get_mask(n); \
+ /* First block */ \
+ _transp(d, 0, 2, n, mask); \
+ _transp(d, 1, 3, n, mask); \
+ /* Second block */ \
+ _transp(d, 4, 6, n, mask); \
+ _transp(d, 5, 7, n, mask); \
+ } while (0)
+
+#define transp_nx4(d, n) \
+ do { \
+ u32 mask = get_mask(n); \
+ _transp(d, 0, 4, n, mask); \
+ _transp(d, 1, 5, n, mask); \
+ _transp(d, 2, 6, n, mask); \
+ _transp(d, 3, 7, n, mask); \
+ } while (0)
+
+#define transp(d, n, m) transp_nx ## m(d, n)
+
+
+ /*
+ * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
+ * containing
+ * - 32 8-bit chunky pixels on input
+ * - permuted planar data on output
+ */
+
+static void c2p_8bpp(u32 d[8])
+{
+ transp(d, 16, 4);
+ transp(d, 8, 2);
+ transp(d, 4, 1);
+ transp(d, 2, 4);
+ transp(d, 1, 2);
+}
+
+
+ /*
+ * Array containing the permution indices of the planar data after c2p
+ */
+
+static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
+
+
+ /*
+ * Compose two values, using a bitmask as decision value
+ * This is equivalent to (a & mask) | (b & ~mask)
+ */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+ unsigned long mask)
+{
+ return ((a ^ b) & mask) ^ b;
+}
+
+
+ /*
+ * Store a full block of planar data after c2p conversion
+ */
+
+static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8])
+{
+ int i;
+
+ for (i = 0; i < bpp; i++, dst += dst_inc)
+ *(u32 *)dst = d[perm_c2p_8bpp[i]];
+}
+
+
+ /*
+ * Store a partial block of planar data after c2p conversion
+ */
+
+static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp,
+ u32 d[8], u32 mask)
+{
+ int i;
+
+ for (i = 0; i < bpp; i++, dst += dst_inc)
+ *(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask);
+}
+
+
+ /*
+ * c2p - Copy 8-bit chunky image data to a planar frame buffer
+ * @dst: Starting address of the planar frame buffer
+ * @dx: Horizontal destination offset (in pixels)
+ * @dy: Vertical destination offset (in pixels)
+ * @width: Image width (in pixels)
+ * @height: Image height (in pixels)
+ * @dst_nextline: Frame buffer offset to the next line (in bytes)
+ * @dst_nextplane: Frame buffer offset to the next plane (in bytes)
+ * @src_nextline: Image offset to the next line (in bytes)
+ * @bpp: Bits per pixel of the planar frame buffer (1-8)
+ */
+
+void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+ u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp)
+{
+ int dst_idx;
+ u32 d[8], first, last, w;
+ const u8 *c;
+ u8 *p;
+
+ dst += dy*dst_nextline+(dx & ~31);
+ dst_idx = dx % 32;
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+width) % 32));
+ while (height--) {
+ c = src;
+ p = dst;
+ w = width;
+ if (dst_idx+width <= 32) {
+ /* Single destination word */
+ first &= last;
+ memset(d, 0, sizeof(d));
+ memcpy((u8 *)d+dst_idx, c, width);
+ c += width;
+ c2p_8bpp(d);
+ store_planar_masked(p, dst_nextplane, bpp, d, first);
+ p += 4;
+ } else {
+ /* Multiple destination words */
+ w = width;
+ /* Leading bits */
+ if (dst_idx) {
+ w = 32 - dst_idx;
+ memset(d, 0, dst_idx);
+ memcpy((u8 *)d+dst_idx, c, w);
+ c += w;
+ c2p_8bpp(d);
+ store_planar_masked(p, dst_nextplane, bpp, d, first);
+ p += 4;
+ w = width-w;
+ }
+ /* Main chunk */
+ while (w >= 32) {
+ memcpy(d, c, 32);
+ c += 32;
+ c2p_8bpp(d);
+ store_planar(p, dst_nextplane, bpp, d);
+ p += 4;
+ w -= 32;
+ }
+ /* Trailing bits */
+ w %= 32;
+ if (w > 0) {
+ memcpy(d, c, w);
+ memset((u8 *)d+w, 0, 32-w);
+ c2p_8bpp(d);
+ store_planar_masked(p, dst_nextplane, bpp, d, last);
+ }
+ }
+ src += src_nextline;
+ dst += dst_nextline;
+ }
+}
+
diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h
new file mode 100644
index 000000000000..c77cbf17e043
--- /dev/null
+++ b/drivers/video/c2p.h
@@ -0,0 +1,16 @@
+/*
+ * Fast C2P (Chunky-to-Planar) Conversion
+ *
+ * Copyright (C) 2003 Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+
+extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+ u32 dst_nextline, u32 dst_nextplane, u32 src_nextline,
+ u32 bpp);
+
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 4b9cfc5e38b9..3fc167670230 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -456,7 +456,7 @@ void accel_clear_margins(struct vc_data *vc, struct display *p,
region.color = attr_bgcol_ec(p, vc);
region.rop = ROP_COPY;
- if (rw & !bottom_only) {
+ if (rw && !bottom_only) {
region.dx = info->var.xoffset + rs;
region.dy = 0;
region.width = rw;
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index 1809827e3af9..9d0a3e908771 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -103,11 +103,6 @@
#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
-#if 0
-#define outb(a,d) *(char *)(a)=(d)
-#define outw(a,d) *(unsigned short *)a=d
-#endif
-
static struct fb_info fb_info;
/* frame buffer operations */
@@ -147,9 +142,9 @@ static struct fb_fix_screeninfo dnfb_fix __initdata = {
static int dnfb_blank(int blank, struct fb_info *info)
{
if (blank)
- outb(0x0, AP_CONTROL_3A);
+ out_8(AP_CONTROL_3A, 0x0);
else
- outb(0x1, AP_CONTROL_3A);
+ out_8(AP_CONTROL_3A, 0x1);
return 0;
}
@@ -175,8 +170,8 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
x_word_count = (x_end >> 4) - (area->dx >> 4) + 1;
start_mask = 0xffff0000 >> (area->dx & 0xf);
end_mask = 0x7ffff >> (x_end & 0xf);
- outb((((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5),
- AP_CONTROL_0);
+ out_8(AP_CONTROL_0,
+ (((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5));
if ((area->dx & 0xf) < (area->sx & 0xf))
pre_read = 1;
} else {
@@ -185,15 +180,16 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
x_word_count = (area->dx >> 4) - (x_end >> 4) + 1;
start_mask = 0x7ffff >> (area->dx & 0xf);
end_mask = 0xffff0000 >> (x_end & 0xf);
- outb(((-((area->sx & 0xf) - (area->dx & 0xf))) %
- 16) | (0x4 << 5), AP_CONTROL_0);
+ out_8(AP_CONTROL_0,
+ ((-((area->sx & 0xf) - (area->dx & 0xf))) % 16) |
+ (0x4 << 5));
if ((area->dx & 0xf) > (area->sx & 0xf))
pre_read = 1;
}
for (i = 0; i < area->height; i++) {
- outb(0xc | (dest >> 16), AP_CONTROL_3A);
+ out_8(AP_CONTROL_3A, 0xc | (dest >> 16));
if (pre_read) {
dummy = *src;
@@ -201,11 +197,11 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
}
if (x_word_count) {
- outb(start_mask, AP_WRITE_ENABLE);
+ out_8(AP_WRITE_ENABLE, start_mask);
*src = dest;
src += incr;
dest += incr;
- outb(0, AP_WRITE_ENABLE);
+ out_8(AP_WRITE_ENABLE, 0);
for (j = 1; j < (x_word_count - 1); j++) {
*src = dest;
@@ -213,12 +209,12 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
dest += incr;
}
- outb(start_mask, AP_WRITE_ENABLE);
+ out_8(AP_WRITE_ENABLE, start_mask);
*src = dest;
dest += incr;
src += incr;
} else {
- outb(start_mask | end_mask, AP_WRITE_ENABLE);
+ out_8(AP_WRITE_ENABLE, start_mask | end_mask);
*src = dest;
dest += incr;
src += incr;
@@ -226,7 +222,7 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
src += (y_delta / 16);
dest += (y_delta / 16);
}
- outb(NORMAL_MODE, AP_CONTROL_0);
+ out_8(AP_CONTROL_0, NORMAL_MODE);
}
@@ -247,12 +243,12 @@ unsigned long __init dnfb_init(unsigned long mem_start)
panic("unable to register apollo frame buffer\n");
/* now we have registered we can safely setup the hardware */
- outb(RESET_CREG, AP_CONTROL_3A);
- outw(0x0, AP_WRITE_ENABLE);
- outb(NORMAL_MODE, AP_CONTROL_0);
- outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
- outb(S_DATA_PLN, AP_CONTROL_2);
- outw(SWAP(0x3), AP_ROP_1);
+ out_8(AP_CONTROL_3A, RESET_CREG);
+ out_be16(AP_WRITE_ENABLE, 0x0);
+ out_8(AP_CONTROL_0, NORMAL_MODE);
+ out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1));
+ out_8(AP_CONTROL_2, S_DATA_PLN);
+ out_be16(AP_ROP_1, SWAP(0x3));
printk("apollo frame buffer alive and kicking !\n");
return mem_start;