[PATCH] nforce update

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi!

I have updated i2c-amd756.c to support multiple adapters.
It was necessary because the nforce has two busses.
I hope I haven't broken anything in the process.
Could somebody with an amd try it? Thanks.

There was no locking in the driver, so I assume that
calls are serialized on a higher level. Therefore
I didn't add any myself.

The base addresses for the nforce are hardcoded, I wonder
if we should extract them from the pci resources (those
are supposed to be set up by the BIOS, right?) Also, a
force parameter could be introduced should the need arise.

Comments welcome.

Greets,
	Csaba

--- i2c-amd756.c.orig	Mon Jul  8 21:38:16 2002
+++ i2c-amd756.c	Tue Jul  9 22:09:02 2002
@@ -26,11 +26,11 @@
 
 /*
     2002-04-08: Added nForce support. (Csaba Halasz)
+    2002-07-09: Added multiple adapter support (Csaba Halasz)
 */
 
 /*
    Supports AMD756, AMD766, AMD768 and nVidia nForce
-   Note: we assume there can only be one device, with one SMBus interface.
 */
 
 #include <linux/version.h>
@@ -55,35 +55,23 @@
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01B4
 #endif
 
-struct sd {
-    const unsigned short vendor;
-    const unsigned short device;
-    const unsigned short function;
-    const char* name;
-    int amdsetup:1;
-};
+/* this could be set to I2C_ADAP_MAX if necessary */
+#define AMD756_ADAP_MAX 2	
 
-static struct sd supported[] = {
-    {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_756, 3, "AMD756", 1},
-    {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_766, 3, "AMD766", 1},
-    {PCI_VENDOR_ID_AMD, 0x7443, 3, "AMD768", 1},
-    {PCI_VENDOR_ID_NVIDIA, 0x01B4, 1, "nVidia nForce", 0},
-    {0, 0, 0}
-};
 
 /* AMD756 SMBus address offsets */
 #define SMB_ADDR_OFFSET        0xE0
 #define SMB_IOSIZE             16
-#define SMB_GLOBAL_STATUS      (0x0 + amd756_smba)
-#define SMB_GLOBAL_ENABLE      (0x2 + amd756_smba)
-#define SMB_HOST_ADDRESS       (0x4 + amd756_smba)
-#define SMB_HOST_DATA          (0x6 + amd756_smba)
-#define SMB_HOST_COMMAND       (0x8 + amd756_smba)
-#define SMB_HOST_BLOCK_DATA    (0x9 + amd756_smba)
-#define SMB_HAS_DATA           (0xA + amd756_smba)
-#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_smba)
-#define SMB_HAS_HOST_ADDRESS   (0xE + amd756_smba)
-#define SMB_SNOOP_ADDRESS      (0xF + amd756_smba)
+#define SMB_GLOBAL_STATUS      (0x0 + base)
+#define SMB_GLOBAL_ENABLE      (0x2 + base)
+#define SMB_HOST_ADDRESS       (0x4 + base)
+#define SMB_HOST_DATA          (0x6 + base)
+#define SMB_HOST_COMMAND       (0x8 + base)
+#define SMB_HOST_BLOCK_DATA    (0x9 + base)
+#define SMB_HAS_DATA           (0xA + base)
+#define SMB_HAS_DEVICE_ADDRESS (0xC + base)
+#define SMB_HAS_HOST_ADDRESS   (0xE + base)
+#define SMB_SNOOP_ADDRESS      (0xF + base)
 
 /* PCI Address Constants */
 
@@ -107,7 +95,23 @@
 #define AMD756_PROCESS_CALL 0x04
 #define AMD756_BLOCK_DATA   0x05
 
-/* insmod parameters */
+struct sd {
+    const unsigned short vendor;
+    const unsigned short device;
+    const unsigned short function;
+    const char* name;
+    int (*setupfn)(struct sd *amd_dev, struct pci_dev *device);
+};
+
+struct amd756_data {
+    const struct sd *device;
+    unsigned short base;
+};
+
+struct amd756_adapter {
+    struct i2c_adapter i2c_adapter;
+    struct amd756_data data;    
+};
 
 #ifdef MODULE
 static
@@ -121,29 +125,39 @@
 			 unsigned short flags, char read_write,
 			 u8 command, int size, union i2c_smbus_data *data);
 static void amd756_do_pause(unsigned int amount);
-static void amd756_abort(void);
-static int amd756_transaction(void);
+static void amd756_abort(unsigned short base);
+static int amd756_transaction(unsigned short base);
 static void amd756_inc(struct i2c_adapter *adapter);
 static void amd756_dec(struct i2c_adapter *adapter);
 static u32 amd756_func(struct i2c_adapter *adapter);
+static int __init amd756_setup_nforce(struct sd *amd_dev, struct pci_dev *device);
+static int __init amd756_setup_amd(struct sd *amd_dev, struct pci_dev *device);
 
 #ifdef MODULE
 extern int init_module(void);
 extern int cleanup_module(void);
 #endif				/* MODULE */
 
+static struct sd supported[] = {
+    {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_756, 3, "AMD756", amd756_setup_amd},
+    {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_766, 3, "AMD766", amd756_setup_amd},
+    {PCI_VENDOR_ID_AMD, 0x7443, 3, "AMD768", amd756_setup_amd},
+    {PCI_VENDOR_ID_NVIDIA, 0x01B4, 1, "nVidia nForce", amd756_setup_nforce},
+    {0, 0, 0}
+};
+
 static struct i2c_algorithm smbus_algorithm = {
 	/* name */ "Non-I2C SMBus adapter",
 	/* id */ I2C_ALGO_SMBUS,
 	/* master_xfer */ NULL,
 	/* smbus_access */ amd756_access,
-	/* slave;_send */ NULL,
+	/* slave_send */ NULL,
 	/* slave_rcv */ NULL,
 	/* algo_control */ NULL,
 	/* functionality */ amd756_func,
 };
 
-static struct i2c_adapter amd756_adapter = {
+const static struct i2c_adapter amd756_adapter_template = {
 	"unset",
 	I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
 	&smbus_algorithm,
@@ -154,19 +168,108 @@
 	NULL,
 };
 
-static int __initdata amd756_initialized;
-static struct sd *amd756_sd = NULL;
-static unsigned short amd756_smba = 0;
-
-/* Detect whether a AMD756 can be found, and initialize it, where necessary.
-   Note the differences between kernels with the old PCI BIOS interface and
-   newer kernels with the real PCI interface. In compat.h some things are
-   defined to make the transition easier. */
-int amd756_setup(void)
+static struct amd756_adapter amd756_adapters[AMD756_ADAP_MAX];
+static int amd756_adapter_count = 0;
+
+static int __init amd756_register_adapter(const struct sd *device, unsigned short base)
+{
+	int res;
+	struct amd756_adapter *new_adapter = NULL;	
+
+	if (amd756_adapter_count == AMD756_ADAP_MAX)
+	{
+		printk("i2c-amd756.o: Error: Max number of adapters (%d) reached!\n", 
+			AMD756_ADAP_MAX);
+    		return -ENOMEM;
+	}
+	
+	if (check_region(base, SMB_IOSIZE)) {
+		printk
+		    ("i2c-amd756.o: SMB region 0x%x already in use!\n", base);
+		return -ENODEV;
+	}
+    
+	new_adapter = amd756_adapters + amd756_adapter_count;
+	memcpy(new_adapter, &amd756_adapter_template, sizeof(amd756_adapter_template));
+
+	sprintf(new_adapter->i2c_adapter.name, "SMBus %s adapter at %04x",
+		device->name, base);
+	new_adapter->data.base = base;
+	new_adapter->data.device = device;
+	new_adapter->i2c_adapter.data = &new_adapter->data;
+		
+	if ((res = i2c_add_adapter(&new_adapter->i2c_adapter))) {
+		printk("i2c-amd756.o: Error registering i2c adapter `%s'\n", 
+			new_adapter->i2c_adapter.name);
+		return res;
+	}
+    
+	/* Everything is happy, let's grab the memory and set things up. */
+	request_region(base, SMB_IOSIZE, "amd756-smbus");
+	
+	amd756_adapter_count++;
+	
+	return 0;
+}
+
+static int __init amd756_setup_amd(struct sd *amd_dev, struct pci_dev *device)
 {
 	unsigned char temp;
+	unsigned short base;
+	int res;
+
+	pci_read_config_byte(device, SMBGCFG, &temp);
+	if ((temp & 128) == 0) {
+		printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n");
+		return -ENODEV;
+	}
+	
+	/* Determine the address of the SMBus areas */
+	/* Technically it is a dword but... */
+	pci_read_config_word(device, SMBBA, &base);
+	base &= 0xff00;
+	base += SMB_ADDR_OFFSET;
+	
+	if ((res = amd756_register_adapter(amd_dev, base)) != 0) {
+		return res;
+	}
+
+#ifdef DEBUG
+	pci_read_config_byte(device, SMBREV, &temp);
+	printk("i2c-amd756.o: SMBREV = 0x%X\n", temp);
+	printk("i2c-amd756.o: address = 0x%X\n", base);
+#endif				/* DEBUG */
+
+	return 0;
+}
+
+static int __init amd756_setup_nforce(struct sd *amd_dev, struct pci_dev *device)
+{
+	int res;
+
+	/* 
+		The nForce has two smbusses.
+		Don't know how to get the base addresses, so just
+		assume 0x5000 & 0x5500.
+		We could look at the pci io resources if necessary.
+	*/
+	
+	if ((res = amd756_register_adapter(amd_dev, 0x5000)) != 0) {
+		return res;
+	}
+
+	if ((res = amd756_register_adapter(amd_dev, 0x5500)) != 0) {
+		return res;
+	}
+
+	return 0;
+}
+
+int __init amd756_setup(void)
+{
 	struct sd *currdev;
 	struct pci_dev *AMD756_dev = NULL;
+	int res = -ENODEV;
 
 	if (pci_present() == 0) {
 		printk("i2c-amd756.o: Error: No PCI-bus found!\n");
@@ -179,54 +282,20 @@
 						currdev->device, AMD756_dev);
 		if (AMD756_dev != NULL)	{
 			if (PCI_FUNC(AMD756_dev->devfn) == currdev->function)
-				break;
+			{
+				printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", 
+					currdev->name);
+				res = currdev->setupfn(currdev, AMD756_dev);
+			}
 		} else {
 		    currdev++;
 		}
 	}
 
-	if (AMD756_dev == NULL) {
-		printk
-		    ("i2c-amd756.o: Error: No AMD756 or compatible device detected!\n");
-		return(-ENODEV);
-	}
-	printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", currdev->name);
-
-	if (currdev->amdsetup)
-	{
-		pci_read_config_byte(AMD756_dev, SMBGCFG, &temp);
-		if ((temp & 128) == 0) {
-			printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n");
-			return(-ENODEV);
-		}
-
-		/* Determine the address of the SMBus areas */
-		/* Technically it is a dword but... */
-		pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba);
-		amd756_smba &= 0xff00;
-		amd756_smba += SMB_ADDR_OFFSET;
-	} else {
-		amd756_smba = 0x5500;
-	}
-	if (check_region(amd756_smba, SMB_IOSIZE)) {
-		printk
-		    ("i2c-amd756.o: SMB region 0x%x already in use!\n",
-		     amd756_smba);
-		return(-ENODEV);
+	if (amd756_adapter_count == 0) {
+		return res;
 	}
-
-	/* Everything is happy, let's grab the memory and set things up. */
-	request_region(amd756_smba, SMB_IOSIZE, "amd756-smbus");
-
-#ifdef DEBUG
-	pci_read_config_byte(AMD756_dev, SMBREV, &temp);
-	printk("i2c-amd756.o: SMBREV = 0x%X\n", temp);
-	printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba);
-#endif				/* DEBUG */
-
-	/* store struct sd * for future reference */
-        amd756_sd = currdev;
-
+	
 	return 0;
 }
 
@@ -258,7 +327,7 @@
 #define GE_HOST_STC (1 << 3)
 #define GE_ABORT (1 << 5)
 
-void amd756_abort(void)
+void amd756_abort(unsigned short base)
 {
 	printk("i2c-amd756.o: Sending abort.\n");
 	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
@@ -266,7 +335,7 @@
 	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
 }
 
-int amd756_transaction(void)
+int amd756_transaction(unsigned short base)
 {
 	int temp;
 	int result = 0;
@@ -289,11 +358,11 @@
 			amd756_do_pause(1);
 			temp = inw_p(SMB_GLOBAL_STATUS);
 		} while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
-		         (timeout++ < MAX_TIMEOUT));
+			 (timeout++ < MAX_TIMEOUT));
 		/* If the SMBus is still busy, we give up */
 		if (timeout >= MAX_TIMEOUT) {
 			printk("i2c-amd756.o: Busy wait timeout! (%04x)\n", temp);
-			amd756_abort();
+			amd756_abort(base);
 			return(-1);
 		}
 		timeout = 0;
@@ -311,7 +380,7 @@
 	/* If the SMBus is still busy, we give up */
 	if (timeout >= MAX_TIMEOUT) {
 		printk("i2c-amd756.o: Completion timeout!\n");
-		amd756_abort ();
+		amd756_abort(base);
 		return(-1);
 	}
 
@@ -362,6 +431,7 @@
 		  u8 command, int size, union i2c_smbus_data * data)
 {
 	int i, len;
+	const unsigned short base = ((struct amd756_data*)adap->data)->base;
 
   /** TODO: Should I supporte the 10-bit transfers? */
 	switch (size) {
@@ -422,7 +492,7 @@
 	/* How about enabling interrupts... */
 	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
 
-	if (amd756_transaction())	/* Error in transaction */
+	if (amd756_transaction(base))	/* Error in transaction */
 		return -1;
 
 	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
@@ -459,7 +529,6 @@
 
 void amd756_dec(struct i2c_adapter *adapter)
 {
-
 	MOD_DEC_USE_COUNT;
 }
 
@@ -476,49 +545,42 @@
 	printk("i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE);
 #ifdef DEBUG
 /* PE- It might be good to make this a permanent part of the code! */
-	if (amd756_initialized) {
+	if (amd756_adapter_count > 0) {
 		printk
 		    ("i2c-amd756.o: Oops, amd756_init called a second time!\n");
 		return -EBUSY;
 	}
 #endif
-	amd756_initialized = 0;
 	if ((res = amd756_setup())) {
 		printk
 		    ("i2c-amd756.o: AMD756 or compatible device not detected, module not inserted.\n");
-		amd756_cleanup();
 		return res;
 	}
-	amd756_initialized++;
-	sprintf(amd756_adapter.name, "SMBus %s adapter at %04x",
-		amd756_sd->name, amd756_smba);
-	if ((res = i2c_add_adapter(&amd756_adapter))) {
-		printk
-		    ("i2c-amd756.o: Adapter registration failed, module not inserted.\n");
-		amd756_cleanup();
-		return res;
-	}
-	amd756_initialized++;
-	printk("i2c-amd756.o: %s bus detected and initialized\n",
-               amd756_sd->name);
+
 	return 0;
 }
 
 int __init amd756_cleanup(void)
 {
 	int res;
-	if (amd756_initialized >= 2) {
-		if ((res = i2c_del_adapter(&amd756_adapter))) {
-			printk
-			    ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n");
-			return res;
-		} else
-			amd756_initialized--;
-	}
-	if (amd756_initialized >= 1) {
-		release_region(amd756_smba, SMB_IOSIZE);
-		amd756_initialized--;
+	int i;
+	
+	for(i = amd756_adapter_count - 1; i >= 0; i--)
+	{
+		struct amd756_adapter *curr = amd756_adapters + i;
+		if (curr->data.base)
+		{
+			if ((res = i2c_del_adapter(&curr->i2c_adapter))) {
+				printk("i2c-amd756.o: Could not delete adapter `%s', module not removed\n",
+					curr->i2c_adapter.name);
+				return res;
+			}
+			release_region(curr->data.base, SMB_IOSIZE);
+			curr->data.base = 0;
+			amd756_adapter_count--;
+		}
 	}
+
 	return 0;
 }
 



[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux