@ -22,6 +22,79 @@
static DEFINE_IDA ( region_ida ) ;
static int nvdimm_map_flush ( struct device * dev , struct nvdimm * nvdimm , int dimm ,
struct nd_region_data * ndrd )
{
int i , j ;
dev_dbg ( dev , " %s: map %d flush address%s \n " , nvdimm_name ( nvdimm ) ,
nvdimm - > num_flush , nvdimm - > num_flush = = 1 ? " " : " es " ) ;
for ( i = 0 ; i < nvdimm - > num_flush ; i + + ) {
struct resource * res = & nvdimm - > flush_wpq [ i ] ;
unsigned long pfn = PHYS_PFN ( res - > start ) ;
void __iomem * flush_page ;
/* check if flush hints share a page */
for ( j = 0 ; j < i ; j + + ) {
struct resource * res_j = & nvdimm - > flush_wpq [ j ] ;
unsigned long pfn_j = PHYS_PFN ( res_j - > start ) ;
if ( pfn = = pfn_j )
break ;
}
if ( j < i )
flush_page = ( void __iomem * ) ( ( unsigned long )
ndrd - > flush_wpq [ dimm ] [ j ] & PAGE_MASK ) ;
else
flush_page = devm_nvdimm_ioremap ( dev ,
PHYS_PFN ( pfn ) , PAGE_SIZE ) ;
if ( ! flush_page )
return - ENXIO ;
ndrd - > flush_wpq [ dimm ] [ i ] = flush_page
+ ( res - > start & ~ PAGE_MASK ) ;
}
return 0 ;
}
int nd_region_activate ( struct nd_region * nd_region )
{
int i ;
struct nd_region_data * ndrd ;
struct device * dev = & nd_region - > dev ;
size_t flush_data_size = sizeof ( void * ) ;
nvdimm_bus_lock ( & nd_region - > dev ) ;
for ( i = 0 ; i < nd_region - > ndr_mappings ; i + + ) {
struct nd_mapping * nd_mapping = & nd_region - > mapping [ i ] ;
struct nvdimm * nvdimm = nd_mapping - > nvdimm ;
/* at least one null hint slot per-dimm for the "no-hint" case */
flush_data_size + = sizeof ( void * ) ;
if ( ! nvdimm - > num_flush )
continue ;
flush_data_size + = nvdimm - > num_flush * sizeof ( void * ) ;
}
nvdimm_bus_unlock ( & nd_region - > dev ) ;
ndrd = devm_kzalloc ( dev , sizeof ( * ndrd ) + flush_data_size , GFP_KERNEL ) ;
if ( ! ndrd )
return - ENOMEM ;
dev_set_drvdata ( dev , ndrd ) ;
for ( i = 0 ; i < nd_region - > ndr_mappings ; i + + ) {
struct nd_mapping * nd_mapping = & nd_region - > mapping [ i ] ;
struct nvdimm * nvdimm = nd_mapping - > nvdimm ;
int rc = nvdimm_map_flush ( & nd_region - > dev , nvdimm , i , ndrd ) ;
if ( rc )
return rc ;
}
return 0 ;
}
static void nd_region_release ( struct device * dev )
{
struct nd_region * nd_region = to_nd_region ( dev ) ;
@ -242,12 +315,12 @@ static DEVICE_ATTR_RO(available_size);
static ssize_t init_namespaces_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nd_region_namespaces * num_ns = dev_get_drvdata ( dev ) ;
struct nd_region_data * ndrd = dev_get_drvdata ( dev ) ;
ssize_t rc ;
nvdimm_bus_lock ( dev ) ;
if ( num_ns )
rc = sprintf ( buf , " %d/%d \n " , num_ns - > active , num_ns - > count ) ;
if ( ndrd )
rc = sprintf ( buf , " %d/%d \n " , ndrd - > ns_ active, ndrd - > ns_ count) ;
else
rc = - ENXIO ;
nvdimm_bus_unlock ( dev ) ;