@@ -1562,13 +1562,84 @@ static int rproc_set_rsc_table(struct rproc *rproc)
1562
1562
return ret ;
1563
1563
}
1564
1564
1565
+ /*
1566
+ * If it is possible to detach the remote processor, keep an untouched
1567
+ * copy of the resource table. That way we can start fresh again when
1568
+ * the remote processor is re-attached, that is:
1569
+ *
1570
+ * DETACHED -> ATTACHED -> DETACHED -> ATTACHED
1571
+ *
1572
+ * Free'd in rproc_reset_rsc_table_on_detach() and
1573
+ * rproc_reset_rsc_table_on_stop().
1574
+ */
1575
+ if (rproc -> ops -> detach ) {
1576
+ rproc -> clean_table = kmemdup (table_ptr , table_sz , GFP_KERNEL );
1577
+ if (!rproc -> clean_table )
1578
+ return - ENOMEM ;
1579
+ } else {
1580
+ rproc -> clean_table = NULL ;
1581
+ }
1582
+
1565
1583
rproc -> cached_table = NULL ;
1566
1584
rproc -> table_ptr = table_ptr ;
1567
1585
rproc -> table_sz = table_sz ;
1568
1586
1569
1587
return 0 ;
1570
1588
}
1571
1589
1590
+ static int rproc_reset_rsc_table_on_detach (struct rproc * rproc )
1591
+ {
1592
+ struct resource_table * table_ptr ;
1593
+
1594
+ /* A resource table was never retrieved, nothing to do here */
1595
+ if (!rproc -> table_ptr )
1596
+ return 0 ;
1597
+
1598
+ /*
1599
+ * If we made it to this point a clean_table _must_ have been
1600
+ * allocated in rproc_set_rsc_table(). If one isn't present
1601
+ * something went really wrong and we must complain.
1602
+ */
1603
+ if (WARN_ON (!rproc -> clean_table ))
1604
+ return - EINVAL ;
1605
+
1606
+ /* Remember where the external entity installed the resource table */
1607
+ table_ptr = rproc -> table_ptr ;
1608
+
1609
+ /*
1610
+ * If we made it here the remote processor was started by another
1611
+ * entity and a cache table doesn't exist. As such make a copy of
1612
+ * the resource table currently used by the remote processor and
1613
+ * use that for the rest of the shutdown process. The memory
1614
+ * allocated here is free'd in rproc_detach().
1615
+ */
1616
+ rproc -> cached_table = kmemdup (rproc -> table_ptr ,
1617
+ rproc -> table_sz , GFP_KERNEL );
1618
+ if (!rproc -> cached_table )
1619
+ return - ENOMEM ;
1620
+
1621
+ /*
1622
+ * Use a copy of the resource table for the remainder of the
1623
+ * shutdown process.
1624
+ */
1625
+ rproc -> table_ptr = rproc -> cached_table ;
1626
+
1627
+ /*
1628
+ * Reset the memory area where the firmware loaded the resource table
1629
+ * to its original value. That way when we re-attach the remote
1630
+ * processor the resource table is clean and ready to be used again.
1631
+ */
1632
+ memcpy (table_ptr , rproc -> clean_table , rproc -> table_sz );
1633
+
1634
+ /*
1635
+ * The clean resource table is no longer needed. Allocated in
1636
+ * rproc_set_rsc_table().
1637
+ */
1638
+ kfree (rproc -> clean_table );
1639
+
1640
+ return 0 ;
1641
+ }
1642
+
1572
1643
/*
1573
1644
* Attach to remote processor - similar to rproc_fw_boot() but without
1574
1645
* the steps that deal with the firmware image.
@@ -1727,6 +1798,13 @@ static int __rproc_detach(struct rproc *rproc)
1727
1798
/* Stop any subdevices for the remote processor */
1728
1799
rproc_stop_subdevices (rproc , false);
1729
1800
1801
+ /* the installed resource table is no longer accessible */
1802
+ ret = rproc_reset_rsc_table_on_detach (rproc );
1803
+ if (ret ) {
1804
+ dev_err (dev , "can't reset resource table: %d\n" , ret );
1805
+ return ret ;
1806
+ }
1807
+
1730
1808
/* Tell the remote processor the core isn't available anymore */
1731
1809
ret = rproc -> ops -> detach (rproc );
1732
1810
if (ret ) {
@@ -2003,6 +2081,9 @@ int rproc_detach(struct rproc *rproc)
2003
2081
2004
2082
rproc_disable_iommu (rproc );
2005
2083
2084
+ /* Free the copy of the resource table */
2085
+ kfree (rproc -> cached_table );
2086
+ rproc -> cached_table = NULL ;
2006
2087
rproc -> table_ptr = NULL ;
2007
2088
out :
2008
2089
mutex_unlock (& rproc -> lock );
0 commit comments