Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bnxt/bnxt_en/bnxt_auxbus_compat.c
39536 views
1
/*-
2
* Broadcom NetXtreme-C/E network driver.
3
*
4
* Copyright (c) 2024 Broadcom, All Rights Reserved.
5
* The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26
* THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#include <linux/device.h>
30
#include <linux/slab.h>
31
#include <linux/string.h>
32
#include <linux/types.h>
33
#include <linux/list.h>
34
#include <linux/delay.h>
35
36
#include "bnxt_auxbus_compat.h"
37
38
static struct list_head bnxt_aux_bus_dev_list = LINUX_LIST_HEAD_INIT(bnxt_aux_bus_dev_list);
39
static struct list_head bnxt_aux_bus_drv_list = LINUX_LIST_HEAD_INIT(bnxt_aux_bus_drv_list);
40
static DEFINE_MUTEX(bnxt_auxbus_lock);
41
42
static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
43
const struct auxiliary_device *auxdev)
44
{
45
for (; id->name[0]; id++) {
46
const char *p = strrchr(dev_name(&auxdev->dev), '.');
47
int match_size;
48
49
if (!p)
50
continue;
51
match_size = p - dev_name(&auxdev->dev);
52
53
if (strlen(id->name) == match_size &&
54
!strncmp(dev_name(&auxdev->dev), id->name, match_size))
55
return id;
56
}
57
return NULL;
58
}
59
60
int auxiliary_device_init(struct auxiliary_device *auxdev)
61
{
62
struct device *dev = &auxdev->dev;
63
char *modname = KBUILD_MODNAME;
64
int ret;
65
66
if (!dev->parent) {
67
pr_err("auxiliary_device has a NULL dev->parent\n");
68
return -EINVAL;
69
}
70
71
if (!auxdev->name) {
72
pr_err("auxiliary_device has a NULL name\n");
73
return -EINVAL;
74
}
75
76
ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id);
77
if (ret) {
78
dev_err(dev, "auxiliary device dev_set_name failed: %d\n", ret);
79
return ret;
80
}
81
82
return 0;
83
}
84
85
int auxiliary_device_add(struct auxiliary_device *auxdev)
86
{
87
const struct auxiliary_device_id *id;
88
struct auxiliary_driver *auxdrv = NULL;
89
bool found = true;
90
int ret = 0;
91
92
mutex_lock(&bnxt_auxbus_lock);
93
list_for_each_entry(auxdrv, &bnxt_aux_bus_drv_list, list) {
94
if (auxdrv) {
95
msleep(2 * 1000);
96
97
id = auxiliary_match_id(auxdrv->id_table, auxdev);
98
if (id) {
99
ret = auxdrv->probe(auxdev, id);
100
if (!ret)
101
auxdev->dev.driver = &auxdrv->driver;
102
else
103
found = false;
104
break;
105
}
106
}
107
}
108
109
if (found)
110
list_add_tail(&auxdev->list, &bnxt_aux_bus_dev_list);
111
mutex_unlock(&bnxt_auxbus_lock);
112
113
return ret;
114
}
115
116
void auxiliary_device_uninit(struct auxiliary_device *auxdev)
117
{
118
return;
119
}
120
121
void auxiliary_device_delete(struct auxiliary_device *auxdev)
122
{
123
struct auxiliary_driver *auxdrv;
124
125
mutex_lock(&bnxt_auxbus_lock);
126
list_for_each_entry(auxdrv, &bnxt_aux_bus_drv_list, list) {
127
if (auxdev->dev.driver != &auxdrv->driver)
128
continue;
129
if (auxdrv->remove)
130
auxdrv->remove(auxdev);
131
auxdev->dev.driver = NULL;
132
}
133
list_del(&auxdev->list);
134
mutex_unlock(&bnxt_auxbus_lock);
135
}
136
137
int auxiliary_driver_register(struct auxiliary_driver *auxdrv)
138
{
139
const struct auxiliary_device_id *id;
140
struct auxiliary_device *auxdev;
141
int ret = 0;
142
143
if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table))
144
return -EINVAL;
145
146
if (auxdrv->name)
147
auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", KBUILD_MODNAME,
148
auxdrv->name);
149
else
150
auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", KBUILD_MODNAME);
151
if (!auxdrv->driver.name)
152
return -ENOMEM;
153
154
mutex_lock(&bnxt_auxbus_lock);
155
list_for_each_entry(auxdev, &bnxt_aux_bus_dev_list, list) {
156
if (auxdev->dev.driver)
157
continue;
158
159
id = auxiliary_match_id(auxdrv->id_table, auxdev);
160
if (id) {
161
ret = auxdrv->probe(auxdev, id);
162
if (ret)
163
continue;
164
auxdev->dev.driver = &auxdrv->driver;
165
}
166
}
167
list_add_tail(&auxdrv->list, &bnxt_aux_bus_drv_list);
168
mutex_unlock(&bnxt_auxbus_lock);
169
return 0;
170
}
171
EXPORT_SYMBOL(auxiliary_driver_register);
172
173
void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
174
{
175
struct auxiliary_device *auxdev;
176
177
/* PF auxiliary devices are added to the list first and then VF devices.
178
* If we remove PF aux device driver first, it causes failures while
179
* removing VF driver.
180
* We need to remove VF auxiliary drivers first, so walk backwards.
181
*/
182
mutex_lock(&bnxt_auxbus_lock);
183
list_for_each_entry_reverse(auxdev, &bnxt_aux_bus_dev_list, list) {
184
if (auxdev->dev.driver != &auxdrv->driver)
185
continue;
186
if (auxdrv->remove)
187
auxdrv->remove(auxdev);
188
auxdev->dev.driver = NULL;
189
}
190
kfree(auxdrv->driver.name);
191
list_del(&auxdrv->list);
192
mutex_unlock(&bnxt_auxbus_lock);
193
}
194
EXPORT_SYMBOL(auxiliary_driver_unregister);
195
196