public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Huw Rogers <count0@localnet.com>
To: <linux-kernel@vger.kernel.org>
Cc: <ncunningham@users.sourceforge.net>, <pavel@ucw.cz>,
	<linux-laptop@mobilix.org>, <acpi-devel@lists.sourceforge.net>
Subject: APM good, ACPI bad (2.6.2-rc1 / p4 HT / Uniwill N258SA0)
Date: Sun, 01 Feb 2004 16:05:16 -0500	[thread overview]
Message-ID: <20040201151411.3A7B.COUNT0@localnet.com> (raw)
In-Reply-To: <37778.199.172.169.20.1075236597.squirrel@webmail.localnet.com>

Got Uniwill N258SA0 laptop suspend/resume working (2.6.2-rc1-mm3) with
APM. Patch enclosed. CPU is desktop P4 with hyperthreading.

Recompiled 2.6.2-rc1-mm3 without ACPI, with APM. Booting with
noirqbalance acpi=ht apm=smp.

apm --suspend works perfectly, including from within fglrx accelerated X
(albeit with occasional minor screen corruption requiring a X refresh on
suspend, easily scripted).

I needed this patch on top of -mm3 (incorporates Oliver's SiS AGP patch
from http://lkml.org/lkml/2004/1/20/233). This fixes the SiS 648FX AGP
driver. I #if 0'd a prohibition on suspend with SMP. I also added
suspend/resume handlers for the SiS 648FX (suspend does nothing, resume
reconfigures).

My earlier report of bad ACPI experience:

> S1 - suspends, does not fully resume (USB devices get re-initted,
>      then hangs). needs power cycle to get back
> S3 - suspends if acpi_os_name="Microsoft Windows NT", but resume
>      disables the display so thoroughly I have to unplug AC and remove
>      battery before power cycling to get it back!
> S4 (pmdisk) - suspends and immediately resumes with spurious wake up
> S4b - ('') - ditto

There's some kind of deep problem with S3 resume and ACPI - "Back to C!"
never even gets output, i.e. wakeup.S has some kind of problem, but it's
difficult to debug.

pmdisk (echo -n "disk" >/sys/power/state) has the same behavior under
APM as reported above under ACPI, i.e. immediate resume. Not sure if
it's supposed to work other than under ACPI anyway...

Patch:

-------- cut here --------
diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h	2004-01-09 01:59:26.000000000 -0500
+++ b/drivers/char/agp/agp.h	2004-01-25 19:42:18.000000000 -0500
@@ -402,6 +402,17 @@
 void get_agp_version(struct agp_bridge_data *bridge);
 unsigned long agp_generic_mask_memory(unsigned long addr, int type);
 
+/* generic routines for agp>=3 */
+int agp3_generic_fetch_size(void);
+void agp3_generic_tlbflush(struct agp_memory *mem);
+int agp3_generic_configure(void);
+void agp3_generic_cleanup(void);
+
+/* aperture sizes have been standardised since v3 */
+#define AGP_GENERIC_SIZES_ENTRIES 11
+extern struct aper_size_info_16 agp3_generic_sizes[];
+
+
 extern int agp_off;
 extern int agp_try_unsupported_boot;
 
@@ -410,7 +421,10 @@
 #define AGPCMD			0x8
 #define AGPNISTAT		0xc
 #define AGPCTRL                 0x10
+#define AGPAPSIZE               0x14
 #define AGPNEPG			0x16
+#define AGPGARTLO               0x18
+#define AGPGARTHI               0x1c
 #define AGPNICMD		0x20
 
 #define AGP_MAJOR_VERSION_SHIFT	(20)
@@ -435,4 +449,8 @@
 #define AGPSTAT3_8X		(1<<1)
 #define AGPSTAT3_4X		(1)
 
+#define AGPCTRL_APERENB         (1<<8)
+#define AGPCTRL_GTLBEN          (1<<7)
+
+
 #endif				/* _AGP_BACKEND_PRIV_H */
diff -Nru a/drivers/char/agp/generic-agp3.c b/drivers/char/agp/generic-agp3.c
--- a/drivers/char/agp/generic-agp3.c	1969-12-31 19:00:00.000000000 -0500
+++ b/drivers/char/agp/generic-agp3.c	2004-01-25 19:42:18.000000000 -0500
@@ -0,0 +1,115 @@
+/*
+ * AGPGART driver.
+ * Copyright (C) 2002-2003 Dave Jones.
+ * Copyright (C) 1999 Jeff Hartmann.
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#include <linux/pci.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+/*
+ * These functions are implemented according to the agpV3 spec,
+ * which covers implementation details that had previously been
+ * left up to manufacturers.
+ */
+
+int agp3_generic_fetch_size(void)
+{
+	u16 temp_size;
+        int i;
+        struct aper_size_info_16 *values;
+ 
+	pci_read_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, &temp_size);
+	values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
+
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+	     if (temp_size == values[i].size_value) {
+		 agp_bridge->previous_size =
+	       		agp_bridge->current_size = (void *) (values + i);
+
+	     	agp_bridge->aperture_size_idx = i;
+	     	return values[i].size;
+	     }
+	}
+	return 0;
+}
+EXPORT_SYMBOL(agp3_generic_fetch_size);
+
+void agp3_generic_tlbflush(struct agp_memory *mem)
+{
+	u32 ctrl;
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_GTLBEN);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl);
+}
+EXPORT_SYMBOL(agp3_generic_tlbflush);
+
+int agp3_generic_configure(void)
+{
+	u32 temp;
+
+	struct aper_size_info_16 *current_size;
+	current_size = A_SIZE_16(agp_bridge->current_size);
+
+	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
+	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	// set aperture size
+	pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value);
+	// set gart pointer
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPGARTLO, agp_bridge->gatt_bus_addr);
+
+	// enable aperture and GTLB
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, temp | AGPCTRL_APERENB | AGPCTRL_GTLBEN);
+
+	return 0;
+}
+EXPORT_SYMBOL(agp3_generic_configure);
+
+void agp3_generic_cleanup(void)
+{
+	u32 ctrl;
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_APERENB);
+}
+EXPORT_SYMBOL(agp3_generic_cleanup);
+
+struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES]=
+{
+        {4096, 1048576, 10,0x000},
+        {2048,  524288, 9, 0x800},
+        {1024,  262144, 8, 0xc00},
+        { 512,  131072, 7, 0xe00},
+	{ 256,   65536, 6, 0xf00},
+	{ 128,   32768, 5, 0xf20},
+	{  64,   16384, 4, 0xf30},
+	{  32,    8192, 3, 0xf38},
+	{  16,    4096, 2, 0xf3c},
+	{   8,    2048, 1, 0xf3e},
+	{   4,    1024, 0, 0xf3f}
+};
+EXPORT_SYMBOL(agp3_generic_sizes);
diff -Nru a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
--- a/drivers/char/agp/Makefile	2004-01-09 01:59:19.000000000 -0500
+++ b/drivers/char/agp/Makefile	2004-01-25 19:42:18.000000000 -0500
@@ -1,4 +1,4 @@
-agpgart-y := backend.o frontend.o generic.o isoch.o
+agpgart-y := backend.o frontend.o generic.o generic-agp3.o isoch.o
 
 obj-$(CONFIG_AGP)		+= agpgart.o
 obj-$(CONFIG_AGP_ALI)		+= ali-agp.o
diff -Nru a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
--- a/drivers/char/agp/sis-agp.c	2004-01-09 01:59:06.000000000 -0500
+++ b/drivers/char/agp/sis-agp.c	2004-02-01 13:06:09.000000000 -0500
@@ -21,7 +21,7 @@
 		    ((temp_size & ~(0x03)) ==
 		     (values[i].size_value & ~(0x03)))) {
 			agp_bridge->previous_size =
-			    agp_bridge->current_size = (void *) (values + i);
+				agp_bridge->current_size = (void *) (values + i);
 
 			agp_bridge->aperture_size_idx = i;
 			return values[i].size;
@@ -61,7 +61,67 @@
 			      (previous_size->size_value & ~(0x03)));
 }
 
-static struct aper_size_info_8 sis_generic_sizes[7] =
+static void sis648_enable(u32 mode)
+{
+	// find the master, this needs to be better
+	struct pci_dev *master = NULL;
+	u8 mcapndx=0;
+
+	while ((master = pci_find_class(PCI_CLASS_DISPLAY_VGA<<8, master)) != NULL) {
+	  mcapndx = pci_find_capability(master, PCI_CAP_ID_AGP);
+	  printk (KERN_INFO PFX "Found AGP device. %x:%x \n", master->vendor, master->device);
+	  break;
+	}
+	if(!mcapndx)
+		return;
+
+	u32 tStatus;
+	u32 mStatus;
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPSTAT, &tStatus);
+	pci_read_config_dword(master, mcapndx+AGPSTAT, &mStatus);
+	
+	printk(KERN_INFO PFX "target status %x\n", tStatus);
+	printk(KERN_INFO PFX "master status %x\n", mStatus);
+
+	int tcc=(tStatus>>10)&3;
+	int mcc=(mStatus>>10)&3;
+	int calcycl=(tcc<mcc) ? tcc : mcc;
+	int sba=(tStatus & AGPSTAT_SBA) && (mStatus & AGPSTAT_SBA);
+	int agp_enable=1;
+	int gart64b=0;
+	int over4g=0;
+	int fw=(tStatus & AGPSTAT_FW) && (mStatus & AGPSTAT_FW);
+	int rate=(tStatus & 2) && (tStatus & 2) ? 2 : 1;
+
+	// init target (bridge)
+	u32 tcmd=(calcycl<<10)|(sba<<9)|(agp_enable<<8)|(gart64b<<7)|(over4g<<5)|(fw<<4)|rate;
+	printk(KERN_INFO PFX "tcmd=%x\n",tcmd);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCMD, tcmd);
+
+	u8 mcaptest = pci_find_capability(master, PCI_CAP_ID_AGP);
+	if(mcaptest!=mcapndx)
+	{
+	  printk(KERN_INFO PFX "master capndx screwed ... waiting 10ms\n");
+	  // weird: on 648fx chipsets any rate change in the target command register
+	  // triggers a 5ms screwup during which the master cannot be configured
+	  set_current_state(TASK_INTERRUPTIBLE);
+	  schedule_timeout (1+(HZ*10)/1000);  
+	}
+	else
+	{
+	  printk(KERN_INFO PFX "bridge is up and master seems okay");
+	}
+
+	// init master (card)
+	int prq=(mStatus>>24)&0xff;
+	int parqsz=(tStatus>>AGPSTAT_ARQSZ_SHIFT) & 3;
+	u32 mcmd=(prq<<24)|(parqsz<<13)|(sba<<9)|(agp_enable<<8)|(over4g<<5)|(fw<<4)|rate;
+	printk(KERN_INFO PFX "mcmd=%x\n",mcmd);
+
+	pci_write_config_dword(master, mcapndx+AGPCMD, mcmd);
+}
+
+static struct aper_size_info_8 sis_generic_sizes[] =
 {
 	{256, 65536, 6, 99},
 	{128, 32768, 5, 83},
@@ -95,6 +155,29 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
+struct agp_bridge_driver sis648_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes 	= agp3_generic_sizes,
+	.size_type		= U16_APER_SIZE,
+	.num_aperture_sizes	= AGP_GENERIC_SIZES_ENTRIES,
+	.configure		= agp3_generic_configure,
+	.fetch_size		= agp3_generic_fetch_size,
+	.cleanup		= agp3_generic_cleanup,
+	.tlb_flush		= agp3_generic_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= sis648_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page
+};
+
 static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
 {
 	{
@@ -192,13 +275,13 @@
 	for (j = 0; devs[j].chipset_name; j++) {
 		if (pdev->device == devs[j].device_id) {
 			printk(KERN_INFO PFX "Detected SiS %s chipset\n",
-					devs[j].chipset_name);
+			       devs[j].chipset_name);
 			goto found;
 		}
 	}
 
 	printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n",
-		    pdev->device);
+	       pdev->device);
 	return -ENODEV;
 
 found:
@@ -206,14 +289,17 @@
 	if (!bridge)
 		return -ENOMEM;
 
-	bridge->driver = &sis_driver;
+	if(pdev->device==PCI_DEVICE_ID_SI_648)
+		bridge->driver = &sis648_driver;
+	else
+		bridge->driver = &sis_driver;
 	bridge->dev = pdev;
 	bridge->capndx = cap_ptr;
 
 	/* Fill in the mode register */
 	pci_read_config_dword(pdev,
-			bridge->capndx+PCI_AGP_STATUS,
-			&bridge->mode);
+			      bridge->capndx+PCI_AGP_STATUS,
+			      &bridge->mode);
 
 	pci_set_drvdata(pdev, bridge);
 	return agp_add_bridge(bridge);
@@ -227,14 +313,31 @@
 	agp_put_bridge(bridge);
 }
 
+static int agp_sis_suspend(struct pci_dev *dev, u32 state)
+{
+	return 0;
+}
+
+static int agp_sis_resume(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	printk(KERN_INFO PFX "agp_sis_resume()\n");
+
+	if (bridge->driver == &sis648_driver)
+		agp3_generic_configure();
+
+	return 0;
+}
+
 static struct pci_device_id agp_sis_pci_table[] = {
 	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_SI,
-	.device		= PCI_ANY_ID,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_ANY_ID,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 	},
 	{ }
 };
@@ -246,6 +349,8 @@
 	.id_table	= agp_sis_pci_table,
 	.probe		= agp_sis_probe,
 	.remove		= agp_sis_remove,
+	.suspend	= agp_sis_suspend,
+	.resume		= agp_sis_resume
 };
 
 static int __init agp_sis_init(void)
diff -Nru a/kernel/power/main.c b/kernel/power/main.c
--- a/kernel/power/main.c	2004-01-09 01:59:19.000000000 -0500
+++ b/kernel/power/main.c	2004-01-25 19:59:35.000000000 -0500
@@ -144,11 +144,13 @@
 	if (down_trylock(&pm_sem))
 		return -EBUSY;
 
+#if 0
 	/* Suspend is hard to get right on SMP. */
 	if (num_online_cpus() != 1) {
 		error = -EPERM;
 		goto Unlock;
 	}
+#endif
 
 	if (state == PM_SUSPEND_DISK) {
 		error = pm_suspend_disk();
-------- cut here --------

-- 
Huw Rogers <count0@localnet.com>


  parent reply	other threads:[~2004-02-01 21:06 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-01-25  5:26 2.6.2-rc1 / ACPI sleep / irqbalance / kirqd / pentium 4 HT problems on Uniwill N258SA0 Huw Rogers
2004-01-25 15:28 ` Zwane Mwaikambo
2004-01-26 23:33 ` bill davidsen
2004-01-27  8:39 ` Pavel Machek
2004-01-27 15:38   ` Bart Samwel
2004-01-27 19:30     ` Nigel Cunningham
     [not found]       ` <37778.199.172.169.20.1075236597.squirrel@webmail.localnet.com>
2004-02-01 21:05         ` Huw Rogers [this message]
2004-02-01 22:46           ` APM good, ACPI bad (2.6.2-rc1 / p4 HT / Uniwill N258SA0) Pavel Machek
2004-02-17  2:26           ` 2.6.3-rc3-mm1 - COMPILE FAILURE Huw Rogers
2004-01-27 20:58     ` 2.6.2-rc1 / ACPI sleep / irqbalance / kirqd / pentium 4 HT problems on Uniwill N258SA0 Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040201151411.3A7B.COUNT0@localnet.com \
    --to=count0@localnet.com \
    --cc=acpi-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-laptop@mobilix.org \
    --cc=ncunningham@users.sourceforge.net \
    --cc=pavel@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox