aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/ec.c73
-rw-r--r--drivers/acpi/thermal.c16
2 files changed, 42 insertions, 47 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 8dfcbb8aff73..a2b82c90a683 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -120,31 +120,6 @@ static struct acpi_ec {
120 spinlock_t curr_lock; 120 spinlock_t curr_lock;
121} *boot_ec, *first_ec; 121} *boot_ec, *first_ec;
122 122
123/*
124 * Some Asus system have exchanged ECDT data/command IO addresses.
125 */
126static int print_ecdt_error(const struct dmi_system_id *id)
127{
128 printk(KERN_NOTICE PREFIX "%s detected - "
129 "ECDT has exchanged control/data I/O address\n",
130 id->ident);
131 return 0;
132}
133
134static struct dmi_system_id __cpuinitdata ec_dmi_table[] = {
135 {
136 print_ecdt_error, "Asus L4R", {
137 DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
138 DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
139 DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
140 {
141 print_ecdt_error, "Asus M6R", {
142 DMI_MATCH(DMI_BIOS_VERSION, "0207"),
143 DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
144 DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
145 {},
146};
147
148/* -------------------------------------------------------------------------- 123/* --------------------------------------------------------------------------
149 Transaction Management 124 Transaction Management
150 -------------------------------------------------------------------------- */ 125 -------------------------------------------------------------------------- */
@@ -983,8 +958,8 @@ static const struct acpi_device_id ec_device_ids[] = {
983int __init acpi_ec_ecdt_probe(void) 958int __init acpi_ec_ecdt_probe(void)
984{ 959{
985 acpi_status status; 960 acpi_status status;
961 struct acpi_ec *saved_ec = NULL;
986 struct acpi_table_ecdt *ecdt_ptr; 962 struct acpi_table_ecdt *ecdt_ptr;
987 acpi_handle dummy;
988 963
989 boot_ec = make_acpi_ec(); 964 boot_ec = make_acpi_ec();
990 if (!boot_ec) 965 if (!boot_ec)
@@ -998,21 +973,16 @@ int __init acpi_ec_ecdt_probe(void)
998 pr_info(PREFIX "EC description table is found, configuring boot EC\n"); 973 pr_info(PREFIX "EC description table is found, configuring boot EC\n");
999 boot_ec->command_addr = ecdt_ptr->control.address; 974 boot_ec->command_addr = ecdt_ptr->control.address;
1000 boot_ec->data_addr = ecdt_ptr->data.address; 975 boot_ec->data_addr = ecdt_ptr->data.address;
1001 if (dmi_check_system(ec_dmi_table)) {
1002 /*
1003 * If the board falls into ec_dmi_table, it means
1004 * that ECDT table gives the incorrect command/status
1005 * & data I/O address. Just fix it.
1006 */
1007 boot_ec->data_addr = ecdt_ptr->control.address;
1008 boot_ec->command_addr = ecdt_ptr->data.address;
1009 }
1010 boot_ec->gpe = ecdt_ptr->gpe; 976 boot_ec->gpe = ecdt_ptr->gpe;
1011 boot_ec->handle = ACPI_ROOT_OBJECT; 977 boot_ec->handle = ACPI_ROOT_OBJECT;
1012 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); 978 acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
1013 /* Add some basic check against completely broken table */ 979 /* Don't trust ECDT, which comes from ASUSTek */
1014 if (boot_ec->data_addr != boot_ec->command_addr) 980 if (!dmi_name_in_vendors("ASUS"))
1015 goto install; 981 goto install;
982 saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
983 if (!saved_ec)
984 return -ENOMEM;
985 memcpy(&saved_ec, boot_ec, sizeof(saved_ec));
1016 /* fall through */ 986 /* fall through */
1017 } 987 }
1018 /* This workaround is needed only on some broken machines, 988 /* This workaround is needed only on some broken machines,
@@ -1023,12 +993,29 @@ int __init acpi_ec_ecdt_probe(void)
1023 /* Check that acpi_get_devices actually find something */ 993 /* Check that acpi_get_devices actually find something */
1024 if (ACPI_FAILURE(status) || !boot_ec->handle) 994 if (ACPI_FAILURE(status) || !boot_ec->handle)
1025 goto error; 995 goto error;
1026 /* We really need to limit this workaround, the only ASUS, 996 if (saved_ec) {
1027 * which needs it, has fake EC._INI method, so use it as flag. 997 /* try to find good ECDT from ASUSTek */
1028 * Keep boot_ec struct as it will be needed soon. 998 if (saved_ec->command_addr != boot_ec->command_addr ||
1029 */ 999 saved_ec->data_addr != boot_ec->data_addr ||
1030 if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy))) 1000 saved_ec->gpe != boot_ec->gpe ||
1031 return -ENODEV; 1001 saved_ec->handle != boot_ec->handle)
1002 pr_info(PREFIX "ASUSTek keeps feeding us with broken "
1003 "ECDT tables, which are very hard to workaround. "
1004 "Trying to use DSDT EC info instead. Please send "
1005 "output of acpidump to linux-acpi@vger.kernel.org\n");
1006 kfree(saved_ec);
1007 saved_ec = NULL;
1008 } else {
1009 /* We really need to limit this workaround, the only ASUS,
1010 * which needs it, has fake EC._INI method, so use it as flag.
1011 * Keep boot_ec struct as it will be needed soon.
1012 */
1013 acpi_handle dummy;
1014 if (!dmi_name_in_vendors("ASUS") ||
1015 ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
1016 &dummy)))
1017 return -ENODEV;
1018 }
1032install: 1019install:
1033 if (!ec_install_handlers(boot_ec)) { 1020 if (!ec_install_handlers(boot_ec)) {
1034 first_ec = boot_ec; 1021 first_ec = boot_ec;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 073ff09218a9..99e6f1f8ea45 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -416,7 +416,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
416 } 416 }
417 417
418 /* Passive (optional) */ 418 /* Passive (optional) */
419 if (flag & ACPI_TRIPS_PASSIVE) { 419 if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
420 (flag == ACPI_TRIPS_INIT)) {
420 valid = tz->trips.passive.flags.valid; 421 valid = tz->trips.passive.flags.valid;
421 if (psv == -1) { 422 if (psv == -1) {
422 status = AE_SUPPORT; 423 status = AE_SUPPORT;
@@ -462,8 +463,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
462 memset(&devices, 0, sizeof(struct acpi_handle_list)); 463 memset(&devices, 0, sizeof(struct acpi_handle_list));
463 status = acpi_evaluate_reference(tz->device->handle, "_PSL", 464 status = acpi_evaluate_reference(tz->device->handle, "_PSL",
464 NULL, &devices); 465 NULL, &devices);
465 if (ACPI_FAILURE(status)) 466 if (ACPI_FAILURE(status)) {
467 printk(KERN_WARNING PREFIX
468 "Invalid passive threshold\n");
466 tz->trips.passive.flags.valid = 0; 469 tz->trips.passive.flags.valid = 0;
470 }
467 else 471 else
468 tz->trips.passive.flags.valid = 1; 472 tz->trips.passive.flags.valid = 1;
469 473
@@ -487,7 +491,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
487 if (act == -1) 491 if (act == -1)
488 break; /* disable all active trip points */ 492 break; /* disable all active trip points */
489 493
490 if (flag & ACPI_TRIPS_ACTIVE) { 494 if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
495 tz->trips.active[i].flags.valid)) {
491 status = acpi_evaluate_integer(tz->device->handle, 496 status = acpi_evaluate_integer(tz->device->handle,
492 name, NULL, &tmp); 497 name, NULL, &tmp);
493 if (ACPI_FAILURE(status)) { 498 if (ACPI_FAILURE(status)) {
@@ -521,8 +526,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
521 memset(&devices, 0, sizeof(struct acpi_handle_list)); 526 memset(&devices, 0, sizeof(struct acpi_handle_list));
522 status = acpi_evaluate_reference(tz->device->handle, 527 status = acpi_evaluate_reference(tz->device->handle,
523 name, NULL, &devices); 528 name, NULL, &devices);
524 if (ACPI_FAILURE(status)) 529 if (ACPI_FAILURE(status)) {
530 printk(KERN_WARNING PREFIX
531 "Invalid active%d threshold\n", i);
525 tz->trips.active[i].flags.valid = 0; 532 tz->trips.active[i].flags.valid = 0;
533 }
526 else 534 else
527 tz->trips.active[i].flags.valid = 1; 535 tz->trips.active[i].flags.valid = 1;
528 536
arvalho de Melo <acme@conectiva.com.br> . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . . Sources: . o SMC databook . o skeleton.c by Donald Becker ( becker@scyld.com ) . o ( a LOT of advice from Becker as well ) . . History: . 12/07/95 Erik Stahlman written, got receive/xmit handled . 01/03/96 Erik Stahlman worked out some bugs, actually usable!!! :-) . 01/06/96 Erik Stahlman cleaned up some, better testing, etc . 01/29/96 Erik Stahlman fixed autoirq, added multicast . 02/01/96 Erik Stahlman 1. disabled all interrupts in smc_reset . 2. got rid of post-decrementing bug -- UGH. . 02/13/96 Erik Stahlman Tried to fix autoirq failure. Added more . descriptive error messages. . 02/15/96 Erik Stahlman Fixed typo that caused detection failure . 02/23/96 Erik Stahlman Modified it to fit into kernel tree . Added support to change hardware address . Cleared stats on opens . 02/26/96 Erik Stahlman Trial support for Kernel 1.2.13 . Kludge for automatic IRQ detection . 03/04/96 Erik Stahlman Fixed kernel 1.3.70 + . Fixed bug reported by Gardner Buchanan in . smc_enable, with outw instead of outb . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" . 11/08/01 Matt Domsch Use common crc32 function ----------------------------------------------------------------------------*/ static const char version[] = "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/in.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/init.h> #include <linux/crc32.h> #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/bitops.h> #include <asm/io.h> #include "smc9194.h" #define DRV_NAME "smc9194" /*------------------------------------------------------------------------ . . Configuration options, for the experienced user to change. . -------------------------------------------------------------------------*/ /* . Do you want to use 32 bit xfers? This should work on all chips, as . the chipset is designed to accommodate them. */ #ifdef __sh__ #undef USE_32_BIT #else #define USE_32_BIT 1 #endif #if defined(__H8300H__) || defined(__H8300S__) #define NO_AUTOPROBE #undef insl #undef outsl #define insl(a,b,l) io_insl_noswap(a,b,l) #define outsl(a,b,l) io_outsl_noswap(a,b,l) #endif /* .the SMC9194 can be at any of the following port addresses. To change, .for a slightly different card, you can add it to the array. Keep in .mind that the array must end in zero. */ struct devlist { unsigned int port; unsigned int irq; }; #if defined(CONFIG_H8S_EDOSK2674) static struct devlist smc_devlist[] __initdata = { {.port = 0xf80000, .irq = 16}, {.port = 0, .irq = 0 }, }; #else static struct devlist smc_devlist[] __initdata = { {.port = 0x200, .irq = 0}, {.port = 0x220, .irq = 0}, {.port = 0x240, .irq = 0}, {.port = 0x260, .irq = 0}, {.port = 0x280, .irq = 0}, {.port = 0x2A0, .irq = 0}, {.port = 0x2C0, .irq = 0}, {.port = 0x2E0, .irq = 0}, {.port = 0x300, .irq = 0}, {.port = 0x320, .irq = 0}, {.port = 0x340, .irq = 0}, {.port = 0x360, .irq = 0}, {.port = 0x380, .irq = 0}, {.port = 0x3A0, .irq = 0}, {.port = 0x3C0, .irq = 0}, {.port = 0x3E0, .irq = 0}, {.port = 0, .irq = 0}, }; #endif /* . Wait time for memory to be free. This probably shouldn't be . tuned that much, as waiting for this means nothing else happens . in the system */ #define MEMORY_WAIT_TIME 16 /* . DEBUGGING LEVELS . . 0 for normal operation . 1 for slightly more details . >2 for various levels of increasingly useless information . 2 for interrupt tracking, status flags . 3 for packet dumps, etc. */ #define SMC_DEBUG 0 #if (SMC_DEBUG > 2 ) #define PRINTK3(x) printk x #else #define PRINTK3(x) #endif #if SMC_DEBUG > 1 #define PRINTK2(x) printk x #else #define PRINTK2(x) #endif #ifdef SMC_DEBUG #define PRINTK(x) printk x #else #define PRINTK(x) #endif /*------------------------------------------------------------------------ . . The internal workings of the driver. If you are changing anything . here with the SMC stuff, you should have the datasheet and known . what you are doing. . -------------------------------------------------------------------------*/ #define CARDNAME "SMC9194" /* store this information for the driver.. */ struct smc_local { /* If I have to wait until memory is available to send a packet, I will store the skbuff here, until I get the desired memory. Then, I'll send it out and free it. */ struct sk_buff * saved_skb; /* . This keeps track of how many packets that I have . sent out. When an TX_EMPTY interrupt comes, I know . that all of these have been sent. */ int packets_waiting; }; /*----------------------------------------------------------------- . . The driver can be entered at any of the following entry points. . .------------------------------------------------------------------ */ /* . This is called by register_netdev(). It is responsible for . checking the portlist for the SMC9000 series chipset. If it finds . one, then it will initialize the device, find the hardware information, . and sets up the appropriate device parameters. . NOTE: Interrupts are *OFF* when this procedure is called. . . NB:This shouldn't be static since it is referred to externally. */ struct net_device *smc_init(int unit); /* . The kernel calls this function when someone wants to use the device, . typically 'ifconfig ethX up'. */ static int smc_open(struct net_device *dev); /* . Our watchdog timed out. Called by the networking layer */ static void smc_timeout(struct net_device *dev); /* . This is called by the kernel in response to 'ifconfig ethX down'. It . is responsible for cleaning up everything that the open routine . does, and maybe putting the card into a powerdown state. */ static int smc_close(struct net_device *dev); /* . Finally, a call to set promiscuous mode ( for TCPDUMP and related . programs ) and multicast modes. */ static void smc_set_multicast_list(struct net_device *dev); /*--------------------------------------------------------------- . . Interrupt level calls.. . ----------------------------------------------------------------*/ /* . Handles the actual interrupt */ static irqreturn_t smc_interrupt(int irq, void *); /* . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner */ static inline void smc_rcv( struct net_device *dev ); /* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent. */ static inline void smc_tx( struct net_device * dev ); /* ------------------------------------------------------------ . . Internal routines . ------------------------------------------------------------ */ /* . Test if a given location contains a chip, trying to cause as . little damage as possible if it's not a SMC chip. */ static int smc_probe(struct net_device *dev, int ioaddr); /* . A rather simple routine to print out a packet for debugging purposes. */ #if SMC_DEBUG > 2 static void print_packet( byte *, int ); #endif #define tx_done(dev) 1 /* this is called to actually send the packet to the chip */ static void smc_hardware_send_packet( struct net_device * dev ); /* Since I am not sure if I will have enough room in the chip's ram . to store the packet, I call this routine, which either sends it . now, or generates an interrupt when the card is ready for the . packet */ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); /* this does a soft reset on the device */ static void smc_reset( int ioaddr ); /* Enable Interrupts, Receive, and Transmit */ static void smc_enable( int ioaddr ); /* this puts the device in an inactive state */ static void smc_shutdown( int ioaddr ); /* This routine will find the IRQ of the driver if one is not . specified in the input to the device. */ static int smc_findirq( int ioaddr ); /* . Function: smc_reset( int ioaddr ) . Purpose: . This sets the SMC91xx chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. . . Maybe I should reset more registers to defaults in here? SOFTRESET should . do that for me. . . Method: . 1. send a SOFT RESET . 2. wait for it to finish . 3. enable autorelease mode . 4. reset the memory management unit . 5. clear all interrupts . */ static void smc_reset( int ioaddr ) { /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ SMC_SELECT_BANK( 0 ); outw( RCR_SOFTRESET, ioaddr + RCR ); /* this should pause enough for the chip to be happy */ SMC_DELAY( ); /* Set the transmit and receive configuration registers to default values */ outw( RCR_CLEAR, ioaddr + RCR ); outw( TCR_CLEAR, ioaddr + TCR ); /* set the control register to automatically release successfully transmitted packets, to make the best use out of our limited memory */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); /* Reset the MMU */ SMC_SELECT_BANK( 2 ); outw( MC_RESET, ioaddr + MMU_CMD ); /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ outb( 0, ioaddr + INT_MASK ); } /* . Function: smc_enable . Purpose: let the chip talk to the outside work . Method: . 1. Enable the transmitter . 2. Enable the receiver . 3. Enable interrupts */ static void smc_enable( int ioaddr ) { SMC_SELECT_BANK( 0 ); /* see the header file for options in TCR/RCR NORMAL*/ outw( TCR_NORMAL, ioaddr + TCR ); outw( RCR_NORMAL, ioaddr + RCR ); /* now, enable interrupts */ SMC_SELECT_BANK( 2 ); outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); } /* . Function: smc_shutdown . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask . 2. clear the enable receive flag . 3. clear the enable xmit flags . . TODO: . (1) maybe utilize power down mode. . Why not yet? Because while the chip will go into power down mode, . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working. */ static void smc_shutdown( int ioaddr ) { /* no more interrupts for me */ SMC_SELECT_BANK( 2 ); outb( 0, ioaddr + INT_MASK ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( 0 ); outb( RCR_CLEAR, ioaddr + RCR ); outb( TCR_CLEAR, ioaddr + TCR ); #if 0 /* finally, shut the chip down */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); #endif } /* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. . . The SMC chip uses a hash table where the high 6 bits of the CRC of . address are the offset into the table. If that bit is 1, then the . multicast packet is accepted. Otherwise, it's dropped silently. . . To use the 6 bits as an offset into the table, the high 3 bits are the . number of the 8 bit register, while the low 3 bits are the bit within . that register. . . This routine is based very heavily on the one provided by Peter Cammaert. */ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { int i; unsigned char multicast_table[ 8 ]; struct dev_mc_list * cur_addr; /* table for flipping the order of 3 bits */ unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* start with a table of all zeros: reject all */ memset( multicast_table, 0, sizeof( multicast_table ) ); cur_addr = addrs; for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { int position; /* do we have a pointer here? */ if ( !cur_addr ) break; /* make sure this is a multicast address - shouldn't this be a given if we have it here ? */ if ( !( *cur_addr->dmi_addr & 1 ) ) continue; /* only use the low order bits */ position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= (1<<invert3[(position>>3)&7]); } /* now, the table can be loaded into the chipset */ SMC_SELECT_BANK( 3 ); for ( i = 0; i < 8 ; i++ ) { outb( multicast_table[i], ioaddr + MULTICAST1 + i ); } } /* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) . Purpose: . Attempt to allocate memory for a packet, if chip-memory is not . available, then tell the card to generate an interrupt when it . is available. . . Algorithm: . . o if the saved_skb is not currently null, then drop this packet . on the floor. This should never happen, because of TBUSY. . o if the saved_skb is null, then replace it with the current packet, . o See if I can sending it now. . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now. */ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) { struct smc_local *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; word length; unsigned short numPages; word time_out; netif_stop_queue(dev); /* Well, I want to send the packet.. but I don't know if I can send it right now... */ if ( lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } lp->saved_skb = skb; length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); return 0; } length = ETH_ZLEN; } /* ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** Pkt size for allocating is data length +6 (for additional status words, ** length and ctl!) If odd size last byte is included in this header. */ numPages = ((length & 0xfffe) + 6) / 256; if (numPages > 7 ) { printk(CARDNAME": Far too big packet error. \n"); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ dev_kfree_skb (skb); lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); return 0; } /* either way, a packet is waiting now */ lp->packets_waiting++; /* now, try to allocate the memory */ SMC_SELECT_BANK( 2 ); outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); /* . Performance Hack . . wait a short amount of time.. if I can send a packet now, I send . it now. Otherwise, I enable an interrupt and wait for one to be . available. . . I could have handled this a slightly different way, by checking to . see if any memory was available in the FREE MEMORY register. However, . either way, I need to generate an allocation, and the allocation works . no matter what, so I saw no point in checking free memory. */ time_out = MEMORY_WAIT_TIME; do { word status; status = inb( ioaddr + INTERRUPT ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); break; } } while ( -- time_out ); if ( !time_out ) { /* oh well, wait until the chip finds memory later */ SMC_ENABLE_INT( IM_ALLOC_INT ); PRINTK2((CARDNAME": memory allocation deferred. \n")); /* it's deferred, but I'll handle it later */ return 0; } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); return 0; } /* . Function: smc_hardware_send_packet(struct net_device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it. */ static void smc_hardware_send_packet( struct net_device * dev ) { struct smc_local *lp = netdev_priv(dev); byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; unsigned int ioaddr; byte * buf; ioaddr = dev->base_addr; if ( !skb ) { PRINTK((CARDNAME": In XMIT with no packet to send \n")); return; } length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buf = skb->data; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = inb( ioaddr + PNR_ARR + 1 ); if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; } /* we have a packet address, so tell the card to use it */ outb( packet_no, ioaddr + PNR_ARR ); /* point to the beginning of the packet */ outw( PTR_AUTOINC , ioaddr + POINTER ); PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length )); #if SMC_DEBUG > 2 print_packet( buf, length ); #endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */ #ifdef USE_32_BIT outl( (length +6 ) << 16 , ioaddr + DATA_1 ); #else outw( 0, ioaddr + DATA_1 ); /* send the packet length ( +6 for status words, length, and ctl*/ outb( (length+6) & 0xFF,ioaddr + DATA_1 ); outb( (length+6) >> 8 , ioaddr + DATA_1 ); #endif /* send the actual data . I _think_ it's faster to send the longs first, and then . mop up by sending the last word. It depends heavily . on alignment, at least on the 486. Maybe it would be . a good idea to check which is optimal? But that could take . almost as much time as is saved? */ #ifdef USE_32_BIT if ( length & 0x2 ) { outsl(ioaddr + DATA_1, buf, length >> 2 ); #if !defined(__H8300H__) && !defined(__H8300S__) outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); #else ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); #endif } else outsl(ioaddr + DATA_1, buf, length >> 2 ); #else outsw(ioaddr + DATA_1 , buf, (length ) >> 1);