[PATCH linux dev-4.7] drivers: fsi: i2c fix probing

eajames at linux.vnet.ibm.com eajames at linux.vnet.ibm.com
Wed Feb 8 07:32:43 AEDT 2017


From: "Edward A. James" <eajames at us.ibm.com>

resolve the problems when probing up the i2c driver a second time.

Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
 drivers/fsi/i2c/iic-fsi.c  | 124 +++------------------------------------------
 drivers/fsi/i2c/iic-mstr.c |  42 +++------------
 2 files changed, 14 insertions(+), 152 deletions(-)

diff --git a/drivers/fsi/i2c/iic-fsi.c b/drivers/fsi/i2c/iic-fsi.c
index 2c0aec9..1723bc3 100644
--- a/drivers/fsi/i2c/iic-fsi.c
+++ b/drivers/fsi/i2c/iic-fsi.c
@@ -36,60 +36,12 @@
 struct class* iic_fsi_class = 0;
 dev_t iic_devnum_start = 0;
 
-static const char iic_fsi_version[] = "3.0";
+static const char iic_fsi_version[] = "3.1";
 
 int iic_fsi_probe(struct device *dev);
 int iic_fsi_remove(struct device *dev);
-void iic_fsi_shutdown(struct device *dev);
 int iic_fsi_suspend(struct device *dev);
 int iic_fsi_resume(struct device *dev);
-static void iic_eng_release(struct kobject* kobj);
-
-/* callback function for when the reference count for an engine reaches 0 */
-static void iic_eng_release(struct kobject* kobj)
-{
-	iic_eng_t* eng = container_of(kobj, iic_eng_t, kobj);
-	struct device* dev = eng->dev;
-	unsigned long flags;
-
-	IENTER();
-
-	/*remove all busses associated with the engine */
-	spin_lock_irqsave(&eng->lock, flags);
-	while(eng->busses){
-		iic_bus_t* temp = eng->busses;
-		eng->busses = temp->next;
-		iic_delete_bus(iic_fsi_class, temp);
-	}
-
-	eng->enabled = 0x0ULL;
-	spin_unlock_irqrestore(&eng->lock, flags);
-
-
-	/* providing an arch specific cleanup routine is optional.
-	 * if not specified, use the default.
-	 */
-	if (iic_eng_ops_is_vaild(eng->ops)) {
-		if(eng->ops->cleanup_eng)
-		{
-			eng->ops->cleanup_eng(eng);
-		}
-		else
-		{
-			IDBGd(0, "free engine\n");
-			kfree(eng);
-		}
-	}
-
-	dev_set_drvdata(dev, 0);
-	kobject_put(&dev->kobj);
-
-	IEXIT(0);
-}
-
-static struct kobj_type iic_eng_ktype = {
-	.release = iic_eng_release,
-};
 
 int readb_wrap(iic_eng_t* eng, unsigned int addr, unsigned char *val, 
 	       iic_ffdc_t** ffdc)
@@ -223,7 +175,7 @@ int iic_add_ports(iic_eng_t* eng, uint64_t ports)
 
 	IENTER();
 
-	IFLDi(3, "Adding ports[0x%08x%08x] to eng[0x%08x]",
+	IFLDi(3, "Adding ports[0x%08x%08x] to eng[0x%08x]\n",
 	      (uint32_t)(ports >> 32),
 	      (uint32_t)ports,
 	      eng->id);
@@ -305,8 +257,6 @@ int iic_del_ports(iic_eng_t* eng, uint64_t ports)
 
 	/* walk unordered SLL and delete bus if it is in the ports bit mask */
 	spin_lock_irqsave(&eng->lock, flags);
-	if(test_bit(IIC_ENG_REMOVED, &eng->flags))
-		goto exit;
 	p_abusp = &eng->busses;
 	abusp = *p_abusp;
 	while(abusp)
@@ -316,7 +266,6 @@ int iic_del_ports(iic_eng_t* eng, uint64_t ports)
 			/* found a match, remove it */
 			*p_abusp = abusp->next;
 			eng->enabled &= ~(0x1ULL << abusp->port);
-			device_destroy(iic_fsi_class, abusp->devnum);
 			iic_delete_bus(iic_fsi_class, abusp);
 		}
 		else
@@ -333,6 +282,7 @@ exit:
 	return 0;
 }
 
+#define IIC_FSI_PORTS	0xFFFULL
 /*
  * Called when an FSI IIC engine is plugged in.  
  * Causes creation of the /dev entry.
@@ -361,12 +311,11 @@ int iic_fsi_probe(struct device *dev)
 	iic_init_eng(eng);
 	set_bit(IIC_ENG_BLOCK, &eng->flags); //block until resumed
 	eng->id = 0x00F5112C;
-	IFLDi(1, "PROBE    eng[%08x]", eng->id);
+	IFLDi(1, "PROBE    eng[%08x]\n", eng->id);
 	eng->ra = &fsi_reg_access;
 	IFLDd(1, "vaddr=%#08lx\n", eng->base);
 	eng->dev = dev;
 	// The new kernel now requires 2 arguments
-	kobject_init(&eng->kobj, &iic_eng_ktype); //ref count = 1
 	eng->ops = iic_get_eng_ops(FSI_ENGID_I2C);
 	if(!eng->ops)
 	{
@@ -382,7 +331,7 @@ int iic_fsi_probe(struct device *dev)
 
 	IFLDd(1, "irq  = %d\n", eng->irq);
 
-	new_ports = 0xFFFULL;
+	new_ports = IIC_FSI_PORTS;
 	set_bit(IIC_ENG_P8_Z8_CENTAUR, &eng->flags);
 
 
@@ -394,21 +343,13 @@ int iic_fsi_probe(struct device *dev)
 	dev_set_drvdata(dev, eng);
 	eng->private_data = 0; //unused
 
-
-	/* set the callback function for when the eng ref count reaches 0 */
-	kobject_get(&eng->dev->kobj);
-
 	iic_fsi_resume(dev);
 
 error:
 	if(rc)
 	{
 		IFLDi(1, "IIC: iic_fsi_probe failed: %d\n", rc);
-		while(eng && eng->busses){
-			iic_bus_t* temp = eng->busses;
-			eng->busses = temp->next;
-			iic_delete_bus(iic_fsi_class, temp);
-		}
+		iic_del_ports(eng, new_ports);
 		if(eng)
 		{
 			kfree(eng);
@@ -430,9 +371,7 @@ error:
 int iic_fsi_remove(struct device* dev)
 {
 	int rc = 0;
-	iic_bus_t* bus;
 	iic_eng_t* eng = (iic_eng_t*)dev_get_drvdata(dev);
-	unsigned long flags;
 
 	IENTER();
        
@@ -453,62 +392,15 @@ int iic_fsi_remove(struct device* dev)
 	IFLDi(1, "REMOVE   eng[%08x]\n", eng->id);
 
 	/* Clean up device files immediately, don't wait for ref count */
-	spin_lock_irqsave(&eng->lock, flags);
-	bus = eng->busses;
-	while(bus)
-	{
-		/* causes hot unplug event */
-		device_destroy(iic_fsi_class, bus->devnum);
-		bus = bus->next;
-	}
-	spin_unlock_irqrestore(&eng->lock, flags);
-
+	iic_del_ports(eng, IIC_FSI_PORTS);
 	/* cleans up engine and bus structures if ref count is zero */
-	kobject_put(&eng->kobj);
+	kfree(eng);
 	
 error:
 	IEXIT(0);
 	return 0;
 }
 
-/* This function is called when a link is removed or the driver is unloaded.
- * It's job is to quiesce and disable the hardware if possible and unregister 
- * interrupts. It always precedes the remove function.
- *
- * The device may be in the resumed or suspended state when this function is
- * called.
- *
- * This function is no longer called for mcp5
- */
-void iic_fsi_shutdown(struct device *dev)
-{
-	int rc = 0;
-	iic_eng_t* eng = (iic_eng_t*)dev_get_drvdata(dev);
-
-	IENTER();
-	if(!eng || !eng->ops)
-	{
-		rc = -1;
-		goto error;
-	}
-	IFLDi(1, "SHUTDOWN eng[%08x]\n", eng->id);
-
-	/* set ENG_REMOVED flag so that aborted operations have status
-	 * set to ENOLINK (lost fsi link) instead of ENODEV (no lbus).
-	 */
-	set_bit(IIC_ENG_REMOVED, &eng->flags);
-
-	iic_fsi_suspend(dev);
-	
-error:
-	if(rc)
-	{
-		IFLDe(1, "iic_fsi_shutdown failed: %d\n", rc);
-	}
-	IEXIT(0);
-	return;
-}
-
 /* This function is called when we loose ownership or are preparing to give
  * up ownership of the local bus.  If we still own lbus, then we try to
  * gracefully halt any pending transfer.  No hot unplug events are caused by
diff --git a/drivers/fsi/i2c/iic-mstr.c b/drivers/fsi/i2c/iic-mstr.c
index 0d97671..5501b22 100644
--- a/drivers/fsi/i2c/iic-mstr.c
+++ b/drivers/fsi/i2c/iic-mstr.c
@@ -83,27 +83,7 @@ iic_opts_t iic_dflt_opts =
 	}
 };
 
-static const char iic_mstr_version[] = "3.0";
-
-/* save off the default cdev type pointer so we can call the default cdev
- * release function in our own bus release function
- */
-static struct kobj_type* cdev_dflt_type = 0;
-struct kobj_type iic_bus_type;
-
-/* funtion called when cdev object (embedded in bus object) ref count
- * reaches zero.  (prevents cdev memory from being freed to early)
- */
-void iic_bus_release(struct kobject* kobj)
-{
-	struct cdev *p = container_of(kobj, struct cdev, kobj);
-	iic_bus_t* bus = container_of(p, iic_bus_t, cdev);
-
-	IFLDi(1, "deleting bus[%08lx]\n", bus->bus_id);
-	if(cdev_dflt_type && cdev_dflt_type->release)
-		cdev_dflt_type->release(kobj);
-	kfree(bus);
-}
+static const char iic_mstr_version[] = "3.1";
 
 int iic_open(struct inode* inode, struct file* filp);
 int iic_release(struct inode* inode, struct file* filp);
@@ -167,7 +147,6 @@ int iic_common_open(iic_client_t ** o_client, iic_bus_t * bus, int engine_num)
 	client->tgid = current->tgid;
 	sema_init(&client->sem, 1);
 	init_waitqueue_head(&client->wait);
-	kobject_get(&bus->eng->kobj);
 	*o_client = client;
 
 exit:
@@ -262,7 +241,6 @@ int iic_common_release(iic_client_t * client)
 
         client->bus = 0;
         kfree(client);
-        kobject_put(&bus->eng->kobj);
 
         IEXIT(rc);
         return rc;
@@ -1170,6 +1148,7 @@ EXPORT_SYMBOL(iic_sideways_read);
 ssize_t iic_read(struct file *filp, char __user *buf, size_t count,
 		 loff_t *offset)
 {
+	int rc_copy;
 	ssize_t rc = count;
 	char *kbuf;
 	iic_client_t *client = (iic_client_t*)filp->private_data;
@@ -1203,7 +1182,7 @@ ssize_t iic_read(struct file *filp, char __user *buf, size_t count,
 	if (rc < 0)
 		goto free;
 
-	rc = copy_to_user(buf, kbuf, count);
+	rc_copy = copy_to_user(buf, kbuf, count);
 
 free:
 	kfree(kbuf);
@@ -2148,23 +2127,11 @@ iic_bus_t*  iic_create_bus(struct class* classp, iic_eng_t* eng,
 	bus->devnum = devnum;
 	bus->i2c_hz = 400000;
 	cdev_init(&bus->cdev, &iic_fops); // ref count = 1
-	/* since cdev is embedded in our bus structure, override the cdev
-	 * cleanup function with our own so that the bus object doesn't get
-	 * freed until the cdev ref count goes to zero.
-	 */
-	if(!cdev_dflt_type)
-	{
-		cdev_dflt_type = bus->cdev.kobj.ktype;
-		memcpy(&iic_bus_type, cdev_dflt_type, sizeof(iic_bus_type));
-		iic_bus_type.release = iic_bus_release;
-	}
-	bus->cdev.kobj.ktype = &iic_bus_type;
 	kobject_set_name(&bus->cdev.kobj, name);
 	rc = cdev_add(&bus->cdev, devnum, 1);
 	if(rc)
 	{
 		IFLDe(1, "cdev_add failed for bus %08lx\n", bus->bus_id);
-		kobject_put(&bus->cdev.kobj);
 		goto exit_cdev_add;
 	}
 
@@ -2186,6 +2153,7 @@ iic_bus_t*  iic_create_bus(struct class* classp, iic_eng_t* eng,
 exit_class_add:
 	cdev_del(&bus->cdev);
 exit_cdev_add:
+	kfree(bus);
 	bus = 0;
 exit:
 	IEXIT((int)bus);
@@ -2202,7 +2170,9 @@ void iic_delete_bus(struct class* classp, iic_bus_t* bus)
 		goto exit;
 	}
 	IFLDi(1, "cleanup bus[%08lx]\n", bus->bus_id);
+	device_destroy(classp, bus->devnum);
 	cdev_del(&bus->cdev);
+	kfree(bus);
 exit:
 	IEXIT(0);
 	return;
-- 
1.8.3.1



More information about the openbmc mailing list