summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2018-01-13 17:37:14 -0500
committerGeert Uytterhoeven <geert@linux-m68k.org>2018-01-16 10:47:29 -0500
commit7f86c765a6a2bb837c45f11526176125ff50e21f (patch)
tree6279c4d31d2bd999852544da73e446e0c28f901d
parentb87eaec27eca3def6c8ed617e3b1bac08d7bc715 (diff)
nubus: Add support for the driver model
This patch brings basic support for the Linux Driver Model to the NuBus subsystem. For flexibility, the matching of boards with drivers is left up to the drivers. This is also the approach taken by NetBSD. A board may have many functions, and drivers may have to consider many functional resources and board resources in order to match a device. This implementation does not bind drivers to resources (nor does it bind many drivers to the same board). Apple's NuBus declaration ROM design is flexible enough to allow that, but I don't see a need to support it as we don't use the "slot zero" resources (in the main logic board ROM). Eliminate the global nubus_boards linked list by rewriting the procfs board iterator around bus_for_each_dev(). Hence the nubus device refcount can be used to determine the lifespan of board objects. Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Tested-by: Stan Johnson <userm57@yahoo.com> Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-rw-r--r--drivers/nubus/Makefile2
-rw-r--r--drivers/nubus/bus.c117
-rw-r--r--drivers/nubus/nubus.c24
-rw-r--r--drivers/nubus/proc.c55
-rw-r--r--include/linux/nubus.h33
5 files changed, 161 insertions, 70 deletions
diff --git a/drivers/nubus/Makefile b/drivers/nubus/Makefile
index 21bda2031e7e..6d063cde39d1 100644
--- a/drivers/nubus/Makefile
+++ b/drivers/nubus/Makefile
@@ -2,6 +2,6 @@
2# Makefile for the nubus specific drivers. 2# Makefile for the nubus specific drivers.
3# 3#
4 4
5obj-y := nubus.o 5obj-y := nubus.o bus.o
6 6
7obj-$(CONFIG_PROC_FS) += proc.o 7obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/nubus/bus.c b/drivers/nubus/bus.c
new file mode 100644
index 000000000000..d306c348c857
--- /dev/null
+++ b/drivers/nubus/bus.c
@@ -0,0 +1,117 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// Bus implementation for the NuBus subsystem.
4//
5// Copyright (C) 2017 Finn Thain
6
7#include <linux/device.h>
8#include <linux/list.h>
9#include <linux/nubus.h>
10#include <linux/seq_file.h>
11#include <linux/slab.h>
12
13#define to_nubus_board(d) container_of(d, struct nubus_board, dev)
14#define to_nubus_driver(d) container_of(d, struct nubus_driver, driver)
15
16static int nubus_bus_match(struct device *dev, struct device_driver *driver)
17{
18 return 1;
19}
20
21static int nubus_device_probe(struct device *dev)
22{
23 struct nubus_driver *ndrv = to_nubus_driver(dev->driver);
24 int err = -ENODEV;
25
26 if (ndrv->probe)
27 err = ndrv->probe(to_nubus_board(dev));
28 return err;
29}
30
31static int nubus_device_remove(struct device *dev)
32{
33 struct nubus_driver *ndrv = to_nubus_driver(dev->driver);
34 int err = -ENODEV;
35
36 if (dev->driver && ndrv->remove)
37 err = ndrv->remove(to_nubus_board(dev));
38 return err;
39}
40
41struct bus_type nubus_bus_type = {
42 .name = "nubus",
43 .match = nubus_bus_match,
44 .probe = nubus_device_probe,
45 .remove = nubus_device_remove,
46};
47EXPORT_SYMBOL(nubus_bus_type);
48
49int nubus_driver_register(struct nubus_driver *ndrv)
50{
51 ndrv->driver.bus = &nubus_bus_type;
52 return driver_register(&ndrv->driver);
53}
54EXPORT_SYMBOL(nubus_driver_register);
55
56void nubus_driver_unregister(struct nubus_driver *ndrv)
57{
58 driver_unregister(&ndrv->driver);
59}
60EXPORT_SYMBOL(nubus_driver_unregister);
61
62static struct device nubus_parent = {
63 .init_name = "nubus",
64};
65
66int __init nubus_bus_register(void)
67{
68 int err;
69
70 err = device_register(&nubus_parent);
71 if (err)
72 return err;
73
74 err = bus_register(&nubus_bus_type);
75 if (!err)
76 return 0;
77
78 device_unregister(&nubus_parent);
79 return err;
80}
81
82static void nubus_device_release(struct device *dev)
83{
84 struct nubus_board *board = to_nubus_board(dev);
85 struct nubus_rsrc *fres, *tmp;
86
87 list_for_each_entry_safe(fres, tmp, &nubus_func_rsrcs, list)
88 if (fres->board == board) {
89 list_del(&fres->list);
90 kfree(fres);
91 }
92 kfree(board);
93}
94
95int nubus_device_register(struct nubus_board *board)
96{
97 board->dev.parent = &nubus_parent;
98 board->dev.release = nubus_device_release;
99 board->dev.bus = &nubus_bus_type;
100 dev_set_name(&board->dev, "slot.%X", board->slot);
101 return device_register(&board->dev);
102}
103
104static int nubus_print_device_name_fn(struct device *dev, void *data)
105{
106 struct nubus_board *board = to_nubus_board(dev);
107 struct seq_file *m = data;
108
109 seq_printf(m, "Slot %X: %s\n", board->slot, board->name);
110 return 0;
111}
112
113int nubus_proc_show(struct seq_file *m, void *data)
114{
115 return bus_for_each_dev(&nubus_bus_type, NULL, m,
116 nubus_print_device_name_fn);
117}
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 0bb54ccd7a1a..4621ff98138c 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -33,7 +33,6 @@
33/* Globals */ 33/* Globals */
34 34
35LIST_HEAD(nubus_func_rsrcs); 35LIST_HEAD(nubus_func_rsrcs);
36struct nubus_board *nubus_boards;
37 36
38/* Meaning of "bytelanes": 37/* Meaning of "bytelanes":
39 38
@@ -715,10 +714,9 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
715 return 0; 714 return 0;
716} 715}
717 716
718static struct nubus_board * __init nubus_add_board(int slot, int bytelanes) 717static void __init nubus_add_board(int slot, int bytelanes)
719{ 718{
720 struct nubus_board *board; 719 struct nubus_board *board;
721 struct nubus_board **boardp;
722 unsigned char *rp; 720 unsigned char *rp;
723 unsigned long dpat; 721 unsigned long dpat;
724 struct nubus_dir dir; 722 struct nubus_dir dir;
@@ -731,7 +729,7 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
731 729
732 /* Actually we should probably panic if this fails */ 730 /* Actually we should probably panic if this fails */
733 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL) 731 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
734 return NULL; 732 return;
735 board->fblock = rp; 733 board->fblock = rp;
736 734
737 /* Dump the format block for debugging purposes */ 735 /* Dump the format block for debugging purposes */
@@ -794,7 +792,8 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
794 if (nubus_readdir(&dir, &ent) == -1) { 792 if (nubus_readdir(&dir, &ent) == -1) {
795 /* We can't have this! */ 793 /* We can't have this! */
796 pr_err("Slot %X: Board resource not found!\n", slot); 794 pr_err("Slot %X: Board resource not found!\n", slot);
797 return NULL; 795 kfree(board);
796 return;
798 } 797 }
799 798
800 if (ent.type < 1 || ent.type > 127) 799 if (ent.type < 1 || ent.type > 127)
@@ -823,14 +822,8 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
823 list_add_tail(&fres->list, &nubus_func_rsrcs); 822 list_add_tail(&fres->list, &nubus_func_rsrcs);
824 } 823 }
825 824
826 /* Put it on the global NuBus board chain. Keep entries in order. */ 825 if (nubus_device_register(board))
827 for (boardp = &nubus_boards; *boardp != NULL; 826 put_device(&board->dev);
828 boardp = &((*boardp)->next))
829 /* spin */;
830 *boardp = board;
831 board->next = NULL;
832
833 return board;
834} 827}
835 828
836static void __init nubus_probe_slot(int slot) 829static void __init nubus_probe_slot(int slot)
@@ -876,10 +869,15 @@ static void __init nubus_scan_bus(void)
876 869
877static int __init nubus_init(void) 870static int __init nubus_init(void)
878{ 871{
872 int err;
873
879 if (!MACH_IS_MAC) 874 if (!MACH_IS_MAC)
880 return 0; 875 return 0;
881 876
882 nubus_proc_init(); 877 nubus_proc_init();
878 err = nubus_bus_register();
879 if (err)
880 return err;
883 nubus_scan_bus(); 881 nubus_scan_bus();
884 return 0; 882 return 0;
885} 883}
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index 60c0f40b4d5e..c2e5a7e6bd3e 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -198,68 +198,17 @@ void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
198/* 198/*
199 * /proc/nubus stuff 199 * /proc/nubus stuff
200 */ 200 */
201static int nubus_proc_show(struct seq_file *m, void *v)
202{
203 const struct nubus_board *board = v;
204
205 /* Display header on line 1 */
206 if (v == SEQ_START_TOKEN)
207 seq_puts(m, "Nubus devices found:\n");
208 else
209 seq_printf(m, "Slot %X: %s\n", board->slot, board->name);
210 return 0;
211}
212
213static void *nubus_proc_start(struct seq_file *m, loff_t *_pos)
214{
215 struct nubus_board *board;
216 unsigned pos;
217
218 if (*_pos > LONG_MAX)
219 return NULL;
220 pos = *_pos;
221 if (pos == 0)
222 return SEQ_START_TOKEN;
223 for (board = nubus_boards; board; board = board->next)
224 if (--pos == 0)
225 break;
226 return board;
227}
228
229static void *nubus_proc_next(struct seq_file *p, void *v, loff_t *_pos)
230{
231 /* Walk the list of NuBus boards */
232 struct nubus_board *board = v;
233
234 ++*_pos;
235 if (v == SEQ_START_TOKEN)
236 board = nubus_boards;
237 else if (board)
238 board = board->next;
239 return board;
240}
241
242static void nubus_proc_stop(struct seq_file *p, void *v)
243{
244}
245
246static const struct seq_operations nubus_proc_seqops = {
247 .start = nubus_proc_start,
248 .next = nubus_proc_next,
249 .stop = nubus_proc_stop,
250 .show = nubus_proc_show,
251};
252 201
253static int nubus_proc_open(struct inode *inode, struct file *file) 202static int nubus_proc_open(struct inode *inode, struct file *file)
254{ 203{
255 return seq_open(file, &nubus_proc_seqops); 204 return single_open(file, nubus_proc_show, NULL);
256} 205}
257 206
258static const struct file_operations nubus_proc_fops = { 207static const struct file_operations nubus_proc_fops = {
259 .open = nubus_proc_open, 208 .open = nubus_proc_open,
260 .read = seq_read, 209 .read = seq_read,
261 .llseek = seq_lseek, 210 .llseek = seq_lseek,
262 .release = seq_release, 211 .release = single_release,
263}; 212};
264 213
265void __init nubus_proc_init(void) 214void __init nubus_proc_init(void)
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index 2cbc7a199bca..6e8200215321 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -10,6 +10,7 @@
10#ifndef LINUX_NUBUS_H 10#ifndef LINUX_NUBUS_H
11#define LINUX_NUBUS_H 11#define LINUX_NUBUS_H
12 12
13#include <linux/device.h>
13#include <asm/nubus.h> 14#include <asm/nubus.h>
14#include <uapi/linux/nubus.h> 15#include <uapi/linux/nubus.h>
15 16
@@ -32,7 +33,7 @@ struct nubus_dirent {
32}; 33};
33 34
34struct nubus_board { 35struct nubus_board {
35 struct nubus_board *next; 36 struct device dev;
36 37
37 /* Only 9-E actually exist, though 0-8 are also theoretically 38 /* Only 9-E actually exist, though 0-8 are also theoretically
38 possible, and 0 is a special case which represents the 39 possible, and 0 is a special case which represents the
@@ -81,8 +82,14 @@ struct nubus_rsrc {
81 82
82/* This is all NuBus functional resources (used to find devices later on) */ 83/* This is all NuBus functional resources (used to find devices later on) */
83extern struct list_head nubus_func_rsrcs; 84extern struct list_head nubus_func_rsrcs;
84/* This is all NuBus cards */ 85
85extern struct nubus_board *nubus_boards; 86struct nubus_driver {
87 struct device_driver driver;
88 int (*probe)(struct nubus_board *board);
89 int (*remove)(struct nubus_board *board);
90};
91
92extern struct bus_type nubus_bus_type;
86 93
87/* Generic NuBus interface functions, modelled after the PCI interface */ 94/* Generic NuBus interface functions, modelled after the PCI interface */
88#ifdef CONFIG_PROC_FS 95#ifdef CONFIG_PROC_FS
@@ -119,6 +126,9 @@ struct nubus_rsrc *nubus_next_rsrc_or_null(struct nubus_rsrc *from);
119#define for_each_func_rsrc(f) \ 126#define for_each_func_rsrc(f) \
120 for (f = nubus_first_rsrc_or_null(); f; f = nubus_next_rsrc_or_null(f)) 127 for (f = nubus_first_rsrc_or_null(); f; f = nubus_next_rsrc_or_null(f))
121 128
129#define for_each_board_func_rsrc(b, f) \
130 for_each_func_rsrc(f) if (f->board != b) {} else
131
122/* These are somewhat more NuBus-specific. They all return 0 for 132/* These are somewhat more NuBus-specific. They all return 0 for
123 success and -1 for failure, as you'd expect. */ 133 success and -1 for failure, as you'd expect. */
124 134
@@ -152,6 +162,23 @@ void nubus_seq_write_rsrc_mem(struct seq_file *m,
152 unsigned int len); 162 unsigned int len);
153unsigned char *nubus_dirptr(const struct nubus_dirent *nd); 163unsigned char *nubus_dirptr(const struct nubus_dirent *nd);
154 164
165/* Declarations relating to driver model objects */
166int nubus_bus_register(void);
167int nubus_device_register(struct nubus_board *board);
168int nubus_driver_register(struct nubus_driver *ndrv);
169void nubus_driver_unregister(struct nubus_driver *ndrv);
170int nubus_proc_show(struct seq_file *m, void *data);
171
172static inline void nubus_set_drvdata(struct nubus_board *board, void *data)
173{
174 dev_set_drvdata(&board->dev, data);
175}
176
177static inline void *nubus_get_drvdata(struct nubus_board *board)
178{
179 return dev_get_drvdata(&board->dev);
180}
181
155/* Returns a pointer to the "standard" slot space. */ 182/* Returns a pointer to the "standard" slot space. */
156static inline void *nubus_slot_addr(int slot) 183static inline void *nubus_slot_addr(int slot)
157{ 184{