18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci// Copyright 2019 IBM Corp.
38c2ecf20Sopenharmony_ci#include <linux/module.h>
48c2ecf20Sopenharmony_ci#include "ocxl_internal.h"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/*
78c2ecf20Sopenharmony_ci * Any opencapi device which wants to use this 'generic' driver should
88c2ecf20Sopenharmony_ci * use the 0x062B device ID. Vendors should define the subsystem
98c2ecf20Sopenharmony_ci * vendor/device ID to help differentiate devices.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_cistatic const struct pci_device_id ocxl_pci_tbl[] = {
128c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x062B), },
138c2ecf20Sopenharmony_ci	{ }
148c2ecf20Sopenharmony_ci};
158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ocxl_pci_tbl);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	int rc;
208c2ecf20Sopenharmony_ci	struct ocxl_afu *afu, *tmp;
218c2ecf20Sopenharmony_ci	struct ocxl_fn *fn;
228c2ecf20Sopenharmony_ci	struct list_head *afu_list;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	fn = ocxl_function_open(dev);
258c2ecf20Sopenharmony_ci	if (IS_ERR(fn))
268c2ecf20Sopenharmony_ci		return PTR_ERR(fn);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, fn);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	afu_list = ocxl_function_afu_list(fn);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	list_for_each_entry_safe(afu, tmp, afu_list, list) {
338c2ecf20Sopenharmony_ci		// Cleanup handled within ocxl_file_register_afu()
348c2ecf20Sopenharmony_ci		rc = ocxl_file_register_afu(afu);
358c2ecf20Sopenharmony_ci		if (rc) {
368c2ecf20Sopenharmony_ci			dev_err(&dev->dev, "Failed to register AFU '%s' index %d",
378c2ecf20Sopenharmony_ci					afu->config.name, afu->config.idx);
388c2ecf20Sopenharmony_ci		}
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	return 0;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic void ocxl_remove(struct pci_dev *dev)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct ocxl_fn *fn;
478c2ecf20Sopenharmony_ci	struct ocxl_afu *afu;
488c2ecf20Sopenharmony_ci	struct list_head *afu_list;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	fn = pci_get_drvdata(dev);
518c2ecf20Sopenharmony_ci	afu_list = ocxl_function_afu_list(fn);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	list_for_each_entry(afu, afu_list, list) {
548c2ecf20Sopenharmony_ci		ocxl_file_unregister_afu(afu);
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ocxl_function_close(fn);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct pci_driver ocxl_pci_driver = {
618c2ecf20Sopenharmony_ci	.name = "ocxl",
628c2ecf20Sopenharmony_ci	.id_table = ocxl_pci_tbl,
638c2ecf20Sopenharmony_ci	.probe = ocxl_probe,
648c2ecf20Sopenharmony_ci	.remove = ocxl_remove,
658c2ecf20Sopenharmony_ci	.shutdown = ocxl_remove,
668c2ecf20Sopenharmony_ci};
67