alpha/PCI: Convert resource files to static attributes

Previously, Alpha's PCI resource files (resourceN, resourceN_sparse,
resourceN_dense) were dynamically created by pci_create_resource_files(),
which overrides the generic __weak implementation.  The previous code
allocated bin_attributes at runtime and managed them via the res_attr[] and
res_attr_wc[] fields in struct pci_dev.

Convert to static const attributes with three attribute groups (plain,
sparse, dense), each with an .is_bin_visible() callback that checks
resource length, has_sparse(), and sparse_mem_mmap_fits().  A .bin_size()
callback provides the resource size to the kernfs node, with the sparse
variant shifting by 5 bits for byte-level addressing.

Register the groups via ARCH_PCI_DEV_GROUPS so the driver model handles
creation and removal automatically.

Use the new pci_resource_is_mem() helper for the type check, replacing the
open-coded bitwise flag test.

Finally, remove pci_create_resource_files(), pci_remove_resource_files(),
pci_create_attr(), and pci_create_one_attr() which are no longer needed.

Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Magnus Lindholm <linmag7@gmail.com>
Tested-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>
Acked-by: Magnus Lindholm <linmag7@gmail.com>
Link: https://patch.msgid.link/20260508043543.217179-18-kwilczynski@kernel.org
This commit is contained in:
Krzysztof Wilczyński 2026-05-08 04:35:36 +00:00 committed by Bjorn Helgaas
parent 5980dcbc4b
commit b7a57ffd4d
2 changed files with 172 additions and 128 deletions

View File

@ -88,4 +88,13 @@ extern void pci_adjust_legacy_attr(struct pci_bus *bus,
enum pci_mmap_state mmap_type);
#define HAVE_PCI_LEGACY 1
extern const struct attribute_group pci_dev_resource_attr_group;
extern const struct attribute_group pci_dev_resource_sparse_attr_group;
extern const struct attribute_group pci_dev_resource_dense_attr_group;
#define ARCH_PCI_DEV_GROUPS \
&pci_dev_resource_attr_group, \
&pci_dev_resource_sparse_attr_group, \
&pci_dev_resource_dense_attr_group,
#endif /* __ALPHA_PCI_H */

View File

@ -12,8 +12,6 @@
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pci.h>
static int hose_mmap_page_range(struct pci_controller *hose,
@ -124,34 +122,6 @@ pci_dev_resource##_bar##_suffix##_attr = { \
__pci_dev_resource_attr(_bar, resource##_bar##_dense, _dense, \
pci_mmap_resource_dense)
/**
* pci_remove_resource_files - cleanup resource files
* @pdev: pci_dev to cleanup
*
* If we created resource files for @dev, remove them from sysfs and
* free their resources.
*/
void pci_remove_resource_files(struct pci_dev *pdev)
{
int i;
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
struct bin_attribute *res_attr;
res_attr = pdev->res_attr[i];
if (res_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
kfree(res_attr);
}
res_attr = pdev->res_attr_wc[i];
if (res_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
kfree(res_attr);
}
}
}
static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
{
struct pci_bus_region bar;
@ -171,104 +141,6 @@ static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
return bar.end < sparse_size;
}
static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
char *suffix, struct bin_attribute *res_attr,
unsigned long sparse)
{
size_t size = pci_resource_len(pdev, num);
sprintf(name, "resource%d%s", num, suffix);
res_attr->mmap = sparse ? pci_mmap_resource_sparse :
pci_mmap_resource_dense;
res_attr->attr.name = name;
res_attr->attr.mode = S_IRUSR | S_IWUSR;
res_attr->size = sparse ? size << 5 : size;
res_attr->private = (void *)(unsigned long)num;
return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
}
static int pci_create_attr(struct pci_dev *pdev, int num)
{
/* allocate attribute structure, piggyback attribute name */
int retval, nlen1, nlen2 = 0, res_count = 1;
unsigned long sparse_base, dense_base;
struct bin_attribute *attr;
struct pci_controller *hose = pdev->sysdata;
char *suffix, *attr_name;
suffix = ""; /* Assume bwx machine, normal resourceN files. */
nlen1 = 10;
if (pci_resource_is_mem(pdev, num)) {
sparse_base = hose->sparse_mem_base;
dense_base = hose->dense_mem_base;
if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
sparse_base = 0;
suffix = "_dense";
nlen1 = 16; /* resourceN_dense */
}
} else {
sparse_base = hose->sparse_io_base;
dense_base = hose->dense_io_base;
}
if (sparse_base) {
suffix = "_sparse";
nlen1 = 17;
if (dense_base) {
nlen2 = 16; /* resourceN_dense */
res_count = 2;
}
}
attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
if (!attr)
return -ENOMEM;
/* Create bwx, sparse or single dense file */
attr_name = (char *)(attr + res_count);
pdev->res_attr[num] = attr;
retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
sparse_base);
if (retval || res_count == 1)
return retval;
/* Create dense file */
attr_name += nlen1;
attr++;
pdev->res_attr_wc[num] = attr;
return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
}
/**
* pci_create_resource_files - create resource files in sysfs for @pdev
* @pdev: pci_dev in question
*
* Walk the resources in @dev creating files for each resource available.
*
* Return: %0 on success, or negative error code
*/
int pci_create_resource_files(struct pci_dev *pdev)
{
int i;
int retval;
/* Expose the PCI resources from this device as files */
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
/* skip empty resources */
if (!pci_resource_len(pdev, i))
continue;
retval = pci_create_attr(pdev, i);
if (retval) {
pci_remove_resource_files(pdev);
return retval;
}
}
return 0;
}
/* Legacy I/O bus mapping stuff. */
static int __legacy_mmap_fits(struct vm_area_struct *vma,
@ -381,3 +253,166 @@ int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
}
return -EINVAL;
}
pci_dev_resource_attr(0);
pci_dev_resource_attr(1);
pci_dev_resource_attr(2);
pci_dev_resource_attr(3);
pci_dev_resource_attr(4);
pci_dev_resource_attr(5);
pci_dev_resource_sparse_attr(0);
pci_dev_resource_sparse_attr(1);
pci_dev_resource_sparse_attr(2);
pci_dev_resource_sparse_attr(3);
pci_dev_resource_sparse_attr(4);
pci_dev_resource_sparse_attr(5);
pci_dev_resource_dense_attr(0);
pci_dev_resource_dense_attr(1);
pci_dev_resource_dense_attr(2);
pci_dev_resource_dense_attr(3);
pci_dev_resource_dense_attr(4);
pci_dev_resource_dense_attr(5);
static inline enum pci_mmap_state pci_bar_mmap_type(struct pci_dev *pdev,
int bar)
{
return pci_resource_is_mem(pdev, bar) ? pci_mmap_mem : pci_mmap_io;
}
static inline umode_t __pci_dev_resource_is_visible(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
if (!pci_resource_len(pdev, bar))
return 0;
return a->attr.mode;
}
static umode_t pci_dev_resource_is_visible(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
struct pci_controller *hose = pdev->sysdata;
if (has_sparse(hose, pci_bar_mmap_type(pdev, bar)))
return 0;
return __pci_dev_resource_is_visible(kobj, a, bar);
}
static umode_t pci_dev_resource_sparse_is_visible(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
struct pci_controller *hose = pdev->sysdata;
enum pci_mmap_state type = pci_bar_mmap_type(pdev, bar);
if (!has_sparse(hose, type))
return 0;
if (type == pci_mmap_mem && !sparse_mem_mmap_fits(pdev, bar))
return 0;
return __pci_dev_resource_is_visible(kobj, a, bar);
}
static umode_t pci_dev_resource_dense_is_visible(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
struct pci_controller *hose = pdev->sysdata;
enum pci_mmap_state type = pci_bar_mmap_type(pdev, bar);
unsigned long dense_base;
if (!has_sparse(hose, type))
return 0;
if (type == pci_mmap_mem && !sparse_mem_mmap_fits(pdev, bar))
return __pci_dev_resource_is_visible(kobj, a, bar);
dense_base = (type == pci_mmap_mem) ? hose->dense_mem_base :
hose->dense_io_base;
if (!dense_base)
return 0;
return __pci_dev_resource_is_visible(kobj, a, bar);
}
static inline size_t __pci_dev_resource_bin_size(struct kobject *kobj,
int bar, bool sparse)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
size_t size = pci_resource_len(pdev, bar);
return sparse ? size << 5 : size;
}
static size_t pci_dev_resource_bin_size(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
return __pci_dev_resource_bin_size(kobj, bar, false);
}
static size_t pci_dev_resource_sparse_bin_size(struct kobject *kobj,
const struct bin_attribute *a,
int bar)
{
return __pci_dev_resource_bin_size(kobj, bar, true);
}
static const struct bin_attribute *const pci_dev_resource_attrs[] = {
&pci_dev_resource0_attr,
&pci_dev_resource1_attr,
&pci_dev_resource2_attr,
&pci_dev_resource3_attr,
&pci_dev_resource4_attr,
&pci_dev_resource5_attr,
NULL,
};
static const struct bin_attribute *const pci_dev_resource_sparse_attrs[] = {
&pci_dev_resource0_sparse_attr,
&pci_dev_resource1_sparse_attr,
&pci_dev_resource2_sparse_attr,
&pci_dev_resource3_sparse_attr,
&pci_dev_resource4_sparse_attr,
&pci_dev_resource5_sparse_attr,
NULL,
};
static const struct bin_attribute *const pci_dev_resource_dense_attrs[] = {
&pci_dev_resource0_dense_attr,
&pci_dev_resource1_dense_attr,
&pci_dev_resource2_dense_attr,
&pci_dev_resource3_dense_attr,
&pci_dev_resource4_dense_attr,
&pci_dev_resource5_dense_attr,
NULL,
};
const struct attribute_group pci_dev_resource_attr_group = {
.bin_attrs = pci_dev_resource_attrs,
.is_bin_visible = pci_dev_resource_is_visible,
.bin_size = pci_dev_resource_bin_size,
};
const struct attribute_group pci_dev_resource_sparse_attr_group = {
.bin_attrs = pci_dev_resource_sparse_attrs,
.is_bin_visible = pci_dev_resource_sparse_is_visible,
.bin_size = pci_dev_resource_sparse_bin_size,
};
const struct attribute_group pci_dev_resource_dense_attr_group = {
.bin_attrs = pci_dev_resource_dense_attrs,
.is_bin_visible = pci_dev_resource_dense_is_visible,
.bin_size = pci_dev_resource_bin_size,
};