Skip to content

Commit 31bdc5d

Browse files
author
Linus Torvalds
committed
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: [SPARC64]: Set vio->desc_buf to NULL after freeing. [SPARC]: Mark sparc and sparc64 as not having virt_to_bus [SPARC64]: Fix reset handling in VNET driver. [SPARC64]: Handle reset events in vio_link_state_change(). [SPARC64]: Handle LDC resets properly in domain-services driver. [SPARC64]: Massively simplify VIO device layer and support hot add/remove. [SPARC64]: Simplify VNET probing. [SPARC64]: Simplify VDC device probing. [SPARC64]: Add basic infrastructure for MD add/remove notification.
2 parents 5cc97bf + a5f8967 commit 31bdc5d

File tree

12 files changed

+344
-261
lines changed

12 files changed

+344
-261
lines changed

arch/sparc/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ config GENERIC_ISA_DMA
2121
bool
2222
default y
2323

24+
config ARCH_NO_VIRT_TO_BUS
25+
def_bool y
26+
2427
source "init/Kconfig"
2528

2629
menu "General machine setup"

arch/sparc64/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ config AUDIT_ARCH
6262
bool
6363
default y
6464

65+
config ARCH_NO_VIRT_TO_BUS
66+
def_bool y
67+
6568
choice
6669
prompt "Kernel page size"
6770
default SPARC64_PAGE_SIZE_8KB

arch/sparc64/kernel/ds.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp)
10131013
dp->hs_state = DS_HS_START;
10141014
}
10151015

1016+
static void ds_reset(struct ds_info *dp)
1017+
{
1018+
int i;
1019+
1020+
dp->hs_state = 0;
1021+
1022+
for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
1023+
struct ds_cap_state *cp = &ds_states[i];
1024+
1025+
cp->state = CAP_STATE_UNKNOWN;
1026+
}
1027+
}
1028+
10161029
static void ds_event(void *arg, int event)
10171030
{
10181031
struct ds_info *dp = arg;
@@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event)
10281041
return;
10291042
}
10301043

1044+
if (event == LDC_EVENT_RESET) {
1045+
ds_reset(dp);
1046+
spin_unlock_irqrestore(&ds_lock, flags);
1047+
return;
1048+
}
1049+
10311050
if (event != LDC_EVENT_DATA_READY) {
10321051
printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
10331052
spin_unlock_irqrestore(&ds_lock, flags);

arch/sparc64/kernel/mdesc.c

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
137137
sizeof(struct mdesc_hdr) +
138138
mdesc_size);
139139

140-
base = kmalloc(handle_size + 15, GFP_KERNEL);
140+
base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
141141
if (base) {
142142
struct mdesc_handle *hp;
143143
unsigned long addr;
@@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
214214
}
215215
EXPORT_SYMBOL(mdesc_release);
216216

217+
static DEFINE_MUTEX(mdesc_mutex);
218+
static struct mdesc_notifier_client *client_list;
219+
220+
void mdesc_register_notifier(struct mdesc_notifier_client *client)
221+
{
222+
u64 node;
223+
224+
mutex_lock(&mdesc_mutex);
225+
client->next = client_list;
226+
client_list = client;
227+
228+
mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
229+
client->add(cur_mdesc, node);
230+
231+
mutex_unlock(&mdesc_mutex);
232+
}
233+
234+
/* Run 'func' on nodes which are in A but not in B. */
235+
static void invoke_on_missing(const char *name,
236+
struct mdesc_handle *a,
237+
struct mdesc_handle *b,
238+
void (*func)(struct mdesc_handle *, u64))
239+
{
240+
u64 node;
241+
242+
mdesc_for_each_node_by_name(a, node, name) {
243+
const u64 *id = mdesc_get_property(a, node, "id", NULL);
244+
int found = 0;
245+
u64 fnode;
246+
247+
mdesc_for_each_node_by_name(b, fnode, name) {
248+
const u64 *fid = mdesc_get_property(b, fnode,
249+
"id", NULL);
250+
251+
if (*id == *fid) {
252+
found = 1;
253+
break;
254+
}
255+
}
256+
if (!found)
257+
func(a, node);
258+
}
259+
}
260+
261+
static void notify_one(struct mdesc_notifier_client *p,
262+
struct mdesc_handle *old_hp,
263+
struct mdesc_handle *new_hp)
264+
{
265+
invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
266+
invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
267+
}
268+
269+
static void mdesc_notify_clients(struct mdesc_handle *old_hp,
270+
struct mdesc_handle *new_hp)
271+
{
272+
struct mdesc_notifier_client *p = client_list;
273+
274+
while (p) {
275+
notify_one(p, old_hp, new_hp);
276+
p = p->next;
277+
}
278+
}
279+
217280
void mdesc_update(void)
218281
{
219282
unsigned long len, real_len, status;
220283
struct mdesc_handle *hp, *orig_hp;
221284
unsigned long flags;
222285

286+
mutex_lock(&mdesc_mutex);
287+
223288
(void) sun4v_mach_desc(0UL, 0UL, &len);
224289

225290
hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
226291
if (!hp) {
227292
printk(KERN_ERR "MD: mdesc alloc fails\n");
228-
return;
293+
goto out;
229294
}
230295

231296
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +299,25 @@ void mdesc_update(void)
234299
status);
235300
atomic_dec(&hp->refcnt);
236301
mdesc_free(hp);
237-
return;
302+
goto out;
238303
}
239304

240305
spin_lock_irqsave(&mdesc_lock, flags);
241306
orig_hp = cur_mdesc;
242307
cur_mdesc = hp;
308+
spin_unlock_irqrestore(&mdesc_lock, flags);
243309

310+
mdesc_notify_clients(orig_hp, hp);
311+
312+
spin_lock_irqsave(&mdesc_lock, flags);
244313
if (atomic_dec_and_test(&orig_hp->refcnt))
245314
mdesc_free(orig_hp);
246315
else
247316
list_add(&orig_hp->list, &mdesc_zombie_list);
248317
spin_unlock_irqrestore(&mdesc_lock, flags);
318+
319+
out:
320+
mutex_unlock(&mdesc_mutex);
249321
}
250322

251323
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)

arch/sparc64/kernel/vio.c

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
201201
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
202202
struct device *parent)
203203
{
204-
const char *type, *compat;
204+
const char *type, *compat, *bus_id_name;
205205
struct device_node *dp;
206206
struct vio_dev *vdev;
207207
int err, tlen, clen;
208+
const u64 *id;
208209

209210
type = mdesc_get_property(hp, mp, "device-type", &tlen);
210211
if (!type) {
@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
220221
return NULL;
221222
}
222223

224+
bus_id_name = type;
225+
if (!strcmp(type, "domain-services-port"))
226+
bus_id_name = "ds";
227+
228+
if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
229+
printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
230+
bus_id_name);
231+
return NULL;
232+
}
233+
223234
compat = mdesc_get_property(hp, mp, "device-type", &clen);
224235
if (!compat) {
225236
clen = 0;
@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
249260

250261
vio_fill_channel_info(hp, mp, vdev);
251262

252-
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
263+
id = mdesc_get_property(hp, mp, "id", NULL);
264+
if (!id)
265+
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
266+
bus_id_name);
267+
else
268+
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
269+
bus_id_name, *id);
270+
253271
vdev->dev.parent = parent;
254272
vdev->dev.bus = &vio_bus_type;
255273
vdev->dev.release = vio_dev_release;
@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
269287
}
270288
vdev->dp = dp;
271289

290+
printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
291+
272292
err = device_register(&vdev->dev);
273293
if (err) {
274294
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
283303
return vdev;
284304
}
285305

286-
static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
306+
static void vio_add(struct mdesc_handle *hp, u64 node)
287307
{
288-
u64 a;
289-
290-
mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
291-
struct vio_dev *vdev;
292-
u64 target;
293-
294-
target = mdesc_arc_target(hp, a);
295-
vdev = vio_create_one(hp, target, &parent->dev);
296-
if (vdev)
297-
walk_tree(hp, target, vdev);
298-
}
308+
(void) vio_create_one(hp, node, &root_vdev->dev);
299309
}
300310

301-
static void create_devices(struct mdesc_handle *hp, u64 root)
311+
static int vio_md_node_match(struct device *dev, void *arg)
302312
{
303-
u64 mp;
313+
struct vio_dev *vdev = to_vio_dev(dev);
304314

305-
root_vdev = vio_create_one(hp, root, NULL);
306-
if (!root_vdev) {
307-
printk(KERN_ERR "VIO: Coult not create root device.\n");
308-
return;
309-
}
315+
if (vdev->mp == (u64) arg)
316+
return 1;
310317

311-
walk_tree(hp, root, root_vdev);
318+
return 0;
319+
}
320+
321+
static void vio_remove(struct mdesc_handle *hp, u64 node)
322+
{
323+
struct device *dev;
312324

313-
/* Domain services is odd as it doesn't sit underneath the
314-
* channel-devices node, so we plug it in manually.
315-
*/
316-
mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
317-
if (mp != MDESC_NODE_NULL) {
318-
struct vio_dev *parent = vio_create_one(hp, mp,
319-
&root_vdev->dev);
325+
dev = device_find_child(&root_vdev->dev, (void *) node,
326+
vio_md_node_match);
327+
if (dev) {
328+
printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
320329

321-
if (parent)
322-
walk_tree(hp, mp, parent);
330+
device_unregister(dev);
323331
}
324332
}
325333

334+
static struct mdesc_notifier_client vio_device_notifier = {
335+
.add = vio_add,
336+
.remove = vio_remove,
337+
.node_name = "virtual-device-port",
338+
};
339+
340+
static struct mdesc_notifier_client vio_ds_notifier = {
341+
.add = vio_add,
342+
.remove = vio_remove,
343+
.node_name = "domain-services-port",
344+
};
345+
326346
const char *channel_devices_node = "channel-devices";
327347
const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
328348
const char *cfg_handle_prop = "cfg-handle";
@@ -381,11 +401,19 @@ static int __init vio_init(void)
381401

382402
cdev_cfg_handle = *cfg_handle;
383403

384-
create_devices(hp, root);
404+
root_vdev = vio_create_one(hp, root, NULL);
405+
err = -ENODEV;
406+
if (!root_vdev) {
407+
printk(KERN_ERR "VIO: Coult not create root device.\n");
408+
goto out_release;
409+
}
410+
411+
mdesc_register_notifier(&vio_device_notifier);
412+
mdesc_register_notifier(&vio_ds_notifier);
385413

386414
mdesc_release(hp);
387415

388-
return 0;
416+
return err;
389417

390418
out_release:
391419
mdesc_release(hp);

arch/sparc64/kernel/viohs.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
7878
return 0;
7979
}
8080

81+
static void flush_rx_dring(struct vio_driver_state *vio)
82+
{
83+
struct vio_dring_state *dr;
84+
u64 ident;
85+
86+
BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
87+
88+
dr = &vio->drings[VIO_DRIVER_RX_RING];
89+
ident = dr->ident;
90+
91+
BUG_ON(!vio->desc_buf);
92+
kfree(vio->desc_buf);
93+
vio->desc_buf = NULL;
94+
95+
memset(dr, 0, sizeof(*dr));
96+
dr->ident = ident;
97+
}
98+
8199
void vio_link_state_change(struct vio_driver_state *vio, int event)
82100
{
83101
if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
98116
break;
99117
}
100118
start_handshake(vio);
119+
} else if (event == LDC_EVENT_RESET) {
120+
vio->hs_state = VIO_HS_INVALID;
121+
122+
if (vio->dr_state & VIO_DR_STATE_RXREG)
123+
flush_rx_dring(vio);
124+
125+
vio->dr_state = 0x00;
126+
memset(&vio->ver, 0, sizeof(vio->ver));
127+
128+
ldc_disconnect(vio->lp);
101129
}
102130
}
103131
EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
396424
if (vio->dr_state & VIO_DR_STATE_RXREG)
397425
goto send_nack;
398426

427+
BUG_ON(vio->desc_buf);
428+
399429
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
400430
if (!vio->desc_buf)
401431
goto send_nack;

0 commit comments

Comments
 (0)