diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-25 06:44:44 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-25 06:44:44 -0400 |
commit | 76a9f26c9e40e9c0ed5dc8f0cedd74e733f0088d (patch) | |
tree | 8e2db4ba9263e92d264ef469c7dac28078f63874 /drivers | |
parent | 9bf2aa129a107a0e9e2a5318d35aca731ae7e666 (diff) | |
parent | dfd8317d3340f03bc06eba6b58f0ec0861da4a13 (diff) | |
download | linux-76a9f26c9e40e9c0ed5dc8f0cedd74e733f0088d.tar.gz linux-76a9f26c9e40e9c0ed5dc8f0cedd74e733f0088d.tar.bz2 linux-76a9f26c9e40e9c0ed5dc8f0cedd74e733f0088d.zip |
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Diffstat (limited to 'drivers')
48 files changed, 1989 insertions, 1733 deletions
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index ceeeba2c56c7..91f230939c1e 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,6 @@ obj-y := shutdown.o obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o +obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 317edbf0feca..520679ce53a8 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -9,6 +9,7 @@ */ #include <linux/device.h> +#include <linux/resume-trace.h> #include "../base.h" #include "power.h" @@ -23,6 +24,8 @@ int resume_device(struct device * dev) { int error = 0; + TRACE_DEVICE(dev); + TRACE_RESUME(0); down(&dev->sem); if (dev->power.pm_parent && dev->power.pm_parent->power.power_state.event) { @@ -36,6 +39,7 @@ int resume_device(struct device * dev) error = dev->bus->resume(dev); } up(&dev->sem); + TRACE_RESUME(error); return error; } diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c new file mode 100644 index 000000000000..a9ab30fefffc --- /dev/null +++ b/drivers/base/power/trace.c @@ -0,0 +1,228 @@ +/* + * drivers/base/power/trace.c + * + * Copyright (C) 2006 Linus Torvalds + * + * Trace facility for suspend/resume problems, when none of the + * devices may be working. + */ + +#include <linux/resume-trace.h> +#include <linux/rtc.h> + +#include <asm/rtc.h> + +#include "power.h" + +/* + * Horrid, horrid, horrid. + * + * It turns out that the _only_ piece of hardware that actually + * keeps its value across a hard boot (and, more importantly, the + * POST init sequence) is literally the realtime clock. + * + * Never mind that an RTC chip has 114 bytes (and often a whole + * other bank of an additional 128 bytes) of nice SRAM that is + * _designed_ to keep data - the POST will clear it. So we literally + * can just use the few bytes of actual time data, which means that + * we're really limited. + * + * It means, for example, that we can't use the seconds at all + * (since the time between the hang and the boot might be more + * than a minute), and we'd better not depend on the low bits of + * the minutes either. + * + * There are the wday fields etc, but I wouldn't guarantee those + * are dependable either. And if the date isn't valid, either the + * hw or POST will do strange things. + * + * So we're left with: + * - year: 0-99 + * - month: 0-11 + * - day-of-month: 1-28 + * - hour: 0-23 + * - min: (0-30)*2 + * + * Giving us a total range of 0-16128000 (0xf61800), ie less + * than 24 bits of actual data we can save across reboots. + * + * And if your box can't boot in less than three minutes, + * you're screwed. + * + * Now, almost 24 bits of data is pitifully small, so we need + * to be pretty dense if we want to use it for anything nice. + * What we do is that instead of saving off nice readable info, + * we save off _hashes_ of information that we can hopefully + * regenerate after the reboot. + * + * In particular, this means that we might be unlucky, and hit + * a case where we have a hash collision, and we end up not + * being able to tell for certain exactly which case happened. + * But that's hopefully unlikely. + * + * What we do is to take the bits we can fit, and split them + * into three parts (16*997*1009 = 16095568), and use the values + * for: + * - 0-15: user-settable + * - 0-996: file + line number + * - 0-1008: device + */ +#define USERHASH (16) +#define FILEHASH (997) +#define DEVHASH (1009) + +#define DEVSEED (7919) + +static unsigned int dev_hash_value; + +static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) +{ + unsigned int n = user + USERHASH*(file + FILEHASH*device); + + // June 7th, 2006 + static struct rtc_time time = { + .tm_sec = 0, + .tm_min = 0, + .tm_hour = 0, + .tm_mday = 7, + .tm_mon = 5, // June - counting from zero + .tm_year = 106, + .tm_wday = 3, + .tm_yday = 160, + .tm_isdst = 1 + }; + + time.tm_year = (n % 100); + n /= 100; + time.tm_mon = (n % 12); + n /= 12; + time.tm_mday = (n % 28) + 1; + n /= 28; + time.tm_hour = (n % 24); + n /= 24; + time.tm_min = (n % 20) * 3; + n /= 20; + set_rtc_time(&time); + return n ? -1 : 0; +} + +static unsigned int read_magic_time(void) +{ + struct rtc_time time; + unsigned int val; + + get_rtc_time(&time); + printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", + time.tm_hour, time.tm_min, time.tm_sec, + time.tm_mon, time.tm_mday, time.tm_year); + val = time.tm_year; /* 100 years */ + if (val > 100) + val -= 100; + val += time.tm_mon * 100; /* 12 months */ + val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */ + val += time.tm_hour * 100 * 12 * 28; /* 24 hours */ + val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */ + return val; +} + +/* + * This is just the sdbm hash function with a user-supplied + * seed and final size parameter. + */ +static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod) +{ + unsigned char c; + while ((c = *data++) != 0) { + seed = (seed << 16) + (seed << 6) - seed + c; + } + return seed % mod; +} + +void set_trace_device(struct device *dev) +{ + dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH); +} + +/* + * We could just take the "tracedata" index into the .tracedata + * section instead. Generating a hash of the data gives us a + * chance to work across kernel versions, and perhaps more + * importantly it also gives us valid/invalid check (ie we will + * likely not give totally bogus reports - if the hash matches, + * it's not any guarantee, but it's a high _likelihood_ that + * the match is valid). + */ +void generate_resume_trace(void *tracedata, unsigned int user) +{ + unsigned short lineno = *(unsigned short *)tracedata; + const char *file = *(const char **)(tracedata + 2); + unsigned int user_hash_value, file_hash_value; + + user_hash_value = user % USERHASH; + file_hash_value = hash_string(lineno, file, FILEHASH); + set_magic_time(user_hash_value, file_hash_value, dev_hash_value); +} + +extern char __tracedata_start, __tracedata_end; +static int show_file_hash(unsigned int value) +{ + int match; + char *tracedata; + + match = 0; + for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) { + unsigned short lineno = *(unsigned short *)tracedata; + const char *file = *(const char **)(tracedata + 2); + unsigned int hash = hash_string(lineno, file, FILEHASH); + if (hash != value) + continue; + printk(" hash matches %s:%u\n", file, lineno); + match++; + } + return match; +} + +static int show_dev_hash(unsigned int value) +{ + int match = 0; + struct list_head * entry = dpm_active.prev; + + while (entry != &dpm_active) { + struct device * dev = to_device(entry); + unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH); + if (hash == value) { + printk(" hash matches device %s\n", dev->bus_id); + match++; + } + entry = entry->prev; + } + return match; +} + +static unsigned int hash_value_early_read; + +static int early_resume_init(void) +{ + hash_value_early_read = read_magic_time(); + return 0; +} + +static int late_resume_init(void) +{ + unsigned int val = hash_value_early_read; + unsigned int user, file, dev; + + user = val % USERHASH; + val = val / USERHASH; + file = val % FILEHASH; + val = val / FILEHASH; + dev = val /* % DEVHASH */; + + printk(" Magic number: %d:%d:%d\n", user, file, dev); + show_file_hash(file); + show_dev_hash(dev); + return 0; +} + +core_initcall(early_resume_init); +late_initcall(late_resume_init); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 9f4b8ce4c05e..a94233bdbc0e 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -758,7 +758,9 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH}, [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY } + [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, + [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, + [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 4cb3da578330..5aa3e0e3bb45 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -124,6 +124,8 @@ typedef struct _drm_i915_sarea { #define DRM_I915_INIT_HEAP 0x0a #define DRM_I915_CMDBUFFER 0x0b #define DRM_I915_DESTROY_HEAP 0x0c +#define DRM_I915_SET_VBLANK_PIPE 0x0d +#define DRM_I915_GET_VBLANK_PIPE 0x0e #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -138,6 +140,8 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t) #define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t) #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) +#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -224,4 +228,13 @@ typedef struct drm_i915_mem_destroy_heap { int region; } drm_i915_mem_destroy_heap_t; +/* Allow X server to configure which pipes to monitor for vblank signals + */ +#define DRM_I915_VBLANK_PIPE_A 1 +#define DRM_I915_VBLANK_PIPE_B 2 + +typedef struct drm_i915_vblank_pipe { + int pipe; +} drm_i915_vblank_pipe_t; + #endif /* _I915_DRM_H_ */ diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 7a65666899e4..2d565031c002 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -45,9 +45,10 @@ * 1.2: Add Power Management * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy + * 1.5: Add vblank pipe configuration */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 4 +#define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 typedef struct _drm_i915_ring_buffer { @@ -96,6 +97,7 @@ typedef struct drm_i915_private { int allow_batchbuffer; struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; + int vblank_pipe; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -119,6 +121,8 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t * dev); extern void i915_driver_irq_postinstall(drm_device_t * dev); extern void i915_driver_irq_uninstall(drm_device_t * dev); +extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); +extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index a752afd86ab8..cd96cfa430db 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -44,7 +44,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u16 temp; temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG); + + temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); @@ -58,7 +59,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (temp & USER_INT_FLAG) DRM_WAKEUP(&dev_priv->irq_queue); - if (temp & VSYNC_PIPEA_FLAG) { + if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); @@ -182,6 +183,68 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } +static int i915_enable_interrupt (drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u16 flag; + + flag = 0; + if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) + flag |= VSYNC_PIPEA_FLAG; + if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) + flag |= VSYNC_PIPEB_FLAG; + if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, dev_priv->vblank_pipe); + return DRM_ERR(EINVAL); + } + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); + return 0; +} + +/* Set the vblank monitor pipe + */ +int i915_vblank_pipe_set(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t pipe; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, + sizeof(pipe)); + + dev_priv->vblank_pipe = pipe.pipe; + return i915_enable_interrupt (dev); +} + +int i915_vblank_pipe_get(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t pipe; + u16 flag; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + flag = I915_READ(I915REG_INT_ENABLE_R); + pipe.pipe = 0; + if (flag & VSYNC_PIPEA_FLAG) + pipe.pipe |= DRM_I915_VBLANK_PIPE_A; + if (flag & VSYNC_PIPEB_FLAG) + pipe.pipe |= DRM_I915_VBLANK_PIPE_B; + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe, + sizeof(pipe)); + return 0; +} + /* drm_dma.h hooks */ void i915_driver_irq_preinstall(drm_device_t * dev) @@ -197,7 +260,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | VSYNC_PIPEA_FLAG); + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 7f949c9c9691..5ad43ba7b5aa 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -39,7 +39,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev); /* CP microcode (from ATI) */ -static u32 R200_cp_microcode[][2] = { +static const u32 R200_cp_microcode[][2] = { {0x21007000, 0000000000}, {0x20007000, 0000000000}, {0x000000ab, 0x00000004}, @@ -298,7 +298,7 @@ static u32 R200_cp_microcode[][2] = { {0000000000, 0000000000}, }; -static u32 radeon_cp_microcode[][2] = { +static const u32 radeon_cp_microcode[][2] = { {0x21007000, 0000000000}, {0x20007000, 0000000000}, {0x000000b4, 0x00000004}, @@ -557,7 +557,7 @@ static u32 radeon_cp_microcode[][2] = { {0000000000, 0000000000}, }; -static u32 R300_cp_microcode[][2] = { +static const u32 R300_cp_microcode[][2] = { {0x4200e000, 0000000000}, {0x4000e000, 0000000000}, {0x000000af, 0x00000008}, diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index c8e279e89c2e..8d6350dd5360 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -161,7 +161,8 @@ #define R200_EMIT_PP_TXCTLALL_3 91 #define R200_EMIT_PP_TXCTLALL_4 92 #define R200_EMIT_PP_TXCTLALL_5 93 -#define RADEON_MAX_STATE_PACKETS 94 +#define R200_EMIT_VAP_PVS_CNTL 94 +#define RADEON_MAX_STATE_PACKETS 95 /* Commands understood by cmd_buffer ioctl. More can be added but * obviously these can't be removed or changed: @@ -176,6 +177,7 @@ #define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note: * doesn't make the cpu wait, just * the graphics hardware */ +#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */ typedef union { int i; @@ -192,6 +194,9 @@ typedef union { unsigned char cmd_type, offset, stride, count; } vectors; struct { + unsigned char cmd_type, addr_lo, addr_hi, count; + } veclinear; + struct { unsigned char cmd_type, buf_idx, pad0, pad1; } dma; struct { diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 78345cee8f8e..e5a256f5429c 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -38,7 +38,7 @@ #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20060225" +#define DRIVER_DATE "20060524" /* Interface history: * @@ -93,9 +93,11 @@ * 1.22- Add support for texture cache flushes (R300_TX_CNTL) * 1.23- Add new radeon memory map work from benh * 1.24- Add general-purpose packet for manipulating scratch registers (r300) + * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, + * new packet type) */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 24 +#define DRIVER_MINOR 25 #define DRIVER_PATCHLEVEL 0 /* @@ -884,6 +886,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 #define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_SE_TCL_STATE_FLUSH 0x2284 + #define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001 #define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000 #define SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT 0x00000012 @@ -905,6 +909,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define R200_PP_AFS_0 0x2f80 #define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */ +#define R200_VAP_PVS_CNTL_1 0x22D0 + /* Constants */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index c5b8f774a599..5bb2234a9094 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -249,6 +249,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case R200_EMIT_PP_TXCTLALL_3: case R200_EMIT_PP_TXCTLALL_4: case R200_EMIT_PP_TXCTLALL_5: + case R200_EMIT_VAP_PVS_CNTL: /* These packets don't contain memory offsets */ break; @@ -626,6 +627,7 @@ static struct { {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"}, {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"}, {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"}, + {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"}, }; /* ================================================================ @@ -2595,7 +2597,8 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv, int stride = header.vectors.stride; RING_LOCALS; - BEGIN_RING(3 + sz); + BEGIN_RING(5 + sz); + OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); @@ -2607,6 +2610,32 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv, return 0; } +static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, + drm_radeon_cmd_header_t header, + drm_radeon_kcmd_buffer_t *cmdbuf) +{ + int sz = header.veclinear.count * 4; + int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8); + RING_LOCALS; + + if (!sz) + return 0; + if (sz * 4 > cmdbuf->bufsz) + return DRM_ERR(EINVAL); + + BEGIN_RING(5 + sz); + OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); + OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); + OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); + OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); + OUT_RING_TABLE(cmdbuf->buf, sz); + ADVANCE_RING(); + + cmdbuf->buf += sz * sizeof(int); + cmdbuf->bufsz -= sz * sizeof(int); + return 0; +} + static int radeon_emit_packet3(drm_device_t * dev, drm_file_t * filp_priv, drm_radeon_kcmd_buffer_t *cmdbuf) @@ -2865,6 +2894,14 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) goto err; } break; + case RADEON_CMD_VECLINEAR: + DRM_DEBUG("RADEON_CMD_VECLINEAR\n"); + if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) { + DRM_ERROR("radeon_emit_veclinear failed\n"); + goto err; + } + break; + default: DRM_ERROR("bad cmd_type %d at %p\n", header.header.cmd_type, diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index f6686fcce809..0897b0c8d528 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -928,7 +928,7 @@ static int __init rtc_init(void) #ifdef __sparc__ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_name, "rtc") == 0) { + if(strcmp(edev->prom_node->name, "rtc") == 0) { rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; goto found; @@ -938,7 +938,7 @@ static int __init rtc_init(void) #ifdef __sparc_v9__ for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_name, "rtc") == 0) { + if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { rtc_port = isa_dev->resource.start; rtc_irq = isa_dev->irq; goto found; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 4bad588d0e5d..a6dfc7455733 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -26,7 +26,7 @@ config INPUT_PCSPKR config INPUT_SPARCSPKR tristate "SPARC Speaker support" - depends on PCI && SPARC + depends on PCI && SPARC64 help Say Y here if you want the standard Speaker on Sparc PCI systems to be used for bells and whistles. diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index f0fd2c4740f1..42c11fbf3c79 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -2,7 +2,7 @@ * Driver for PC-speaker like devices found on various Sparc systems. * * Copyright (c) 2002 Vojtech Pavlik - * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net) */ #include <linux/config.h> #include <linux/kernel.h> @@ -13,21 +13,23 @@ #include <asm/io.h> #include <asm/ebus.h> -#ifdef CONFIG_SPARC64 #include <asm/isa.h> -#endif -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); -const char *beep_name; -static unsigned long beep_iobase; -static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); -static DEFINE_SPINLOCK(beep_lock); +struct sparcspkr_state { + const char *name; + unsigned long iobase; + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + spinlock_t lock; + struct input_dev *input_dev; +}; static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -43,24 +45,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in if (value > 20 && value < 32767) count = 1193182 / value; - spin_lock_irqsave(&beep_lock, flags); + spin_lock_irqsave(&state->lock, flags); /* EBUS speaker only has on/off state, the frequency does not * appear to be programmable. */ - if (beep_iobase & 0x2UL) - outb(!!count, beep_iobase); + if (state->iobase & 0x2UL) + outb(!!count, state->iobase); else - outl(!!count, beep_iobase); + outl(!!count, state->iobase); - spin_unlock_irqrestore(&beep_lock, flags); + spin_unlock_irqrestore(&state->lock, flags); return 0; } -#ifdef CONFIG_SPARC64 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -76,29 +78,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int if (value > 20 && value < 32767) count = 1193182 / value; - spin_lock_irqsave(&beep_lock, flags); + spin_lock_irqsave(&state->lock, flags); if (count) { /* enable counter 2 */ - outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); + outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61); /* set command for counter 2, 2 byte write */ - outb(0xB6, beep_iobase + 0x43); + outb(0xB6, state->iobase + 0x43); /* select desired HZ */ - outb(count & 0xff, beep_iobase + 0x42); - outb((count >> 8) & 0xff, beep_iobase + 0x42); + outb(count & 0xff, state->iobase + 0x42); + outb((count >> 8) & 0xff, state->iobase + 0x42); } else { /* disable counter 2 */ - outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); + outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61); } - spin_unlock_irqrestore(&beep_lock, flags); + spin_unlock_irqrestore(&state->lock, flags); return 0; } -#endif -static int __devinit sparcspkr_probe(struct platform_device *dev) +static int __devinit sparcspkr_probe(struct device *dev) { + struct sparcspkr_state *state = dev_get_drvdata(dev); struct input_dev *input_dev; int error; @@ -106,18 +108,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev) if (!input_dev) return -ENOMEM; - input_dev->name = beep_name; + input_dev->name = state->name; input_dev->phys = "sparc/input0"; input_dev->id.bustype = BUS_ISA; input_dev->id.vendor = 0x001f; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->cdev.dev = &dev->dev; + input_dev->cdev.dev = dev; input_dev->evbit[0] = BIT(EV_SND); input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - input_dev->event = beep_event; + input_dev->event = state->event; error = input_register_device(input_dev); if (error) { @@ -125,111 +127,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev) return error; } - platform_set_drvdata(dev, input_dev); + state->input_dev = input_dev; return 0; } -static int __devexit sparcspkr_remove(struct platform_device *dev) +static int __devexit sparcspkr_remove(struct of_device *dev) { - struct input_dev *input_dev = platform_get_drvdata(dev); + struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); + struct input_dev *input_dev = state->input_dev; - input_unregister_device(input_dev); - platform_set_drvdata(dev, NULL); /* turn off the speaker */ - beep_event(NULL, EV_SND, SND_BELL, 0); + state->event(input_dev, EV_SND, SND_BELL, 0); + + input_unregister_device(input_dev); + + dev_set_drvdata(&dev->dev, NULL); + kfree(state); return 0; } -static void sparcspkr_shutdown(struct platform_device *dev) +static int sparcspkr_shutdown(struct of_device *dev) { + struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); + struct input_dev *input_dev = state->input_dev; + /* turn off the speaker */ - beep_event(NULL, EV_SND, SND_BELL, 0); + state->event(input_dev, EV_SND, SND_BELL, 0); + + return 0; +} + +static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct sparcspkr_state *state; + int err; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->name = "Sparc EBUS Speaker"; + state->iobase = edev->resource[0].start; + state->event = ebus_spkr_event; + spin_lock_init(&state->lock); + + dev_set_drvdata(&dev->dev, state); + + err = sparcspkr_probe(&dev->dev); + if (err) { + dev_set_drvdata(&dev->dev, NULL); + kfree(state); + } + + return 0; } -static struct platform_driver sparcspkr_platform_driver = { - .driver = { - .name = "sparcspkr", - .owner = THIS_MODULE, +static struct of_device_id ebus_beep_match[] = { + { + .name = "beep", }, - .probe = sparcspkr_probe, - .remove = __devexit_p(sparcspkr_remove), - .shutdown = sparcspkr_shutdown, + {}, }; -static struct platform_device *sparcspkr_platform_device; +static struct of_platform_driver ebus_beep_driver = { + .name = "beep", + .match_table = ebus_beep_match, + .probe = ebus_beep_probe, + .remove = sparcspkr_remove, + .shutdown = sparcspkr_shutdown, +}; -static int __init sparcspkr_drv_init(void) +static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match) { - int error; + struct sparc_isa_device *idev = to_isa_device(&dev->dev); + struct sparcspkr_state *state; + int err; - error = platform_driver_register(&sparcspkr_platform_driver); - if (error) - return error; + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; - sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1); - if (!sparcspkr_platform_device) { - error = -ENOMEM; - goto err_unregister_driver; - } + state->name = "Sparc ISA Speaker"; + state->iobase = idev->resource.start; + state->event = isa_spkr_event; + spin_lock_init(&state->lock); + + dev_set_drvdata(&dev->dev, state); - error = platform_device_add(sparcspkr_platform_device); - if (error) - goto err_free_device; + err = sparcspkr_probe(&dev->dev); + if (err) { + dev_set_drvdata(&dev->dev, NULL); + kfree(state); + } return 0; +} - err_free_device: - platform_device_put(sparcspkr_platform_device); - err_unregister_driver: - platform_driver_unregister(&sparcspkr_platform_driver); +static struct of_device_id isa_beep_match[] = { + { + .name = "dma", + }, + {}, +}; - return error; -} +static struct of_platform_driver isa_beep_driver = { + .name = "beep", + .match_table = isa_beep_match, + .probe = isa_beep_probe, + .remove = sparcspkr_remove, + .shutdown = sparcspkr_shutdown, +}; static int __init sparcspkr_init(void) { - struct linux_ebus *ebus; - struct linux_ebus_device *edev; -#ifdef CONFIG_SPARC64 - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "beep")) { - beep_name = "Sparc EBUS Speaker"; - beep_event = ebus_spkr_event; - beep_iobase = edev->resource[0].start; - return sparcspkr_drv_init(); - } - } - } -#ifdef CONFIG_SPARC64 - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - /* A hack, the beep device's base lives in - * the DMA isa node. - */ - if (!strcmp(isa_dev->prom_name, "dma")) { - beep_name = "Sparc ISA Speaker"; - beep_event = isa_spkr_event, - beep_iobase = isa_dev->resource.start; - return sparcspkr_drv_init(); - } - } + int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type); + + if (!err) { + err = of_register_driver(&isa_beep_driver, &isa_bus_type); + if (err) + of_unregister_driver(&ebus_beep_driver); } -#endif - return -ENODEV; + return err; } static void __exit sparcspkr_exit(void) { - platform_device_unregister(sparcspkr_platform_device); - platform_driver_unregister(&sparcspkr_platform_driver); + of_unregister_driver(&ebus_beep_driver); + of_unregister_driver(&isa_beep_driver); } module_init(sparcspkr_init); diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index ed9446f6d7e3..6d66351805a2 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -74,7 +74,7 @@ static int __init i8042_platform_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "8042")) + if (!strcmp(edev->prom_node->name, "8042")) goto edev_found; } } @@ -82,14 +82,14 @@ static int __init i8042_platform_init(void) edev_found: for_each_edevchild(edev, child) { - if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || - !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { + if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) { i8042_kbd_irq = child->irqs[0]; kbd_iobase = ioremap(child->resource[0].start, 8); } - if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || - !strcmp(child->prom_name, OBP_PS2MS_NAME2)) + if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2MS_NAME2)) i8042_aux_irq = child->irqs[0]; } if (i8042_kbd_irq == -1 || diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 6c86dca62e2a..d9f616fea3d9 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1,10 +1,10 @@ -/* myri_sbus.h: MyriCOM MyriNET SBUS card driver. +/* myri_sbus.c: MyriCOM MyriNET SBUS card driver. * - * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net) */ static char version[] = - "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n"; + "myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n"; #include <linux/module.h> #include <linux/config.h> @@ -81,10 +81,6 @@ static char version[] = #define DHDR(x) #endif -#ifdef MODULE -static struct myri_eth *root_myri_dev; -#endif - static void myri_reset_off(void __iomem *lp, void __iomem *cregs) { /* Clear IRQ mask. */ @@ -896,8 +892,9 @@ static void dump_eeprom(struct myri_eth *mp) } #endif -static int __init myri_ether_init(struct sbus_dev *sdev, int num) +static int __init myri_ether_init(struct sbus_dev *sdev) { + static int num; static unsigned version_printed; struct net_device *dev; struct myri_eth *mp; @@ -913,6 +910,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num) if (version_printed++ == 0) printk(version); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + mp = (struct myri_eth *) dev->priv; spin_lock_init(&mp->irq_lock); mp->myri_sdev = sdev; @@ -1092,10 +1092,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num) goto err_free_irq; } -#ifdef MODULE - mp->next_module = root_myri_dev; - root_myri_dev = mp; -#endif + dev_set_drvdata(&sdev->ofdev.dev, mp); + + num++; printk("%s: MyriCOM MyriNET Ethernet ", dev->name); @@ -1114,61 +1113,68 @@ err: return -ENODEV; } -static int __init myri_sbus_match(struct sbus_dev *sdev) -{ - char *name = sdev->prom_name; - if (!strcmp(name, "MYRICOM,mlanai") || - !strcmp(name, "myri")) - return 1; +static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); - return 0; + return myri_ether_init(sdev); } -static int __init myri_sbus_probe(void) +static int __devexit myri_sbus_remove(struct of_device *dev) { - struct sbus_bus *bus; - struct sbus_dev *sdev = NULL; - static int called; - int cards = 0, v; + struct myri_eth *mp = dev_get_drvdata(&dev->dev); + struct net_device *net_dev = mp->dev; -#ifdef MODULE - root_myri_dev = NULL; -#endif + unregister_netdevice(net_dev); - if (called) - return -ENODEV; - called++; - - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { - if (myri_sbus_match(sdev)) { - cards++; - DET(("Found myricom myrinet as %s\n", sdev->prom_name)); - if ((v = myri_ether_init(sdev, (cards - 1)))) - return v; - } - } + free_irq(net_dev->irq, net_dev); + + if (mp->eeprom.cpuvers < CPUVERS_4_0) { + sbus_iounmap(mp->regs, mp->reg_size); + } else { + sbus_iounmap(mp->cregs, PAGE_SIZE); + sbus_iounmap(mp->lregs, (256 * 1024)); + sbus_iounmap(mp->lanai, (512 * 1024)); } - if (!cards) - return -ENODEV; + + free_netdev(net_dev); + + dev_set_drvdata(&dev->dev, NULL); + return 0; } -static void __exit myri_sbus_cleanup(void) +static struct of_device_id myri_sbus_match[] = { + { + .name = "MYRICOM,mlanai", + }, + { + .name = "myri", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, myri_sbus_match); + +static struct of_platform_driver myri_sbus_driver = { + .name = "myri", + .match_table = myri_sbus_match, + .probe = myri_sbus_probe, + .remove = __devexit_p(myri_sbus_remove), +}; + +static int __init myri_sbus_init(void) +{ + return of_register_driver(&myri_sbus_driver, &sbus_bus_type); +} + +static void __exit myri_sbus_exit(void) { -#ifdef MODULE - while (root_myri_dev) { - struct myri_eth *next = root_myri_dev->next_module; - - unregister_netdev(root_myri_dev->dev); - /* this will also free the co-allocated 'root_myri_dev' */ - free_netdev(root_myri_dev->dev); - root_myri_dev = next; - } -#endif /* MODULE */ + of_unregister_driver(&myri_sbus_driver); } -module_init(myri_sbus_probe); -module_exit(myri_sbus_cleanup); +module_init(myri_sbus_init); +module_exit(myri_sbus_exit); + MODULE_LICENSE("GPL"); diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 47722f708a41..2f69ef7cdccb 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -290,7 +290,6 @@ struct myri_eth { unsigned int reg_size; /* Size of register space. */ unsigned int shmem_base; /* Offset to shared ram. */ struct sbus_dev *myri_sdev; /* Our SBUS device struct. */ - struct myri_eth *next_module; /* Next in adapter chain. */ }; /* We use this to acquire receive skb's that we can DMA directly into. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index cfaf47c63c58..7127f0f36f0e 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -72,8 +72,6 @@ MODULE_LICENSE("GPL"); #define DIRQ(x) #endif -static struct bigmac *root_bigmac_dev; - #define DEFAULT_JAMSIZE 4 /* Toe jam */ #define QEC_RESET_TRIES 200 @@ -491,7 +489,7 @@ static void bigmac_tcvr_init(struct bigmac *bp) } } -static int bigmac_init(struct bigmac *, int); +static int bigmac_init_hw(struct bigmac *, int); static int try_next_permutation(struct bigmac *bp, void __iomem *tregs) { @@ -551,7 +549,7 @@ static void bigmac_timer(unsigned long data) if (ret == -1) { printk(KERN_ERR "%s: Link down, cable problem?\n", bp->dev->name); - ret = bigmac_init(bp, 0); + ret = bigmac_init_hw(bp, 0); if (ret) { printk(KERN_ERR "%s: Error, cannot re-init the " "BigMAC.\n", bp->dev->name); @@ -621,7 +619,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp) add_timer(&bp->bigmac_timer); } -static int bigmac_init(struct bigmac *bp, int from_irq) +static int bigmac_init_hw(struct bigmac *bp, int from_irq) { void __iomem *gregs = bp->gregs; void __iomem *cregs = bp->creg; @@ -752,7 +750,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_st } printk(" RESET\n"); - bigmac_init(bp, 1); + bigmac_init_hw(bp, 1); } /* BigMAC transmit complete service routines. */ @@ -926,7 +924,7 @@ static int bigmac_open(struct net_device *dev) return ret; } init_timer(&bp->bigmac_timer); - ret = bigmac_init(bp, 0); + ret = bigmac_init_hw(bp, 0); if (ret) free_irq(dev->irq, bp); return ret; @@ -950,7 +948,7 @@ static void bigmac_tx_timeout(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; - bigmac_init(bp, 0); + bigmac_init_hw(bp, 0); netif_wake_queue(dev); } @@ -1104,6 +1102,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) bp->qec_sdev = qec_sdev; bp->bigmac_sdev = qec_sdev->child; + SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev); + spin_lock_init(&bp->lock); /* Verify the registers we expect, are actually there. */ @@ -1226,11 +1226,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) goto fail_and_cleanup; } - /* Put us into the list of instances attached for later driver - * exit. - */ - bp->next_module = root_bigmac_dev; - root_bigmac_dev = bp; + dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name); for (i = 0; i < 6; i++) @@ -1266,69 +1262,68 @@ fail_and_cleanup: /* QEC can be the parent of either QuadEthernet or * a BigMAC. We want the latter. */ -static int __init bigmac_match(struct sbus_dev *sdev) +static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_dev *child = sdev->child; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; - if (strcmp(sdev->prom_name, "qec") != 0) - return 0; + if (!strcmp(dp->name, "be")) + sdev = sdev->parent; - if (child == NULL) - return 0; - - if (strcmp(child->prom_name, "be") != 0) - return 0; - - return 1; + return bigmac_ether_init(sdev); } -static int __init bigmac_probe(void) +static int __devexit bigmac_sbus_remove(struct of_device *dev) { - struct sbus_bus *sbus; - struct sbus_dev *sdev = NULL; - static int called; - int cards = 0, v; - - root_bigmac_dev = NULL; - - if (called) - return -ENODEV; - called++; - - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - if (bigmac_match(sdev)) { - cards++; - if ((v = bigmac_ether_init(sdev))) - return v; - } - } - } - if (!cards) - return -ENODEV; + struct bigmac *bp = dev_get_drvdata(&dev->dev); + struct net_device *net_dev = bp->dev; + + unregister_netdevice(net_dev); + + sbus_iounmap(bp->gregs, GLOB_REG_SIZE); + sbus_iounmap(bp->creg, CREG_REG_SIZE); + sbus_iounmap(bp->bregs, BMAC_REG_SIZE); + sbus_iounmap(bp->tregs, TCVR_REG_SIZE); + sbus_free_consistent(bp->bigmac_sdev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); + + free_netdev(net_dev); + + dev_set_drvdata(&dev->dev, NULL); + return 0; } -static void __exit bigmac_cleanup(void) -{ - while (root_bigmac_dev) { - struct bigmac *bp = root_bigmac_dev; - struct bigmac *bp_nxt = root_bigmac_dev->next_module; +static struct of_device_id bigmac_sbus_match[] = { + { + .name = "qec", + }, + { + .name = "be", + }, + {}, +}; - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); - sbus_iounmap(bp->creg, CREG_REG_SIZE); - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); +MODULE_DEVICE_TABLE(of, bigmac_sbus_match); - unregister_netdev(bp->dev); - free_netdev(bp->dev); - root_bigmac_dev = bp_nxt; - } +static struct of_platform_driver bigmac_sbus_driver = { + .name = "sunbmac", + .match_table = bigmac_sbus_match, + .probe = bigmac_sbus_probe, + .remove = __devexit_p(bigmac_sbus_remove), +}; + +static int __init bigmac_init(void) +{ + return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type); +} + +static void __exit bigmac_exit(void) +{ + of_unregister_driver(&bigmac_sbus_driver); } -module_init(bigmac_probe); -module_exit(bigmac_cleanup); +module_init(bigmac_init); +module_exit(bigmac_exit); diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index b0dbc5187143..b563d3c2993e 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -332,7 +332,6 @@ struct bigmac { struct sbus_dev *qec_sdev; struct sbus_dev *bigmac_sdev; struct net_device *dev; - struct bigmac *next_module; }; /* We use this to acquire receive skb's that we can DMA directly into. */ diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 38cd30cb7c75..5248670d29f7 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2880,17 +2880,20 @@ static int __devinit gem_get_device_address(struct gem *gp) #if defined(__sparc__) struct pci_dev *pdev = gp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; - int node = -1; + int use_idprom = 1; if (pcp != NULL) { - node = pcp->prom_node; - if (prom_getproplen(node, "local-mac-address") == 6) - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); - else - node = -1; + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + use_idprom = 0; + memcpy(dev->dev_addr, addr, 6); + } } - if (node == -1) + if (use_idprom) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); #elif defined(CONFIG_PPC_PMAC) unsigned char *addr; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index bd5d2668a362..c33ead3470db 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1,9 +1,9 @@ -/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $ - * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, +/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. * - * Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1998, 1999, 2002, 2003, + 2006 David S. Miller (davem@davemloft.net) * * Changes : * 2000/11/11 Willy Tarreau <willy AT meta-x.org> @@ -40,15 +40,13 @@ #include <asm/dma.h> #include <asm/byteorder.h> -#ifdef __sparc__ +#ifdef CONFIG_SPARC #include <asm/idprom.h> #include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> +#include <asm/prom.h> #include <asm/auxio.h> -#ifndef __sparc_v9__ -#include <asm/io-unit.h> -#endif #endif #include <asm/uaccess.h> @@ -57,7 +55,7 @@ #ifdef CONFIG_PCI #include <linux/pci.h> -#ifdef __sparc__ +#ifdef CONFIG_SPARC #include <asm/pbm.h> #endif #endif @@ -65,9 +63,9 @@ #include "sunhme.h" #define DRV_NAME "sunhme" -#define DRV_VERSION "2.02" -#define DRV_RELDATE "8/24/03" -#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" +#define DRV_VERSION "3.00" +#define DRV_RELDATE "June 23, 2006" +#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; @@ -83,8 +81,6 @@ static int macaddr[6]; module_param_array(macaddr, int, NULL, 0); MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set"); -static struct happy_meal *root_happy_dev; - #ifdef CONFIG_SBUS static struct quattro *qfe_sbus_list; #endif @@ -181,26 +177,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp) #define DEFAULT_IPG2 4 /* For all modes */ #define DEFAULT_JAMSIZE 4 /* Toe jam */ -#if defined(CONFIG_PCI) && defined(MODULE) -/* This happy_pci_ids is declared __initdata because it is only used - as an advisory to depmod. If this is ported to the new PCI interface - where it could be referenced at any time due to hot plugging, - the __initdata reference should be removed. */ - -static struct pci_device_id happymeal_pci_ids[] = { - { - .vendor = PCI_VENDOR_ID_SUN, - .device = PCI_DEVICE_ID_SUN_HAPPYMEAL, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, happymeal_pci_ids); - -#endif - /* NOTE: In the descriptor writes one _must_ write the address * member _first_. The card must not be allowed to see * the updated descriptor flags until the address is @@ -1610,7 +1586,7 @@ static int happy_meal_init(struct happy_meal *hp) HMD(("happy_meal_init: old[%08x] bursts<", hme_read32(hp, gregs + GREG_CFG))); -#ifndef __sparc__ +#ifndef CONFIG_SPARC /* It is always PCI and can handle 64byte bursts. */ hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64); #else @@ -1647,7 +1623,7 @@ static int happy_meal_init(struct happy_meal *hp) HMD(("XXX>")); hme_write32(hp, gregs + GREG_CFG, 0); } -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC */ /* Turn off interrupts we do not want to hear. */ HMD((", enable global interrupts, ")); @@ -2592,14 +2568,10 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h */ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev) { - struct sbus_bus *sbus; struct sbus_dev *sdev; struct quattro *qp; int i; - if (qfe_sbus_list == NULL) - goto found; - for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { for (i = 0, sdev = qp->quattro_dev; (sdev != NULL) && (i < 4); @@ -2608,17 +2580,7 @@ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev) return qp; } } - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - if (sdev == goal_sdev) - goto found; - } - } - - /* Cannot find quattro parent, fail. */ - return NULL; -found: qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); if (qp != NULL) { int i; @@ -2655,6 +2617,17 @@ static void __init quattro_sbus_register_irqs(void) } } } + +static void __devexit quattro_sbus_free_irqs(void) +{ + struct quattro *qp; + + for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { + struct sbus_dev *sdev = qp->quattro_dev; + + free_irq(sdev->irqs[0], qp); + } +} #endif /* CONFIG_SBUS */ #ifdef CONFIG_PCI @@ -2689,8 +2662,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) +static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) { + struct device_node *dp = sdev->ofdev.node; struct quattro *qp = NULL; struct happy_meal *hp; struct net_device *dev; @@ -2713,6 +2687,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) if (!dev) goto err_out; SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2728,13 +2703,16 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) for (i = 0; i < 6; i++) dev->dev_addr[i] = macaddr[i]; macaddr[5]++; - } else if (qfe_slot != -1 && - prom_getproplen(sdev->prom_node, - "local-mac-address") == 6) { - prom_getproperty(sdev->prom_node, "local-mac-address", - dev->dev_addr, 6); } else { - memcpy(dev->dev_addr, idprom->id_ethaddr, 6); + unsigned char *addr; + int len; + + addr = of_get_property(dp, "local-mac-address", &len); + + if (qfe_slot != -1 && addr && len == 6) + memcpy(dev->dev_addr, addr, 6); + else + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } hp = dev->priv; @@ -2745,9 +2723,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) err = -ENODEV; if (sdev->num_registers != 5) { - printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n", + printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n", sdev->num_registers); - printk(KERN_ERR "happymeal: Would you like that for here or to go?\n"); goto err_out_free_netdev; } @@ -2761,39 +2738,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) hp->gregs = sbus_ioremap(&sdev->resource[0], 0, GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { - printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n"); + printk(KERN_ERR "happymeal: Cannot map global registers.\n"); goto err_out_free_netdev; } hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { - printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n"); + printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n"); goto err_out_iounmap; } hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { - printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n"); + printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n"); goto err_out_iounmap; } hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { - printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n"); + printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n"); goto err_out_iounmap; } hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { - printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n"); + printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n"); goto err_out_iounmap; } - hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff); + hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff); if (hp->hm_revision == 0xff) hp->hm_revision = 0xa0; @@ -2807,8 +2784,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) hp->happy_flags |= HFLAG_QUATTRO; /* Get the supported DVMA burst sizes from our Happy SBUS. */ - hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node, - "burst-sizes", 0x00); + hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node, + "burst-sizes", 0x00); hp->happy_block = sbus_alloc_consistent(hp->happy_dev, PAGE_SIZE, @@ -2871,6 +2848,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) goto err_out_free_consistent; } + dev_set_drvdata(&sdev->ofdev.dev, hp); + if (qfe_slot != -1) printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", dev->name, qfe_slot); @@ -2883,12 +2862,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); - /* We are home free at this point, link us in to the happy - * device list. - */ - hp->next_module = root_happy_dev; - root_happy_dev = hp; - return 0; err_out_free_consistent: @@ -2918,7 +2891,7 @@ err_out: #endif #ifdef CONFIG_PCI -#ifndef __sparc__ +#ifndef CONFIG_SPARC static int is_quattro_p(struct pci_dev *pdev) { struct pci_dev *busdev = pdev->bus->self; @@ -3006,14 +2979,14 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) get_random_bytes(&dev_addr[3], 3); return; } -#endif /* !(__sparc__) */ +#endif /* !(CONFIG_SPARC) */ -static int __init happy_meal_pci_init(struct pci_dev *pdev) +static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct quattro *qp = NULL; -#ifdef __sparc__ +#ifdef CONFIG_SPARC struct pcidev_cookie *pcp; - int node; #endif struct happy_meal *hp; struct net_device *dev; @@ -3024,15 +2997,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) int err; /* Now make sure pci_dev cookie is there. */ -#ifdef __sparc__ +#ifdef CONFIG_SPARC pcp = pdev->sysdata; - if (pcp == NULL || pcp->prom_node == -1) { + if (pcp == NULL) { printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n"); return -ENODEV; } - node = pcp->prom_node; - prom_getstring(node, "name", prom_name, sizeof(prom_name)); + strcpy(prom_name, pcp->prom_node->name); #else if (is_quattro_p(pdev)) strcpy(prom_name, "SUNW,qfe"); @@ -3103,11 +3075,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) dev->dev_addr[i] = macaddr[i]; macaddr[5]++; } else { -#ifdef __sparc__ +#ifdef CONFIG_SPARC + unsigned char *addr; + int len; + if (qfe_slot != -1 && - prom_getproplen(node, "local-mac-address") == 6) { - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); + (addr = of_get_property(pcp->prom_node, + "local-mac-address", &len)) != NULL + && len == 6) { + memcpy(dev->dev_addr, addr, 6); } else { memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } @@ -3123,8 +3099,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) hp->bigmacregs = (hpreg_base + 0x6000UL); hp->tcvregs = (hpreg_base + 0x7000UL); -#ifdef __sparc__ - hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff); +#ifdef CONFIG_SPARC + hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff); if (hp->hm_revision == 0xff) { unsigned char prev; @@ -3148,7 +3124,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) /* And of course, indicate this is PCI. */ hp->happy_flags |= HFLAG_PCI; -#ifdef __sparc__ +#ifdef CONFIG_SPARC /* Assume PCI happy meals can handle all burst sizes. */ hp->happy_bursts = DMA_BURSTBITS; #endif @@ -3211,6 +3187,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) goto err_out_iounmap; } + dev_set_drvdata(&pdev->dev, hp); + if (!qfe_slot) { struct pci_dev *qpdev = qp->quattro_dev; @@ -3240,12 +3218,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) printk("\n"); - /* We are home free at this point, link us in to the happy - * device list. - */ - hp->next_module = root_happy_dev; - root_happy_dev = hp; - return 0; err_out_iounmap: @@ -3263,136 +3235,146 @@ err_out_clear_quattro: err_out: return err; } -#endif -#ifdef CONFIG_SBUS -static int __init happy_meal_sbus_probe(void) +static void __devexit happy_meal_pci_remove(struct pci_dev *pdev) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int cards = 0; - char model[128]; - - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - char *name = sdev->prom_name; - - if (!strcmp(name, "SUNW,hme")) { - cards++; - prom_getstring(sdev->prom_node, "model", - model, sizeof(model)); - if (!strcmp(model, "SUNW,sbus-qfe")) - happy_meal_sbus_init(sdev, 1); - else - happy_meal_sbus_init(sdev, 0); - } else if (!strcmp(name, "qfe") || - !strcmp(name, "SUNW,qfe")) { - cards++; - happy_meal_sbus_init(sdev, 1); - } - } - } - if (cards != 0) - quattro_sbus_register_irqs(); - return cards; + struct happy_meal *hp = dev_get_drvdata(&pdev->dev); + struct net_device *net_dev = hp->dev; + + unregister_netdev(net_dev); + + pci_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); + iounmap(hp->gregs); + pci_release_regions(hp->happy_dev); + + free_netdev(net_dev); + + dev_set_drvdata(&pdev->dev, NULL); } -#endif -#ifdef CONFIG_PCI -static int __init happy_meal_pci_probe(void) +static struct pci_device_id happymeal_pci_ids[] = { + { + .vendor = PCI_VENDOR_ID_SUN, + .device = PCI_DEVICE_ID_SUN_HAPPYMEAL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(pci, happymeal_pci_ids); + +static struct pci_driver hme_pci_driver = { + .name = "hme", + .id_table = happymeal_pci_ids, + .probe = happy_meal_pci_probe, + .remove = __devexit_p(happy_meal_pci_remove), +}; + +static int __init happy_meal_pci_init(void) { - struct pci_dev *pdev = NULL; - int cards = 0; + return pci_module_init(&hme_pci_driver); +} - while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) { - if (pci_enable_device(pdev)) - continue; - pci_set_master(pdev); - cards++; - happy_meal_pci_init(pdev); +static void happy_meal_pci_exit(void) +{ + pci_unregister_driver(&hme_pci_driver); + + while (qfe_pci_list) { + struct quattro *qfe = qfe_pci_list; + struct quattro *next = qfe->next; + + kfree(qfe); + + qfe_pci_list = next; } - return cards; } + #endif -static int __init happy_meal_probe(void) +#ifdef CONFIG_SBUS +static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - static int called = 0; - int cards; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + char *model = of_get_property(dp, "model", NULL); + int is_qfe = (match->data != NULL); - root_happy_dev = NULL; + if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) + is_qfe = 1; - if (called) - return -ENODEV; - called++; + return happy_meal_sbus_probe_one(sdev, is_qfe); +} + +static int __devexit hme_sbus_remove(struct of_device *dev) +{ + struct happy_meal *hp = dev_get_drvdata(&dev->dev); + struct net_device *net_dev = hp->dev; + + unregister_netdevice(net_dev); + + /* XXX qfe parent interrupt... */ + + sbus_iounmap(hp->gregs, GREG_REG_SIZE); + sbus_iounmap(hp->etxregs, ETX_REG_SIZE); + sbus_iounmap(hp->erxregs, ERX_REG_SIZE); + sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); + sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); + sbus_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); + + free_netdev(net_dev); + + dev_set_drvdata(&dev->dev, NULL); - cards = 0; -#ifdef CONFIG_SBUS - cards += happy_meal_sbus_probe(); -#endif -#ifdef CONFIG_PCI - cards += happy_meal_pci_probe(); -#endif - if (!cards) - return -ENODEV; return 0; } +static struct of_device_id hme_sbus_match[] = { + { + .name = "SUNW,hme", + }, + { + .name = "SUNW,qfe", + .data = (void *) 1, + }, + { + .name = "qfe", + .data = (void *) 1, + }, + {}, +}; -static void __exit happy_meal_cleanup_module(void) -{ -#ifdef CONFIG_SBUS - struct quattro *last_seen_qfe = NULL; -#endif +MODULE_DEVICE_TABLE(of, hme_sbus_match); - while (root_happy_dev) { - struct happy_meal *hp = root_happy_dev; - struct happy_meal *next = root_happy_dev->next_module; - struct net_device *dev = hp->dev; +static struct of_platform_driver hme_sbus_driver = { + .name = "hme", + .match_table = hme_sbus_match, + .probe = hme_sbus_probe, + .remove = __devexit_p(hme_sbus_remove), +}; - /* Unregister netdev before unmapping registers as this - * call can end up trying to access those registers. - */ - unregister_netdev(dev); +static int __init happy_meal_sbus_init(void) +{ + int err; -#ifdef CONFIG_SBUS - if (!(hp->happy_flags & HFLAG_PCI)) { - if (hp->happy_flags & HFLAG_QUATTRO) { - if (hp->qfe_parent != last_seen_qfe) { - free_irq(dev->irq, hp->qfe_parent); - last_seen_qfe = hp->qfe_parent; - } - } + err = of_register_driver(&hme_sbus_driver, &sbus_bus_type); + if (!err) + quattro_sbus_register_irqs(); - sbus_iounmap(hp->gregs, GREG_REG_SIZE); - sbus_iounmap(hp->etxregs, ETX_REG_SIZE); - sbus_iounmap(hp->erxregs, ERX_REG_SIZE); - sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); - sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); - sbus_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); - } -#endif -#ifdef CONFIG_PCI - if ((hp->happy_flags & HFLAG_PCI)) { - pci_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); - iounmap(hp->gregs); - pci_release_regions(hp->happy_dev); - } -#endif - free_netdev(dev); + return err; +} - root_happy_dev = next; - } +static void happy_meal_sbus_exit(void) +{ + of_unregister_driver(&hme_sbus_driver); + quattro_sbus_free_irqs(); - /* Now cleanup the quattro lists. */ -#ifdef CONFIG_SBUS while (qfe_sbus_list) { struct quattro *qfe = qfe_sbus_list; struct quattro *next = qfe->next; @@ -3401,18 +3383,39 @@ static void __exit happy_meal_cleanup_module(void) qfe_sbus_list = next; } +} #endif -#ifdef CONFIG_PCI - while (qfe_pci_list) { - struct quattro *qfe = qfe_pci_list; - struct quattro *next = qfe->next; - kfree(qfe); +static int __init happy_meal_probe(void) +{ + int err = 0; - qfe_pci_list = next; +#ifdef CONFIG_SBUS + err = happy_meal_sbus_init(); +#endif +#ifdef CONFIG_PCI + if (!err) { + err = happy_meal_pci_init(); +#ifdef CONFIG_SBUS + if (err) + happy_meal_sbus_exit(); +#endif } #endif + + return err; +} + + +static void __exit happy_meal_exit(void) +{ +#ifdef CONFIG_SBUS + happy_meal_sbus_exit(); +#endif +#ifdef CONFIG_PCI + happy_meal_pci_exit(); +#endif } module_init(happy_meal_probe); -module_exit(happy_meal_cleanup_module); +module_exit(happy_meal_exit); diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 34e9f953cea4..9b7ccaeeee89 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -461,7 +461,6 @@ struct happy_meal { struct net_device *dev; /* Backpointer */ struct quattro *qfe_parent; /* For Quattro cards */ int qfe_ent; /* Which instance on quattro */ - struct happy_meal *next_module; }; /* Here are the happy flags. */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 6381243d8d00..2c239ab63a80 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -266,7 +266,6 @@ struct lance_private { char *name; dma_addr_t init_block_dvma; struct net_device *dev; /* Backpointer */ - struct lance_private *next_module; struct sbus_dev *sdev; struct timer_list multicast_timer; }; @@ -298,8 +297,6 @@ int sparc_lance_debug = 2; #define LANCE_ADDR(x) ((long)(x) & ~0xff000000) -static struct lance_private *root_lance_dev; - /* Load the CSR registers */ static void load_csrs(struct lance_private *lp) { @@ -1327,9 +1324,9 @@ static struct ethtool_ops sparc_lance_ethtool_ops = { .get_link = sparc_lance_get_link, }; -static int __init sparc_lance_init(struct sbus_dev *sdev, - struct sbus_dma *ledma, - struct sbus_dev *lebuffer) +static int __init sparc_lance_probe_one(struct sbus_dev *sdev, + struct sbus_dma *ledma, + struct sbus_dev *lebuffer) { static unsigned version_printed; struct net_device *dev; @@ -1473,6 +1470,7 @@ no_link_test: lp->dev = dev; SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; @@ -1500,8 +1498,7 @@ no_link_test: goto fail; } - lp->next_module = root_lance_dev; - root_lance_dev = lp; + dev_set_drvdata(&sdev->ofdev.dev, lp); printk(KERN_INFO "%s: LANCE ", dev->name); @@ -1536,88 +1533,112 @@ static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev) #include <asm/machines.h> /* Find all the lance cards on the system and initialize them */ -static int __init sparc_lance_probe(void) +static struct sbus_dev sun4_sdev; +static int __init sparc_lance_init(void) { - static struct sbus_dev sdev; - static int called; - - root_lance_dev = NULL; - - if (called) - return -ENODEV; - called++; - if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || (idprom->id_machtype == (SM_SUN4|SM_4_470))) { - memset(&sdev, 0, sizeof(sdev)); - sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; - sdev.irqs[0] = 6; - return sparc_lance_init(&sdev, NULL, NULL); + memset(&sun4_sdev, 0, sizeof(sdev)); + sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; + sun4_sdev.irqs[0] = 6; + return sparc_lance_probe_one(&sun4_sdev, NULL, NULL); } return -ENODEV; } -#else /* !CONFIG_SUN4 */ - -/* Find all the lance cards on the system and initialize them */ -static int __init sparc_lance_probe(void) +static int __exit sunlance_sun4_remove(void) { - struct sbus_bus *bus; - struct sbus_dev *sdev = NULL; - struct sbus_dma *ledma = NULL; - static int called; - int cards = 0, v; - - root_lance_dev = NULL; - - if (called) - return -ENODEV; - called++; - - for_each_sbus (bus) { - for_each_sbusdev (sdev, bus) { - if (strcmp(sdev->prom_name, "le") == 0) { - cards++; - if ((v = sparc_lance_init(sdev, NULL, NULL))) - return v; - continue; - } - if (strcmp(sdev->prom_name, "ledma") == 0) { - cards++; - ledma = find_ledma(sdev); - if ((v = sparc_lance_init(sdev->child, - ledma, NULL))) - return v; - continue; - } - if (strcmp(sdev->prom_name, "lebuffer") == 0){ - cards++; - if ((v = sparc_lance_init(sdev->child, - NULL, sdev))) - return v; - continue; - } - } /* for each sbusdev */ - } /* for each sbus */ - if (!cards) - return -ENODEV; + struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev); + struct net_device *net_dev = lp->dev; + + unregister_netdevice(net_dev); + + lance_free_hwresources(root_lance_dev); + + free_netdev(net_dev); + + dev_set_drvdata(&sun4_sdev->dev, NULL); + return 0; } -#endif /* !CONFIG_SUN4 */ -static void __exit sparc_lance_cleanup(void) +#else /* !CONFIG_SUN4 */ + +static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct lance_private *lp; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + int err; + + if (!strcmp(dp->name, "le")) { + err = sparc_lance_probe_one(sdev, NULL, NULL); + } else if (!strcmp(dp->name, "ledma")) { + struct sbus_dma *ledma = find_ledma(sdev); - while (root_lance_dev) { - lp = root_lance_dev->next_module; + err = sparc_lance_probe_one(sdev->child, ledma, NULL); + } else { + BUG_ON(strcmp(dp->name, "lebuffer")); - unregister_netdev(root_lance_dev->dev); - lance_free_hwresources(root_lance_dev); - free_netdev(root_lance_dev->dev); - root_lance_dev = lp; + err = sparc_lance_probe_one(sdev->child, NULL, sdev); } + + return err; +} + +static int __devexit sunlance_sbus_remove(struct of_device *dev) +{ + struct lance_private *lp = dev_get_drvdata(&dev->dev); + struct net_device *net_dev = lp->dev; + + unregister_netdevice(net_dev); + + lance_free_hwresources(lp); + + free_netdev(net_dev); + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static struct of_device_id sunlance_sbus_match[] = { + { + .name = "le", + }, + { + .name = "ledma", + }, + { + .name = "lebuffer", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, sunlance_sbus_match); + +static struct of_platform_driver sunlance_sbus_driver = { + .name = "sunlance", + .match_table = sunlance_sbus_match, + .probe = sunlance_sbus_probe, + .remove = __devexit_p(sunlance_sbus_remove), +}; + + +/* Find all the lance cards on the system and initialize them */ +static int __init sparc_lance_init(void) +{ + return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type); +} +#endif /* !CONFIG_SUN4 */ + +static void __exit sparc_lance_exit(void) +{ +#ifdef CONFIG_SUN4 + sunlance_sun4_remove(); +#else + of_unregister_driver(&sunlance_sbus_driver); +#endif } -module_init(sparc_lance_probe); -module_exit(sparc_lance_cleanup); +module_init(sparc_lance_init); +module_exit(sparc_lance_exit); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 1f2323be60d4..9da6d5b87173 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1,10 +1,9 @@ -/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $ - * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. +/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed * if you make it look like a LANCE. * - * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -41,9 +40,9 @@ #include "sunqe.h" #define DRV_NAME "sunqe" -#define DRV_VERSION "3.0" -#define DRV_RELDATE "8/24/03" -#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" +#define DRV_VERSION "4.0" +#define DRV_RELDATE "June 23, 2006" +#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; @@ -755,298 +754,269 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) qecp->gregs + GLOB_RSIZE); } -/* Four QE's per QEC card. */ -static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev) +static u8 __init qec_get_burst(struct device_node *dp) { - static unsigned version_printed; - struct net_device *qe_devs[4]; - struct sunqe *qeps[4]; - struct sbus_dev *qesdevs[4]; - struct sbus_dev *child; - struct sunqec *qecp = NULL; u8 bsizes, bsizes_more; - int i, j, res = -ENOMEM; - for (i = 0; i < 4; i++) { - qe_devs[i] = alloc_etherdev(sizeof(struct sunqe)); - if (!qe_devs[i]) - goto out; - } + /* Find and set the burst sizes for the QEC, since it + * does the actual dma for all 4 channels. + */ + bsizes = of_getintprop_default(dp, "burst-sizes", 0xff); + bsizes &= 0xff; + bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff); - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); + if (bsizes_more != 0xff) + bsizes &= bsizes_more; + if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || + (bsizes & DMA_BURST32)==0) + bsizes = (DMA_BURST32 - 1); - for (i = 0; i < 4; i++) { - qeps[i] = (struct sunqe *) qe_devs[i]->priv; - for (j = 0; j < 6; j++) - qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j]; - qeps[i]->channel = i; - spin_lock_init(&qeps[i]->lock); - } + return bsizes; +} - qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL); - if (qecp == NULL) - goto out1; - qecp->qec_sdev = sdev; +static struct sunqec * __init get_qec(struct sbus_dev *child_sdev) +{ + struct sbus_dev *qec_sdev = child_sdev->parent; + struct sunqec *qecp; - for (i = 0; i < 4; i++) { - qecp->qes[i] = qeps[i]; - qeps[i]->dev = qe_devs[i]; - qeps[i]->parent = qecp; + for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) { + if (qecp->qec_sdev == qec_sdev) + break; } + if (!qecp) { + qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL); + if (qecp) { + u32 ctrl; + + qecp->qec_sdev = qec_sdev; + qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0, + GLOB_REG_SIZE, + "QEC Global Registers"); + if (!qecp->gregs) + goto fail; + + /* Make sure the QEC is in MACE mode. */ + ctrl = sbus_readl(qecp->gregs + GLOB_CTRL); + ctrl &= 0xf0000000; + if (ctrl != GLOB_CTRL_MMODE) { + printk(KERN_ERR "qec: Not in MACE mode!\n"); + goto fail; + } - res = -ENODEV; + if (qec_global_reset(qecp->gregs)) + goto fail; - for (i = 0, child = sdev->child; i < 4; i++, child = child->next) { - /* Link in channel */ - j = prom_getintdefault(child->prom_node, "channel#", -1); - if (j == -1) - goto out2; - qesdevs[j] = child; - } + qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node); - for (i = 0; i < 4; i++) - qeps[i]->qe_sdev = qesdevs[i]; + qec_init_once(qecp, qec_sdev); - /* Now map in the registers, QEC globals first. */ - qecp->gregs = sbus_ioremap(&sdev->resource[0], 0, - GLOB_REG_SIZE, "QEC Global Registers"); - if (!qecp->gregs) { - printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n"); - goto out2; - } + if (request_irq(qec_sdev->irqs[0], &qec_interrupt, + SA_SHIRQ, "qec", (void *) qecp)) { + printk(KERN_ERR "qec: Can't register irq.\n"); + goto fail; + } - /* Make sure the QEC is in MACE mode. */ - if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) { - printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n"); - goto out3; + qecp->next_module = root_qec_dev; + root_qec_dev = qecp; + } } - /* Reset the QEC. */ - if (qec_global_reset(qecp->gregs)) - goto out3; + return qecp; - /* Find and set the burst sizes for the QEC, since it does - * the actual dma for all 4 channels. - */ - bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff); - bsizes &= 0xff; - bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff); +fail: + if (qecp->gregs) + sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); + kfree(qecp); + return NULL; +} - if (bsizes_more != 0xff) - bsizes &= bsizes_more; - if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || - (bsizes & DMA_BURST32)==0) - bsizes = (DMA_BURST32 - 1); +static int __init qec_ether_init(struct sbus_dev *sdev) +{ + static unsigned version_printed; + struct net_device *dev; + struct sunqe *qe; + struct sunqec *qecp; + int i, res; - qecp->qec_bursts = bsizes; + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); - /* Perform one time QEC initialization, we never touch the QEC - * globals again after this. - */ - qec_init_once(qecp, sdev); - - for (i = 0; i < 4; i++) { - struct sunqe *qe = qeps[i]; - /* Map in QEC per-channel control registers. */ - qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); - if (!qe->qcregs) { - printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i); - goto out4; - } + dev = alloc_etherdev(sizeof(struct sunqe)); + if (!dev) + return -ENOMEM; - /* Map in per-channel AMD MACE registers. */ - qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); - if (!qe->mregs) { - printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i); - goto out4; - } + qe = netdev_priv(dev); - qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, - PAGE_SIZE, - &qe->qblock_dvma); - qe->buffers = sbus_alloc_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - &qe->buffers_dvma); - if (qe->qe_block == NULL || qe->qblock_dvma == 0 || - qe->buffers == NULL || qe->buffers_dvma == 0) { - goto out4; + i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); + if (i == -1) { + struct sbus_dev *td = sdev->parent->child; + i = 0; + while (td != sdev) { + td = td->next; + i++; } - - /* Stop this QE. */ - qe_stop(qe); } + qe->channel = i; + spin_lock_init(&qe->lock); + + res = -ENODEV; + qecp = get_qec(sdev); + if (!qecp) + goto fail; - for (i = 0; i < 4; i++) { - SET_MODULE_OWNER(qe_devs[i]); - qe_devs[i]->open = qe_open; - qe_devs[i]->stop = qe_close; - qe_devs[i]->hard_start_xmit = qe_start_xmit; - qe_devs[i]->get_stats = qe_get_stats; - qe_devs[i]->set_multicast_list = qe_set_multicast; - qe_devs[i]->tx_timeout = qe_tx_timeout; - qe_devs[i]->watchdog_timeo = 5*HZ; - qe_devs[i]->irq = sdev->irqs[0]; - qe_devs[i]->dma = 0; - qe_devs[i]->ethtool_ops = &qe_ethtool_ops; - } + qecp->qes[qe->channel] = qe; + qe->dev = dev; + qe->parent = qecp; + qe->qe_sdev = sdev; - /* QEC receives interrupts from each QE, then it sends the actual - * IRQ to the cpu itself. Since QEC is the single point of - * interrupt for all QE channels we register the IRQ handler - * for it now. - */ - if (request_irq(sdev->irqs[0], &qec_interrupt, - SA_SHIRQ, "QuadEther", (void *) qecp)) { - printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n"); - res = -EAGAIN; - goto out4; + res = -ENOMEM; + qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); + if (!qe->qcregs) { + printk(KERN_ERR "qe: Cannot map channel registers.\n"); + goto fail; } - for (i = 0; i < 4; i++) { - if (register_netdev(qe_devs[i]) != 0) - goto out5; + qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); + if (!qe->mregs) { + printk(KERN_ERR "qe: Cannot map MACE registers.\n"); + goto fail; } - /* Report the QE channels. */ - for (i = 0; i < 4; i++) { - printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i); - for (j = 0; j < 6; j++) - printk ("%2.2x%c", - qe_devs[i]->dev_addr[j], - j == 5 ? ' ': ':'); - printk("\n"); - } + qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, + PAGE_SIZE, + &qe->qblock_dvma); + qe->buffers = sbus_alloc_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + &qe->buffers_dvma); + if (qe->qe_block == NULL || qe->qblock_dvma == 0 || + qe->buffers == NULL || qe->buffers_dvma == 0) + goto fail; + + /* Stop this QE. */ + qe_stop(qe); + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + + dev->open = qe_open; + dev->stop = qe_close; + dev->hard_start_xmit = qe_start_xmit; + dev->get_stats = qe_get_stats; + dev->set_multicast_list = qe_set_multicast; + dev->tx_timeout = qe_tx_timeout; + dev->watchdog_timeo = 5*HZ; + dev->irq = sdev->irqs[0]; + dev->dma = 0; + dev->ethtool_ops = &qe_ethtool_ops; + + res = register_netdev(dev); + if (res) + goto fail; + + dev_set_drvdata(&sdev->ofdev.dev, qe); + + printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel); + for (i = 0; i < 6; i++) + printk ("%2.2x%c", + dev->dev_addr[i], + i == 5 ? ' ': ':'); + printk("\n"); - /* We are home free at this point, link the qe's into - * the master list for later driver exit. - */ - qecp->next_module = root_qec_dev; - root_qec_dev = qecp; return 0; -out5: - while (i--) - unregister_netdev(qe_devs[i]); - free_irq(sdev->irqs[0], (void *)qecp); -out4: - for (i = 0; i < 4; i++) { - struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; - - if (qe->qcregs) - sbus_iounmap(qe->qcregs, CREG_REG_SIZE); - if (qe->mregs) - sbus_iounmap(qe->mregs, MREGS_REG_SIZE); - if (qe->qe_block) - sbus_free_consistent(qe->qe_sdev, - PAGE_SIZE, - qe->qe_block, - qe->qblock_dvma); - if (qe->buffers) - sbus_free_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); - } -out3: - sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); -out2: - kfree(qecp); -out1: - i = 4; -out: - while (i--) - free_netdev(qe_devs[i]); +fail: + if (qe->qcregs) + sbus_iounmap(qe->qcregs, CREG_REG_SIZE); + if (qe->mregs) + sbus_iounmap(qe->mregs, MREGS_REG_SIZE); + if (qe->qe_block) + sbus_free_consistent(qe->qe_sdev, + PAGE_SIZE, + qe->qe_block, + qe->qblock_dvma); + if (qe->buffers) + sbus_free_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); + + free_netdev(dev); + return res; } -static int __init qec_match(struct sbus_dev *sdev) +static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_dev *sibling; - int i; - - if (strcmp(sdev->prom_name, "qec") != 0) - return 0; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); - /* QEC can be parent of either QuadEthernet or BigMAC - * children. Do not confuse this with qfe/SUNW,qfe - * which is a quad-happymeal card and handled by - * a different driver. - */ - sibling = sdev->child; - for (i = 0; i < 4; i++) { - if (sibling == NULL) - return 0; - if (strcmp(sibling->prom_name, "qe") != 0) - return 0; - sibling = sibling->next; - } - return 1; + return qec_ether_init(sdev); } -static int __init qec_probe(void) +static int __devexit qec_sbus_remove(struct of_device *dev) { - struct net_device *dev = NULL; - struct sbus_bus *bus; - struct sbus_dev *sdev = NULL; - static int called; - int cards = 0, v; - - root_qec_dev = NULL; - - if (called) - return -ENODEV; - called++; - - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { - if (cards) - dev = NULL; - - if (qec_match(sdev)) { - cards++; - if ((v = qec_ether_init(dev, sdev))) - return v; - } - } - } - if (!cards) - return -ENODEV; + struct sunqe *qp = dev_get_drvdata(&dev->dev); + struct net_device *net_dev = qp->dev; + + unregister_netdevice(net_dev); + + sbus_iounmap(qp->qcregs, CREG_REG_SIZE); + sbus_iounmap(qp->mregs, MREGS_REG_SIZE); + sbus_free_consistent(qp->qe_sdev, + PAGE_SIZE, + qp->qe_block, + qp->qblock_dvma); + sbus_free_consistent(qp->qe_sdev, + sizeof(struct sunqe_buffers), + qp->buffers, + qp->buffers_dvma); + + free_netdev(net_dev); + + dev_set_drvdata(&dev->dev, NULL); + return 0; } -static void __exit qec_cleanup(void) +static struct of_device_id qec_sbus_match[] = { + { + .name = "qe", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, qec_sbus_match); + +static struct of_platform_driver qec_sbus_driver = { + .name = "qec", + .match_table = qec_sbus_match, + .probe = qec_sbus_probe, + .remove = __devexit_p(qec_sbus_remove), +}; + +static int __init qec_init(void) +{ + return of_register_driver(&qec_sbus_driver, &sbus_bus_type); +} + +static void __exit qec_exit(void) { - struct sunqec *next_qec; - int i; + of_unregister_driver(&qec_sbus_driver); while (root_qec_dev) { - next_qec = root_qec_dev->next_module; - - /* Release all four QE channels, then the QEC itself. */ - for (i = 0; i < 4; i++) { - unregister_netdev(root_qec_dev->qes[i]->dev); - sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE); - sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE); - sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, - PAGE_SIZE, - root_qec_dev->qes[i]->qe_block, - root_qec_dev->qes[i]->qblock_dvma); - sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, - sizeof(struct sunqe_buffers), - root_qec_dev->qes[i]->buffers, - root_qec_dev->qes[i]->buffers_dvma); - free_netdev(root_qec_dev->qes[i]->dev); - } - free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev); + struct sunqec *next = root_qec_dev->next_module; + + free_irq(root_qec_dev->qec_sdev->irqs[0], + (void *) root_qec_dev); sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); + kfree(root_qec_dev); - root_qec_dev = next_qec; + + root_qec_dev = next; } } -module_init(qec_probe); -module_exit(qec_cleanup); +module_init(qec_init); +module_exit(qec_exit); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e3e380f90f86..35f931638750 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10549,11 +10549,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { - int node = pcp->prom_node; + unsigned char *addr; + int len; - if (prom_getproplen(node, "local-mac-address") == 6) { - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + memcpy(dev->dev_addr, addr, 6); memcpy(dev->perm_addr, dev->dev_addr, 6); return 0; } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index cabdf894e21e..e0de66739a42 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1550,10 +1550,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; #if defined(__sparc__) - if ((pcp != NULL) && prom_getproplen(pcp->prom_node, - "local-mac-address") == 6) { - prom_getproperty(pcp->prom_node, "local-mac-address", - dev->dev_addr, 6); + if (pcp) { + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, + "local-mac-address", &len); + if (addr && len == 6) + memcpy(dev->dev_addr, addr, 6); } #endif #if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 36a1556e64c7..69a4bbd4cbee 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -1,5 +1,4 @@ -/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $ - * Parallel-port routines for Sun architecture +/* parport_sunbpp.c: Parallel-port routines for SBUS * * Author: Derrick J. Brashear <shadow@dementia.org> * @@ -14,6 +13,9 @@ * Gus Baldauf (gbaldauf@ix.netcom.com) * Peter Zaitcev * Tom Dyas + * + * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net> + * */ #include <linux/string.h> @@ -287,14 +289,7 @@ static struct parport_operations parport_sunbpp_ops = .owner = THIS_MODULE, }; -typedef struct { - struct list_head list; - struct parport *port; -} Node; -/* no locks, everything's serialized */ -static LIST_HEAD(port_list); - -static int __init init_one_port(struct sbus_dev *sdev) +static int __devinit init_one_port(struct sbus_dev *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ @@ -303,109 +298,120 @@ static int __init init_one_port(struct sbus_dev *sdev) int irq, dma, err = 0, size; struct bpp_regs __iomem *regs; unsigned char value_tcr; - Node *node; - - dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); - node = kmalloc(sizeof(Node), GFP_KERNEL); - if (!node) - goto out0; irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "sunbpp"); if (!base) - goto out1; + return -ENODEV; size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; - dprintk(("alloc(ppops), ")); - ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); + ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); if (!ops) - goto out2; + goto out_unmap; memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) - goto out3; + goto out_free_ops; p->size = size; - dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ", - p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); if ((err = request_irq(p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)) != 0) { - dprintk(("ERROR %d\n", err)); - goto out4; + goto out_put_port; } - dprintk(("OK\n")); + parport_sunbpp_enable_irq(p); regs = (struct bpp_regs __iomem *)p->base; - dprintk((KERN_DEBUG "forward\n")); + value_tcr = sbus_readb(®s->p_tcr); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); - node->port = p; - list_add(&node->list, &port_list); - parport_announce_port (p); - return 1; + dev_set_drvdata(&sdev->ofdev.dev, p); + + parport_announce_port(p); + + return 0; -out4: +out_put_port: parport_put_port(p); -out3: + +out_free_ops: kfree(ops); -out2: + +out_unmap: sbus_iounmap(base, size); -out1: - kfree(node); -out0: + return err; } -static int __init parport_sunbpp_init(void) +static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int count = 0; - - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "SUNW,bpp")) - count += init_one_port(sdev); - } + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + return init_one_port(sdev); +} + +static int __devexit bpp_remove(struct of_device *dev) +{ + struct parport *p = dev_get_drvdata(&dev->dev); + struct parport_operations *ops = p->ops; + + parport_remove_port(p); + + if (p->irq != PARPORT_IRQ_NONE) { + parport_sunbpp_disable_irq(p); + free_irq(p->irq, p); } - return count ? 0 : -ENODEV; + + sbus_iounmap((void __iomem *) p->base, p->size); + parport_put_port(p); + kfree(ops); + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static struct of_device_id bpp_match[] = { + { + .name = "SUNW,bpp", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, qec_sbus_match); + +static struct of_platform_driver bpp_sbus_driver = { + .name = "bpp", + .match_table = bpp_match, + .probe = bpp_probe, + .remove = __devexit_p(bpp_remove), +}; + +static int __init parport_sunbpp_init(void) +{ + return of_register_driver(&bpp_sbus_driver, &sbus_bus_type); } static void __exit parport_sunbpp_exit(void) { - while (!list_empty(&port_list)) { - Node *node = list_entry(port_list.next, Node, list); - struct parport *p = node->port; - struct parport_operations *ops = p->ops; - parport_remove_port(p); - - if (p->irq != PARPORT_IRQ_NONE) { - parport_sunbpp_disable_irq(p); - free_irq(p->irq, p); - } - sbus_iounmap((void __iomem *)p->base, p->size); - parport_put_port(p); - kfree (ops); - list_del(&node->list); - kfree (node); - } + of_unregister_driver(&bpp_sbus_driver); } MODULE_AUTHOR("Derrick J Brashear"); MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port"); MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); module_init(parport_sunbpp_init) diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index d89f83f769f5..1cc706e11119 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -575,9 +575,9 @@ int bbc_envctrl_init(void) int devidx = 0; while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { - if (!strcmp(echild->prom_name, "temperature")) + if (!strcmp(echild->prom_node->name, "temperature")) attach_one_temp(echild, temp_index++); - if (!strcmp(echild->prom_name, "fan-control")) + if (!strcmp(echild->prom_node->name, "fan-control")) attach_one_fan(echild, fan_index++); } if (temp_index != 0 && fan_index != 0) { diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 3e156e005f2e..73634371393b 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -423,7 +423,7 @@ static int __init bbc_present(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) + if (!strcmp(edev->prom_node->name, "bbc")) return 1; } } @@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "i2c")) { + if (!strcmp(edev->prom_node->name, "i2c")) { if (!attach_one_i2c(edev, index)) index++; } diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index c3a51d1fae5d..d92bc8827a9e 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -184,7 +184,7 @@ static int __init d7s_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, D7S_OBPNAME)) + if (!strcmp(edev->prom_node->name, D7S_OBPNAME)) goto ebus_done; } } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 19e8eddf887a..cf97e9efe9b6 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -768,16 +768,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, * decoding tables, monitor type, optional properties. * Return: None. */ -static void envctrl_init_adc(struct i2c_child_t *pchild, int node) +static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { - char chnls_desc[CHANNEL_DESC_SZ]; int i = 0, len; - char *pos = chnls_desc; + char *pos; + unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ - len = prom_getproperty(node, "channels-description", chnls_desc, - CHANNEL_DESC_SZ); - chnls_desc[CHANNEL_DESC_SZ - 1] = '\0'; + pos = of_get_property(dp, "channels-description", &len); while (len > 0) { int l = strlen(pos) + 1; @@ -787,10 +785,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node) } /* Get optional properties. */ - len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature, - sizeof(warning_temperature)); - len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature, - sizeof(shutdown_temperature)); + pval = of_get_property(dp, "warning-temp", NULL); + if (pval) + warning_temperature = *pval; + + pval = of_get_property(dp, "shutdown-temp", NULL); + if (pval) + shutdown_temperature = *pval; } /* Function Description: Initialize child device monitoring fan status. @@ -864,21 +865,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, struct i2c_child_t *pchild) { - int node, len, i, tbls_size = 0; - - node = edev_child->prom_node; + int len, i, tbls_size = 0; + struct device_node *dp = edev_child->prom_node; + void *pval; /* Get device address. */ - len = prom_getproperty(node, "reg", - (char *) &(pchild->addr), - sizeof(pchild->addr)); + pval = of_get_property(dp, "reg", &len); + memcpy(&pchild->addr, pval, len); /* Get tables property. Read firmware temperature tables. */ - len = prom_getproperty(node, "translation", - (char *) pchild->tblprop_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_tblprop))); - if (len > 0) { + pval = of_get_property(dp, "translation", &len); + if (pval && len > 0) { + memcpy(pchild->tblprop_array, pval, len); pchild->total_tbls = len / sizeof(struct pcf8584_tblprop); for (i = 0; i < pchild->total_tbls; i++) { if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) { @@ -891,12 +889,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, printk("envctrl: Failed to allocate table.\n"); return; } - len = prom_getproperty(node, "tables", - (char *) pchild->tables, tbls_size); - if (len <= 0) { + pval = of_get_property(dp, "tables", &len); + if (!pval || len <= 0) { printk("envctrl: Failed to get table.\n"); return; } + memcpy(pchild->tables, pval, len); } /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04) @@ -907,12 +905,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, * 'NULL' monitor type. */ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) { + struct device_node *root_node; int len; - char prop[56]; - len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); - if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) - { + root_node = of_find_node_by_path("/"); + if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) { for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) { pchild->mon_type[len] = ENVCTRL_NOMON; } @@ -921,16 +918,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } /* Get the monitor channels. */ - len = prom_getproperty(node, "channels-in-use", - (char *) pchild->chnl_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_channel))); + pval = of_get_property(dp, "channels-in-use", &len); + memcpy(pchild->chnl_array, pval, len); pchild->total_chnls = len / sizeof(struct pcf8584_channel); for (i = 0; i < pchild->total_chnls; i++) { switch (pchild->chnl_array[i].type) { case PCF8584_TEMP_TYPE: - envctrl_init_adc(pchild, node); + envctrl_init_adc(pchild, dp); break; case PCF8584_GLOBALADDR_TYPE: @@ -945,7 +940,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, case PCF8584_VOLTAGE_TYPE: if (pchild->i2ctype == I2C_ADC) { - envctrl_init_adc(pchild,node); + envctrl_init_adc(pchild,dp); } else { envctrl_init_voltage_status(pchild); } @@ -1046,7 +1041,7 @@ static int __init envctrl_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) { + if (!strcmp(edev->prom_node->name, "bbc")) { /* If we find a boot-bus controller node, * then this envctrl driver is not for us. */ @@ -1060,14 +1055,14 @@ static int __init envctrl_init(void) */ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "i2c")) { + if (!strcmp(edev->prom_node->name, "i2c")) { i2c = ioremap(edev->resource[0].start, 0x2); for_each_edevchild(edev, edev_child) { - if (!strcmp("gpio", edev_child->prom_name)) { + if (!strcmp("gpio", edev_child->prom_node->name)) { i2c_childlist[i].i2ctype = I2C_GPIO; envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); } - if (!strcmp("adc", edev_child->prom_name)) { + if (!strcmp("adc", edev_child->prom_node->name)) { i2c_childlist[i].i2ctype = I2C_ADC; envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); } diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 2beb3dded087..5ae684c011f8 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -192,9 +192,11 @@ static int __init flash_init(void) } if (!sdev) { #ifdef CONFIG_PCI + struct linux_prom_registers *ebus_regs; + for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "flashprom")) + if (!strcmp(edev->prom_node->name, "flashprom")) goto ebus_done; } } @@ -202,23 +204,23 @@ static int __init flash_init(void) if (!edev) return -ENODEV; - len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs)); - if ((len % sizeof(regs[0])) != 0) { + ebus_regs = of_get_property(edev->prom_node, "reg", &len); + if (!ebus_regs || (len % sizeof(regs[0])) != 0) { printk("flash: Strange reg property size %d\n", len); return -ENODEV; } - nregs = len / sizeof(regs[0]); + nregs = len / sizeof(ebus_regs[0]); flash.read_base = edev->resource[0].start; - flash.read_size = regs[0].reg_size; + flash.read_size = ebus_regs[0].reg_size; if (nregs == 1) { flash.write_base = edev->resource[0].start; - flash.write_size = regs[0].reg_size; + flash.write_size = ebus_regs[0].reg_size; } else if (nregs == 2) { flash.write_base = edev->resource[1].start; - flash.write_size = regs[1].reg_size; + flash.write_size = ebus_regs[1].reg_size; } else { printk("flash: Strange number of regs %d\n", nregs); return -ENODEV; diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 239e108b8ed1..cf5b476b5496 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -243,8 +243,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, ((int *) opp->oprom_array)[1]); pcp = pdev->sysdata; - if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) { - node = pcp->prom_node; + if (pcp != NULL) { + node = pcp->prom_node->node; data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 5d30a3ebfccd..387a6aa8c020 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,7 +1,6 @@ -/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $ - * sbus.c: SBus support routines. +/* sbus.c: SBus support routines. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> @@ -14,237 +13,76 @@ #include <asm/sbus.h> #include <asm/dma.h> #include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/bpp.h> #include <asm/irq.h> -struct sbus_bus *sbus_root = NULL; +struct sbus_bus *sbus_root; -static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } }; -#ifdef CONFIG_SPARC32 -static int interrupts[PROMINTR_MAX] __initdata = { 0 }; -#endif - -#ifdef CONFIG_PCI -extern int pcic_present(void); -#endif - -/* Perhaps when I figure out more about the iommu we'll put a - * device registration routine here that probe_sbus() calls to - * setup the iommu for each Sbus. - */ - -/* We call this for each SBus device, and fill the structure based - * upon the prom device tree. We return the start of memory after - * the things we have allocated. - */ - -/* #define DEBUG_FILL */ - -static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) +static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { - unsigned long address, base; + unsigned long base; + void *pval; int len; - sdev->prom_node = prom_node; - prom_getstring(prom_node, "name", - sdev->prom_name, sizeof(sdev->prom_name)); - address = prom_getint(prom_node, "address"); - len = prom_getproperty(prom_node, "reg", - (char *) sdev->reg_addrs, - sizeof(sdev->reg_addrs)); - if (len == -1) { - sdev->num_registers = 0; - goto no_regs; - } + sdev->prom_node = dp->node; + strcpy(sdev->prom_name, dp->name); - if (len % sizeof(struct linux_prom_registers)) { - prom_printf("fill_sbus_device: proplen for regs of %s " - " was %d, need multiple of %d\n", - sdev->prom_name, len, - (int) sizeof(struct linux_prom_registers)); - prom_halt(); - } - if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) { - prom_printf("fill_sbus_device: Too many register properties " - "for device %s, len=%d\n", - sdev->prom_name, len); - prom_halt(); - } - sdev->num_registers = len / sizeof(struct linux_prom_registers); - sdev->ranges_applied = 0; + pval = of_get_property(dp, "reg", &len); + sdev->num_registers = 0; + if (pval) { + memcpy(sdev->reg_addrs, pval, len); - base = (unsigned long) sdev->reg_addrs[0].phys_addr; + sdev->num_registers = + len / sizeof(struct linux_prom_registers); - /* Compute the slot number. */ - if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) { - sdev->slot = sbus_dev_slot(base); - } else { - sdev->slot = sdev->reg_addrs[0].which_io; - } + base = (unsigned long) sdev->reg_addrs[0].phys_addr; -no_regs: - len = prom_getproperty(prom_node, "ranges", - (char *)sdev->device_ranges, - sizeof(sdev->device_ranges)); - if (len == -1) { - sdev->num_device_ranges = 0; - goto no_ranges; - } - if (len % sizeof(struct linux_prom_ranges)) { - prom_printf("fill_sbus_device: proplen for ranges of %s " - " was %d, need multiple of %d\n", - sdev->prom_name, len, - (int) sizeof(struct linux_prom_ranges)); - prom_halt(); - } - if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) { - prom_printf("fill_sbus_device: Too many range properties " - "for device %s, len=%d\n", - sdev->prom_name, len); - prom_halt(); + /* Compute the slot number. */ + if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) + sdev->slot = sbus_dev_slot(base); + else + sdev->slot = sdev->reg_addrs[0].which_io; } - sdev->num_device_ranges = - len / sizeof(struct linux_prom_ranges); - -no_ranges: - /* XXX Unfortunately, IRQ issues are very arch specific. - * XXX Pull this crud out into an arch specific area - * XXX at some point. -DaveM - */ -#ifdef CONFIG_SPARC64 - len = prom_getproperty(prom_node, "interrupts", - (char *) irqs, sizeof(irqs)); - if (len == -1 || len == 0) { - sdev->irqs[0] = 0; - sdev->num_irqs = 0; - } else { - unsigned int pri = irqs[0].pri; - - sdev->num_irqs = 1; - if (pri < 0x20) - pri += sdev->slot * 8; - - sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); + + pval = of_get_property(dp, "ranges", &len); + sdev->num_device_ranges = 0; + if (pval) { + memcpy(sdev->device_ranges, pval, len); + sdev->num_device_ranges = + len / sizeof(struct linux_prom_ranges); } -#endif /* CONFIG_SPARC64 */ - -#ifdef CONFIG_SPARC32 - len = prom_getproperty(prom_node, "intr", - (char *)irqs, sizeof(irqs)); - if (len != -1) { - sdev->num_irqs = len / 8; - if (sdev->num_irqs == 0) { - sdev->irqs[0] = 0; - } else if (sparc_cpu_model == sun4d) { - extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); - - for (len = 0; len < sdev->num_irqs; len++) - sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri); - } else { - for (len = 0; len < sdev->num_irqs; len++) - sdev->irqs[len] = irqs[len].pri; - } - } else { - /* No "intr" node found-- check for "interrupts" node. - * This node contains SBus interrupt levels, not IPLs - * as in "intr", and no vector values. We convert - * SBus interrupt levels to PILs (platform specific). - */ - len = prom_getproperty(prom_node, "interrupts", - (char *)interrupts, sizeof(interrupts)); - if (len == -1) { - sdev->irqs[0] = 0; - sdev->num_irqs = 0; - } else { - sdev->num_irqs = len / sizeof(int); - for (len = 0; len < sdev->num_irqs; len++) { - sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]); - } - } - } -#endif /* CONFIG_SPARC32 */ -} -/* This routine gets called from whoever needs the sbus first, to scan - * the SBus device tree. Currently it just prints out the devices - * found on the bus and builds trees of SBUS structs and attached - * devices. - */ + sbus_fill_device_irq(sdev); -extern void iommu_init(int iommu_node, struct sbus_bus *sbus); -extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus); -void sun4_init(void); -#ifdef CONFIG_SUN_AUXIO -extern void auxio_probe(void); -#endif - -static void __init sbus_do_child_siblings(int start_node, - struct sbus_dev *child, - struct sbus_dev *parent, - struct sbus_bus *sbus) -{ - struct sbus_dev *this_dev = child; - int this_node = start_node; - - /* Child already filled in, just need to traverse siblings. */ - child->child = NULL; - child->parent = parent; - while((this_node = prom_getsibling(this_node)) != 0) { - this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - this_dev = this_dev->next; - this_dev->next = NULL; - this_dev->parent = parent; - - this_dev->bus = sbus; - fill_sbus_device(this_node, this_dev); - - if(prom_getchild(this_node)) { - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(this_node), this_dev->child); - sbus_do_child_siblings(prom_getchild(this_node), - this_dev->child, this_dev, sbus); - } else { - this_dev->child = NULL; - } - } -} + sdev->ofdev.node = dp; + if (sdev->parent) + sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; + else + sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; + sdev->ofdev.dev.bus = &sbus_bus_type; + strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name); -/* - * XXX This functions appears to be a distorted version of - * prom_sbus_ranges_init(), with all sun4d stuff cut away. - * Ask DaveM what is going on here, how is sun4d supposed to work... XXX - */ -/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ + if (of_device_register(&sdev->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + sdev->ofdev.dev.bus_id); +} -static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus) +static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) { + void *pval; int len; - len = prom_getproperty(sbus->prom_node, "ranges", - (char *) sbus->sbus_ranges, - sizeof(sbus->sbus_ranges)); - if (len == -1 || len == 0) { - sbus->num_sbus_ranges = 0; - return; - } - sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges); -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) { - struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; - int num_iounit_ranges; - - len = prom_getproperty(parent_node, "ranges", - (char *) iounit_ranges, - sizeof (iounit_ranges)); - if (len != -1) { - num_iounit_ranges = (len/sizeof(struct linux_prom_ranges)); - prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges); - } + pval = of_get_property(dp, "ranges", &len); + sbus->num_sbus_ranges = 0; + if (pval) { + memcpy(sbus->sbus_ranges, pval, len); + sbus->num_sbus_ranges = + len / sizeof(struct linux_prom_ranges); + + sbus_arch_bus_ranges_init(dp->parent, sbus); } -#endif } static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, @@ -322,241 +160,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) } } -extern void register_proc_sparc_ioport(void); -extern void firetruck_init(void); +/* We preserve the "probe order" of these bus and device lists to give + * the same ordering as the old code. + */ +static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) +{ + while (*root) + root = &(*root)->next; + *root = sbus; + sbus->next = NULL; +} -#ifdef CONFIG_SUN4 -extern void sun4_dvma_init(void); -#endif +static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) +{ + while (*root) + root = &(*root)->next; + *root = sdev; + sdev->next = NULL; +} -static int __init sbus_init(void) +static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) { - int nd, this_sbus, sbus_devs, topnd, iommund; - unsigned int sbus_clock; - struct sbus_bus *sbus; - struct sbus_dev *this_dev; - int num_sbus = 0; /* How many did we find? */ + dp = dp->child; + while (dp) { + struct sbus_dev *sdev; -#ifdef CONFIG_SPARC32 - register_proc_sparc_ioport(); -#endif + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &parent->child); -#ifdef CONFIG_SUN4 - sun4_dvma_init(); - return 0; -#endif - - topnd = prom_getchild(prom_root_node); - - /* Finding the first sbus is a special case... */ - iommund = 0; - if(sparc_cpu_model == sun4u) { - nd = prom_searchsiblings(topnd, "sbus"); - if(nd == 0) { -#ifdef CONFIG_PCI - if (!pcic_present()) { - prom_printf("Neither SBUS nor PCI found.\n"); - prom_halt(); - } else { -#ifdef CONFIG_SPARC64 - firetruck_init(); -#endif - } - return 0; -#else - prom_printf("YEEE, UltraSparc sbus not found\n"); - prom_halt(); -#endif - } - } else if(sparc_cpu_model == sun4d) { - if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 || - (nd = prom_getchild(iommund)) == 0 || - (nd = prom_searchsiblings(nd, "sbi")) == 0) { - panic("sbi not found"); - } - } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) { - if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || - (nd = prom_getchild(iommund)) == 0 || - (nd = prom_searchsiblings(nd, "sbus")) == 0) { -#ifdef CONFIG_PCI - if (!pcic_present()) { - prom_printf("Neither SBUS nor PCI found.\n"); - prom_halt(); - } - return 0; -#else - /* No reason to run further - the data access trap will occur. */ - panic("sbus not found"); -#endif + sdev->bus = sbus; + sdev->parent = parent; + + fill_sbus_device(dp, sdev); + + walk_children(dp, sdev, sbus); } + dp = dp->sibling; } +} - /* Ok, we've found the first one, allocate first SBus struct - * and place in chain. - */ - sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - sbus->next = NULL; - sbus->prom_node = nd; - this_sbus = nd; +static void __init build_one_sbus(struct device_node *dp, int num_sbus) +{ + struct sbus_bus *sbus; + unsigned int sbus_clock; + struct device_node *dev_dp; - if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) - iommu_init(iommund, sbus); + sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); + if (!sbus) + return; - /* Loop until we find no more SBUS's */ - while(this_sbus) { -#ifdef CONFIG_SPARC64 - /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */ - if(sparc_cpu_model == sun4u) { - extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus); + sbus_insert(sbus, &sbus_root); + sbus->prom_node = dp->node; - sbus_iommu_init(this_sbus, sbus); - } -#endif /* CONFIG_SPARC64 */ - -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) - iounit_init(this_sbus, iommund, sbus); -#endif /* CONFIG_SPARC32 */ - printk("sbus%d: ", num_sbus); - sbus_clock = prom_getint(this_sbus, "clock-frequency"); - if(sbus_clock == -1) - sbus_clock = (25*1000*1000); - printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), - (int) (((sbus_clock/1000)%1000 != 0) ? - (((sbus_clock/1000)%1000) + 1000) : 0)); - - prom_getstring(this_sbus, "name", - sbus->prom_name, sizeof(sbus->prom_name)); - sbus->clock_freq = sbus_clock; -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) { - sbus->devid = prom_getint(iommund, "device-id"); - sbus->board = prom_getint(iommund, "board#"); - } -#endif - - sbus_bus_ranges_init(iommund, sbus); - - sbus_devs = prom_getchild(this_sbus); - if (!sbus_devs) { - sbus->devices = NULL; - goto next_bus; - } + sbus_setup_iommu(sbus, dp); - sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - - this_dev = sbus->devices; - this_dev->next = NULL; - - this_dev->bus = sbus; - this_dev->parent = NULL; - fill_sbus_device(sbus_devs, this_dev); - - /* Should we traverse for children? */ - if(prom_getchild(sbus_devs)) { - /* Allocate device node */ - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - /* Fill it */ - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(sbus_devs), - this_dev->child); - sbus_do_child_siblings(prom_getchild(sbus_devs), - this_dev->child, - this_dev, - sbus); - } else { - this_dev->child = NULL; - } + printk("sbus%d: ", num_sbus); - while((sbus_devs = prom_getsibling(sbus_devs)) != 0) { - /* Allocate device node */ - this_dev->next = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - this_dev = this_dev->next; - this_dev->next = NULL; - - /* Fill it */ - this_dev->bus = sbus; - this_dev->parent = NULL; - fill_sbus_device(sbus_devs, this_dev); - - /* Is there a child node hanging off of us? */ - if(prom_getchild(sbus_devs)) { - /* Get new device struct */ - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - /* Fill it */ - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(sbus_devs), - this_dev->child); - sbus_do_child_siblings(prom_getchild(sbus_devs), - this_dev->child, - this_dev, - sbus); - } else { - this_dev->child = NULL; - } + sbus_clock = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + sbus->clock_freq = sbus_clock; + + printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), + (int) (((sbus_clock/1000)%1000 != 0) ? + (((sbus_clock/1000)%1000) + 1000) : 0)); + + strcpy(sbus->prom_name, dp->name); + + sbus_setup_arch_props(sbus, dp); + + sbus_bus_ranges_init(dp, sbus); + + sbus->ofdev.node = dp; + sbus->ofdev.dev.parent = NULL; + sbus->ofdev.dev.bus = &sbus_bus_type; + strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name); + + if (of_device_register(&sbus->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + sbus->ofdev.dev.bus_id); + + dev_dp = dp->child; + while (dev_dp) { + struct sbus_dev *sdev; + + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &sbus->devices); + + sdev->bus = sbus; + sdev->parent = NULL; + fill_sbus_device(dev_dp, sdev); + + walk_children(dev_dp, sdev, sbus); } + dev_dp = dev_dp->sibling; + } - /* Walk all devices and apply parent ranges. */ - sbus_fixup_all_regs(sbus->devices); + sbus_fixup_all_regs(sbus->devices); - dvma_init(sbus); - next_bus: + dvma_init(sbus); +} + +static int __init sbus_init(void) +{ + struct device_node *dp; + const char *sbus_name = "sbus"; + int num_sbus = 0; + + if (sbus_arch_preinit()) + return 0; + + if (sparc_cpu_model == sun4d) + sbus_name = "sbi"; + + for_each_node_by_name(dp, sbus_name) { + build_one_sbus(dp, num_sbus); num_sbus++; - if(sparc_cpu_model == sun4u) { - this_sbus = prom_getsibling(this_sbus); - if(!this_sbus) - break; - this_sbus = prom_searchsiblings(this_sbus, "sbus"); - } else if(sparc_cpu_model == sun4d) { - iommund = prom_getsibling(iommund); - if(!iommund) - break; - iommund = prom_searchsiblings(iommund, "io-unit"); - if(!iommund) - break; - this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi"); - } else { - this_sbus = prom_getsibling(this_sbus); - if(!this_sbus) - break; - this_sbus = prom_searchsiblings(this_sbus, "sbus"); - } - if(this_sbus) { - sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - sbus = sbus->next; - sbus->next = NULL; - sbus->prom_node = this_sbus; - } else { - break; - } - } /* while(this_sbus) */ - if (sparc_cpu_model == sun4d) { - extern void sun4d_init_sbi_irq(void); - sun4d_init_sbi_irq(); - } - -#ifdef CONFIG_SPARC64 - if (sparc_cpu_model == sun4u) { - firetruck_init(); } -#endif -#ifdef CONFIG_SUN_AUXIO - if (sparc_cpu_model == sun4u) - auxio_probe (); -#endif -#ifdef CONFIG_SPARC64 - if (sparc_cpu_model == sun4u) { - extern void clock_probe(void); - - clock_probe(); - } -#endif + + sbus_arch_postinit(); return 0; } diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 0a3e45d7a972..ddb512463b45 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1,7 +1,6 @@ -/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $ - * esp.c: EnhancedScsiProcessor Sun SCSI driver code. +/* esp.c: ESP Sun SCSI driver. * - * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net) */ /* TODO: @@ -185,11 +184,6 @@ enum { /*5*/ do_intr_end }; -/* The master ring of all esp hosts we are managing in this driver. */ -static struct esp *espchain; -static DEFINE_SPINLOCK(espchain_lock); -static int esps_running = 0; - /* Forward declarations. */ static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); @@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp) sbus_readb(esp->eregs + ESP_INTRPT); } -static void esp_chain_add(struct esp *esp) -{ - spin_lock_irq(&espchain_lock); - if (espchain) { - struct esp *elink = espchain; - while (elink->next) - elink = elink->next; - elink->next = esp; - } else { - espchain = esp; - } - esp->next = NULL; - spin_unlock_irq(&espchain_lock); -} - -static void esp_chain_del(struct esp *esp) -{ - spin_lock_irq(&espchain_lock); - if (espchain == esp) { - espchain = esp->next; - } else { - struct esp *elink = espchain; - while (elink->next != esp) - elink = elink->next; - elink->next = esp->next; - } - esp->next = NULL; - spin_unlock_irq(&espchain_lock); -} - static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev) { struct sbus_dev *sdev = esp->sdev; @@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp) static void __init esp_get_scsi_id(struct esp *esp) { struct sbus_dev *sdev = esp->sdev; + struct device_node *dp = sdev->ofdev.node; - esp->scsi_id = prom_getintdefault(esp->prom_node, - "initiator-id", - -1); + esp->scsi_id = of_getintprop_default(dp, + "initiator-id", + -1); if (esp->scsi_id == -1) - esp->scsi_id = prom_getintdefault(esp->prom_node, - "scsi-initiator-id", - -1); + esp->scsi_id = of_getintprop_default(dp, + "scsi-initiator-id", + -1); if (esp->scsi_id == -1) esp->scsi_id = (sdev->bus == NULL) ? 7 : - prom_getintdefault(sdev->bus->prom_node, - "scsi-initiator-id", - 7); + of_getintprop_default(sdev->bus->ofdev.node, + "scsi-initiator-id", + 7); esp->ehost->this_id = esp->scsi_id; esp->scsi_id_mask = (1 << esp->scsi_id); @@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp) esp->prev_hme_dmacsr = 0xffffffff; } -static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev, - struct sbus_dev *espdma, struct sbus_bus *sbus, - int id, int hme) +static int __init detect_one_esp(struct scsi_host_template *tpnt, + struct device *dev, + struct sbus_dev *esp_dev, + struct sbus_dev *espdma, + struct sbus_bus *sbus, + int hme) { - struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp)); + static int instance; + struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp)); struct esp *esp; - if (!esp_host) { - printk("ESP: Cannot register SCSI host\n"); - return -1; - } + if (!esp_host) + return -ENOMEM; + if (hme) esp_host->max_id = 16; esp = (struct esp *) esp_host->hostdata; esp->ehost = esp_host; esp->sdev = esp_dev; - esp->esp_id = id; + esp->esp_id = instance; esp->prom_node = esp_dev->prom_node; prom_getstring(esp->prom_node, "name", esp->prom_name, sizeof(esp->prom_name)); - esp_chain_add(esp); if (esp_find_dvma(esp, espdma) < 0) goto fail_unlink; if (esp_map_regs(esp, hme) < 0) { @@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de esp_bootup_reset(esp); + if (scsi_add_host(esp_host, dev)) + goto fail_free_irq; + + dev_set_drvdata(&esp_dev->ofdev.dev, esp); + + scsi_scan_host(esp_host); + instance++; + return 0; +fail_free_irq: + free_irq(esp->ehost->irq, esp); + fail_unmap_cmdarea: sbus_free_consistent(esp->sdev, 16, (void *) esp->esp_command, @@ -1129,119 +1107,98 @@ fail_dvma_release: esp->dma->allocated = 0; fail_unlink: - esp_chain_del(esp); - scsi_unregister(esp_host); + scsi_host_put(esp_host); return -1; } /* Detecting ESP chips on the machine. This is the simple and easy * version. */ +static int __devexit esp_remove_common(struct esp *esp) +{ + unsigned int irq = esp->ehost->irq; + + scsi_remove_host(esp->ehost); + + ESP_INTSOFF(esp->dregs); +#if 0 + esp_reset_dma(esp); + esp_reset_esp(esp); +#endif + + free_irq(irq, esp); + sbus_free_consistent(esp->sdev, 16, + (void *) esp->esp_command, esp->esp_command_dvma); + sbus_iounmap(esp->eregs, ESP_REG_SIZE); + esp->dma->allocated = 0; + + scsi_host_put(esp->ehost); + + return 0; +} + #ifdef CONFIG_SUN4 #include <asm/sun4paddr.h> -static int __init esp_detect(struct scsi_host_template *tpnt) -{ - static struct sbus_dev esp_dev; - int esps_in_use = 0; - - espchain = NULL; +static struct sbus_dev sun4_esp_dev; +static int __init esp_sun4_probe(struct scsi_host_template *tpnt) +{ if (sun4_esp_physaddr) { - memset (&esp_dev, 0, sizeof(esp_dev)); - esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; - esp_dev.irqs[0] = 4; - esp_dev.resource[0].start = sun4_esp_physaddr; - esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1; - esp_dev.resource[0].flags = IORESOURCE_IO; - - if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0)) - esps_in_use++; - printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use); - esps_running = esps_in_use; + memset(&sun4_esp_dev, 0, sizeof(esp_dev)); + sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; + sun4_esp_dev.irqs[0] = 4; + sun4_esp_dev.resource[0].start = sun4_esp_physaddr; + sun4_esp_dev.resource[0].end = + sun4_esp_physaddr + ESP_REG_SIZE - 1; + sun4_esp_dev.resource[0].flags = IORESOURCE_IO; + + return detect_one_esp(tpnt, NULL, + &sun4_esp_dev, NULL, NULL, 0); } - return esps_in_use; + return 0; } -#else /* !CONFIG_SUN4 */ - -static int __init esp_detect(struct scsi_host_template *tpnt) +static int __devexit esp_sun4_remove(void) { - struct sbus_bus *sbus; - struct sbus_dev *esp_dev, *sbdev_iter; - int nesps = 0, esps_in_use = 0; + struct esp *esp = dev_get_drvdata(&dev->dev); - espchain = 0; - if (!sbus_root) { -#ifdef CONFIG_PCI - return 0; -#else - panic("No SBUS in esp_detect()"); -#endif - } - for_each_sbus(sbus) { - for_each_sbusdev(sbdev_iter, sbus) { - struct sbus_dev *espdma = NULL; - int hme = 0; - - /* Is it an esp sbus device? */ - esp_dev = sbdev_iter; - if (strcmp(esp_dev->prom_name, "esp") && - strcmp(esp_dev->prom_name, "SUNW,esp")) { - if (!strcmp(esp_dev->prom_name, "SUNW,fas")) { - hme = 1; - espdma = esp_dev; - } else { - if (!esp_dev->child || - (strcmp(esp_dev->prom_name, "espdma") && - strcmp(esp_dev->prom_name, "dma"))) - continue; /* nope... */ - espdma = esp_dev; - esp_dev = esp_dev->child; - if (strcmp(esp_dev->prom_name, "esp") && - strcmp(esp_dev->prom_name, "SUNW,esp")) - continue; /* how can this happen? */ - } - } - - if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0) - continue; - - esps_in_use++; - } /* for each sbusdev */ - } /* for each sbus */ - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, - esps_in_use); - esps_running = esps_in_use; - return esps_in_use; + return esp_remove_common(esp); } -#endif /* !CONFIG_SUN4 */ +#else /* !CONFIG_SUN4 */ -/* - */ -static int esp_release(struct Scsi_Host *host) +static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct esp *esp = (struct esp *) host->hostdata; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + struct sbus_dev *dma_sdev = NULL; + int hme = 0; + + if (dp->parent && + (!strcmp(dp->parent->name, "espdma") || + !strcmp(dp->parent->name, "dma"))) + dma_sdev = sdev->parent; + else if (!strcmp(dp->name, "SUNW,fas")) { + dma_sdev = sdev; + hme = 1; + } - ESP_INTSOFF(esp->dregs); -#if 0 - esp_reset_dma(esp); - esp_reset_esp(esp); -#endif + return detect_one_esp(match->data, &dev->dev, + sdev, dma_sdev, sdev->bus, hme); +} - free_irq(esp->ehost->irq, esp); - sbus_free_consistent(esp->sdev, 16, - (void *) esp->esp_command, esp->esp_command_dvma); - sbus_iounmap(esp->eregs, ESP_REG_SIZE); - esp->dma->allocated = 0; - esp_chain_del(esp); +static int __devexit esp_sbus_remove(struct of_device *dev) +{ + struct esp *esp = dev_get_drvdata(&dev->dev); - return 0; + return esp_remove_common(esp); } +#endif /* !CONFIG_SUN4 */ + /* The info function will return whatever useful * information the developer sees fit. If not provided, then * the name field will be used instead. @@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) { - struct esp *esp; + struct esp *esp = (struct esp *) host->hostdata; if (inout) return -EINVAL; /* not yet */ - for_each_esp(esp) { - if (esp->ehost == host) - break; - } - if (!esp) - return -EINVAL; - if (start) *start = buffer; @@ -4377,15 +4327,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr) SDptr->hostdata = NULL; } -static struct scsi_host_template driver_template = { - .proc_name = "esp", - .proc_info = esp_proc_info, - .name = "Sun ESP 100/100a/200", - .detect = esp_detect, +static struct scsi_host_template esp_template = { + .module = THIS_MODULE, + .name = "esp", + .info = esp_info, .slave_alloc = esp_slave_alloc, .slave_destroy = esp_slave_destroy, - .release = esp_release, - .info = esp_info, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, @@ -4394,12 +4341,58 @@ static struct scsi_host_template driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .proc_name = "esp", + .proc_info = esp_proc_info, +}; + +#ifndef CONFIG_SUN4 +static struct of_device_id esp_match[] = { + { + .name = "SUNW,esp", + .data = &esp_template, + }, + { + .name = "SUNW,fas", + .data = &esp_template, + }, + { + .name = "esp", + .data = &esp_template, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, esp_match); + +static struct of_platform_driver esp_sbus_driver = { + .name = "esp", + .match_table = esp_match, + .probe = esp_sbus_probe, + .remove = __devexit_p(esp_sbus_remove), }; +#endif + +static int __init esp_init(void) +{ +#ifdef CONFIG_SUN4 + return esp_sun4_probe(&esp_template); +#else + return of_register_driver(&esp_sbus_driver, &sbus_bus_type); +#endif +} -#include "scsi_module.c" +static void __exit esp_exit(void) +{ +#ifdef CONFIG_SUN4 + esp_sun4_remove(); +#else + of_unregister_driver(&esp_sbus_driver); +#endif +} -MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver"); -MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("ESP Sun SCSI driver"); +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +module_init(esp_init); +module_exit(esp_exit); diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h index 73f7d6968ab6..a98cda9121fc 100644 --- a/drivers/scsi/esp.h +++ b/drivers/scsi/esp.h @@ -403,8 +403,4 @@ struct esp { #define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) #define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) -/* For our interrupt engine. */ -#define for_each_esp(esp) \ - for((esp) = espchain; (esp); (esp) = (esp)->next) - #endif /* !(_SPARC_ESP_H) */ diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 2203103adced..329ead263714 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1,6 +1,6 @@ /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net) * * A lot of this driver was directly stolen from Erik H. Moe's PCI * Qlogic ISP driver. Mucho kudos to him for this code. @@ -46,8 +46,6 @@ #include <scsi/scsi_tcq.h> #include <scsi/scsi_host.h> - - #define MAX_TARGETS 16 #define MAX_LUNS 8 /* 32 for 1.31 F/W */ @@ -57,7 +55,6 @@ static struct qlogicpti *qptichain = NULL; static DEFINE_SPINLOCK(qptichain_lock); -static int qptis_running = 0; #define PACKB(a, b) (((a)<<4)|(b)) @@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti) return 0; } -/* Detect all PTI Qlogic ISP's in the machine. */ -static int __init qlogicpti_detect(struct scsi_host_template *tpnt) -{ - struct qlogicpti *qpti; - struct Scsi_Host *qpti_host; - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int nqptis = 0, nqptis_in_use = 0; - - tpnt->proc_name = "qlogicpti"; - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - /* Is this a red snapper? */ - if (strcmp(sdev->prom_name, "ptisp") && - strcmp(sdev->prom_name, "PTI,ptisp") && - strcmp(sdev->prom_name, "QLGC,isp") && - strcmp(sdev->prom_name, "SUNW,isp")) - continue; - - /* Sometimes Antares cards come up not completely - * setup, and we get a report of a zero IRQ. - * Skip over them in such cases so we survive. - */ - if (sdev->irqs[0] == 0) { - printk("qpti%d: Adapter reports no interrupt, " - "skipping over this card.", nqptis); - continue; - } - - /* Yep, register and allocate software state. */ - qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti)); - if (!qpti_host) { - printk("QPTI: Cannot register PTI Qlogic ISP SCSI host"); - continue; - } - qpti = (struct qlogicpti *) qpti_host->hostdata; - - /* We are wide capable, 16 targets. */ - qpti_host->max_id = MAX_TARGETS; - - /* Setup back pointers and misc. state. */ - qpti->qhost = qpti_host; - qpti->sdev = sdev; - qpti->qpti_id = nqptis++; - qpti->prom_node = sdev->prom_node; - prom_getstring(qpti->prom_node, "name", - qpti->prom_name, - sizeof(qpti->prom_name)); - - /* This is not correct, actually. There's a switch - * on the PTI cards that put them into "emulation" - * mode- i.e., report themselves as QLGC,isp - * instead of PTI,ptisp. The only real substantive - * difference between non-pti and pti cards is - * the tmon register. Which is possibly even - * there for Qlogic cards, but non-functional. - */ - qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0); - - qpti_chain_add(qpti); - if (qpti_map_regs(qpti) < 0) - goto fail_unlink; - - if (qpti_register_irq(qpti) < 0) - goto fail_unmap_regs; - - qpti_get_scsi_id(qpti); - qpti_get_bursts(qpti); - qpti_get_clock(qpti); - - /* Clear out scsi_cmnd array. */ - memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots)); - - if (qpti_map_queues(qpti) < 0) - goto fail_free_irq; - - /* Load the firmware. */ - if (qlogicpti_load_firmware(qpti)) - goto fail_unmap_queues; - if (qpti->is_pti) { - /* Check the PTI status reg. */ - if (qlogicpti_verify_tmon(qpti)) - goto fail_unmap_queues; - } - - /* Reset the ISP and init res/req queues. */ - if (qlogicpti_reset_hardware(qpti_host)) - goto fail_unmap_queues; - - printk("(Firmware v%d.%d.%d)", qpti->fware_majrev, - qpti->fware_minrev, qpti->fware_micrev); - { - char buffer[60]; - - prom_getstring (qpti->prom_node, - "isp-fcode", buffer, 60); - if (buffer[0]) - printk("(Firmware %s)", buffer); - if (prom_getbool(qpti->prom_node, "differential")) - qpti->differential = 1; - } - - printk (" [%s Wide, using %s interface]\n", - (qpti->ultra ? "Ultra" : "Fast"), - (qpti->differential ? "differential" : "single ended")); - - nqptis_in_use++; - continue; - - fail_unmap_queues: -#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - sbus_free_consistent(qpti->sdev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - sbus_free_consistent(qpti->sdev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); -#undef QSIZE - fail_free_irq: - free_irq(qpti->irq, qpti); - - fail_unmap_regs: - sbus_iounmap(qpti->qregs, - qpti->sdev->reg_addrs[0].reg_size); - if (qpti->is_pti) - sbus_iounmap(qpti->sreg, sizeof(unsigned char)); - fail_unlink: - qpti_chain_del(qpti); - scsi_unregister(qpti->qhost); - } - } - if (nqptis) - printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n", - nqptis, nqptis_in_use); - qptis_running = nqptis_in_use; - return nqptis; -} - -static int qlogicpti_release(struct Scsi_Host *host) -{ - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - - /* Remove visibility from IRQ handlers. */ - qpti_chain_del(qpti); - - /* Shut up the card. */ - sbus_writew(0, qpti->qregs + SBUS_CTRL); - - /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */ - free_irq(qpti->irq, qpti); - -#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - sbus_free_consistent(qpti->sdev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - sbus_free_consistent(qpti->sdev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); -#undef QSIZE - - sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size); - if (qpti->is_pti) - sbus_iounmap(qpti->sreg, sizeof(unsigned char)); - - return 0; -} - const char *qlogicpti_info(struct Scsi_Host *host) { static char buf[80]; @@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd) return return_status; } -static struct scsi_host_template driver_template = { - .detect = qlogicpti_detect, - .release = qlogicpti_release, +static struct scsi_host_template qpti_template = { + .module = THIS_MODULE, + .name = "qlogicpti", .info = qlogicpti_info, .queuecommand = qlogicpti_queuecommand_slow, .eh_abort_handler = qlogicpti_abort, @@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = { .use_clustering = ENABLE_CLUSTERING, }; +static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + static int nqptis; + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + struct scsi_host_template *tpnt = match->data; + struct Scsi_Host *host; + struct qlogicpti *qpti; + char *fcode; + + /* Sometimes Antares cards come up not completely + * setup, and we get a report of a zero IRQ. + */ + if (sdev->irqs[0] == 0) + return -ENODEV; + + host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); + if (!host) + return -ENOMEM; + + qpti = (struct qlogicpti *) host->hostdata; + + host->max_id = MAX_TARGETS; + qpti->qhost = host; + qpti->sdev = sdev; + qpti->qpti_id = nqptis; + qpti->prom_node = sdev->prom_node; + strcpy(qpti->prom_name, sdev->ofdev.node->name); + qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp"); + + if (qpti_map_regs(qpti) < 0) + goto fail_unlink; + + if (qpti_register_irq(qpti) < 0) + goto fail_unmap_regs; + + qpti_get_scsi_id(qpti); + qpti_get_bursts(qpti); + qpti_get_clock(qpti); + + /* Clear out scsi_cmnd array. */ + memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots)); + + if (qpti_map_queues(qpti) < 0) + goto fail_free_irq; + + /* Load the firmware. */ + if (qlogicpti_load_firmware(qpti)) + goto fail_unmap_queues; + if (qpti->is_pti) { + /* Check the PTI status reg. */ + if (qlogicpti_verify_tmon(qpti)) + goto fail_unmap_queues; + } + + /* Reset the ISP and init res/req queues. */ + if (qlogicpti_reset_hardware(host)) + goto fail_unmap_queues; + + if (scsi_add_host(host, &dev->dev)) + goto fail_unmap_queues; + + printk("(Firmware v%d.%d.%d)", qpti->fware_majrev, + qpti->fware_minrev, qpti->fware_micrev); + + fcode = of_get_property(dp, "isp-fcode", NULL); + if (fcode && fcode[0]) + printk("(Firmware %s)", fcode); + if (of_find_property(dp, "differential", NULL) != NULL) + qpti->differential = 1; + + printk (" [%s Wide, using %s interface]\n", + (qpti->ultra ? "Ultra" : "Fast"), + (qpti->differential ? "differential" : "single ended")); + + dev_set_drvdata(&sdev->ofdev.dev, qpti); + + qpti_chain_add(qpti); + + scsi_scan_host(host); + nqptis++; + + return 0; + +fail_unmap_queues: +#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) + sbus_free_consistent(qpti->sdev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); +#undef QSIZE + +fail_unmap_regs: + sbus_iounmap(qpti->qregs, + qpti->sdev->reg_addrs[0].reg_size); + if (qpti->is_pti) + sbus_iounmap(qpti->sreg, sizeof(unsigned char)); + +fail_free_irq: + free_irq(qpti->irq, qpti); + +fail_unlink: + scsi_host_put(host); + + return -ENODEV; +} + +static int __devexit qpti_sbus_remove(struct of_device *dev) +{ + struct qlogicpti *qpti = dev_get_drvdata(&dev->dev); + + qpti_chain_del(qpti); + + scsi_remove_host(qpti->qhost); + + /* Shut up the card. */ + sbus_writew(0, qpti->qregs + SBUS_CTRL); + + /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */ + free_irq(qpti->irq, qpti); + +#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) + sbus_free_consistent(qpti->sdev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + sbus_free_consistent(qpti->sdev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); +#undef QSIZE + + sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size); + if (qpti->is_pti) + sbus_iounmap(qpti->sreg, sizeof(unsigned char)); + + scsi_host_put(qpti->qhost); + + return 0; +} + +static struct of_device_id qpti_match[] = { + { + .name = "ptisp", + .data = &qpti_template, + }, + { + .name = "PTI,ptisp", + .data = &qpti_template, + }, + { + .name = "QLGC,isp", + .data = &qpti_template, + }, + { + .name = "SUNW,isp", + .data = &qpti_template, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, qpti_match); + +static struct of_platform_driver qpti_sbus_driver = { + .name = "qpti", + .match_table = qpti_match, + .probe = qpti_sbus_probe, + .remove = __devexit_p(qpti_sbus_remove), +}; -#include "scsi_module.c" +static int __init qpti_init(void) +{ + return of_register_driver(&qpti_sbus_driver, &sbus_bus_type); +} + +static void __exit qpti_exit(void) +{ + of_unregister_driver(&qpti_sbus_driver); +} +MODULE_DESCRIPTION("QlogicISP SBUS driver"); +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_LICENSE("GPL"); +MODULE_VERSION("2.0"); +module_init(qpti_init); +module_exit(qpti_exit); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bef4a9622ed7..5b48ac22c9c5 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE kernel at boot time.) config SERIAL_S3C2410 - tristate "Samsung S3C2410 Serial port support" + tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support" depends on ARM && ARCH_S3C2410 select SERIAL_CORE help - Support for the on-chip UARTs on the Samsung S3C2410X CPU, + Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of these ports, depending on how the serial port pins are configured. + Currently this driver supports the UARTS on the S3C2410, S3C2440, + S3C2442, S3C2412 and S3C2413 CPUs. + config SERIAL_S3C2410_CONSOLE bool "Support for console on S3C2410 serial port" depends on SERIAL_S3C2410=y select SERIAL_CORE_CONSOLE help - Allow selection of the S3C2410 on-board serial ports for use as + Allow selection of the S3C24XX on-board serial ports for use as an virtual console. Even if you say Y here, the currently visible virtual console diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 53c2465bad2d..837b6da520b3 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port) return "S3C2410"; case PORT_S3C2440: return "S3C2440"; + case PORT_S3C2412: + return "S3C2412"; default: return NULL; } @@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void) #define s3c2440_uart_inf_at NULL #endif /* CONFIG_CPU_S3C2440 */ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + +static int s3c2412_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~S3C2412_UCON_CLKMASK; + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2440_UCON_UCLK; + else if (strcmp(clk->name, "pclk") == 0) + ucon |= S3C2440_UCON_PCLK; + else if (strcmp(clk->name, "usysclk") == 0) + ucon |= S3C2412_UCON_USYSCLK; + else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s3c2412_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + switch (ucon & S3C2412_UCON_CLKMASK) { + case S3C2412_UCON_UCLK: + clk->divisor = 1; + clk->name = "uclk"; + break; + + case S3C2412_UCON_PCLK: + case S3C2412_UCON_PCLK2: + clk->divisor = 1; + clk->name = "pclk"; + break; + + case S3C2412_UCON_USYSCLK: + clk->divisor = 1; + clk->name = "usysclk"; + break; + } + + return 0; +} + +static int s3c2412_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + dbg("%s: port=%p (%08lx), cfg=%p\n", + __FUNCTION__, port, port->mapbase, cfg); + + /* ensure we don't change the clock settings... */ + + ucon &= S3C2412_UCON_CLKMASK; + + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2412_uart_inf = { + .name = "Samsung S3C2412 UART", + .type = PORT_S3C2412, + .fifosize = 64, + .rx_fifomask = S3C2440_UFSTAT_RXMASK, + .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2440_UFSTAT_RXFULL, + .tx_fifofull = S3C2440_UFSTAT_TXFULL, + .tx_fifomask = S3C2440_UFSTAT_TXMASK, + .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, + .get_clksrc = s3c2412_serial_getsource, + .set_clksrc = s3c2412_serial_setsource, + .reset_port = s3c2412_serial_resetport, +}; + +/* device management */ + +static int s3c2412_serial_probe(struct platform_device *dev) +{ + dbg("s3c2440_serial_probe: dev=%p\n", dev); + return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); +} + +static struct platform_driver s3c2412_serial_drv = { + .probe = s3c2412_serial_probe, + .remove = s3c24xx_serial_remove, + .suspend = s3c24xx_serial_suspend, + .resume = s3c24xx_serial_resume, + .driver = { + .name = "s3c2412-uart", + .owner = THIS_MODULE, + }, +}; + + +static inline int s3c2412_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf); +} + +static inline void s3c2412_serial_exit(void) +{ + platform_driver_unregister(&s3c2412_serial_drv); +} + +#define s3c2412_uart_inf_at &s3c2412_uart_inf +#else + +static inline int s3c2412_serial_init(void) +{ + return 0; +} + +static inline void s3c2412_serial_exit(void) +{ +} + +#define s3c2412_uart_inf_at NULL +#endif /* CONFIG_CPU_S3C2440 */ + + /* module initialisation code */ static int __init s3c24xx_serial_modinit(void) @@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void) s3c2400_serial_init(); s3c2410_serial_init(); + s3c2412_serial_init(); s3c2440_serial_init(); return 0; @@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void) { s3c2400_serial_exit(); s3c2410_serial_exit(); + s3c2412_serial_exit(); s3c2440_serial_exit(); uart_unregister_driver(&s3c24xx_uart_drv); @@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void) info = s3c2410_uart_inf_at; } else if (strcmp(dev->name, "s3c2440-uart") == 0) { info = s3c2440_uart_inf_at; + } else if (strcmp(dev->name, "s3c2412-uart") == 0) { + info = s3c2412_uart_inf_at; } else { printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name); return 0; @@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver"); +MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver"); diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index f137804b3133..ba22e256c6f7 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -427,31 +427,32 @@ static int __init hv_console_compatible(char *buf, int len) static unsigned int __init get_interrupt(void) { - const char *cons_str = "console"; - const char *compat_str = "compatible"; - int node = prom_getchild(sun4v_vdev_root); - char buf[64]; - int err, len; - - node = prom_searchsiblings(node, cons_str); - if (!node) - return 0; + struct device_node *dev_node; - len = prom_getproplen(node, compat_str); - if (len == 0 || len == -1) - return 0; + dev_node = sun4v_vdev_root->child; + while (dev_node != NULL) { + struct property *prop; - err = prom_getproperty(node, compat_str, buf, 64); - if (err == -1) - return 0; + if (strcmp(dev_node->name, "console")) + goto next_sibling; + + prop = of_find_property(dev_node, "compatible", NULL); + if (!prop) + goto next_sibling; - if (!hv_console_compatible(buf, len)) + if (hv_console_compatible(prop->value, prop->length)) + break; + + next_sibling: + dev_node = dev_node->sibling; + } + if (!dev_node) return 0; /* Ok, the this is the OBP node for the sun4v hypervisor * console device. Decode the interrupt. */ - return sun4v_vdev_device_interrupt(node); + return sun4v_vdev_device_interrupt(dev_node); } static int __init sunhv_init(void) diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index bfbe9dc90cca..e4c0fd2d6a9d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -984,19 +984,19 @@ static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device * for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "se")) { + if (!strcmp(edev->prom_node->name, "se")) { callback(edev, arg); continue; - } else if (!strcmp(edev->prom_name, "serial")) { - char compat[32]; + } else if (!strcmp(edev->prom_node->name, "serial")) { + char *compat; int clen; /* On RIO this can be an SE, check it. We could * just check ebus->is_rio, but this is more portable. */ - clen = prom_getproperty(edev->prom_node, "compatible", - compat, sizeof(compat)); - if (clen > 0) { + compat = of_get_property(edev->prom_node, + "compatible", &clen); + if (compat && clen > 0) { if (strncmp(compat, "sab82532", 8) == 0) { callback(edev, arg); continue; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 4cdb610cdd37..0268b307c01e 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1053,7 +1053,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) */ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { - if (dev->prom_node == up->port_node) { + if (dev->prom_node->node == up->port_node) { /* * The EBus is broken on sparc; it delivers * virtual addresses in resources. Oh well... @@ -1073,7 +1073,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) #ifdef CONFIG_SPARC64 for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (isa_dev->prom_node == up->port_node) { + if (isa_dev->prom_node->node == up->port_node) { /* Same on sparc64. Cool architecure... */ up->port.membase = (char *) isa_dev->resource.start; up->port.mapbase = isa_dev->resource.start; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 5b6569728a9c..76c9bac9271f 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1106,7 +1106,7 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) + FHC_UREGS_ICLR; imap = central_bus->child->fhc_regs.uregs + FHC_UREGS_IMAP; - zilog_irq = build_irq(12, 0, iclr, imap); + zilog_irq = build_irq(0, iclr, imap); } else { err = prom_getproperty(zsnode, "interrupts", (char *) &sun4u_ino, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3f8e06279c92..bcbeaf7101d1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1078,9 +1078,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - return proc_do_submiturb(ps, &uurb, - (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc, - arg); + return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); } static int proc_unlinkurb(struct dev_state *ps, void __user *arg) @@ -1205,9 +1203,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) return -EFAULT; - return proc_do_submiturb(ps, &uurb, - (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc, - arg); + return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg); } static int processcompl_compat(struct async *as, void __user * __user *arg) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index eb6aa42be60e..c054bb28b1c4 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2966,7 +2966,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, } pcp = pdev->sysdata; - if (node == pcp->prom_node) { + if (node == pcp->prom_node->node) { struct fb_var_screeninfo *var = &default_var; unsigned int N, P, Q, M, T, R; u32 v_total, h_total; diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 469b06c29180..e290d7460e1b 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -237,7 +237,7 @@ struct intelfb_info { u32 fb_start; /* ring buffer */ - u8 __iomem *ring_head; + u32 ring_head; u32 ring_tail; u32 ring_tail_mask; u32 ring_space; diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 076fa56be192..0a0a8b199ecc 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -707,7 +707,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) + (dinfo->ring.offset << 12); dinfo->ring.virtual = dinfo->aperture.virtual + (dinfo->ring.offset << 12); - dinfo->ring_head = dinfo->ring.virtual; + dinfo->ring_head = 0; } if (dinfo->hwcursor) { agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY @@ -766,18 +766,18 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) if (mtrr) set_mtrr(dinfo); - DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", + DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n", dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, - (u32 __iomem ) dinfo->fb.virtual); - DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", + dinfo->fb.virtual); + DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n", dinfo->mmio_base_phys, INTEL_REG_SIZE, - (u32 __iomem) dinfo->mmio_base); - DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", + dinfo->mmio_base); + DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n", dinfo->ring.physical, dinfo->ring.size, - (u32 __iomem ) dinfo->ring.virtual); - DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", + dinfo->ring.virtual); + DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n", dinfo->cursor.physical, dinfo->cursor.size, - (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset, + dinfo->cursor.virtual, dinfo->cursor.offset, dinfo->cursor.physical); DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 426b7430b125..7533b3dd08ac 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -1423,19 +1423,17 @@ wait_ring(struct intelfb_info *dinfo, int n) end = jiffies + (HZ * 3); while (dinfo->ring_space < n) { - dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) & - RING_HEAD_MASK); - if (dinfo->ring_tail + RING_MIN_FREE < - (u32 __iomem) dinfo->ring_head) - dinfo->ring_space = (u32 __iomem) dinfo->ring_head + dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; + if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head) + dinfo->ring_space = dinfo->ring_head - (dinfo->ring_tail + RING_MIN_FREE); else dinfo->ring_space = (dinfo->ring.size + - (u32 __iomem) dinfo->ring_head) + dinfo->ring_head) - (dinfo->ring_tail + RING_MIN_FREE); - if ((u32 __iomem) dinfo->ring_head != last_head) { + if (dinfo->ring_head != last_head) { end = jiffies + (HZ * 3); - last_head = (u32 __iomem) dinfo->ring_head; + last_head = dinfo->ring_head; } i++; if (time_before(end, jiffies)) { @@ -1495,15 +1493,13 @@ refresh_ring(struct intelfb_info *dinfo) DBG_MSG("refresh_ring\n"); #endif - dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) & - RING_HEAD_MASK); + dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; - if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head) - dinfo->ring_space = (u32 __iomem) dinfo->ring_head + if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head) + dinfo->ring_space = dinfo->ring_head - (dinfo->ring_tail + RING_MIN_FREE); else - dinfo->ring_space = (dinfo->ring.size + - (u32 __iomem) dinfo->ring_head) + dinfo->ring_space = (dinfo->ring.size + dinfo->ring_head) - (dinfo->ring_tail + RING_MIN_FREE); } |