Commit 159f5e24 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.35pre4

parent 587f241d
SiS 900/7016 Fast Ethernet Device Driver
by Ollie Lho (ollie@sis.com.tw)
November 4, 1999. Document Revision: 0.1
November 4, 1999. Document Revision: 0.2
This document gives some information on installation and usage of SiS
900/7016 device driver under Linux.
......@@ -17,7 +17,7 @@
4. Tested Environment
5. Files in This Rackage
5. Files in This Package
6. Installation
......@@ -111,9 +111,11 @@
9. Names of variables were changed to be more consistent.
10. Clean up of auo-negotiation and timer code.
10.
Clean up of auo-negotiation and timer code.
11. Automatic detection and change of PHY on the fly.
11.
Automatic detection and change of PHY on the fly.
4. Tested Environment
......@@ -137,7 +139,7 @@
o Samba version 2.0.3
5. Files in This Rackage
5. Files in This Package
In the package you can find these files:
......@@ -157,10 +159,16 @@
6. Installation
Before trying to install the driver, be sure to get the latest
revision from SiS' Home Page. If you have no prior experience in
networking under Linux, please read Ethernet HOWTO and Networking
HOWTO available from Linux Documentation Project (LDP).
Silicon Integrated System Corp. is cooperating closely with core Linux
Kernel developers. The revisions of SiS 900 driver are distributed by
the usuall channels for kernel tar files and patches. Those kernel tar
files for official kernel and patches for kernel pre-release can be
download at official kernel ftp site
<http://ftp.kernel.org/pub/linux/kernel/> and its mirrors. The 1.06
revision can be found in kernel version later than 2.3.15 and
pre-2.2.14. If you have no prior experience in networking under
Linux, please read Ethernet HOWTO and Networking HOWTO available from
Linux Documentation Project (LDP).
The installation procedure are different according to your kernel
versions.
......@@ -244,6 +252,7 @@
sis900.c: v1.06 11/04/99
eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
eth0: SiS 900 Internal MII PHY transceiver found at address 1.
eth0: Using SiS 900 Internal MII PHY as default
......@@ -269,7 +278,6 @@
eth0: Using SiS 900 Internal MII PHY as default
eth0: Media Link On 100mbps full-duplex
......
......@@ -119,6 +119,7 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
source drivers/parport/Config.in
bool 'ACPI support' CONFIG_ACPI
bool 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
......
......@@ -71,6 +71,7 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
# CONFIG_PARPORT is not set
CONFIG_ACPI=y
# CONFIG_APM is not set
#
......@@ -405,7 +406,6 @@ CONFIG_DRM_TDFX=y
#
# Misc devices
#
CONFIG_ACPI=y
#
# Filesystems
......
......@@ -39,6 +39,10 @@ else
endif
endif
ifeq ($(CONFIG_ACPI),y)
OX_OBJS += acpi.o
endif
ifeq ($(CONFIG_APM),y)
OX_OBJS += apm.o
else
......
......@@ -110,6 +110,8 @@ static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(acpi_devs);
/* Make it impossible to enter C2/C3 until after we've initialized */
static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT;
......@@ -636,87 +638,143 @@ static int acpi_disable(struct acpi_facp *facp)
return 0;
}
static inline int bm_activity(void)
{
return 0 && acpi_read_pm1_status(acpi_facp) & ACPI_BM;
}
static inline void clear_bm_activity(void)
{
acpi_write_pm1_status(acpi_facp, ACPI_BM);
}
static void sleep_on_busmaster(void)
{
u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
if (pm1_cntr & ACPI_BM_RLD) {
pm1_cntr &= ~ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cntr);
}
}
static void wake_on_busmaster(void)
{
u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
if (!(pm1_cntr & ACPI_BM_RLD)) {
pm1_cntr |= ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cntr);
}
clear_bm_activity();
}
/*
* Idle loop (uniprocessor only)
*/
static void acpi_idle_handler(void)
{
static int sleep_level = 1;
u32 pm1_cnt, timer, pm2_cnt, bm_active;
unsigned long time;
// return to C0 on bus master request (necessary for C3 only)
pm1_cnt = acpi_read_pm1_control(acpi_facp);
if (sleep_level == 3) {
if (!(pm1_cnt & ACPI_BM_RLD)) {
pm1_cnt |= ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cnt);
}
}
else {
if (pm1_cnt & ACPI_BM_RLD) {
pm1_cnt &= ~ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cnt);
}
}
// clear bus master activity flag
acpi_write_pm1_status(acpi_facp, ACPI_BM);
if (!acpi_facp->pm_tmr || !acpi_p_blk)
goto not_initialized;
// get current time
timer = acpi_facp->pm_tmr;
time = inl(timer);
// sleep
switch (sleep_level) {
case 1:
__asm__ __volatile__("sti ; hlt": : :"memory");
break;
case 2:
inb(acpi_p_blk + ACPI_P_LVL2);
break;
case 3:
pm2_cnt = acpi_facp->pm2_cnt;
if (pm2_cnt) {
/* Disable PCI arbitration while sleeping,
to avoid DMA corruption? */
cli();
outb(inb(pm2_cnt) | ACPI_ARB_DIS, pm2_cnt);
inb(acpi_p_blk + ACPI_P_LVL3);
outb(inb(pm2_cnt) & ~ACPI_ARB_DIS, pm2_cnt);
sti();
}
else {
inb(acpi_p_blk + ACPI_P_LVL3);
}
break;
/*
* start from the previous sleep level..
*/
if (sleep_level == 1)
goto sleep1;
if (sleep_level == 2 || bm_activity())
goto sleep2;
sleep3:
sleep_level = 3;
if (!acpi_p_lvl3_tested) {
printk("ACPI C3 works\n");
acpi_p_lvl3_tested = 1;
}
wake_on_busmaster();
if (acpi_facp->pm2_cnt)
goto sleep3_with_arbiter;
// calculate time spent sleeping
time = (inl(timer) - time) & ACPI_TMR_MASK;
for (;;) {
unsigned long time;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
inb(acpi_p_blk + ACPI_P_LVL3);
time = inl(acpi_facp->pm_tmr) - time;
__sti();
if (time > acpi_p_lvl3_lat || bm_activity())
goto sleep2;
}
// check for bus master activity
bm_active = (acpi_read_pm1_status(acpi_facp) & ACPI_BM);
sleep3_with_arbiter:
for (;;) {
unsigned long time;
unsigned int pm2_cntr = acpi_facp->pm2_cnt;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
outb(inb(pm2_cntr) | ACPI_ARB_DIS, pm2_cntr);
inb(acpi_p_blk + ACPI_P_LVL3);
outb(inb(pm2_cntr) & ~ACPI_ARB_DIS, pm2_cntr);
time = inl(acpi_facp->pm_tmr) - time;
__sti();
if (time > acpi_p_lvl3_lat || bm_activity())
goto sleep2;
}
// record working C2/C3
if (sleep_level == 2 && !acpi_p_lvl2_tested) {
sleep2:
sleep_level = 2;
if (!acpi_p_lvl2_tested) {
printk("ACPI C2 works\n");
acpi_p_lvl2_tested = 1;
printk(KERN_INFO "ACPI: C2 works\n");
}
else if (sleep_level == 3 && !acpi_p_lvl3_tested) {
acpi_p_lvl3_tested = 1;
printk(KERN_INFO "ACPI: C3 works\n");
wake_on_busmaster(); /* Required to track BM activity.. */
for (;;) {
unsigned long time;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
inb(acpi_p_blk + ACPI_P_LVL2);
time = inl(acpi_facp->pm_tmr) - time;
__sti();
if (time > acpi_p_lvl2_lat)
goto sleep1;
if (bm_activity()) {
clear_bm_activity();
continue;
}
if (time < acpi_enter_lvl3_lat)
goto sleep3;
}
// pick next C-state based on time spent sleeping,
// C-state latencies, and bus master activity
sleep1:
sleep_level = 1;
if (acpi_p_blk) {
if (time > acpi_p_lvl3_lat && !bm_active)
sleep_level = 3;
else if (time > acpi_p_lvl2_lat)
sleep_level = 2;
sleep_on_busmaster();
for (;;) {
unsigned long time;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
__asm__ __volatile__("sti ; hlt": : :"memory");
time = inl(acpi_facp->pm_tmr) - time;
if (time < acpi_enter_lvl2_lat)
goto sleep2;
}
not_initialized:
for (;;) {
__cli();
if (current->need_resched)
goto out;
__asm__ __volatile__("sti ; hlt": : :"memory");
}
out:
__sti();
}
/*
......@@ -1119,10 +1177,12 @@ static int __init acpi_init(void)
if (acpi_facp->p_lvl2_lat
&& acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat;
acpi_enter_lvl2_lat = ACPI_TMR_HZ / 1000;
}
if (acpi_facp->p_lvl3_lat
&& acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat;
acpi_enter_lvl3_lat = acpi_facp->p_lvl3_lat * 5;
}
if (acpi_facp->sci_int
......
......@@ -772,6 +772,41 @@ unsigned long probe_irq_on(void)
return 0x12345678;
}
/*
* Return a mask of triggered interrupts (this
* can handle only legacy ISA interrupts).
*/
unsigned int probe_irq_mask(unsigned long unused)
{
int i;
unsigned int mask;
if (unused != 0x12345678)
printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
mask = 0;
spin_lock_irq(&irq_controller_lock);
for (i = 0; i < 16; i++) {
unsigned int status = irq_desc[i].status;
if (!(status & IRQ_AUTODETECT))
continue;
if (!(status & IRQ_WAITING))
mask |= 1 << i;
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
}
spin_unlock_irq(&irq_controller_lock);
return mask;
}
/*
* Return the one interrupt that triggered (this can
* handle any interrupt source)
*/
int probe_irq_off(unsigned long unused)
{
int i, irq_found, nr_irqs;
......
......@@ -709,7 +709,7 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE) {
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) {
reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start =
......
......@@ -185,6 +185,8 @@ static void rd_request(request_queue_t * q)
{
unsigned int minor;
unsigned long offset, len;
struct buffer_head *rbh;
struct buffer_head *sbh;
repeat:
INIT_REQUEST;
......@@ -211,16 +213,66 @@ static void rd_request(request_queue_t * q)
}
/*
* If we're reading, fill the buffer with 0's. This is okay since
* we're using protected buffers which should never get freed...
* This has become somewhat more complicated with the addition of
* the page cache. The problem is that in some cases the furnished
* buffer is "real", i.e., part of the existing ramdisk, while in
* others it is "unreal", e.g., part of a page. In the first case
* not much needs to be done, while in the second, some kind of
* transfer is needed.
*
* The two cases are distinguished here by checking whether the
* real buffer is already in the buffer cache, and whether it is
* the same as the one supplied.
*
* If we're writing, we protect the buffer.
*/
* There are three cases with read/write to consider:
*
* 1. Supplied buffer matched one in the buffer cache:
* Read - Clear the buffer, as it wasn't already valid.
* Write - Mark the buffer as "Protected".
*
* 2. Supplied buffer mismatched one in the buffer cache:
* Read - Copy the data from the buffer cache entry.
* Write - Copy the data to the buffer cache entry.
*
* 3 No buffer cache entry existed:
* Read - Clear the supplied buffer, but do not create a real
* one.
* Write - Create a real buffer, copy the data to it, and mark
* it as "Protected".
*
* NOTE: There seems to be some schizophrenia here - the logic
* using "len" seems to assume arbitrary request lengths, while
* the "protect" logic assumes a single buffer cache entry.
* This seems to be left over from the ancient contiguous ramdisk
* logic.
*/
if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 0, len);
else
set_bit(BH_Protected, &CURRENT->bh->b_state);
sbh = CURRENT->bh;
rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
if (sbh == rbh) {
if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 1, len);
} else if (rbh) {
if (CURRENT->cmd == READ)
memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
else
memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
} else { /* !rbh */
if (CURRENT->cmd == READ)
memset(sbh->b_data, 2, len);
else {
rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
if (rbh)
memcpy(rbh->b_data, CURRENT->buffer,
rbh->b_size);
else
BUG(); /* No buffer, what to do here? */
}
}
if (rbh) {
set_bit(BH_Protected, &rbh->b_state);
brelse(rbh);
}
end_request(1);
goto repeat;
......
......@@ -4,6 +4,4 @@
mainmenu_option next_comment
comment 'Misc devices'
bool 'ACPI support' CONFIG_ACPI
endmenu
......@@ -18,10 +18,6 @@ M_OBJS :=
O_OBJS :=
OX_OBJS :=
ifeq ($(CONFIG_ACPI),y)
OX_OBJS += acpi.o
endif
include $(TOPDIR)/Rules.make
fastdep:
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Silicon Integrated System Corporation
Revision: 1.05 Aug 7 1999
Copyright 1999 Silicon Integrated System Corporation
Revision: 1.06.03 Dec 23 1999
Modified from the driver which is originally written by Donald Becker.
......@@ -18,6 +18,9 @@
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release
Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx
Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
......@@ -47,7 +50,7 @@
#include "sis900.h"
static const char *version =
"sis900.c: v1.06 11/04/99\n";
"sis900.c: v1.06.03 12/23/99\n";
static int max_interrupt_work = 20;
#define sis900_debug debug
......@@ -221,6 +224,8 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct
if (did_version++ == 0)
printk(KERN_INFO "%s", version);
if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
return NULL;
/* check to see if we have sane EEPROM */
signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) {
......@@ -229,9 +234,6 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct
return NULL;
}
if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
return NULL;
printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
ioaddr, irq);
......@@ -509,7 +511,7 @@ sis900_open(struct net_device *net_dev)
net_dev->start = 1;
/* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
outl(RxENA, ioaddr + cr);
outl(IE, ioaddr + ier);
......@@ -787,6 +789,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
{
struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
long ioaddr = net_dev->base_addr;
int i;
printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
......@@ -794,14 +797,26 @@ static void sis900_tx_timeout(struct net_device *net_dev)
/* Disable interrupts by clearing the interrupt mask. */
outl(0x0000, ioaddr + imr);
sis_priv->cur_rx = 0;
/* discard unsent packets, should this code section be protected by
cli(), sti() ?? */
sis_priv->dirty_tx = sis_priv->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
if (sis_priv->tx_skbuff[i] != NULL) {
dev_kfree_skb(sis_priv->tx_skbuff[i]);
sis_priv->tx_skbuff[i] = 0;
sis_priv->tx_ring[i].cmdsts = 0;
sis_priv->tx_ring[i].bufptr = 0;
sis_priv->stats.tx_dropped++;
}
}
net_dev->trans_start = jiffies;
sis_priv->stats.tx_errors++;
net_dev->tbusy = sis_priv->tx_full = 0;
/* FIXME: Should we restart the transmission thread here ?? */
/* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
return;
}
......@@ -876,13 +891,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
do {
status = inl(ioaddr + isr);
if (sis900_debug > 3)
printk(KERN_INFO "%s: entering interrupt, "
"original status = %#8.8x, "
"new status = %#8.8x.\n",
net_dev->name, status, inl(ioaddr + isr));
if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0)
if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
/* nothing intresting happened */
break;
......@@ -891,7 +900,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Rx interrupt */
sis900_rx(net_dev);
if (status & (TxURN | TxERR | TxOK))
if (status & (TxURN | TxERR | TxIDLE))
/* Tx interrupt */
sis900_finish_xmit(net_dev);
......@@ -961,6 +970,9 @@ static int sis900_rx(struct net_device *net_dev)
} else {
struct sk_buff * skb;
/* This situation should never happen, but due to
some unknow bugs, it is possible that
we are working on NULL sk_buff :-( */
if (sis_priv->rx_skbuff[entry] == NULL) {
printk(KERN_INFO "%s: NULL pointer "
"encountered in Rx ring, skipping\n",
......@@ -1033,7 +1045,9 @@ static void sis900_finish_xmit (struct net_device *net_dev)
tx_status = sis_priv->tx_ring[entry].cmdsts;
if (tx_status & OWN) {
/* The packet is not transmited yet (owned by hardware) ! */
/* The packet is not transmited yet (owned by hardware) !
Note: the interrupt is generated only when Tx Machine
is idle, so this is an almost impossible case */
break;
}
......@@ -1054,8 +1068,6 @@ static void sis900_finish_xmit (struct net_device *net_dev)
sis_priv->stats.tx_window_errors++;
} else {
/* packet successfully transmited */
if (sis900_debug > 3)
printk(KERN_INFO "Tx Transmit OK\n");
sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
sis_priv->stats.tx_bytes += tx_status & DSIZE;
sis_priv->stats.tx_packets++;
......@@ -1069,8 +1081,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (sis_priv->tx_full && net_dev->tbusy &&
sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
/* The ring is no longer full, clear tbusy, tx_full and schedule
more transmission by marking NET_BH */
/* The ring is no longer full, clear tbusy, tx_full and
schedule more transmission by marking NET_BH */
sis_priv->tx_full = 0;
clear_bit(0, (void *)&net_dev->tbusy);
mark_bh(NET_BH);
......@@ -1153,11 +1165,13 @@ static u16 sis900_compute_hashtable_index(u8 *addr)
{
/* what is the correct value of the POLYNOMIAL ??
Donald Becker use 0x04C11DB7U */
#define POLYNOMIAL 0x04C11DB6L
Donald Becker use 0x04C11DB7U
Joseph Zbiciak im14u2c@primenet.com gives me the
correct answer, thank you Joe !! */
#define POLYNOMIAL 0x04C11DB7L
u32 crc = 0xffffffff, msb;
int i, j;
u8 byte;
u32 byte;
for (i = 0; i < 6; i++) {
byte = *addr++;
......@@ -1166,7 +1180,6 @@ static u16 sis900_compute_hashtable_index(u8 *addr)
crc <<= 1;
if (msb ^ (byte & 1)) {
crc ^= POLYNOMIAL;
crc |= 1;
}
byte >>= 1;
}
......@@ -1208,7 +1221,7 @@ static void set_rx_mode(struct net_device *net_dev)
/* update Multicast Hash Table in Receive Filter */
for (i = 0; i < 8; i++) {
/* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */
+ /* why plus 0x04 ??, That makes the correct value for hash table. */
outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
outl(mc_filter[i], ioaddr + rfdr);
}
......
......@@ -92,8 +92,8 @@ enum sis900_transmit_config_register_bits {
/* recevie FIFO thresholds */
#define RxDRNT_shift 1
#define RxDRNT_100 24 /* 3/4 FIFO size */
#define RxDRNT_10 16 /* 1/2 FIFO size */
#define RxDRNT_100 16 /* 1/2 FIFO size */
#define RxDRNT_10 24 /* 3/4 FIFO size */
enum sis900_reveive_config_register_bits {
RxAEP = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000,
......
This diff is collapsed.
......@@ -8,11 +8,12 @@ struct pci_socket_ops;
typedef struct pci_socket {
struct pci_dev *dev;
int irq;
int cb_irq, io_irq;
void *base;
void (*handler)(void *, unsigned int);
void *info;
struct pci_socket_ops *op;
socket_cap_t cap;
} pci_socket_t;
struct pci_socket_ops {
......
......@@ -7,6 +7,7 @@
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <pcmcia/ss.h>
......@@ -19,19 +20,9 @@
#define to_cycles(ns) ((ns)/120)
#define to_ns(cycles) ((cycles)*120)
/* Fixme! */
static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
{
cap->features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
cap->irq_mask = 0xdeb8; /* irq 15,14,12,11,10,9,7,5,4,3 */
cap->map_size = 0x1000;
cap->pci_irq = socket->irq;
cap->cardbus = 0;
cap->cb_bus = NULL;
cap->bus = NULL;
printk("yenta_inquire()\n");
*cap = socket->cap;
return 0;
}
......@@ -92,7 +83,7 @@ static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state)
state->Vcc = yenta_Vcc_power(control);
state->Vpp = yenta_Vpp_power(control);
state->io_irq = socket->irq;
state->io_irq = socket->io_irq;
reg = exca_readb(socket, I365_POWER);
state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
......@@ -129,14 +120,37 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta
bridge &= ~CB_BRIDGE_CRST;
bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
reg = socket->irq;
/* Set the IO interrupt and socket state */
reg = state->io_irq;
reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
exca_writeb(socket, I365_INTCTL, reg);
/* Set host interrupt and CSC mask state */
reg = socket->cb_irq << 4;
reg |= (state->csc_mask & SS_DETECT) ? I365_CSC_DETECT : 0;
if (state->flags & SS_IOCARD) {
reg |= (state->csc_mask & SS_STSCHG) ? I365_CSC_STSCHG : 0;
} else {
reg |= (state->csc_mask & SS_BATDEAD) ? I365_CSC_BVD1 : 0;
reg |= (state->csc_mask & SS_BATWARN) ? I365_CSC_BVD2 : 0;
reg |= (state->csc_mask & SS_READY) ? I365_CSC_READY : 0;
}
exca_writeb(socket, I365_CSCINT, reg);
exca_readb(socket, I365_CSC);
/*
* Set power state..
*
* I wonder if we could do the Vcc/Vpp part through the
* CB interface only..
*/
reg = I365_PWR_NORESET;
control = 0; /* CB_STOPCLK ? Better power management */
reg |= (state->flags & SS_PWR_AUTO) ? I365_PWR_AUTO : 0;
reg |= (state->flags & SS_OUTPUT_ENA) ? I365_PWR_OUT : 0;
control = CB_STOPCLK;
switch (state->Vcc) {
case 33:
control |= CB_PWR3V << CB_VCCCTRL;
......@@ -161,24 +175,8 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta
reg |= I365_VPP1_12V;
break;
}
cb_writel(socket, CB_SOCKET_CONTROL, control);
reg |= (state->flags & SS_PWR_AUTO) ? I365_PWR_AUTO : 0;
reg |= (state->flags & SS_OUTPUT_ENA) ? I365_PWR_OUT : 0;
if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
exca_writeb(socket, I365_POWER, reg);
reg = socket->irq;
reg |= (state->csc_mask & SS_DETECT) ? I365_CSC_DETECT : 0;
if (state->flags & SS_IOCARD) {
reg |= (state->csc_mask & SS_STSCHG) ? I365_CSC_STSCHG : 0;
} else {
reg |= (state->csc_mask & SS_BATDEAD) ? I365_CSC_BVD1 : 0;
reg |= (state->csc_mask & SS_BATWARN) ? I365_CSC_BVD2 : 0;
reg |= (state->csc_mask & SS_READY) ? I365_CSC_READY : 0;
}
exca_writeb(socket, I365_CSCINT, reg);
exca_readb(socket, I365_CSC);
cb_writel(socket, CB_SOCKET_CONTROL, control);
return 0;
}
......@@ -329,6 +327,8 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
word |= I365_MEM_REG;
exca_writew(socket, I365_MEM(map) + I365_W_OFF, word);
exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
if (mem->flags & MAP_ACTIVE)
exca_writeb(socket, I365_ADDRWIN, addr | enable);
return 0;
......@@ -336,14 +336,65 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
static int yenta_get_bridge(pci_socket_t *socket, struct cb_bridge_map *m)
{
printk("yenta_get_bridge() called\n");
return -EINVAL;
unsigned map;
map = m->map;
if (map > 1)
return -EINVAL;
m->flags &= MAP_IOSPACE;
map += (m->flags & MAP_IOSPACE) ? 2 : 0;
m->start = config_readl(socket, CB_BRIDGE_BASE(map));
m->stop = config_readl(socket, CB_BRIDGE_LIMIT(map));
if (m->start || m->stop) {
m->flags |= MAP_ACTIVE;
m->stop |= (map > 1) ? 3 : 0x0fff;
}
/* Get prefetch state for memory mappings */
if (map < 2) {
u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map;
ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
m->flags |= (ctrl & prefetch_mask) ? MAP_PREFETCH : 0;
}
return 0;
}
static int yenta_set_bridge(pci_socket_t *socket, struct cb_bridge_map *m)
{
printk("yenta_set_bridge() called\n");
return -EINVAL;
unsigned map;
u32 start, end;
map = m->map;
if (map > 1 || m->stop < m->start)
return -EINVAL;
if (m->flags & MAP_IOSPACE) {
if ((m->stop > 0xffff) || (m->start & 3) ||
((m->stop & 3) != 3))
return -EINVAL;
map += 2;
} else {
u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map;
if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff))
return -EINVAL;
ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
ctrl &= ~prefetch_mask;
ctrl |= (m->flags & MAP_PREFETCH) ? prefetch_mask : 0;
config_writew(socket, CB_BRIDGE_CONTROL, ctrl);
}
start = 0;
end = 0;
if (m->flags & MAP_ACTIVE) {
start = m->start;
end = m->stop;
}
config_writel(socket, CB_BRIDGE_BASE(map), start);
config_writel(socket, CB_BRIDGE_LIMIT(map), end);
return 0;
}
static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base)
......@@ -380,6 +431,39 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
socket->handler(socket->info, events);
}
static unsigned int yenta_probe_irq(pci_socket_t *socket)
{
int i;
unsigned long val;
cb_writel(socket, CB_SOCKET_EVENT, -1);
cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
val = probe_irq_on();
for (i = 1; i < 16; i++) {
exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
udelay(100);
cb_writel(socket, CB_SOCKET_EVENT, -1);
}
cb_writel(socket, CB_SOCKET_MASK, 0);
return probe_irq_mask(val);
}
static void yenta_get_socket_capabilities(pci_socket_t *socket)
{
socket->cap.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
socket->cap.irq_mask = yenta_probe_irq(socket);
if (socket->cb_irq && socket->cb_irq < 16)
socket->cap.irq_mask |= 1 << socket->cb_irq;
socket->cap.map_size = 0x1000;
socket->cap.pci_irq = socket->cb_irq;
socket->cap.cardbus = config_readb(socket, PCI_CB_CARD_BUS);
socket->cap.cb_bus = socket->dev->subordinate;
socket->cap.bus = NULL;
printk("Yenta IRQ list %04x\n", socket->cap.irq_mask);
}
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
......@@ -396,10 +480,6 @@ static int yenta_open(pci_socket_t *socket)
printk("Unable to enable device\n");
return -1;
}
if (!dev->irq) {
printk("No cardbus irq!\n");
return -1;
}
if (!dev->resource[0].start) {
printk("No cardbus resource!\n");
return -1;
......@@ -412,9 +492,12 @@ static int yenta_open(pci_socket_t *socket)
socket->base = ioremap(dev->resource[0].start, 0x1000);
if (!socket->base)
return -1;
if (request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
return -1;
socket->irq = dev->irq;
if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
socket->cb_irq = dev->irq;
/* Figure out what the dang thing can do.. */
yenta_get_socket_capabilities(socket);
/* Enable all events */
writel(0x0f, socket->base + 4);
......@@ -428,8 +511,8 @@ static int yenta_open(pci_socket_t *socket)
*/
static void yenta_close(pci_socket_t *sock)
{
if (sock->irq)
free_irq(sock->irq, sock);
if (sock->cb_irq)
free_irq(sock->cb_irq, sock);
if (sock->base)
iounmap(sock->base);
}
......
......@@ -102,6 +102,8 @@
/*
* Cardbus configuration space
*/
#define CB_BRIDGE_BASE(m) (0x1c + 8*(m))
#define CB_BRIDGE_LIMIT(m) (0x20 + 8*(m))
#define CB_BRIDGE_CONTROL 0x3e
#define CB_BRIDGE_CPERREN 0x00000001
#define CB_BRIDGE_CSERREN 0x00000002
......
......@@ -821,12 +821,14 @@ void scsi_request_fn(request_queue_t * q)
* get those allocated here.
*/
if (!SDpnt->scsi_init_io_fn(SCpnt)) {
spin_lock_irq(&io_request_lock);
continue;
}
/*
* Initialize the actual SCSI command for this request.
*/
if (!STpnt->init_command(SCpnt)) {
spin_lock_irq(&io_request_lock);
continue;
}
}
......
This diff is collapsed.
......@@ -513,7 +513,7 @@ static struct pid_entry base_stuff[] = {
E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO),
E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO),
#ifdef SMP
#ifdef __SMP__
E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO),
#endif
#if CONFIG_AP1000
......@@ -865,7 +865,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
case PROC_PID_MAPS:
inode->i_op = &proc_maps_inode_operations;
break;
#ifdef SMP
#ifdef __SMP__
case PROC_PID_CPU:
inode->i_op = &proc_info_inode_operations;
inode->u.proc_i.op.proc_read = proc_pid_cpu;
......
......@@ -42,6 +42,7 @@ struct i2c_device;
#define I2C_BUSID_PARPORT 2 /* Bit banging on a parallel port */
#define I2C_BUSID_BUZ 3
#define I2C_BUSID_ZORAN 4
#define I2C_BUSID_CYBER2000 5
/*
* struct for a driver for a i2c chip (tuner, soundprocessor,
......
......@@ -80,5 +80,6 @@ enum {
*/
extern unsigned long probe_irq_on(void); /* returns 0 on failure */
extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */
extern unsigned int probe_irq_mask(unsigned long); /* returns mask of ISA interrupts */
#endif
......@@ -299,6 +299,7 @@ struct pci_dev {
int ro; /* Read/Only */
struct pci_bus *bus; /* bus this device is on */
struct pci_bus *subordinate; /* bus this device bridges to */
struct pci_dev *sibling; /* next device on this bus */
struct pci_dev *next; /* chain of all devices */
......
......@@ -484,6 +484,7 @@ asmlinkage void __init start_kernel(void)
kmem_cache_init();
sti();
calibrate_delay();
#if 0000
#ifdef CONFIG_BLK_DEV_INITRD
// FIXME, use the bootmem.h interface.
if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
......@@ -492,6 +493,7 @@ asmlinkage void __init start_kernel(void)
initrd_start = 0;
}
#endif
#endif /* 0000 */
mem_init();
kmem_cache_sizes_init();
#ifdef CONFIG_PROC_FS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment