diff options
author | Greg KH <greg@press.(none)> | 2005-10-28 10:13:16 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 10:13:16 -0700 |
commit | 6fbfddcb52d8d9fa2cd209f5ac2a1c87497d55b5 (patch) | |
tree | c0414e89678fcef7ce3493e048d855bde781ae8d /drivers | |
parent | 1a222bca26ca691e83be1b08f5e96ae96d0d8cae (diff) | |
parent | 27d1097d39509494706eaa2620ef3b1e780a3224 (diff) | |
download | blackbird-op-linux-6fbfddcb52d8d9fa2cd209f5ac2a1c87497d55b5.tar.gz blackbird-op-linux-6fbfddcb52d8d9fa2cd209f5ac2a1c87497d55b5.zip |
Merge ../bleed-2.6
Diffstat (limited to 'drivers')
230 files changed, 11543 insertions, 5911 deletions
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 95c0a3690b0f..4081c36c8c19 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -98,7 +98,6 @@ struct as_data { struct as_rq *next_arq[2]; /* next in sort order */ sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned long exit_prob; /* probability a task will exit while @@ -239,6 +238,25 @@ static struct io_context *as_get_io_context(void) return ioc; } +static void as_put_io_context(struct as_rq *arq) +{ + struct as_io_context *aic; + + if (unlikely(!arq->io_context)) + return; + + aic = arq->io_context->aic; + + if (arq->is_sync == REQ_SYNC && aic) { + spin_lock(&aic->lock); + set_bit(AS_TASK_IORUNNING, &aic->state); + aic->last_end_request = jiffies; + spin_unlock(&aic->lock); + } + + put_io_context(arq->io_context); +} + /* * the back merge hash support functions */ @@ -261,14 +279,6 @@ static inline void as_del_arq_hash(struct as_rq *arq) __as_del_arq_hash(arq); } -static void as_remove_merge_hints(request_queue_t *q, struct as_rq *arq) -{ - as_del_arq_hash(arq); - - if (q->last_merge == arq->request) - q->last_merge = NULL; -} - static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; @@ -312,7 +322,7 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) BUG_ON(!arq->on_hash); if (!rq_mergeable(__rq)) { - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); continue; } @@ -950,23 +960,12 @@ static void as_completed_request(request_queue_t *q, struct request *rq) WARN_ON(!list_empty(&rq->queuelist)); - if (arq->state == AS_RQ_PRESCHED) { - WARN_ON(arq->io_context); - goto out; - } - - if (arq->state == AS_RQ_MERGED) - goto out_ioc; - if (arq->state != AS_RQ_REMOVED) { printk("arq->state %d\n", arq->state); WARN_ON(1); goto out; } - if (!blk_fs_request(rq)) - goto out; - if (ad->changed_batch && ad->nr_dispatched == 1) { kblockd_schedule_work(&ad->antic_work); ad->changed_batch = 0; @@ -1001,21 +1000,7 @@ static void as_completed_request(request_queue_t *q, struct request *rq) } } -out_ioc: - if (!arq->io_context) - goto out; - - if (arq->is_sync == REQ_SYNC) { - struct as_io_context *aic = arq->io_context->aic; - if (aic) { - spin_lock(&aic->lock); - set_bit(AS_TASK_IORUNNING, &aic->state); - aic->last_end_request = jiffies; - spin_unlock(&aic->lock); - } - } - - put_io_context(arq->io_context); + as_put_io_context(arq); out: arq->state = AS_RQ_POSTSCHED; } @@ -1047,73 +1032,11 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) ad->next_arq[data_dir] = as_find_next_arq(ad, arq); list_del_init(&arq->fifo); - as_remove_merge_hints(q, arq); + as_del_arq_hash(arq); as_del_arq_rb(ad, arq); } /* - * as_remove_dispatched_request is called to remove a request which has gone - * to the dispatch list. - */ -static void as_remove_dispatched_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - struct as_io_context *aic; - - if (!arq) { - WARN_ON(1); - return; - } - - WARN_ON(arq->state != AS_RQ_DISPATCHED); - WARN_ON(ON_RB(&arq->rb_node)); - if (arq->io_context && arq->io_context->aic) { - aic = arq->io_context->aic; - if (aic) { - WARN_ON(!atomic_read(&aic->nr_dispatched)); - atomic_dec(&aic->nr_dispatched); - } - } -} - -/* - * as_remove_request is called when a driver has finished with a request. - * This should be only called for dispatched requests, but for some reason - * a POWER4 box running hwscan it does not. - */ -static void as_remove_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - - if (unlikely(arq->state == AS_RQ_NEW)) - goto out; - - if (ON_RB(&arq->rb_node)) { - if (arq->state != AS_RQ_QUEUED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - /* - * We'll lose the aliased request(s) here. I don't think this - * will ever happen, but if it does, hopefully someone will - * report it. - */ - WARN_ON(!list_empty(&rq->queuelist)); - as_remove_queued_request(q, rq); - } else { - if (arq->state != AS_RQ_DISPATCHED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - as_remove_dispatched_request(q, rq); - } -out: - arq->state = AS_RQ_REMOVED; -} - -/* * as_fifo_expired returns 0 if there are no expired reads on the fifo, * 1 otherwise. It is ratelimited so that we only perform the check once per * `fifo_expire' interval. Otherwise a large number of expired requests @@ -1165,7 +1088,6 @@ static inline int as_batch_expired(struct as_data *ad) static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; - struct list_head *insert; const int data_dir = arq->is_sync; BUG_ON(!ON_RB(&arq->rb_node)); @@ -1198,13 +1120,13 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) /* * take it off the sort and fifo list, add to dispatch queue */ - insert = ad->dispatch->prev; - while (!list_empty(&rq->queuelist)) { struct request *__rq = list_entry_rq(rq->queuelist.next); struct as_rq *__arq = RQ_DATA(__rq); - list_move_tail(&__rq->queuelist, ad->dispatch); + list_del(&__rq->queuelist); + + elv_dispatch_add_tail(ad->q, __rq); if (__arq->io_context && __arq->io_context->aic) atomic_inc(&__arq->io_context->aic->nr_dispatched); @@ -1218,7 +1140,8 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) as_remove_queued_request(ad->q, rq); WARN_ON(arq->state != AS_RQ_QUEUED); - list_add(&rq->queuelist, insert); + elv_dispatch_sort(ad->q, rq); + arq->state = AS_RQ_DISPATCHED; if (arq->io_context && arq->io_context->aic) atomic_inc(&arq->io_context->aic->nr_dispatched); @@ -1230,12 +1153,42 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) * read/write expire, batch expire, etc, and moves it to the dispatch * queue. Returns 1 if a request was found, 0 otherwise. */ -static int as_dispatch_request(struct as_data *ad) +static int as_dispatch_request(request_queue_t *q, int force) { + struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq; const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]); const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]); + if (unlikely(force)) { + /* + * Forced dispatch, accounting is useless. Reset + * accounting states and dump fifo_lists. Note that + * batch_data_dir is reset to REQ_SYNC to avoid + * screwing write batch accounting as write batch + * accounting occurs on W->R transition. + */ + int dispatched = 0; + + ad->batch_data_dir = REQ_SYNC; + ad->changed_batch = 0; + ad->new_batch = 0; + + while (ad->next_arq[REQ_SYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_SYNC] = jiffies; + + while (ad->next_arq[REQ_ASYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_ASYNC] = jiffies; + + return dispatched; + } + /* Signal that the write batch was uncontended, so we can't time it */ if (ad->batch_data_dir == REQ_ASYNC && !reads) { if (ad->current_write_count == 0 || !writes) @@ -1359,20 +1312,6 @@ fifo_expired: return 1; } -static struct request *as_next_request(request_queue_t *q) -{ - struct as_data *ad = q->elevator->elevator_data; - struct request *rq = NULL; - - /* - * if there are still requests on the dispatch queue, grab the first - */ - if (!list_empty(ad->dispatch) || as_dispatch_request(ad)) - rq = list_entry_rq(ad->dispatch->next); - - return rq; -} - /* * Add arq to a list behind alias */ @@ -1404,17 +1343,25 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia /* * Don't want to have to handle merges. */ - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); } /* * add arq to rbtree and fifo */ -static void as_add_request(struct as_data *ad, struct as_rq *arq) +static void as_add_request(request_queue_t *q, struct request *rq) { + struct as_data *ad = q->elevator->elevator_data; + struct as_rq *arq = RQ_DATA(rq); struct as_rq *alias; int data_dir; + if (arq->state != AS_RQ_PRESCHED) { + printk("arq->state: %d\n", arq->state); + WARN_ON(1); + } + arq->state = AS_RQ_NEW; + if (rq_data_dir(arq->request) == READ || current->flags&PF_SYNCWRITE) arq->is_sync = 1; @@ -1437,12 +1384,8 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->expires = jiffies + ad->fifo_expire[data_dir]; list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]); - if (rq_mergeable(arq->request)) { + if (rq_mergeable(arq->request)) as_add_arq_hash(ad, arq); - - if (!ad->q->last_merge) - ad->q->last_merge = arq->request; - } as_update_arq(ad, arq); /* keep state machine up to date */ } else { @@ -1463,96 +1406,24 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->state = AS_RQ_QUEUED; } -static void as_deactivate_request(request_queue_t *q, struct request *rq) +static void as_activate_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state == AS_RQ_REMOVED) { - arq->state = AS_RQ_DISPATCHED; - if (arq->io_context && arq->io_context->aic) - atomic_inc(&arq->io_context->aic->nr_dispatched); - } - } else - WARN_ON(blk_fs_request(rq) - && (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) ); - - /* Stop anticipating - let this request get through */ - as_antic_stop(ad); -} - -/* - * requeue the request. The request has not been completed, nor is it a - * new request, so don't touch accounting. - */ -static void as_requeue_request(request_queue_t *q, struct request *rq) -{ - as_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); -} - -/* - * Account a request that is inserted directly onto the dispatch queue. - * arq->io_context->aic->nr_dispatched should not need to be incremented - * because only new requests should come through here: requeues go through - * our explicit requeue handler. - */ -static void as_account_queued_request(struct as_data *ad, struct request *rq) -{ - if (blk_fs_request(rq)) { - struct as_rq *arq = RQ_DATA(rq); - arq->state = AS_RQ_DISPATCHED; - ad->nr_dispatched++; - } + WARN_ON(arq->state != AS_RQ_DISPATCHED); + arq->state = AS_RQ_REMOVED; + if (arq->io_context && arq->io_context->aic) + atomic_dec(&arq->io_context->aic->nr_dispatched); } -static void -as_insert_request(request_queue_t *q, struct request *rq, int where) +static void as_deactivate_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state != AS_RQ_PRESCHED) { - printk("arq->state: %d\n", arq->state); - WARN_ON(1); - } - arq->state = AS_RQ_NEW; - } - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) { - WARN_ON(1); - where = ELEVATOR_INSERT_BACK; - } - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (ad->next_arq[REQ_SYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); - - while (ad->next_arq[REQ_ASYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); - - list_add_tail(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - as_add_request(ad, arq); - break; - default: - BUG(); - return; - } + WARN_ON(arq->state != AS_RQ_REMOVED); + arq->state = AS_RQ_DISPATCHED; + if (arq->io_context && arq->io_context->aic) + atomic_inc(&arq->io_context->aic->nr_dispatched); } /* @@ -1565,12 +1436,8 @@ static int as_queue_empty(request_queue_t *q) { struct as_data *ad = q->elevator->elevator_data; - if (!list_empty(&ad->fifo_list[REQ_ASYNC]) - || !list_empty(&ad->fifo_list[REQ_SYNC]) - || !list_empty(ad->dispatch)) - return 0; - - return 1; + return list_empty(&ad->fifo_list[REQ_ASYNC]) + && list_empty(&ad->fifo_list[REQ_SYNC]); } static struct request * @@ -1608,15 +1475,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) int ret; /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - - /* * see if the merge hash can satisfy a back merge */ __rq = as_find_arq_hash(ad, bio->bi_sector); @@ -1644,9 +1502,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - if (rq_mergeable(__rq)) - q->last_merge = __rq; -out_insert: if (ret) { if (rq_mergeable(__rq)) as_hot_arq_hash(ad, RQ_DATA(__rq)); @@ -1693,9 +1548,6 @@ static void as_merged_request(request_queue_t *q, struct request *req) * behind the disk head. We currently don't bother adjusting. */ } - - if (arq->on_hash) - q->last_merge = req; } static void @@ -1763,6 +1615,7 @@ as_merged_requests(request_queue_t *q, struct request *req, * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); + as_put_io_context(anext); anext->state = AS_RQ_MERGED; } @@ -1782,7 +1635,7 @@ static void as_work_handler(void *data) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - if (as_next_request(q)) + if (!as_queue_empty(q)) q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1797,7 +1650,9 @@ static void as_put_request(request_queue_t *q, struct request *rq) return; } - if (arq->state != AS_RQ_POSTSCHED && arq->state != AS_RQ_PRESCHED) { + if (unlikely(arq->state != AS_RQ_POSTSCHED && + arq->state != AS_RQ_PRESCHED && + arq->state != AS_RQ_MERGED)) { printk("arq->state %d\n", arq->state); WARN_ON(1); } @@ -1807,7 +1662,7 @@ static void as_put_request(request_queue_t *q, struct request *rq) } static int as_set_request(request_queue_t *q, struct request *rq, - struct bio *bio, int gfp_mask) + struct bio *bio, gfp_t gfp_mask) { struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask); @@ -1907,7 +1762,6 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); ad->sort_list[REQ_SYNC] = RB_ROOT; ad->sort_list[REQ_ASYNC] = RB_ROOT; - ad->dispatch = &q->queue_head; ad->fifo_expire[REQ_SYNC] = default_read_expire; ad->fifo_expire[REQ_ASYNC] = default_write_expire; ad->antic_expire = default_antic_expire; @@ -2072,10 +1926,9 @@ static struct elevator_type iosched_as = { .elevator_merge_fn = as_merge, .elevator_merged_fn = as_merged_request, .elevator_merge_req_fn = as_merged_requests, - .elevator_next_req_fn = as_next_request, - .elevator_add_req_fn = as_insert_request, - .elevator_remove_req_fn = as_remove_request, - .elevator_requeue_req_fn = as_requeue_request, + .elevator_dispatch_fn = as_dispatch_request, + .elevator_add_req_fn = as_add_request, + .elevator_activate_req_fn = as_activate_request, .elevator_deactivate_req_fn = as_deactivate_request, .elevator_queue_empty_fn = as_queue_empty, .elevator_completed_req_fn = as_completed_request, diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index cd056e7e64ec..94690e4d41e0 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -84,7 +84,6 @@ static int cfq_max_depth = 2; (node)->rb_left = NULL; \ } while (0) #define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) -#define ON_RB(node) ((node)->rb_color != RB_NONE) #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) #define rq_rb_key(rq) (rq)->sector @@ -271,10 +270,7 @@ CFQ_CFQQ_FNS(expired); #undef CFQ_CFQQ_FNS enum cfq_rq_state_flags { - CFQ_CRQ_FLAG_in_flight = 0, - CFQ_CRQ_FLAG_in_driver, - CFQ_CRQ_FLAG_is_sync, - CFQ_CRQ_FLAG_requeued, + CFQ_CRQ_FLAG_is_sync = 0, }; #define CFQ_CRQ_FNS(name) \ @@ -291,14 +287,11 @@ static inline int cfq_crq_##name(const struct cfq_rq *crq) \ return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \ } -CFQ_CRQ_FNS(in_flight); -CFQ_CRQ_FNS(in_driver); CFQ_CRQ_FNS(is_sync); -CFQ_CRQ_FNS(requeued); #undef CFQ_CRQ_FNS static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); -static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *); +static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); static void cfq_put_cfqd(struct cfq_data *cfqd); #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) @@ -311,14 +304,6 @@ static inline void cfq_del_crq_hash(struct cfq_rq *crq) hlist_del_init(&crq->hash); } -static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq) -{ - cfq_del_crq_hash(crq); - - if (q->last_merge == crq->request) - q->last_merge = NULL; -} - static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) { const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); @@ -347,18 +332,13 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) return NULL; } -static inline int cfq_pending_requests(struct cfq_data *cfqd) -{ - return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues; -} - /* * scheduler run of queue, if there are requests pending and no one in the * driver that will restart queueing */ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { - if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd)) + if (!cfqd->rq_in_driver && cfqd->busy_queues) kblockd_schedule_work(&cfqd->unplug_work); } @@ -366,7 +346,7 @@ static int cfq_queue_empty(request_queue_t *q) { struct cfq_data *cfqd = q->elevator->elevator_data; - return !cfq_pending_requests(cfqd); + return !cfqd->busy_queues; } /* @@ -386,11 +366,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) if (crq2 == NULL) return crq1; - if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) - return crq1; - else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) - return crq2; - if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) return crq1; else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) @@ -461,10 +436,7 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq_next = NULL, *crq_prev = NULL; struct rb_node *rbnext, *rbprev; - rbnext = NULL; - if (ON_RB(&last->rb_node)) - rbnext = rb_next(&last->rb_node); - if (!rbnext) { + if (!(rbnext = rb_next(&last->rb_node))) { rbnext = rb_first(&cfqq->sort_list); if (rbnext == &last->rb_node) rbnext = NULL; @@ -545,13 +517,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) * the pending list according to last request service */ static inline void -cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue) +cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { BUG_ON(cfq_cfqq_on_rr(cfqq)); cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; - cfq_resort_rr_list(cfqq, requeue); + cfq_resort_rr_list(cfqq, 0); } static inline void @@ -571,22 +543,19 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) static inline void cfq_del_crq_rb(struct cfq_rq *crq) { struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); - if (ON_RB(&crq->rb_node)) { - struct cfq_data *cfqd = cfqq->cfqd; - const int sync = cfq_crq_is_sync(crq); + BUG_ON(!cfqq->queued[sync]); + cfqq->queued[sync]--; - BUG_ON(!cfqq->queued[sync]); - cfqq->queued[sync]--; + cfq_update_next_crq(crq); - cfq_update_next_crq(crq); + rb_erase(&crq->rb_node, &cfqq->sort_list); + RB_CLEAR_COLOR(&crq->rb_node); - rb_erase(&crq->rb_node, &cfqq->sort_list); - RB_CLEAR_COLOR(&crq->rb_node); - - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) - cfq_del_cfqq_rr(cfqd, cfqq); - } + if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) + cfq_del_cfqq_rr(cfqd, cfqq); } static struct cfq_rq * @@ -627,12 +596,12 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) * if that happens, put the alias on the dispatch list */ while ((__alias = __cfq_add_crq_rb(crq)) != NULL) - cfq_dispatch_sort(cfqd->queue, __alias); + cfq_dispatch_insert(cfqd->queue, __alias); rb_insert_color(&crq->rb_node, &cfqq->sort_list); if (!cfq_cfqq_on_rr(cfqq)) - cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq)); + cfq_add_cfqq_rr(cfqd, cfqq); /* * check if this request is a better next-serve candidate @@ -643,10 +612,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) static inline void cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) { - if (ON_RB(&crq->rb_node)) { - rb_erase(&crq->rb_node, &cfqq->sort_list); - cfqq->queued[cfq_crq_is_sync(crq)]--; - } + rb_erase(&crq->rb_node, &cfqq->sort_list); + cfqq->queued[cfq_crq_is_sync(crq)]--; cfq_add_crq_rb(crq); } @@ -676,49 +643,28 @@ out: return NULL; } -static void cfq_deactivate_request(request_queue_t *q, struct request *rq) +static void cfq_activate_request(request_queue_t *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_rq *crq = RQ_DATA(rq); - - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - - if (cfq_crq_in_driver(crq)) { - cfq_clear_crq_in_driver(crq); - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - } - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); - cfq_clear_crq_in_flight(crq); - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; - } - cfq_mark_crq_requeued(crq); - } + cfqd->rq_in_driver++; } -/* - * make sure the service time gets corrected on reissue of this request - */ -static void cfq_requeue_request(request_queue_t *q, struct request *rq) +static void cfq_deactivate_request(request_queue_t *q, struct request *rq) { - cfq_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); + struct cfq_data *cfqd = q->elevator->elevator_data; + + WARN_ON(!cfqd->rq_in_driver); + cfqd->rq_in_driver--; } -static void cfq_remove_request(request_queue_t *q, struct request *rq) +static void cfq_remove_request(struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - if (crq) { - list_del_init(&rq->queuelist); - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - } + list_del_init(&rq->queuelist); + cfq_del_crq_rb(crq); + cfq_del_crq_hash(crq); } static int @@ -728,12 +674,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_BACK_MERGE; @@ -748,8 +688,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: *req = __rq; return ret; } @@ -762,14 +700,12 @@ static void cfq_merged_request(request_queue_t *q, struct request *req) cfq_del_crq_hash(crq); cfq_add_crq_hash(cfqd, crq); - if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { + if (rq_rb_key(req) != crq->rb_key) { struct cfq_queue *cfqq = crq->cfq_queue; cfq_update_next_crq(crq); cfq_reposition_crq_rb(cfqq, crq); } - - q->last_merge = req; } static void @@ -785,7 +721,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq, time_before(next->start_time, rq->start_time)) list_move(&rq->queuelist, &next->queuelist); - cfq_remove_request(q, next); + cfq_remove_request(next); } static inline void @@ -992,53 +928,15 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) return 1; } -/* - * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues, - * this function sector sorts the selected request to minimize seeks. we start - * at cfqd->last_sector, not 0. - */ -static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq) +static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = crq->cfq_queue; - struct list_head *head = &q->queue_head, *entry = head; - struct request *__rq; - sector_t last; - - list_del(&crq->request->queuelist); - - last = cfqd->last_sector; - list_for_each_entry_reverse(__rq, head, queuelist) { - struct cfq_rq *__crq = RQ_DATA(__rq); - - if (blk_barrier_rq(__rq)) - break; - if (!blk_fs_request(__rq)) - break; - if (cfq_crq_requeued(__crq)) - break; - - if (__rq->sector <= crq->request->sector) - break; - if (__rq->sector > last && crq->request->sector < last) { - last = crq->request->sector + crq->request->nr_sectors; - break; - } - entry = &__rq->queuelist; - } - - cfqd->last_sector = last; cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq); - - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - cfq_mark_crq_in_flight(crq); - cfq_clear_crq_requeued(crq); - + cfq_remove_request(crq->request); cfqq->on_dispatch[cfq_crq_is_sync(crq)]++; - list_add_tail(&crq->request->queuelist, entry); + elv_dispatch_sort(q, crq->request); } /* @@ -1159,7 +1057,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, /* * finally, insert request into driver dispatch list */ - cfq_dispatch_sort(cfqd->queue, crq); + cfq_dispatch_insert(cfqd->queue, crq); cfqd->dispatch_slice++; dispatched++; @@ -1194,7 +1092,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, } static int -cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) +cfq_dispatch_requests(request_queue_t *q, int force) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq; @@ -1204,12 +1102,25 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) cfqq = cfq_select_queue(cfqd, force); if (cfqq) { + int max_dispatch; + + /* + * if idle window is disabled, allow queue buildup + */ + if (!cfq_cfqq_idle_window(cfqq) && + cfqd->rq_in_driver >= cfqd->cfq_max_depth) + return 0; + cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); del_timer(&cfqd->idle_slice_timer); - if (cfq_class_idle(cfqq)) - max_dispatch = 1; + if (!force) { + max_dispatch = cfqd->cfq_quantum; + if (cfq_class_idle(cfqq)) + max_dispatch = 1; + } else + max_dispatch = INT_MAX; return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); } @@ -1217,93 +1128,6 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) return 0; } -static inline void cfq_account_dispatch(struct cfq_rq *crq) -{ - struct cfq_queue *cfqq = crq->cfq_queue; - struct cfq_data *cfqd = cfqq->cfqd; - - if (unlikely(!blk_fs_request(crq->request))) - return; - - /* - * accounted bit is necessary since some drivers will call - * elv_next_request() many times for the same request (eg ide) - */ - if (cfq_crq_in_driver(crq)) - return; - - cfq_mark_crq_in_driver(crq); - cfqd->rq_in_driver++; -} - -static inline void -cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq) -{ - struct cfq_data *cfqd = cfqq->cfqd; - unsigned long now; - - if (!cfq_crq_in_driver(crq)) - return; - - now = jiffies; - - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - - if (!cfq_class_idle(cfqq)) - cfqd->last_end_request = now; - - if (!cfq_cfqq_dispatched(cfqq)) { - if (cfq_cfqq_on_rr(cfqq)) { - cfqq->service_last = now; - cfq_resort_rr_list(cfqq, 0); - } - if (cfq_cfqq_expired(cfqq)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - } - - if (cfq_crq_is_sync(crq)) - crq->io_context->last_end_request = now; -} - -static struct request *cfq_next_request(request_queue_t *q) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct request *rq; - - if (!list_empty(&q->queue_head)) { - struct cfq_rq *crq; -dispatch: - rq = list_entry_rq(q->queue_head.next); - - crq = RQ_DATA(rq); - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - - /* - * if idle window is disabled, allow queue buildup - */ - if (!cfq_crq_in_driver(crq) && - !cfq_cfqq_idle_window(cfqq) && - !blk_barrier_rq(rq) && - cfqd->rq_in_driver >= cfqd->cfq_max_depth) - return NULL; - - cfq_remove_merge_hints(q, crq); - cfq_account_dispatch(crq); - } - - return rq; - } - - if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0)) - goto dispatch; - - return NULL; -} - /* * task holds one reference to the queue, dropped when task exits. each crq * in-flight on this queue also holds a reference, dropped when crq is freed. @@ -1422,7 +1246,7 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) } static struct cfq_io_context * -cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask) +cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) { struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); @@ -1517,7 +1341,7 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, - int gfp_mask) + gfp_t gfp_mask) { const int hashval = hash_long(key, CFQ_QHASH_SHIFT); struct cfq_queue *cfqq, *new_cfqq = NULL; @@ -1578,7 +1402,7 @@ out: * cfqq, so we don't need to worry about it disappearing */ static struct cfq_io_context * -cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask) +cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) { struct io_context *ioc = NULL; struct cfq_io_context *cic; @@ -1816,8 +1640,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } } -static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) +static void cfq_insert_request(request_queue_t *q, struct request *rq) { + struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_rq *crq = RQ_DATA(rq); struct cfq_queue *cfqq = crq->cfq_queue; @@ -1827,66 +1652,43 @@ static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) list_add_tail(&rq->queuelist, &cfqq->fifo); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) cfq_add_crq_hash(cfqd, crq); - if (!cfqd->queue->last_merge) - cfqd->queue->last_merge = rq; - } - cfq_crq_enqueued(cfqd, cfqq, crq); } -static void -cfq_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (cfq_dispatch_requests(q, INT_MAX, 1)) - ; - list_add_tail(&rq->queuelist, &q->queue_head); - /* - * If we were idling with pending requests on - * inactive cfqqs, force dispatching will - * remove the idle timer and the queue won't - * be kicked by __make_request() afterward. - * Kick it here. - */ - cfq_schedule_dispatch(cfqd); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, &q->queue_head); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - cfq_enqueue(cfqd, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static void cfq_completed_request(request_queue_t *q, struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - struct cfq_queue *cfqq; + struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); + unsigned long now; - if (unlikely(!blk_fs_request(rq))) - return; + now = jiffies; - cfqq = crq->cfq_queue; + WARN_ON(!cfqd->rq_in_driver); + WARN_ON(!cfqq->on_dispatch[sync]); + cfqd->rq_in_driver--; + cfqq->on_dispatch[sync]--; - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); + if (!cfq_class_idle(cfqq)) + cfqd->last_end_request = now; - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; + if (!cfq_cfqq_dispatched(cfqq)) { + if (cfq_cfqq_on_rr(cfqq)) { + cfqq->service_last = now; + cfq_resort_rr_list(cfqq, 0); + } + if (cfq_cfqq_expired(cfqq)) { + __cfq_slice_expired(cfqd, cfqq, 0); + cfq_schedule_dispatch(cfqd); + } } - cfq_account_completion(cfqq, crq); + if (cfq_crq_is_sync(crq)) + crq->io_context->last_end_request = now; } static struct request * @@ -2075,7 +1877,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq) */ static int cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -2118,9 +1920,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, INIT_HLIST_NODE(&crq->hash); crq->cfq_queue = cfqq; crq->io_context = cic; - cfq_clear_crq_in_flight(crq); - cfq_clear_crq_in_driver(crq); - cfq_clear_crq_requeued(crq); if (rw == READ || process_sync(tsk)) cfq_mark_crq_is_sync(crq); @@ -2201,7 +2000,7 @@ static void cfq_idle_slice_timer(unsigned long data) * only expire and reinvoke request handler, if there are * other queues with pending requests */ - if (!cfq_pending_requests(cfqd)) { + if (!cfqd->busy_queues) { cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end); add_timer(&cfqd->idle_slice_timer); goto out_cont; @@ -2576,10 +2375,9 @@ static struct elevator_type iosched_cfq = { .elevator_merge_fn = cfq_merge, .elevator_merged_fn = cfq_merged_request, .elevator_merge_req_fn = cfq_merged_requests, - .elevator_next_req_fn = cfq_next_request, + .elevator_dispatch_fn = cfq_dispatch_requests, .elevator_add_req_fn = cfq_insert_request, - .elevator_remove_req_fn = cfq_remove_request, - .elevator_requeue_req_fn = cfq_requeue_request, + .elevator_activate_req_fn = cfq_activate_request, .elevator_deactivate_req_fn = cfq_deactivate_request, .elevator_queue_empty_fn = cfq_queue_empty, .elevator_completed_req_fn = cfq_completed_request, diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 52a3ae5289a0..7929471d7df7 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -50,7 +50,6 @@ struct deadline_data { * next in sort order. read, write or both are NULL */ struct deadline_rq *next_drq[2]; - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned int batching; /* number of sequential requests made */ sector_t last_sector; /* head position */ @@ -113,15 +112,6 @@ static inline void deadline_del_drq_hash(struct deadline_rq *drq) __deadline_del_drq_hash(drq); } -static void -deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq) -{ - deadline_del_drq_hash(drq); - - if (q->last_merge == drq->request) - q->last_merge = NULL; -} - static inline void deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) { @@ -239,10 +229,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq) dd->next_drq[data_dir] = rb_entry_drq(rbnext); } - if (ON_RB(&drq->rb_node)) { - rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); - RB_CLEAR(&drq->rb_node); - } + BUG_ON(!ON_RB(&drq->rb_node)); + rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); + RB_CLEAR(&drq->rb_node); } static struct request * @@ -286,7 +275,7 @@ deadline_find_first_drq(struct deadline_data *dd, int data_dir) /* * add drq to rbtree and fifo */ -static inline void +static void deadline_add_request(struct request_queue *q, struct request *rq) { struct deadline_data *dd = q->elevator->elevator_data; @@ -301,12 +290,8 @@ deadline_add_request(struct request_queue *q, struct request *rq) drq->expires = jiffies + dd->fifo_expire[data_dir]; list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) deadline_add_drq_hash(dd, drq); - - if (!q->last_merge) - q->last_merge = rq; - } } /* @@ -315,14 +300,11 @@ deadline_add_request(struct request_queue *q, struct request *rq) static void deadline_remove_request(request_queue_t *q, struct request *rq) { struct deadline_rq *drq = RQ_DATA(rq); + struct deadline_data *dd = q->elevator->elevator_data; - if (drq) { - struct deadline_data *dd = q->elevator->elevator_data; - - list_del_init(&drq->fifo); - deadline_remove_merge_hints(q, drq); - deadline_del_drq_rb(dd, drq); - } + list_del_init(&drq->fifo); + deadline_del_drq_rb(dd, drq); + deadline_del_drq_hash(drq); } static int @@ -333,15 +315,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) int ret; /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - - /* * see if the merge hash can satisfy a back merge */ __rq = deadline_find_drq_hash(dd, bio->bi_sector); @@ -373,8 +346,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: if (ret) deadline_hot_drq_hash(dd, RQ_DATA(__rq)); *req = __rq; @@ -399,8 +370,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req) deadline_del_drq_rb(dd, drq); deadline_add_drq_rb(dd, drq); } - - q->last_merge = req; } static void @@ -452,7 +421,7 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq) request_queue_t *q = drq->request->q; deadline_remove_request(q, drq->request); - list_add_tail(&drq->request->queuelist, dd->dispatch); + elv_dispatch_add_tail(q, drq->request); } /* @@ -502,8 +471,9 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) * deadline_dispatch_requests selects the best request according to * read/write expire, fifo_batch, etc */ -static int deadline_dispatch_requests(struct deadline_data *dd) +static int deadline_dispatch_requests(request_queue_t *q, int force) { + struct deadline_data *dd = q->elevator->elevator_data; const int reads = !list_empty(&dd->fifo_list[READ]); const int writes = !list_empty(&dd->fifo_list[WRITE]); struct deadline_rq *drq; @@ -597,65 +567,12 @@ dispatch_request: return 1; } -static struct request *deadline_next_request(request_queue_t *q) -{ - struct deadline_data *dd = q->elevator->elevator_data; - struct request *rq; - - /* - * if there are still requests on the dispatch queue, grab the first one - */ - if (!list_empty(dd->dispatch)) { -dispatch: - rq = list_entry_rq(dd->dispatch->next); - return rq; - } - - if (deadline_dispatch_requests(dd)) - goto dispatch; - - return NULL; -} - -static void -deadline_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct deadline_data *dd = q->elevator->elevator_data; - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) - where = ELEVATOR_INSERT_BACK; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (deadline_dispatch_requests(dd)) - ; - list_add_tail(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - deadline_add_request(q, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static int deadline_queue_empty(request_queue_t *q) { struct deadline_data *dd = q->elevator->elevator_data; - if (!list_empty(&dd->fifo_list[WRITE]) - || !list_empty(&dd->fifo_list[READ]) - || !list_empty(dd->dispatch)) - return 0; - - return 1; + return list_empty(&dd->fifo_list[WRITE]) + && list_empty(&dd->fifo_list[READ]); } static struct request * @@ -733,7 +650,6 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&dd->fifo_list[WRITE]); dd->sort_list[READ] = RB_ROOT; dd->sort_list[WRITE] = RB_ROOT; - dd->dispatch = &q->queue_head; dd->fifo_expire[READ] = read_expire; dd->fifo_expire[WRITE] = write_expire; dd->writes_starved = writes_starved; @@ -748,15 +664,13 @@ static void deadline_put_request(request_queue_t *q, struct request *rq) struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq = RQ_DATA(rq); - if (drq) { - mempool_free(drq, dd->drq_pool); - rq->elevator_private = NULL; - } + mempool_free(drq, dd->drq_pool); + rq->elevator_private = NULL; } static int deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq; @@ -917,9 +831,8 @@ static struct elevator_type iosched_deadline = { .elevator_merge_fn = deadline_merge, .elevator_merged_fn = deadline_merged_request, .elevator_merge_req_fn = deadline_merged_requests, - .elevator_next_req_fn = deadline_next_request, - .elevator_add_req_fn = deadline_insert_request, - .elevator_remove_req_fn = deadline_remove_request, + .elevator_dispatch_fn = deadline_dispatch_requests, + .elevator_add_req_fn = deadline_add_request, .elevator_queue_empty_fn = deadline_queue_empty, .elevator_former_req_fn = deadline_former_request, .elevator_latter_req_fn = deadline_latter_request, diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 98f0126a2deb..55621d5c5774 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/compiler.h> +#include <linux/delay.h> #include <asm/uaccess.h> @@ -83,21 +84,11 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) } EXPORT_SYMBOL(elv_try_merge); -inline int elv_try_last_merge(request_queue_t *q, struct bio *bio) -{ - if (q->last_merge) - return elv_try_merge(q->last_merge, bio); - - return ELEVATOR_NO_MERGE; -} -EXPORT_SYMBOL(elv_try_last_merge); - static struct elevator_type *elevator_find(const char *name) { struct elevator_type *e = NULL; struct list_head *entry; - spin_lock_irq(&elv_list_lock); list_for_each(entry, &elv_list) { struct elevator_type *__e; @@ -108,7 +99,6 @@ static struct elevator_type *elevator_find(const char *name) break; } } - spin_unlock_irq(&elv_list_lock); return e; } @@ -120,12 +110,15 @@ static void elevator_put(struct elevator_type *e) static struct elevator_type *elevator_get(const char *name) { - struct elevator_type *e = elevator_find(name); + struct elevator_type *e; - if (!e) - return NULL; - if (!try_module_get(e->elevator_owner)) - return NULL; + spin_lock_irq(&elv_list_lock); + + e = elevator_find(name); + if (e && !try_module_get(e->elevator_owner)) + e = NULL; + + spin_unlock_irq(&elv_list_lock); return e; } @@ -139,8 +132,6 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, eq->ops = &e->ops; eq->elevator_type = e; - INIT_LIST_HEAD(&q->queue_head); - q->last_merge = NULL; q->elevator = eq; if (eq->ops->elevator_init_fn) @@ -153,11 +144,15 @@ static char chosen_elevator[16]; static void elevator_setup_default(void) { + struct elevator_type *e; + /* * check if default is set and exists */ - if (chosen_elevator[0] && elevator_find(chosen_elevator)) + if (chosen_elevator[0] && (e = elevator_get(chosen_elevator))) { + elevator_put(e); return; + } #if defined(CONFIG_IOSCHED_AS) strcpy(chosen_elevator, "anticipatory"); @@ -186,6 +181,11 @@ int elevator_init(request_queue_t *q, char *name) struct elevator_queue *eq; int ret = 0; + INIT_LIST_HEAD(&q->queue_head); + q->last_merge = NULL; + q->end_sector = 0; + q->boundary_rq = NULL; + elevator_setup_default(); if (!name) @@ -220,9 +220,52 @@ void elevator_exit(elevator_t *e) kfree(e); } +/* + * Insert rq into dispatch queue of q. Queue lock must be held on + * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be + * appended to the dispatch queue. To be used by specific elevators. + */ +void elv_dispatch_sort(request_queue_t *q, struct request *rq) +{ + sector_t boundary; + struct list_head *entry; + + if (q->last_merge == rq) + q->last_merge = NULL; + + boundary = q->end_sector; + + list_for_each_prev(entry, &q->queue_head) { + struct request *pos = list_entry_rq(entry); + + if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) + break; + if (rq->sector >= boundary) { + if (pos->sector < boundary) + continue; + } else { + if (pos->sector >= boundary) + break; + } + if (rq->sector >= pos->sector) + break; + } + + list_add(&rq->queuelist, entry); +} + int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; + int ret; + + if (q->last_merge) { + ret = elv_try_merge(q->last_merge, bio); + if (ret != ELEVATOR_NO_MERGE) { + *req = q->last_merge; + return ret; + } + } if (e->ops->elevator_merge_fn) return e->ops->elevator_merge_fn(q, req, bio); @@ -236,6 +279,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) if (e->ops->elevator_merged_fn) e->ops->elevator_merged_fn(q, rq); + + q->last_merge = rq; } void elv_merge_requests(request_queue_t *q, struct request *rq, @@ -243,20 +288,13 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, { elevator_t *e = q->elevator; - if (q->last_merge == next) - q->last_merge = NULL; - if (e->ops->elevator_merge_req_fn) e->ops->elevator_merge_req_fn(q, rq, next); + + q->last_merge = rq; } -/* - * For careful internal use by the block layer. Essentially the same as - * a requeue in that it tells the io scheduler that this request is not - * active in the driver or hardware anymore, but we don't want the request - * added back to the scheduler. Function is not exported. - */ -void elv_deactivate_request(request_queue_t *q, struct request *rq) +void elv_requeue_request(request_queue_t *q, struct request *rq) { elevator_t *e = q->elevator; @@ -264,19 +302,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq) * it already went through dequeue, we need to decrement the * in_flight count again */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; + if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); + } rq->flags &= ~REQ_STARTED; - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); -} - -void elv_requeue_request(request_queue_t *q, struct request *rq) -{ - elv_deactivate_request(q, rq); - /* * if this is the flush, requeue the original instead and drop the flush */ @@ -285,31 +318,27 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) rq = rq->end_io_data; } - /* - * the request is prepped and may have some resources allocated. - * allowing unprepped requests to pass this one may cause resource - * deadlock. turn on softbarrier. - */ - rq->flags |= REQ_SOFTBARRIER; - - /* - * if iosched has an explicit requeue hook, then use that. otherwise - * just put the request at the front of the queue - */ - if (q->elevator->ops->elevator_requeue_req_fn) - q->elevator->ops->elevator_requeue_req_fn(q, rq); - else - __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); + __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); } void __elv_add_request(request_queue_t *q, struct request *rq, int where, int plug) { - /* - * barriers implicitly indicate back insertion - */ - if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) && - where == ELEVATOR_INSERT_SORT) + if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { + /* + * barriers implicitly indicate back insertion + */ + if (where == ELEVATOR_INSERT_SORT) + where = ELEVATOR_INSERT_BACK; + + /* + * this request is scheduling boundary, update end_sector + */ + if (blk_fs_request(rq)) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = rq; + } + } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) where = ELEVATOR_INSERT_BACK; if (plug) @@ -317,23 +346,54 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, rq->q = q; - if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) { - q->elevator->ops->elevator_add_req_fn(q, rq, where); + switch (where) { + case ELEVATOR_INSERT_FRONT: + rq->flags |= REQ_SOFTBARRIER; - if (blk_queue_plugged(q)) { - int nrq = q->rq.count[READ] + q->rq.count[WRITE] - - q->in_flight; + list_add(&rq->queuelist, &q->queue_head); + break; - if (nrq >= q->unplug_thresh) - __generic_unplug_device(q); - } - } else + case ELEVATOR_INSERT_BACK: + rq->flags |= REQ_SOFTBARRIER; + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + list_add_tail(&rq->queuelist, &q->queue_head); /* - * if drain is set, store the request "locally". when the drain - * is finished, the requests will be handed ordered to the io - * scheduler + * We kick the queue here for the following reasons. + * - The elevator might have returned NULL previously + * to delay requests and returned them now. As the + * queue wasn't empty before this request, ll_rw_blk + * won't run the queue on return, resulting in hang. + * - Usually, back inserted requests won't be merged + * with anything. There's no point in delaying queue + * processing. */ - list_add_tail(&rq->queuelist, &q->drain_list); + blk_remove_plug(q); + q->request_fn(q); + break; + + case ELEVATOR_INSERT_SORT: + BUG_ON(!blk_fs_request(rq)); + rq->flags |= REQ_SORTED; + q->elevator->ops->elevator_add_req_fn(q, rq); + if (q->last_merge == NULL && rq_mergeable(rq)) + q->last_merge = rq; + break; + + default: + printk(KERN_ERR "%s: bad insertion point %d\n", + __FUNCTION__, where); + BUG(); + } + + if (blk_queue_plugged(q)) { + int nrq = q->rq.count[READ] + q->rq.count[WRITE] + - q->in_flight; + + if (nrq >= q->unplug_thresh) + __generic_unplug_device(q); + } } void elv_add_request(request_queue_t *q, struct request *rq, int where, @@ -348,13 +408,19 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, static inline struct request *__elv_next_request(request_queue_t *q) { - struct request *rq = q->elevator->ops->elevator_next_req_fn(q); + struct request *rq; + + if (unlikely(list_empty(&q->queue_head) && + !q->elevator->ops->elevator_dispatch_fn(q, 0))) + return NULL; + + rq = list_entry_rq(q->queue_head.next); /* * if this is a barrier write and the device has to issue a * flush sequence to support it, check how far we are */ - if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) { + if (blk_fs_request(rq) && blk_barrier_rq(rq)) { BUG_ON(q->ordered == QUEUE_ORDERED_NONE); if (q->ordered == QUEUE_ORDERED_FLUSH && @@ -371,15 +437,30 @@ struct request *elv_next_request(request_queue_t *q) int ret; while ((rq = __elv_next_request(q)) != NULL) { - /* - * just mark as started even if we don't start it, a request - * that has been delayed should not be passed by new incoming - * requests - */ - rq->flags |= REQ_STARTED; + if (!(rq->flags & REQ_STARTED)) { + elevator_t *e = q->elevator; - if (rq == q->last_merge) - q->last_merge = NULL; + /* + * This is the first time the device driver + * sees this request (possibly after + * requeueing). Notify IO scheduler. + */ + if (blk_sorted_rq(rq) && + e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); + + /* + * just mark as started even if we don't start + * it, a request that has been delayed should + * not be passed by new incoming requests + */ + rq->flags |= REQ_STARTED; + } + + if (!q->boundary_rq || q->boundary_rq == rq) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = NULL; + } if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn) break; @@ -391,9 +472,9 @@ struct request *elv_next_request(request_queue_t *q) /* * the request may have been (partially) prepped. * we need to keep this request in the front to - * avoid resource deadlock. turn on softbarrier. + * avoid resource deadlock. REQ_STARTED will + * prevent other fs requests from passing this one. */ - rq->flags |= REQ_SOFTBARRIER; rq = NULL; break; } else if (ret == BLKPREP_KILL) { @@ -416,42 +497,32 @@ struct request *elv_next_request(request_queue_t *q) return rq; } -void elv_remove_request(request_queue_t *q, struct request *rq) +void elv_dequeue_request(request_queue_t *q, struct request *rq) { - elevator_t *e = q->elevator; + BUG_ON(list_empty(&rq->queuelist)); + + list_del_init(&rq->queuelist); /* * the time frame between a request being removed from the lists * and to it is freed is accounted as io that is in progress at - * the driver side. note that we only account requests that the - * driver has seen (REQ_STARTED set), to avoid false accounting - * for request-request merges + * the driver side. */ if (blk_account_rq(rq)) q->in_flight++; - - /* - * the main clearing point for q->last_merge is on retrieval of - * request by driver (it calls elv_next_request()), but it _can_ - * also happen here if a request is added to the queue but later - * deleted without ever being given to driver (merged with another - * request). - */ - if (rq == q->last_merge) - q->last_merge = NULL; - - if (e->ops->elevator_remove_req_fn) - e->ops->elevator_remove_req_fn(q, rq); } int elv_queue_empty(request_queue_t *q) { elevator_t *e = q->elevator; + if (!list_empty(&q->queue_head)) + return 0; + if (e->ops->elevator_queue_empty_fn) return e->ops->elevator_queue_empty_fn(q); - return list_empty(&q->queue_head); + return 1; } struct request *elv_latter_request(request_queue_t *q, struct request *rq) @@ -487,7 +558,7 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq) } int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { elevator_t *e = q->elevator; @@ -523,11 +594,11 @@ void elv_completed_request(request_queue_t *q, struct request *rq) /* * request is released from the driver, io must be done */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; - - if (e->ops->elevator_completed_req_fn) - e->ops->elevator_completed_req_fn(q, rq); + if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) + e->ops->elevator_completed_req_fn(q, rq); + } } int elv_register_queue(struct request_queue *q) @@ -555,10 +626,9 @@ void elv_unregister_queue(struct request_queue *q) int elv_register(struct elevator_type *e) { + spin_lock_irq(&elv_list_lock); if (elevator_find(e->elevator_name)) BUG(); - - spin_lock_irq(&elv_list_lock); list_add_tail(&e->list, &elv_list); spin_unlock_irq(&elv_list_lock); @@ -582,25 +652,36 @@ EXPORT_SYMBOL_GPL(elv_unregister); * switch to new_e io scheduler. be careful not to introduce deadlocks - * we don't free the old io scheduler, before we have allocated what we * need for the new one. this way we have a chance of going back to the old - * one, if the new one fails init for some reason. we also do an intermediate - * switch to noop to ensure safety with stack-allocated requests, since they - * don't originate from the block layer allocator. noop is safe here, because - * it never needs to touch the elevator itself for completion events. DRAIN - * flags will make sure we don't touch it for additions either. + * one, if the new one fails init for some reason. */ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) { - elevator_t *e = kmalloc(sizeof(elevator_t), GFP_KERNEL); - struct elevator_type *noop_elevator = NULL; - elevator_t *old_elevator; + elevator_t *old_elevator, *e; + /* + * Allocate new elevator + */ + e = kmalloc(sizeof(elevator_t), GFP_KERNEL); if (!e) goto error; /* - * first step, drain requests from the block freelist + * Turn on BYPASS and drain all requests w/ elevator private data */ - blk_wait_queue_drained(q, 0); + spin_lock_irq(q->queue_lock); + + set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + + while (q->rq.elvpriv) { + spin_unlock_irq(q->queue_lock); + msleep(10); + spin_lock_irq(q->queue_lock); + } + + spin_unlock_irq(q->queue_lock); /* * unregister old elevator data @@ -609,18 +690,6 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) old_elevator = q->elevator; /* - * next step, switch to noop since it uses no private rq structures - * and doesn't allocate any memory for anything. then wait for any - * non-fs requests in-flight - */ - noop_elevator = elevator_get("noop"); - spin_lock_irq(q->queue_lock); - elevator_attach(q, noop_elevator, e); - spin_unlock_irq(q->queue_lock); - - blk_wait_queue_drained(q, 1); - - /* * attach and start new elevator */ if (elevator_attach(q, new_e, e)) @@ -630,11 +699,10 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) goto fail_register; /* - * finally exit old elevator and start queue again + * finally exit old elevator and turn off BYPASS. */ elevator_exit(old_elevator); - blk_finish_queue_drain(q); - elevator_put(noop_elevator); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); return; fail_register: @@ -643,13 +711,13 @@ fail_register: * one again (along with re-adding the sysfs dir) */ elevator_exit(e); + e = NULL; fail: q->elevator = old_elevator; elv_register_queue(q); - blk_finish_queue_drain(q); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + kfree(e); error: - if (noop_elevator) - elevator_put(noop_elevator); elevator_put(new_e); printk(KERN_ERR "elevator: switch to %s failed\n",new_e->elevator_name); } @@ -701,11 +769,12 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } +EXPORT_SYMBOL(elv_dispatch_sort); EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_requeue_request); EXPORT_SYMBOL(elv_next_request); -EXPORT_SYMBOL(elv_remove_request); +EXPORT_SYMBOL(elv_dequeue_request); EXPORT_SYMBOL(elv_queue_empty); EXPORT_SYMBOL(elv_completed_request); EXPORT_SYMBOL(elevator_exit); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index baedac522945..0af73512b9a8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -263,8 +263,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); blk_queue_activity_fn(q, NULL, NULL); - - INIT_LIST_HEAD(&q->drain_list); } EXPORT_SYMBOL(blk_queue_make_request); @@ -353,6 +351,8 @@ static void blk_pre_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_PREFLUSH; if (!flush_rq->errors) @@ -369,6 +369,8 @@ static void blk_post_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_POSTFLUSH; q->end_flush_fn(q, flush_rq); @@ -408,8 +410,6 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) if (!list_empty(&rq->queuelist)) blkdev_dequeue_request(rq); - elv_deactivate_request(q, rq); - flush_rq->end_io_data = rq; flush_rq->end_io = blk_pre_flush_end_io; @@ -1040,6 +1040,7 @@ EXPORT_SYMBOL(blk_queue_invalidate_tags); static char *rq_flags[] = { "REQ_RW", "REQ_FAILFAST", + "REQ_SORTED", "REQ_SOFTBARRIER", "REQ_HARDBARRIER", "REQ_CMD", @@ -1047,6 +1048,7 @@ static char *rq_flags[] = { "REQ_STARTED", "REQ_DONTPREP", "REQ_QUEUED", + "REQ_ELVPRIV", "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE", @@ -1637,9 +1639,9 @@ static int blk_init_free_list(request_queue_t *q) rl->count[READ] = rl->count[WRITE] = 0; rl->starved[READ] = rl->starved[WRITE] = 0; + rl->elvpriv = 0; init_waitqueue_head(&rl->wait[READ]); init_waitqueue_head(&rl->wait[WRITE]); - init_waitqueue_head(&rl->drain); rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep, q->node); @@ -1652,13 +1654,13 @@ static int blk_init_free_list(request_queue_t *q) static int __make_request(request_queue_t *, struct bio *); -request_queue_t *blk_alloc_queue(int gfp_mask) +request_queue_t *blk_alloc_queue(gfp_t gfp_mask) { return blk_alloc_queue_node(gfp_mask, -1); } EXPORT_SYMBOL(blk_alloc_queue); -request_queue_t *blk_alloc_queue_node(int gfp_mask, int node_id) +request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) { request_queue_t *q; @@ -1782,12 +1784,14 @@ EXPORT_SYMBOL(blk_get_queue); static inline void blk_free_request(request_queue_t *q, struct request *rq) { - elv_put_request(q, rq); + if (rq->flags & REQ_ELVPRIV) + elv_put_request(q, rq); mempool_free(rq, q->rq.rq_pool); } static inline struct request * -blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) +blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, + int priv, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -1800,11 +1804,15 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) */ rq->flags = rw; - if (!elv_set_request(q, rq, bio, gfp_mask)) - return rq; + if (priv) { + if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { + mempool_free(rq, q->rq.rq_pool); + return NULL; + } + rq->flags |= REQ_ELVPRIV; + } - mempool_free(rq, q->rq.rq_pool); - return NULL; + return rq; } /* @@ -1860,22 +1868,18 @@ static void __freed_request(request_queue_t *q, int rw) * A request has just been released. Account for it, update the full and * congestion status, wake up any waiters. Called under q->queue_lock. */ -static void freed_request(request_queue_t *q, int rw) +static void freed_request(request_queue_t *q, int rw, int priv) { struct request_list *rl = &q->rq; rl->count[rw]--; + if (priv) + rl->elvpriv--; __freed_request(q, rw); if (unlikely(rl->starved[rw ^ 1])) __freed_request(q, rw ^ 1); - - if (!rl->count[READ] && !rl->count[WRITE]) { - smp_mb(); - if (unlikely(waitqueue_active(&rl->drain))) - wake_up(&rl->drain); - } } #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) @@ -1885,14 +1889,12 @@ static void freed_request(request_queue_t *q, int rw) * Returns !NULL on success, with queue_lock *not held*. */ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct request *rq = NULL; struct request_list *rl = &q->rq; struct io_context *ioc = current_io_context(GFP_ATOMIC); - - if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) - goto out; + int priv; if (rl->count[rw]+1 >= q->nr_requests) { /* @@ -1937,9 +1939,14 @@ get_rq: rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); + + priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + if (priv) + rl->elvpriv++; + spin_unlock_irq(q->queue_lock); - rq = blk_alloc_request(q, rw, bio, gfp_mask); + rq = blk_alloc_request(q, rw, bio, priv, gfp_mask); if (!rq) { /* * Allocation failed presumably due to memory. Undo anything @@ -1949,7 +1956,7 @@ get_rq: * wait queue, but this is pretty rare. */ spin_lock_irq(q->queue_lock); - freed_request(q, rw); + freed_request(q, rw, priv); /* * in the very unlikely event that allocation failed and no @@ -2019,7 +2026,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw, return rq; } -struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) +struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask) { struct request *rq; @@ -2251,7 +2258,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * @gfp_mask: memory allocation flags */ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, - unsigned int len, unsigned int gfp_mask) + unsigned int len, gfp_t gfp_mask) { struct bio *bio; @@ -2433,13 +2440,15 @@ void disk_round_stats(struct gendisk *disk) { unsigned long now = jiffies; - __disk_stat_add(disk, time_in_queue, - disk->in_flight * (now - disk->stamp)); - disk->stamp = now; + if (now == disk->stamp) + return; - if (disk->in_flight) - __disk_stat_add(disk, io_ticks, (now - disk->stamp_idle)); - disk->stamp_idle = now; + if (disk->in_flight) { + __disk_stat_add(disk, time_in_queue, + disk->in_flight * (now - disk->stamp)); + __disk_stat_add(disk, io_ticks, (now - disk->stamp)); + } + disk->stamp = now; } /* @@ -2454,6 +2463,8 @@ static void __blk_put_request(request_queue_t *q, struct request *req) if (unlikely(--req->ref_count)) return; + elv_completed_request(q, req); + req->rq_status = RQ_INACTIVE; req->rl = NULL; @@ -2463,26 +2474,25 @@ static void __blk_put_request(request_queue_t *q, struct request *req) */ if (rl) { int rw = rq_data_dir(req); - - elv_completed_request(q, req); + int priv = req->flags & REQ_ELVPRIV; BUG_ON(!list_empty(&req->queuelist)); blk_free_request(q, req); - freed_request(q, rw); + freed_request(q, rw, priv); } } void blk_put_request(struct request *req) { + unsigned long flags; + request_queue_t *q = req->q; + /* - * if req->rl isn't set, this request didnt originate from the - * block layer, so it's safe to just disregard it + * Gee, IDE calls in w/ NULL q. Fix IDE and remove the + * following if (q) test. */ - if (req->rl) { - unsigned long flags; - request_queue_t *q = req->q; - + if (q) { spin_lock_irqsave(q->queue_lock, flags); __blk_put_request(q, req); spin_unlock_irqrestore(q->queue_lock, flags); @@ -2797,97 +2807,6 @@ static inline void blk_partition_remap(struct bio *bio) } } -void blk_finish_queue_drain(request_queue_t *q) -{ - struct request_list *rl = &q->rq; - struct request *rq; - int requeued = 0; - - spin_lock_irq(q->queue_lock); - clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (!list_empty(&q->drain_list)) { - rq = list_entry_rq(q->drain_list.next); - - list_del_init(&rq->queuelist); - elv_requeue_request(q, rq); - requeued++; - } - - if (requeued) - q->request_fn(q); - - spin_unlock_irq(q->queue_lock); - - wake_up(&rl->wait[0]); - wake_up(&rl->wait[1]); - wake_up(&rl->drain); -} - -static int wait_drain(request_queue_t *q, struct request_list *rl, int dispatch) -{ - int wait = rl->count[READ] + rl->count[WRITE]; - - if (dispatch) - wait += !list_empty(&q->queue_head); - - return wait; -} - -/* - * We rely on the fact that only requests allocated through blk_alloc_request() - * have io scheduler private data structures associated with them. Any other - * type of request (allocated on stack or through kmalloc()) should not go - * to the io scheduler core, but be attached to the queue head instead. - */ -void blk_wait_queue_drained(request_queue_t *q, int wait_dispatch) -{ - struct request_list *rl = &q->rq; - DEFINE_WAIT(wait); - - spin_lock_irq(q->queue_lock); - set_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (wait_drain(q, rl, wait_dispatch)) { - prepare_to_wait(&rl->drain, &wait, TASK_UNINTERRUPTIBLE); - - if (wait_drain(q, rl, wait_dispatch)) { - __generic_unplug_device(q); - spin_unlock_irq(q->queue_lock); - io_schedule(); - spin_lock_irq(q->queue_lock); - } - - finish_wait(&rl->drain, &wait); - } - - spin_unlock_irq(q->queue_lock); -} - -/* - * block waiting for the io scheduler being started again. - */ -static inline void block_wait_queue_running(request_queue_t *q) -{ - DEFINE_WAIT(wait); - - while (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { - struct request_list *rl = &q->rq; - - prepare_to_wait_exclusive(&rl->drain, &wait, - TASK_UNINTERRUPTIBLE); - - /* - * re-check the condition. avoids using prepare_to_wait() - * in the fast path (queue is running) - */ - if (test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) - io_schedule(); - - finish_wait(&rl->drain, &wait); - } -} - static void handle_bad_sector(struct bio *bio) { char b[BDEVNAME_SIZE]; @@ -2983,8 +2902,6 @@ end_io: if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) goto end_io; - block_wait_queue_running(q); - /* * If this device has partitions, remap block n * of partition p to block n+start(p) of the disk. @@ -3393,7 +3310,7 @@ void exit_io_context(void) * but since the current task itself holds a reference, the context can be * used in general code, so long as it stays within `current` context. */ -struct io_context *current_io_context(int gfp_flags) +struct io_context *current_io_context(gfp_t gfp_flags) { struct task_struct *tsk = current; struct io_context *ret; @@ -3424,7 +3341,7 @@ EXPORT_SYMBOL(current_io_context); * * This is always called in the context of the task which submitted the I/O. */ -struct io_context *get_io_context(int gfp_flags) +struct io_context *get_io_context(gfp_t gfp_flags) { struct io_context *ret; ret = current_io_context(gfp_flags); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b35e08876dd4..96c664af8d06 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -881,7 +881,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) { struct file *filp = lo->lo_backing_file; - int gfp = lo->old_gfp_mask; + gfp_t gfp = lo->old_gfp_mask; if (lo->lo_state != Lo_bound) return -ENXIO; diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index b1730b62c37e..f56b8edb06e4 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c @@ -7,57 +7,19 @@ #include <linux/module.h> #include <linux/init.h> -/* - * See if we can find a request that this buffer can be coalesced with. - */ -static int elevator_noop_merge(request_queue_t *q, struct request **req, - struct bio *bio) -{ - int ret; - - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) - *req = q->last_merge; - - return ret; -} - -static void elevator_noop_merge_requests(request_queue_t *q, struct request *req, - struct request *next) -{ - list_del_init(&next->queuelist); -} - -static void elevator_noop_add_request(request_queue_t *q, struct request *rq, - int where) +static void elevator_noop_add_request(request_queue_t *q, struct request *rq) { - if (where == ELEVATOR_INSERT_FRONT) - list_add(&rq->queuelist, &q->queue_head); - else - list_add_tail(&rq->queuelist, &q->queue_head); - - /* - * new merges must not precede this barrier - */ - if (rq->flags & REQ_HARDBARRIER) - q->last_merge = NULL; - else if (!q->last_merge) - q->last_merge = rq; + elv_dispatch_add_tail(q, rq); } -static struct request *elevator_noop_next_request(request_queue_t *q) +static int elevator_noop_dispatch(request_queue_t *q, int force) { - if (!list_empty(&q->queue_head)) - return list_entry_rq(q->queue_head.next); - - return NULL; + return 0; } static struct elevator_type elevator_noop = { .ops = { - .elevator_merge_fn = elevator_noop_merge, - .elevator_merge_req_fn = elevator_noop_merge_requests, - .elevator_next_req_fn = elevator_noop_next_request, + .elevator_dispatch_fn = elevator_noop_dispatch, .elevator_add_req_fn = elevator_noop_add_request, }, .elevator_name = "noop", diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 145c1fbffe01..68c60a5bcdab 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -348,7 +348,7 @@ static int rd_open(struct inode *inode, struct file *filp) struct block_device *bdev = inode->i_bdev; struct address_space *mapping; unsigned bsize; - int gfp_mask; + gfp_t gfp_mask; inode = igrab(bdev->bd_inode); rd_bdev[unit] = bdev; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index d57007b92f77..1ded3b433459 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1,7 +1,7 @@ /* * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware * - * Copyright 2004 Red Hat, Inc. + * Copyright 2004-2005 Red Hat, Inc. * * Author/maintainer: Jeff Garzik <jgarzik@pobox.com> * @@ -31,10 +31,6 @@ #include <asm/semaphore.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Jeff Garzik"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Promise SATA SX8 block driver"); - #if 0 #define CARM_DEBUG #define CARM_VERBOSE_DEBUG @@ -45,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver"); #undef CARM_NDEBUG #define DRV_NAME "sx8" -#define DRV_VERSION "0.8" +#define DRV_VERSION "1.0" #define PFX DRV_NAME ": " +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SATA SX8 block driver"); +MODULE_VERSION(DRV_VERSION); + +/* + * SX8 hardware has a single message queue for all ATA ports. + * When this driver was written, the hardware (firmware?) would + * corrupt data eventually, if more than one request was outstanding. + * As one can imagine, having 8 ports bottlenecking on a single + * command hurts performance. + * + * Based on user reports, later versions of the hardware (firmware?) + * seem to be able to survive with more than one command queued. + * + * Therefore, we default to the safe option -- 1 command -- but + * allow the user to increase this. + * + * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ), + * but problems seem to occur when you exceed ~30, even on newer hardware. + */ +static int max_queue = 1; +module_param(max_queue, int, 0444); +MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)"); + + #define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) /* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ @@ -90,12 +112,10 @@ enum { /* command message queue limits */ CARM_MAX_REQ = 64, /* max command msgs per host */ - CARM_MAX_Q = 1, /* one command at a time */ CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ /* S/G limits, host-wide and per-request */ CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ - CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ @@ -181,6 +201,10 @@ enum { FL_DYN_MAJOR = (1 << 17), }; +enum { + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ +}; + enum scatter_gather_types { SGT_32BIT = 0, SGT_64BIT = 1, @@ -218,7 +242,6 @@ static const char *state_name[] = { struct carm_port { unsigned int port_no; - unsigned int n_queued; struct gendisk *disk; struct carm_host *host; @@ -448,7 +471,7 @@ static inline int carm_lookup_bucket(u32 msg_size) for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) if (msg_size <= msg_sizes[i]) return i; - + return -ENOENT; } @@ -509,7 +532,7 @@ static struct carm_request *carm_get_request(struct carm_host *host) if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) return NULL; - for (i = 0; i < CARM_MAX_Q; i++) + for (i = 0; i < max_queue; i++) if ((host->msg_alloc & (1ULL << i)) == 0) { struct carm_request *crq = &host->req[i]; crq->port = NULL; @@ -521,14 +544,14 @@ static struct carm_request *carm_get_request(struct carm_host *host) assert(host->n_msgs <= CARM_MAX_REQ); return crq; } - + DPRINTK("no request available, returning NULL\n"); return NULL; } static int carm_put_request(struct carm_host *host, struct carm_request *crq) { - assert(crq->tag < CARM_MAX_Q); + assert(crq->tag < max_queue); if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) return -EINVAL; /* tried to clear a tag that was not active */ @@ -791,7 +814,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, int is_ok) { carm_end_request_queued(host, crq, is_ok); - if (CARM_MAX_Q == 1) + if (max_queue == 1) carm_round_robin(host); else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && (host->hw_sg_used <= CARM_SG_LOW_WATER)) { diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index c9bdf544ed2c..c556f4d3ccd7 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 1af733d07321..9e24bbd4090c 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -32,9 +32,11 @@ * added changelog * 1.2 Erik Gilling: Cobalt Networks support * Tim Hockin: general cleanup, Cobalt support + * 1.3 Jon Ringle: Comdial MP1000 support + * */ -#define NVRAM_VERSION "1.2" +#define NVRAM_VERSION "1.3" #include <linux/module.h> #include <linux/config.h> @@ -45,6 +47,7 @@ #define PC 1 #define ATARI 2 #define COBALT 3 +#define MP1000 4 /* select machine configuration */ #if defined(CONFIG_ATARI) @@ -54,6 +57,9 @@ # if defined(CONFIG_COBALT) # include <linux/cobalt-nvram.h> # define MACH COBALT +# elif defined(CONFIG_MACH_MP1000) +# undef MACH +# define MACH MP1000 # else # define MACH PC # endif @@ -112,6 +118,23 @@ #endif +#if MACH == MP1000 + +/* RTC in a MP1000 */ +#define CHECK_DRIVER_INIT() 1 + +#define MP1000_CKS_RANGE_START 0 +#define MP1000_CKS_RANGE_END 111 +#define MP1000_CKS_LOC 112 + +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) + +#define mach_check_checksum mp1000_check_checksum +#define mach_set_checksum mp1000_set_checksum +#define mach_proc_infos mp1000_proc_infos + +#endif + /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with * rtc_lock held. Due to the index-port/data-port design of the RTC, we * don't want two different things trying to get to it at once. (e.g. the @@ -915,6 +938,91 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len, #endif /* MACH == ATARI */ +#if MACH == MP1000 + +static int +mp1000_check_checksum(void) +{ + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + + expect = __nvram_read_byte(MP1000_CKS_LOC+1)<<8 | + __nvram_read_byte(MP1000_CKS_LOC); + return ((sum & 0xffff) == expect); +} + +static void +mp1000_set_checksum(void) +{ + int i; + unsigned short sum = 0; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + __nvram_write_byte(sum >> 8, MP1000_CKS_LOC + 1); + __nvram_write_byte(sum & 0xff, MP1000_CKS_LOC); +} + +#ifdef CONFIG_PROC_FS + +#define SERVER_N_LEN 32 +#define PATH_N_LEN 32 +#define FILE_N_LEN 32 +#define NVRAM_MAGIC_SIG 0xdead + +typedef struct NvRamImage +{ + unsigned short int magic; + unsigned short int mode; + char fname[FILE_N_LEN]; + char path[PATH_N_LEN]; + char server[SERVER_N_LEN]; + char pad[12]; +} NvRam; + +static int +mp1000_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + int checksum; + NvRam* nv = (NvRam*)nvram; + + spin_lock_irq(&rtc_lock); + checksum = __nvram_check_checksum(); + spin_unlock_irq(&rtc_lock); + + PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + + switch( nv->mode ) + { + case 0 : + PRINT_PROC( "\tMode 0, tftp prompt\n" ); + break; + case 1 : + PRINT_PROC( "\tMode 1, booting from disk\n" ); + break; + case 2 : + PRINT_PROC( "\tMode 2, Alternate boot from disk /boot/%s\n", nv->fname ); + break; + case 3 : + PRINT_PROC( "\tMode 3, Booting from net:\n" ); + PRINT_PROC( "\t\t%s:%s%s\n",nv->server, nv->path, nv->fname ); + break; + default: + PRINT_PROC( "\tInconsistant nvram?\n" ); + break; + } + + return 1; +} +#endif + +#endif /* MACH == MP1000 */ + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(__nvram_read_byte); diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 4802bbbb6dc9..c9e92d85c893 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1630,7 +1630,7 @@ static void ether1394_complete_cb(void *__ptask) /* Transmit a packet (called by kernel) */ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) { - int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct eth1394hdr *eth; struct eth1394_priv *priv = netdev_priv(dev); int proto; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f6a8ac026557..378646b5a1b8 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -524,7 +524,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev) } struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_mailbox *mailbox; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h index 65f976a13e02..18175bec84c2 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.h +++ b/drivers/infiniband/hw/mthca/mthca_cmd.h @@ -248,7 +248,7 @@ void mthca_cmd_event(struct mthca_dev *dev, u16 token, u8 status, u64 out_param); struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox); int mthca_SYS_EN(struct mthca_dev *dev, u8 *status); diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 7bd7a4bec7b4..9ad8b3b6cfef 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -82,7 +82,7 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) } struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_icm *icm; struct mthca_icm_chunk *chunk = NULL; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index bafa51544aa3..29433f295253 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -77,7 +77,7 @@ struct mthca_icm_iter { struct mthca_dev; struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm); struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2fba2bbe72d8..01654fcabc52 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -91,7 +91,7 @@ int bitmap_active(struct bitmap *bitmap) #define WRITE_POOL_SIZE 256 /* mempool for queueing pending writes on the bitmap file */ -static void *write_pool_alloc(unsigned int gfp_flags, void *data) +static void *write_pool_alloc(gfp_t gfp_flags, void *data) { return kmalloc(sizeof(struct page_list), gfp_flags); } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b6148f6f7836..28c1a628621f 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -331,7 +331,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size, { struct bio *bio; unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - int gfp_mask = GFP_NOIO | __GFP_HIGHMEM; + gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM; unsigned int i; /* diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 91c74843dc0d..1e6bdba26756 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/scatterlist.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> #include <asm/mach/mmc.h> diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 55f21ddec3df..6a8e0caf9fdc 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -21,6 +21,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/concat.h> +#include <asm/hardware.h> #include <asm/io.h> #include <asm/sizes.h> #include <asm/mach/flash.h> diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index bc537440ca02..f822cd3025ff 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1027,8 +1027,7 @@ static void cp_reset_hw (struct cp_private *cp) if (!(cpr8(Cmd) & CmdReset)) return; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); @@ -1575,6 +1574,7 @@ static struct ethtool_ops cp_ethtool_ops = { .set_wol = cp_set_wol, .get_strings = cp_get_strings, .get_ethtool_stats = cp_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) @@ -1773,6 +1773,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; dev->stop = cp_close; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 4c2cf7bbd252..30bee11c48bd 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -552,7 +552,8 @@ const static struct { { "RTL-8100B/8139D", HW_REVID(1, 1, 1, 0, 1, 0, 1), - HasLWake, + HasHltClk /* XXX undocumented? */ + | HasLWake, }, { "RTL-8101", @@ -970,6 +971,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; @@ -2465,6 +2467,7 @@ static struct ethtool_ops rtl8139_ethtool_ops = { .get_strings = rtl8139_get_strings, .get_stats_count = rtl8139_get_stats_count, .get_ethtool_stats = rtl8139_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c748b0e16419..fee8c5cf1f3a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -475,6 +475,14 @@ config SGI_IOC3_ETH_HW_TX_CSUM the moment only acceleration of IPv4 is supported. This option enables offloading for checksums on transmit. If unsure, say Y. +config MIPS_SIM_NET + tristate "MIPS simulator Network device (EXPERIMENTAL)" + depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL + help + The MIPSNET device is a simple Ethernet network device which is + emulated by the MIPS Simulator. + If you are not using a MIPSsim or are unsure, say N. + config SGI_O2MACE_ETH tristate "SGI O2 MACE Fast Ethernet support" depends on NET_ETHERNET && SGI_IP32=y @@ -1330,7 +1338,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 || MACH_MP1000 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -2083,6 +2091,7 @@ config SPIDER_NET config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx + select PHYLIB help This driver supports the Gigabit TSEC on the MPC85xx family of chips, and the FEC on the 8540 @@ -2243,6 +2252,20 @@ config ISERIES_VETH tristate "iSeries Virtual Ethernet driver support" depends on PPC_ISERIES +config RIONET + tristate "RapidIO Ethernet over messaging driver support" + depends on NETDEVICES && RAPIDIO + +config RIONET_TX_SIZE + int "Number of outbound queue entries" + depends on RIONET + default "128" + +config RIONET_RX_SIZE + int "Number of inbound queue entries" + depends on RIONET + default "128" + config FDDI bool "FDDI driver support" depends on (PCI || EISA) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8aeec9f2495b..1a84e0435f64 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o -gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o # # link order important here @@ -64,6 +64,7 @@ obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o +obj-$(CONFIG_RIONET) += rionet.o # # end link order section @@ -166,6 +167,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o +obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index c56d86d371a9..3d50e953faaa 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -29,6 +29,7 @@ #include <asm/system.h> #include <asm/irq.h> +#include <asm/hardware.h> #include <asm/io.h> #define TX_BUFFERS 15 diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index c82b9cd1c924..78506911d656 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -151,13 +151,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ SUPPORTED_Autoneg -static char *phy_link[] = -{ "unknown", - "10Base2", "10BaseT", - "AUI", - "100BaseT", "100BaseTX", "100BaseFX" -}; - int bcm_5201_init(struct net_device *dev, int phy_addr) { s16 data; @@ -785,6 +778,7 @@ static struct mii_chip_info { {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0}, {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0}, {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1}, + {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0}, {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0}, {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0}, {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0}, @@ -1045,7 +1039,7 @@ found: #endif if (aup->mii->chip_info == NULL) { - printk(KERN_ERR "%s: Au1x No MII transceivers found!\n", + printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n", dev->name); return -1; } @@ -1546,6 +1540,9 @@ au1000_probe(u32 ioaddr, int irq, int port_num) printk(KERN_ERR "%s: out of memory\n", dev->name); goto err_out; } + aup->mii->next = NULL; + aup->mii->chip_info = NULL; + aup->mii->status = 0; aup->mii->mii_control_reg = 0; aup->mii->mii_data_reg = 0; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 94939f570f78..282ebd15f011 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -106,6 +106,29 @@ static int b44_poll(struct net_device *dev, int *budget); static void b44_poll_controller(struct net_device *dev); #endif +static int dma_desc_align_mask; +static int dma_desc_sync_size; + +static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_device(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + +static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_cpu(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + static inline unsigned long br32(const struct b44 *bp, unsigned long reg) { return readl(bp->regs + reg); @@ -668,6 +691,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dp->ctrl = cpu_to_le32(ctrl); dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dp), + DMA_BIDIRECTIONAL); + return RX_PKT_BUF_SZ; } @@ -692,6 +720,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) pci_unmap_addr_set(dest_map, mapping, pci_unmap_addr(src_map, mapping)); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, + src_idx * sizeof(src_desc), + DMA_BIDIRECTIONAL); + ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) ctrl |= cpu_to_le32(DESC_CTRL_EOT); @@ -700,8 +733,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; + src_map->skb = NULL; + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); @@ -959,6 +998,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); + if (bp->flags & B44_FLAG_TX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, + entry * sizeof(bp->tx_ring[0]), + DMA_TO_DEVICE); + entry = NEXT_TX(entry); bp->tx_prod = entry; @@ -1064,6 +1108,16 @@ static void b44_init_rings(struct b44 *bp) memset(bp->rx_ring, 0, B44_RX_RING_BYTES); memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + if (bp->flags & B44_FLAG_RX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_TODEVICE); + for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) break; @@ -1085,14 +1139,28 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; } if (bp->rx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->rx_ring, bp->rx_ring_dma); + if (bp->flags & B44_FLAG_RX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->tx_ring, bp->tx_ring_dma); + if (bp->flags & B44_FLAG_TX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; } } @@ -1118,12 +1186,56 @@ static int b44_alloc_consistent(struct b44 *bp) size = DMA_TABLE_BYTES; bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); - if (!bp->rx_ring) - goto out_err; + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + + if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(rx_ring, 0, size); + rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + + if (rx_ring_dma + size > B44_DMA_MASK) { + kfree(rx_ring); + goto out_err; + } + + bp->rx_ring = rx_ring; + bp->rx_ring_dma = rx_ring_dma; + bp->flags |= B44_FLAG_RX_RING_HACK; + } bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); - if (!bp->tx_ring) - goto out_err; + if (!bp->tx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *tx_ring; + dma_addr_t tx_ring_dma; + + if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(tx_ring, 0, size); + tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + + if (tx_ring_dma + size > B44_DMA_MASK) { + kfree(tx_ring); + goto out_err; + } + + bp->tx_ring = tx_ring; + bp->tx_ring_dma = tx_ring_dma; + bp->flags |= B44_FLAG_TX_RING_HACK; + } return 0; @@ -1676,6 +1788,7 @@ static struct ethtool_ops b44_ethtool_ops = { .set_pauseparam = b44_set_pauseparam, .get_msglevel = b44_get_msglevel, .set_msglevel = b44_set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1718,6 +1831,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->dev->dev_addr[3] = eeprom[80]; bp->dev->dev_addr[4] = eeprom[83]; bp->dev->dev_addr[5] = eeprom[82]; + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); bp->phy_addr = eeprom[90] & 0x1f; @@ -1971,6 +2085,12 @@ static struct pci_driver b44_driver = { static int __init b44_init(void) { + unsigned int dma_desc_align_size = dma_get_cache_alignment(); + + /* Setup paramaters for syncing RX/TX DMA descriptors */ + dma_desc_align_mask = ~(dma_desc_align_size - 1); + dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc)); + return pci_module_init(&b44_driver); } diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 11c40a2e71c7..593cb0ad4100 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -400,6 +400,8 @@ struct b44 { #define B44_FLAG_ADV_100HALF 0x04000000 #define B44_FLAG_ADV_100FULL 0x08000000 #define B44_FLAG_INTERNAL_PHY 0x10000000 +#define B44_FLAG_RX_RING_HACK 0x20000000 +#define B44_FLAG_TX_RING_HACK 0x40000000 u32 rx_offset; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f264ff162979..8032126fd589 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4241,6 +4241,43 @@ out: return 0; } +static void bond_activebackup_xmit_copy(struct sk_buff *skb, + struct bonding *bond, + struct slave *slave) +{ + struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); + struct ethhdr *eth_data; + u8 *hwaddr; + int res; + + if (!skb2) { + printk(KERN_ERR DRV_NAME ": Error: " + "bond_activebackup_xmit_copy(): skb_copy() failed\n"); + return; + } + + skb2->mac.raw = (unsigned char *)skb2->data; + eth_data = eth_hdr(skb2); + + /* Pick an appropriate source MAC address + * -- use slave's perm MAC addr, unless used by bond + * -- otherwise, borrow active slave's perm MAC addr + * since that will not be used + */ + hwaddr = slave->perm_hwaddr; + if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN)) + hwaddr = bond->curr_active_slave->perm_hwaddr; + + /* Set source MAC address appropriately */ + memcpy(eth_data->h_source, hwaddr, ETH_ALEN); + + res = bond_dev_queue_xmit(bond, skb2, slave->dev); + if (res) + dev_kfree_skb(skb2); + + return; +} + /* * in active-backup mode, we know that bond->curr_active_slave is always valid if * the bond has a usable interface. @@ -4257,10 +4294,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d goto out; } - if (bond->curr_active_slave) { /* one usable interface */ - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + if (!bond->curr_active_slave) + goto out; + + /* Xmit IGMP frames on all slaves to ensure rapid fail-over + for multicast traffic on snooping switches */ + if (skb->protocol == __constant_htons(ETH_P_IP) && + skb->nh.iph->protocol == IPPROTO_IGMP) { + struct slave *slave, *active_slave; + int i; + + active_slave = bond->curr_active_slave; + bond_for_each_slave_from_to(bond, slave, i, active_slave->next, + active_slave->prev) + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP)) + bond_activebackup_xmit_copy(skb, bond, slave); } + res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + out: if (res) { /* no suitable interface, frame not sent */ diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 2e617424d3fb..50f43dbf31ae 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -489,7 +489,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page) /* local page allocation routines for the receive buffers. jumbo pages * require at least 8K contiguous and 8K aligned buffers. */ -static cas_page_t *cas_page_alloc(struct cas *cp, const int flags) +static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags) { cas_page_t *page; @@ -561,7 +561,7 @@ static void cas_spare_free(struct cas *cp) } /* replenish spares if needed */ -static void cas_spare_recover(struct cas *cp, const int flags) +static void cas_spare_recover(struct cas *cp, const gfp_t flags) { struct list_head list, *elem, *tmp; int needed, i; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index a6078ad9b654..bfdae10036ed 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -182,6 +182,10 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0}; static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0}; +#elif defined(CONFIG_MACH_MP1000) +#include <asm/arch/mp1000-seprom.h> +static unsigned int netcard_portlist[] __initdata = {MP1000_EIO_BASE+0x300, 0}; +static unsigned int cs8900_irq_map[] = {IRQ_EINT3,0,0,0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -590,6 +594,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) cnt -= j; } } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + memcpy(dev->dev_addr, get_eeprom_mac_address(), ETH_ALEN); + } else #endif if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == @@ -649,6 +657,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (1) { printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n"); } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + lp->force |= FORCE_RJ45; + } else #endif if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n"); @@ -1231,7 +1243,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) +#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) && !defined(CONFIG_MACH_MP1000) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index decea264f121..f19d1ebe0183 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,7 +16,7 @@ #include <linux/config.h> -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) +#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) || defined (CONFIG_MACH_MP1000) /* IXDP2401/IXDP2801 uses dword-aligned register addressing */ #define CS89x0_PORT(reg) ((reg) * 2) #else diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 521c83137bf6..f130bdab3fd3 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -5,7 +5,7 @@ * * adopted from sunlance.c by Richard van den Berg * - * Copyright (C) 2002, 2003 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, @@ -57,13 +57,15 @@ #include <linux/string.h> #include <asm/addrspace.h> +#include <asm/system.h> + #include <asm/dec/interrupts.h> #include <asm/dec/ioasic.h> #include <asm/dec/ioasic_addrs.h> #include <asm/dec/kn01.h> #include <asm/dec/machtype.h> +#include <asm/dec/system.h> #include <asm/dec/tc.h> -#include <asm/system.h> static char version[] __devinitdata = "declance.c: v0.009 by Linux MIPS DECstation task force\n"; @@ -79,10 +81,6 @@ MODULE_LICENSE("GPL"); #define PMAD_LANCE 2 #define PMAX_LANCE 3 -#ifndef CONFIG_TC -unsigned long system_base; -unsigned long dmaptr; -#endif #define LE_CSR0 0 #define LE_CSR1 1 @@ -237,7 +235,7 @@ struct lance_init_block { /* * This works *only* for the ring descriptors */ -#define LANCE_ADDR(x) (PHYSADDR(x) >> 1) +#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1) struct lance_private { struct net_device *next; @@ -697,12 +695,13 @@ out: spin_unlock(&lp->lock); } -static void lance_dma_merr_int(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; printk("%s: DMA error\n", dev->name); + return IRQ_HANDLED; } static irqreturn_t @@ -1026,10 +1025,6 @@ static int __init dec_lance_init(const int type, const int slot) unsigned long esar_base; unsigned char *esar; -#ifndef CONFIG_TC - system_base = KN01_LANCE_BASE; -#endif - if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1062,16 +1057,16 @@ static int __init dec_lance_init(const int type, const int slot) switch (type) { #ifdef CONFIG_TC case ASIC_LANCE: - dev->base_addr = system_base + IOASIC_LANCE; + dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); /* buffer space for the on-board LANCE shared memory */ /* * FIXME: ugly hack! */ - dev->mem_start = KSEG1ADDR(0x00020000); + dev->mem_start = CKSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - esar_base = system_base + IOASIC_ESAR; + esar_base = CKSEG1ADDR(dec_kn_slot_base + IOASIC_ESAR); /* Workaround crash with booting KN04 2.1k from Disk */ memset((void *)dev->mem_start, 0, @@ -1101,14 +1096,14 @@ static int __init dec_lance_init(const int type, const int slot) /* Setup I/O ASIC LANCE DMA. */ lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR]; ioasic_write(IO_REG_LANCE_DMA_P, - PHYSADDR(dev->mem_start) << 3); + CPHYSADDR(dev->mem_start) << 3); break; case PMAD_LANCE: claim_tc_card(slot); - dev->mem_start = get_tc_base_addr(slot); + dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); dev->base_addr = dev->mem_start + 0x100000; dev->irq = get_tc_irq_nr(slot); esar_base = dev->mem_start + 0x1c0002; @@ -1137,9 +1132,9 @@ static int __init dec_lance_init(const int type, const int slot) case PMAX_LANCE: dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - dev->base_addr = KN01_LANCE_BASE; - dev->mem_start = KN01_LANCE_BASE + 0x01000000; - esar_base = KN01_RTC_BASE + 1; + dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE); + dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM); + esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1); lp->dma_irq = -1; /* diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 40887f09b681..eb169a8e8773 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2201,6 +2201,7 @@ static struct ethtool_ops e100_ethtool_ops = { .phys_id = e100_phys_id, .get_stats_count = e100_get_stats_count, .get_ethtool_stats = e100_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) @@ -2351,7 +2352,8 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_phy_init(nic); memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); - if(!is_valid_ether_addr(netdev->dev_addr)) { + memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC address from " "EEPROM, aborting.\n"); err = -EAGAIN; diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 092757bc721f..3f653a93e1bc 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -72,6 +72,10 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> +#ifdef CONFIG_E1000_MQ +#include <linux/cpu.h> +#include <linux/smp.h> +#endif #define BAR_0 0 #define BAR_1 1 @@ -165,10 +169,33 @@ struct e1000_buffer { uint16_t next_to_watch; }; -struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; }; -struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; }; +struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; +struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; + +struct e1000_tx_ring { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical address of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; + /* number of descriptors in the ring */ + unsigned int count; + /* next descriptor to associate a buffer with */ + unsigned int next_to_use; + /* next descriptor to check for DD status bit */ + unsigned int next_to_clean; + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + + struct e1000_buffer previous_buffer_info; + spinlock_t tx_lock; + uint16_t tdh; + uint16_t tdt; + uint64_t pkt; +}; -struct e1000_desc_ring { +struct e1000_rx_ring { /* pointer to the descriptor ring memory */ void *desc; /* physical address of the descriptor ring */ @@ -186,6 +213,10 @@ struct e1000_desc_ring { /* arrays of page information for packet split */ struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; + + uint16_t rdh; + uint16_t rdt; + uint64_t pkt; }; #define E1000_DESC_UNUSED(R) \ @@ -227,9 +258,10 @@ struct e1000_adapter { unsigned long led_status; /* TX */ - struct e1000_desc_ring tx_ring; - struct e1000_buffer previous_buffer_info; - spinlock_t tx_lock; + struct e1000_tx_ring *tx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_MQ + struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */ +#endif uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; @@ -246,19 +278,33 @@ struct e1000_adapter { /* RX */ #ifdef CONFIG_E1000_NAPI - boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done, - int work_to_do); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); #else - boolean_t (*clean_rx) (struct e1000_adapter *adapter); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif - void (*alloc_rx_buf) (struct e1000_adapter *adapter); - struct e1000_desc_ring rx_ring; + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_NAPI + struct net_device *polling_netdev; /* One per active queue */ +#endif +#ifdef CONFIG_E1000_MQ + struct net_device **cpu_netdev; /* per-cpu */ + struct call_async_data_struct rx_sched_call_data; + int cpu_for_queue[4]; +#endif + int num_queues; + uint64_t hw_csum_err; uint64_t hw_csum_good; + uint64_t rx_hdr_split; uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; - boolean_t rx_ps; + unsigned int rx_ps_pages; uint32_t gorcl; uint64_t gorcl_old; uint16_t rx_ps_bsize0; @@ -278,8 +324,8 @@ struct e1000_adapter { struct e1000_phy_stats phy_stats; uint32_t test_icr; - struct e1000_desc_ring test_tx_ring; - struct e1000_desc_ring test_rx_ring; + struct e1000_tx_ring test_tx_ring; + struct e1000_rx_ring test_rx_ring; int msg_enable; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f133ff0b0b94..6b9acc7f94a3 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -39,10 +39,10 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); -extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); -extern void e1000_free_rx_resources(struct e1000_adapter *adapter); -extern void e1000_free_tx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_update_stats(struct e1000_adapter *adapter); struct e1000_stats { @@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) @@ -546,8 +547,10 @@ e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); - /* Update the checksum over the first part of the EEPROM if needed */ - if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG) + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 conrollers */ + if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || + (hw->mac_type == e1000_82573))) e1000_update_eeprom_checksum(hw); kfree(eeprom_buff); @@ -576,8 +579,8 @@ e1000_get_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; + struct e1000_tx_ring *txdr = adapter->tx_ring; + struct e1000_rx_ring *rxdr = adapter->rx_ring; ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -597,20 +600,40 @@ e1000_set_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; - int err; + struct e1000_tx_ring *txdr, *tx_old, *tx_new; + struct e1000_rx_ring *rxdr, *rx_old, *rx_new; + int i, err, tx_ring_size, rx_ring_size; + + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + + if (netif_running(adapter->netdev)) + e1000_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; + adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL); + if (!adapter->tx_ring) { + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->tx_ring, 0, tx_ring_size); + + adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->rx_ring, 0, rx_ring_size); + + txdr = adapter->tx_ring; + rxdr = adapter->rx_ring; + if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - if(netif_running(adapter->netdev)) - e1000_down(adapter); - rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); @@ -621,11 +644,16 @@ e1000_set_ringparam(struct net_device *netdev, E1000_MAX_TXD : E1000_MAX_82544_TXD)); E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + for (i = 0; i < adapter->num_queues; i++) { + txdr[i].count = txdr->count; + rxdr[i].count = rxdr->count; + } + if(netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, @@ -635,8 +663,10 @@ e1000_set_ringparam(struct net_device *netdev, tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; - e1000_free_rx_resources(adapter); - e1000_free_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; if((err = e1000_up(adapter))) @@ -645,7 +675,7 @@ e1000_set_ringparam(struct net_device *netdev, return 0; err_setup_tx: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; @@ -696,6 +726,11 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) * Some bits that get toggled are ignored. */ switch (adapter->hw.mac_type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + toggle = 0x7FFFF3FF; + break; case e1000_82573: toggle = 0x7FFFF033; break; @@ -898,8 +933,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) static void e1000_free_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; @@ -941,8 +976,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) static int e1000_setup_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; int size, i, ret_val; @@ -1245,6 +1280,8 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82541_rev_2: case e1000_82547: case e1000_82547_rev_2: + case e1000_82571: + case e1000_82572: case e1000_82573: return e1000_integrated_phy_loopback(adapter); break; @@ -1340,8 +1377,8 @@ e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) static int e1000_run_loopback_test(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i, j, k, l, lc, good_cnt, ret_val=0; unsigned long time; @@ -1509,6 +1546,7 @@ e1000_diag_test(struct net_device *netdev, data[2] = 0; data[3] = 0; } + msleep_interruptible(4 * 1000); } static void @@ -1625,7 +1663,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); - if(adapter->hw.mac_type < e1000_82573) { + if(adapter->hw.mac_type < e1000_82571) { if(!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; @@ -1739,6 +1777,7 @@ struct ethtool_ops e1000_ethtool_ops = { .phys_id = e1000_phys_id, .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 045f5426ab9a..8fc876da43b4 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -83,14 +83,14 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = static const uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = - { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, - 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, - 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, - 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, - 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, - 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, - 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, - 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; /****************************************************************************** @@ -286,7 +286,6 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: - case E1000_DEV_ID_82546GB_QUAD_COPPER: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -305,8 +304,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = e1000_82547_rev_2; break; + case E1000_DEV_ID_82571EB_COPPER: + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82571EB_SERDES: + hw->mac_type = e1000_82571; + break; + case E1000_DEV_ID_82572EI_COPPER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82572EI_SERDES: + hw->mac_type = e1000_82572; + break; case E1000_DEV_ID_82573E: case E1000_DEV_ID_82573E_IAMT: + case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; default: @@ -315,6 +325,8 @@ e1000_set_mac_type(struct e1000_hw *hw) } switch(hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: hw->eeprom_semaphore_present = TRUE; /* fall through */ @@ -351,6 +363,8 @@ e1000_set_media_type(struct e1000_hw *hw) switch (hw->device_id) { case E1000_DEV_ID_82545GM_SERDES: case E1000_DEV_ID_82546GB_SERDES: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -523,6 +537,8 @@ e1000_reset_hw(struct e1000_hw *hw) E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); E1000_WRITE_FLUSH(hw); /* fall through */ + case e1000_82571: + case e1000_82572: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) /* We don't want to continue accessing MAC registers. */ @@ -683,6 +699,9 @@ e1000_init_hw(struct e1000_hw *hw) switch (hw->mac_type) { default: break; + case e1000_82571: + case e1000_82572: + ctrl |= (1 << 22); case e1000_82573: ctrl |= E1000_TXDCTL_COUNT_DESC; break; @@ -694,6 +713,26 @@ e1000_init_hw(struct e1000_hw *hw) e1000_enable_tx_pkt_filtering(hw); } + switch (hw->mac_type) { + default: + break; + case e1000_82571: + case e1000_82572: + ctrl = E1000_READ_REG(hw, TXDCTL1); + ctrl &= ~E1000_TXDCTL_WTHRESH; + ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; + ctrl |= (1 << 22); + E1000_WRITE_REG(hw, TXDCTL1, ctrl); + break; + } + + + + if (hw->mac_type == e1000_82573) { + uint32_t gcr = E1000_READ_REG(hw, GCR); + gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, GCR, gcr); + } /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -878,6 +917,14 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_fiber_serdes_link"); + /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists + * until explicitly turned off or a power cycle is performed. A read to + * the register does not indicate its status. Therefore, we ensure + * loopback mode is disabled during initialization. + */ + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) + E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK); + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal. This applies to fiber media only. @@ -2943,6 +2990,8 @@ e1000_phy_reset(struct e1000_hw *hw) switch (hw->mac_type) { case e1000_82541_rev_2: + case e1000_82571: + case e1000_82572: ret_val = e1000_phy_hw_reset(hw); if(ret_val) return ret_val; @@ -2981,6 +3030,16 @@ e1000_detect_gig_phy(struct e1000_hw *hw) DEBUGFUNC("e1000_detect_gig_phy"); + /* The 82571 firmware may still be configuring the PHY. In this + * case, we cannot access the PHY until the configuration is done. So + * we explicitly set the PHY values. */ + if(hw->mac_type == e1000_82571 || + hw->mac_type == e1000_82572) { + hw->phy_id = IGP01E1000_I_PHY_ID; + hw->phy_type = e1000_phy_igp_2; + return E1000_SUCCESS; + } + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); if(ret_val) @@ -3334,6 +3393,21 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->use_eerd = FALSE; eeprom->use_eewr = FALSE; break; + case e1000_82571: + case e1000_82572: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; case e1000_82573: eeprom->type = e1000_eeprom_spi; eeprom->opcode_bits = 8; @@ -3543,25 +3617,26 @@ e1000_acquire_eeprom(struct e1000_hw *hw) eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != e1000_82573) { - /* Request EEPROM Access */ - if(hw->mac_type > e1000_82544) { - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && - (i < E1000_EEPROM_GRANT_ATTEMPTS)) { - i++; - udelay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; + /* Request EEPROM Access */ + if(hw->mac_type > e1000_82544) { + eecd |= E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + udelay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + e1000_put_hw_eeprom_semaphore(hw); + return -E1000_ERR_EEPROM; + } } } - } /* Setup EEPROM for Read/Write */ @@ -4064,7 +4139,7 @@ e1000_write_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* 82573 reads only through eerd */ + /* 82573 writes only through eewr */ if(eeprom->use_eewr == TRUE) return e1000_write_eeprom_eewr(hw, offset, words, data); @@ -4353,9 +4428,16 @@ e1000_read_mac_addr(struct e1000_hw * hw) hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } - if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + switch (hw->mac_type) { + default: + break; + case e1000_82546: + case e1000_82546_rev_3: + case e1000_82571: + if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; + break; + } for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; @@ -4385,6 +4467,12 @@ e1000_init_rx_addrs(struct e1000_hw *hw) e1000_rar_set(hw, hw->mac_addr, 0); rar_num = E1000_RAR_ENTRIES; + + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + rar_num -= 1; /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < rar_num; i++) { @@ -4427,6 +4515,12 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); num_rar_entry = E1000_RAR_ENTRIES; + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + num_rar_entry -= 1; + for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); @@ -4984,7 +5078,6 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, ICTXQEC); temp = E1000_READ_REG(hw, ICTXQMTC); temp = E1000_READ_REG(hw, ICRXDMTC); - } /****************************************************************************** @@ -5151,6 +5244,8 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; + case e1000_82571: + case e1000_82572: case e1000_82573: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; @@ -5250,6 +5345,7 @@ e1000_get_cable_length(struct e1000_hw *hw, int32_t ret_val; uint16_t agc_value = 0; uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t max_agc = 0; uint16_t i, phy_data; uint16_t cable_length; @@ -5338,6 +5434,40 @@ e1000_get_cable_length(struct e1000_hw *hw, IGP01E1000_AGC_RANGE) : 0; *max_length = e1000_igp_cable_length_table[agc_value] + IGP01E1000_AGC_RANGE; + } else if (hw->phy_type == e1000_phy_igp_2) { + uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of course and + * fine gain values. The result is a number that can be put into + * the lookup table to obtain the approximate cable length. */ + cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc]) + min_agc = cur_agc; + if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc]) + max_agc = cur_agc; + + agc_value += e1000_igp_2_cable_length_table[cur_agc]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + *max_length = agc_value + IGP02E1000_AGC_RANGE; } return E1000_SUCCESS; @@ -6465,6 +6595,8 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) default: msec_delay(5); break; + case e1000_82571: + case e1000_82572: case e1000_82573: while(timeout) { if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; @@ -6494,10 +6626,31 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw) { + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t cfg_mask = E1000_EEPROM_CFG_DONE; + DEBUGFUNC("e1000_get_phy_cfg_done"); - /* Simply wait for 10ms */ - msec_delay(10); + switch (hw->mac_type) { + default: + msec_delay(10); + break; + case e1000_82571: + case e1000_82572: + while (timeout) { + if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask) + break; + else + msec_delay(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } return E1000_SUCCESS; } @@ -6569,8 +6722,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) return; swsm = E1000_READ_REG(hw, SWSM); - /* Release both semaphores. */ - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); } @@ -6606,6 +6758,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) * if this is the case. We read FWSM to determine the manageability mode. */ switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: fwsm = E1000_READ_REG(hw, FWSM); if((fwsm & E1000_FWSM_MODE_MASK) != 0) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 51c2b3a18b6f..4f2c196dc314 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -57,6 +57,8 @@ typedef enum { e1000_82541_rev_2, e1000_82547, e1000_82547_rev_2, + e1000_82571, + e1000_82572, e1000_82573, e1000_num_macs } e1000_mac_type; @@ -478,10 +480,16 @@ uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A #define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -833,6 +841,8 @@ struct e1000_ffvt_entry { #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_DISABLE_SERDES_LOOPBACK 0x0400 + /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. @@ -853,6 +863,7 @@ struct e1000_ffvt_entry { #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -864,6 +875,12 @@ struct e1000_ffvt_entry { #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ +#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ +#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ +#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ +#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ +#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ @@ -895,6 +912,12 @@ struct e1000_ffvt_entry { #define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ #define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ #define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ +#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ +#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ +#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ +#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ +#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ #define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ @@ -980,15 +1003,15 @@ struct e1000_ffvt_entry { #define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ -#define E1000_IAC 0x4100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */ -#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */ -#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */ -#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */ -#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ -#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ -#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ @@ -1018,6 +1041,14 @@ struct e1000_ffvt_entry { #define E1000_FWSM 0x05B54 /* FW Semaphore */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ +#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ /* Register Set (82542) * * Some of the 82542 registers are located at different offsets than they are @@ -1032,6 +1063,7 @@ struct e1000_ffvt_entry { #define E1000_82542_CTRL_EXT E1000_CTRL_EXT #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_SCTL E1000_SCTL #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1049,6 +1081,18 @@ struct e1000_ffvt_entry { #define E1000_82542_RDLEN 0x00118 #define E1000_82542_RDH 0x00120 #define E1000_82542_RDT 0x00128 +#define E1000_82542_RDTR0 E1000_82542_RDTR +#define E1000_82542_RDBAL0 E1000_82542_RDBAL +#define E1000_82542_RDBAH0 E1000_82542_RDBAH +#define E1000_82542_RDLEN0 E1000_82542_RDLEN +#define E1000_82542_RDH0 E1000_82542_RDH +#define E1000_82542_RDT0 E1000_82542_RDT +#define E1000_82542_RDTR1 0x00130 +#define E1000_82542_RDBAL1 0x00138 +#define E1000_82542_RDBAH1 0x0013C +#define E1000_82542_RDLEN1 0x00140 +#define E1000_82542_RDH1 0x00148 +#define E1000_82542_RDT1 0x00150 #define E1000_82542_FCRTH 0x00160 #define E1000_82542_FCRTL 0x00168 #define E1000_82542_FCTTV E1000_FCTTV @@ -1197,6 +1241,13 @@ struct e1000_ffvt_entry { #define E1000_82542_ICRXOC E1000_ICRXOC #define E1000_82542_HICR E1000_HICR +#define E1000_82542_CPUVEC E1000_CPUVEC +#define E1000_82542_MRQC E1000_MRQC +#define E1000_82542_RETA E1000_RETA +#define E1000_82542_RSSRK E1000_RSSRK +#define E1000_82542_RSSIM E1000_RSSIM +#define E1000_82542_RSSIR E1000_RSSIR + /* Statistics counters collected by the MAC */ struct e1000_hw_stats { uint64_t crcerrs; @@ -1336,6 +1387,7 @@ struct e1000_hw { boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; + boolean_t laa_is_present; boolean_t phy_reset_disable; boolean_t fc_send_xon; boolean_t fc_strict_ieee; @@ -1374,6 +1426,7 @@ struct e1000_hw { #define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ #define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ @@ -1491,6 +1544,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ @@ -1524,6 +1579,7 @@ struct e1000_hw { #define E1000_LEDCTL_LED2_BLINK 0x00800000 #define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 #define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 #define E1000_LEDCTL_LED3_IVRT 0x40000000 #define E1000_LEDCTL_LED3_BLINK 0x80000000 @@ -1784,6 +1840,16 @@ struct e1000_hw { #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ +/* Multiple Receive Queue Control */ +#define E1000_MRQC_ENABLE_MASK 0x00000003 +#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 +#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 +#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -1928,6 +1994,7 @@ struct e1000_host_command_info { #define E1000_MDALIGN 4096 #define E1000_GCR_BEM32 0x00400000 +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 #define E1000_FACTPS_LAN0_VALID 0x00000004 @@ -1980,6 +2047,7 @@ struct e1000_host_command_info { /* EEPROM Word Offsets */ #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_VERSION 0x0005 #define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ #define EEPROM_PHY_CLASS_WORD 0x0007 #define EEPROM_INIT_CONTROL1_REG 0x000A @@ -1990,6 +2058,8 @@ struct e1000_host_command_info { #define EEPROM_FLASH_VERSION 0x0032 #define EEPROM_CHECKSUM_REG 0x003F +#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 #define ID_LED_RESERVED_FFFF 0xFFFF @@ -2108,6 +2178,8 @@ struct e1000_host_command_info { #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 #define E1000_PBA_30K 0x001E +#define E1000_PBA_32K 0x0020 +#define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ @@ -2592,11 +2664,11 @@ struct e1000_host_command_info { /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 -#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128 +#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113 /* The precision error of the cable length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 -#define IGP02E1000_AGC_RANGE 10 +#define IGP02E1000_AGC_RANGE 15 /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ee687c902a20..6b72f6acdd54 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -43,7 +43,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "6.0.60-k2"DRIVERNAPI +#define DRV_VERSION "6.1.16-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; @@ -80,6 +80,9 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x105E), + INTEL_E1000_ETHERNET_DEVICE(0x105F), + INTEL_E1000_ETHERNET_DEVICE(0x1060), INTEL_E1000_ETHERNET_DEVICE(0x1075), INTEL_E1000_ETHERNET_DEVICE(0x1076), INTEL_E1000_ETHERNET_DEVICE(0x1077), @@ -88,10 +91,13 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x107A), INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), + INTEL_E1000_ETHERNET_DEVICE(0x107D), + INTEL_E1000_ETHERNET_DEVICE(0x107E), + INTEL_E1000_ETHERNET_DEVICE(0x107F), INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x108B), INTEL_E1000_ETHERNET_DEVICE(0x108C), - INTEL_E1000_ETHERNET_DEVICE(0x1099), + INTEL_E1000_ETHERNET_DEVICE(0x109A), /* required last entry */ {0,} }; @@ -102,10 +108,18 @@ int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -int e1000_setup_tx_resources(struct e1000_adapter *adapter); -int e1000_setup_rx_resources(struct e1000_adapter *adapter); -void e1000_free_tx_resources(struct e1000_adapter *adapter); -void e1000_free_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +void e1000_free_all_tx_resources(struct e1000_adapter *adapter); +void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr); +int e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr); +void e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +void e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -114,14 +128,22 @@ static int e1000_init_module(void); static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void __devexit e1000_remove(struct pci_dev *pdev); +static int e1000_alloc_queues(struct e1000_adapter *adapter); +#ifdef CONFIG_E1000_MQ +static void e1000_setup_queue_mapping(struct e1000_adapter *adapter); +#endif static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); -static void e1000_clean_tx_ring(struct e1000_adapter *adapter); -static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter); +static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -132,19 +154,26 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); -static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI -static int e1000_clean(struct net_device *netdev, int *budget); +static int e1000_clean(struct net_device *poll_dev, int *budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); #else -static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); -static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter); +static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif -static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); -static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -172,6 +201,11 @@ static int e1000_resume(struct pci_dev *pdev); static void e1000_netpoll (struct net_device *netdev); #endif +#ifdef CONFIG_E1000_MQ +/* for multiple Rx queues */ +void e1000_rx_schedule(void *data); +#endif + /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -289,7 +323,7 @@ int e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int err; + int i, err; /* hardware has been reset, we need to reload some things */ @@ -308,7 +342,8 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); - adapter->alloc_rx_buf(adapter); + for (i = 0; i < adapter->num_queues; i++) + adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2) { @@ -344,6 +379,9 @@ e1000_down(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); +#ifdef CONFIG_E1000_MQ + while (atomic_read(&adapter->rx_sched_call_data.count) != 0); +#endif free_irq(adapter->pdev->irq, netdev); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2 && @@ -363,11 +401,10 @@ e1000_down(struct e1000_adapter *adapter) netif_stop_queue(netdev); e1000_reset(adapter); - e1000_clean_tx_ring(adapter); - e1000_clean_rx_ring(adapter); + e1000_clean_all_tx_rings(adapter); + e1000_clean_all_rx_rings(adapter); - /* If WoL is not enabled - * and management mode is not IAMT + /* If WoL is not enabled and management mode is not IAMT * Power down the PHY so no link is implied when interface is down */ if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper && @@ -398,6 +435,10 @@ e1000_reset(struct e1000_adapter *adapter) case e1000_82547_rev_2: pba = E1000_PBA_30K; break; + case e1000_82571: + case e1000_82572: + pba = E1000_PBA_38K; + break; case e1000_82573: pba = E1000_PBA_12K; break; @@ -475,6 +516,7 @@ e1000_probe(struct pci_dev *pdev, struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; + uint32_t ctrl_ext; uint32_t swsm; static int cards_found = 0; @@ -614,8 +656,9 @@ e1000_probe(struct pci_dev *pdev, if(e1000_read_mac_addr(&adapter->hw)) DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; @@ -687,6 +730,12 @@ e1000_probe(struct pci_dev *pdev, /* Let firmware know the driver has taken over */ switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -731,7 +780,11 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + uint32_t ctrl_ext; uint32_t manc, swsm; +#ifdef CONFIG_E1000_NAPI + int i; +#endif flush_scheduled_work(); @@ -745,6 +798,12 @@ e1000_remove(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -756,13 +815,27 @@ e1000_remove(struct pci_dev *pdev) } unregister_netdev(netdev); +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) + __dev_put(&adapter->polling_netdev[i]); +#endif if(!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +#ifdef CONFIG_E1000_NAPI + kfree(adapter->polling_netdev); +#endif + iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); +#ifdef CONFIG_E1000_MQ + free_percpu(adapter->cpu_netdev); + free_percpu(adapter->cpu_tx_ring); +#endif free_netdev(netdev); pci_disable_device(pdev); @@ -783,6 +856,9 @@ e1000_sw_init(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; +#ifdef CONFIG_E1000_NAPI + int i; +#endif /* PCI config space info */ @@ -840,14 +916,123 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->master_slave = E1000_MASTER_SLAVE; } +#ifdef CONFIG_E1000_MQ + /* Number of supported queues */ + switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: + adapter->num_queues = 2; + break; + default: + adapter->num_queues = 1; + break; + } + adapter->num_queues = min(adapter->num_queues, num_online_cpus()); +#else + adapter->num_queues = 1; +#endif + + if (e1000_alloc_queues(adapter)) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) { + adapter->polling_netdev[i].priv = adapter; + adapter->polling_netdev[i].poll = &e1000_clean; + adapter->polling_netdev[i].weight = 64; + dev_hold(&adapter->polling_netdev[i]); + set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); + } +#endif + +#ifdef CONFIG_E1000_MQ + e1000_setup_queue_mapping(adapter); +#endif + atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); - spin_lock_init(&adapter->tx_lock); return 0; } /** + * e1000_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ + +static int __devinit +e1000_alloc_queues(struct e1000_adapter *adapter) +{ + int size; + + size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + adapter->tx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + memset(adapter->tx_ring, 0, size); + + size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + adapter->rx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + memset(adapter->rx_ring, 0, size); + +#ifdef CONFIG_E1000_NAPI + size = sizeof(struct net_device) * adapter->num_queues; + adapter->polling_netdev = kmalloc(size, GFP_KERNEL); + if (!adapter->polling_netdev) { + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + return -ENOMEM; + } + memset(adapter->polling_netdev, 0, size); +#endif + + return E1000_SUCCESS; +} + +#ifdef CONFIG_E1000_MQ +static void __devinit +e1000_setup_queue_mapping(struct e1000_adapter *adapter) +{ + int i, cpu; + + adapter->rx_sched_call_data.func = e1000_rx_schedule; + adapter->rx_sched_call_data.info = adapter->netdev; + cpus_clear(adapter->rx_sched_call_data.cpumask); + + adapter->cpu_netdev = alloc_percpu(struct net_device *); + adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); + + lock_cpu_hotplug(); + i = 0; + for_each_online_cpu(cpu) { + *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues]; + /* This is incomplete because we'd like to assign separate + * physical cpus to these netdev polling structures and + * avoid saturating a subset of cpus. + */ + if (i < adapter->num_queues) { + *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; + adapter->cpu_for_queue[i] = cpu; + } else + *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; + + i++; + } + unlock_cpu_hotplug(); +} +#endif + +/** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -868,12 +1053,12 @@ e1000_open(struct net_device *netdev) /* allocate transmit descriptors */ - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* allocate receive descriptors */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_up(adapter))) @@ -887,9 +1072,9 @@ e1000_open(struct net_device *netdev) return E1000_SUCCESS; err_up: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: - e1000_free_tx_resources(adapter); + e1000_free_all_tx_resources(adapter); err_setup_tx: e1000_reset(adapter); @@ -915,8 +1100,8 @@ e1000_close(struct net_device *netdev) e1000_down(adapter); - e1000_free_tx_resources(adapter); - e1000_free_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); if((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { @@ -951,14 +1136,15 @@ e1000_check_64k_bound(struct e1000_adapter *adapter, /** * e1000_setup_tx_resources - allocate Tx resources (Descriptors) * @adapter: board private structure + * @txdr: tx descriptor ring (for a specific queue) to setup * * Return 0 on success, negative on failure **/ int -e1000_setup_tx_resources(struct e1000_adapter *adapter) +e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr) { - struct e1000_desc_ring *txdr = &adapter->tx_ring; struct pci_dev *pdev = adapter->pdev; int size; @@ -970,6 +1156,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) return -ENOMEM; } memset(txdr->buffer_info, 0, size); + memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer)); /* round up to nearest 4K */ @@ -1018,11 +1205,41 @@ setup_tx_desc_die: txdr->next_to_use = 0; txdr->next_to_clean = 0; + spin_lock_init(&txdr->tx_lock); return 0; } /** + * e1000_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_tx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** * e1000_configure_tx - Configure 8254x Transmit Unit after Reset * @adapter: board private structure * @@ -1032,23 +1249,43 @@ setup_tx_desc_die: static void e1000_configure_tx(struct e1000_adapter *adapter) { - uint64_t tdba = adapter->tx_ring.dma; - uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); - uint32_t tctl, tipg; - - E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32)); - - E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen); + uint64_t tdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t tdlen, tctl, tipg, tarc; /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + switch (adapter->num_queues) { + case 2: + tdba = adapter->tx_ring[1].dma; + tdlen = adapter->tx_ring[1].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN1, tdlen); + E1000_WRITE_REG(hw, TDH1, 0); + E1000_WRITE_REG(hw, TDT1, 0); + adapter->tx_ring[1].tdh = E1000_TDH1; + adapter->tx_ring[1].tdt = E1000_TDT1; + /* Fall Through */ + case 1: + default: + tdba = adapter->tx_ring[0].dma; + tdlen = adapter->tx_ring[0].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN, tdlen); + E1000_WRITE_REG(hw, TDH, 0); + E1000_WRITE_REG(hw, TDT, 0); + adapter->tx_ring[0].tdh = E1000_TDH; + adapter->tx_ring[0].tdt = E1000_TDT; + break; + } /* Set the default values for the Tx Inter Packet Gap timer */ - switch (adapter->hw.mac_type) { + switch (hw->mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: tipg = DEFAULT_82542_TIPG_IPGT; @@ -1056,67 +1293,81 @@ e1000_configure_tx(struct e1000_adapter *adapter) tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; break; default: - if(adapter->hw.media_type == e1000_media_type_fiber || - adapter->hw.media_type == e1000_media_type_internal_serdes) + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else tipg = DEFAULT_82543_TIPG_IPGT_COPPER; tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; } - E1000_WRITE_REG(&adapter->hw, TIPG, tipg); + E1000_WRITE_REG(hw, TIPG, tipg); /* Set the Tx Interrupt Delay register */ - E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) - E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); + E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay); + if (hw->mac_type >= e1000_82540) + E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay); /* Program the Transmit Control Register */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | + tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + E1000_WRITE_REG(hw, TCTL, tctl); - e1000_config_collision_dist(&adapter->hw); + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) { + tarc = E1000_READ_REG(hw, TARC0); + tarc |= ((1 << 25) | (1 << 21)); + E1000_WRITE_REG(hw, TARC0, tarc); + tarc = E1000_READ_REG(hw, TARC1); + tarc |= (1 << 25); + if (tctl & E1000_TCTL_MULR) + tarc &= ~(1 << 28); + else + tarc |= (1 << 28); + E1000_WRITE_REG(hw, TARC1, tarc); + } + + e1000_config_collision_dist(hw); /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.mac_type < e1000_82543) + if (hw->mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; else adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ - if(adapter->hw.mac_type == e1000_82544 && - adapter->hw.bus_type == e1000_bus_type_pcix) + if (hw->mac_type == e1000_82544 && + hw->bus_type == e1000_bus_type_pcix) adapter->pcix_82544 = 1; } /** * e1000_setup_rx_resources - allocate Rx resources (Descriptors) * @adapter: board private structure + * @rxdr: rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure **/ int -e1000_setup_rx_resources(struct e1000_adapter *adapter) +e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr) { - struct e1000_desc_ring *rxdr = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; rxdr->buffer_info = vmalloc(size); - if(!rxdr->buffer_info) { + if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; @@ -1156,13 +1407,13 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { + if (!rxdr->desc) { + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); setup_rx_desc_die: vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } @@ -1174,9 +1425,12 @@ setup_rx_desc_die: "at %p\n", rxdr->size, rxdr->desc); /* Try again, without freeing the previous */ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { /* Failed allocation, critical failure */ + if (!rxdr->desc) { pci_free_consistent(pdev, rxdr->size, olddesc, olddma); + DPRINTK(PROBE, ERR, + "Unable to allocate memory " + "for the receive descriptor ring\n"); goto setup_rx_desc_die; } @@ -1188,10 +1442,7 @@ setup_rx_desc_die: DPRINTK(PROBE, ERR, "Unable to allocate aligned memory " "for the receive descriptor ring\n"); - vfree(rxdr->buffer_info); - kfree(rxdr->ps_page); - kfree(rxdr->ps_page_dma); - return -ENOMEM; + goto setup_rx_desc_die; } else { /* Free old allocation, new allocation was successful */ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); @@ -1206,15 +1457,48 @@ setup_rx_desc_die: } /** + * e1000_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_rx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** * e1000_setup_rctl - configure the receive control registers * @adapter: Board private structure **/ - +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) static void e1000_setup_rctl(struct e1000_adapter *adapter) { uint32_t rctl, rfctl; uint32_t psrctl = 0; +#ifdef CONFIG_E1000_PACKET_SPLIT + uint32_t pages = 0; +#endif rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1235,7 +1519,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl |= E1000_RCTL_LPE; /* Setup buffer sizes */ - if(adapter->hw.mac_type == e1000_82573) { + if(adapter->hw.mac_type >= e1000_82571) { /* We can now specify buffers in 1K increments. * BSIZE and BSEX are ignored in this case. */ rctl |= adapter->rx_buffer_len << 0x11; @@ -1268,11 +1552,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter) * followed by the page buffers. Therefore, skb->data is * sized to hold the largest protocol header. */ - adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2) - && (adapter->netdev->mtu - < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0)); + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) && + PAGE_SIZE <= 16384) + adapter->rx_ps_pages = pages; + else + adapter->rx_ps_pages = 0; #endif - if(adapter->rx_ps) { + if (adapter->rx_ps_pages) { /* Configure extra packet-split registers */ rfctl = E1000_READ_REG(&adapter->hw, RFCTL); rfctl |= E1000_RFCTL_EXTEN; @@ -1284,12 +1571,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter) psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; - psrctl |= PAGE_SIZE >> - E1000_PSRCTL_BSIZE1_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE2_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE3_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); } @@ -1307,91 +1601,181 @@ e1000_setup_rctl(struct e1000_adapter *adapter) static void e1000_configure_rx(struct e1000_adapter *adapter) { - uint64_t rdba = adapter->rx_ring.dma; - uint32_t rdlen, rctl, rxcsum; + uint64_t rdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t rdlen, rctl, rxcsum, ctrl_ext; +#ifdef CONFIG_E1000_MQ + uint32_t reta, mrqc; + int i; +#endif - if(adapter->rx_ps) { - rdlen = adapter->rx_ring.count * + if (adapter->rx_ps_pages) { + rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; } else { - rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); adapter->clean_rx = e1000_clean_rx_irq; adapter->alloc_rx_buf = e1000_alloc_rx_buffers; } /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); - E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); + rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); + E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + if (hw->mac_type >= e1000_82540) { + E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); if(adapter->itr > 1) - E1000_WRITE_REG(&adapter->hw, ITR, + E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256)); } - /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); + if (hw->mac_type >= e1000_82571) { + /* Reset delay timers after every interrupt */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_CANC; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + } + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + switch (adapter->num_queues) { +#ifdef CONFIG_E1000_MQ + case 2: + rdba = adapter->rx_ring[1].dma; + E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN1, rdlen); + E1000_WRITE_REG(hw, RDH1, 0); + E1000_WRITE_REG(hw, RDT1, 0); + adapter->rx_ring[1].rdh = E1000_RDH1; + adapter->rx_ring[1].rdt = E1000_RDT1; + /* Fall Through */ +#endif + case 1: + default: + rdba = adapter->rx_ring[0].dma; + E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN, rdlen); + E1000_WRITE_REG(hw, RDH, 0); + E1000_WRITE_REG(hw, RDT, 0); + adapter->rx_ring[0].rdh = E1000_RDH; + adapter->rx_ring[0].rdt = E1000_RDT; + break; + } + +#ifdef CONFIG_E1000_MQ + if (adapter->num_queues > 1) { + uint32_t random[10]; + + get_random_bytes(&random[0], 40); + + if (hw->mac_type <= e1000_82572) { + E1000_WRITE_REG(hw, RSSIR, 0); + E1000_WRITE_REG(hw, RSSIM, 0); + } + + switch (adapter->num_queues) { + case 2: + default: + reta = 0x00800080; + mrqc = E1000_MRQC_ENABLE_RSS_2Q; + break; + } + + /* Fill out redirection table */ + for (i = 0; i < 32; i++) + E1000_WRITE_REG_ARRAY(hw, RETA, i, reta); + /* Fill out hash function seeds */ + for (i = 0; i < 10; i++) + E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]); + + mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP); + E1000_WRITE_REG(hw, MRQC, mrqc); + } - E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen); + /* Multiqueue and packet checksumming are mutually exclusive. */ + if (hw->mac_type >= e1000_82571) { + rxcsum = E1000_READ_REG(hw, RXCSUM); + rxcsum |= E1000_RXCSUM_PCSD; + E1000_WRITE_REG(hw, RXCSUM, rxcsum); + } - /* Setup the HW Rx Head and Tail Descriptor Pointers */ - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); +#else /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if(adapter->hw.mac_type >= e1000_82543) { - rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); + if (hw->mac_type >= e1000_82543) { + rxcsum = E1000_READ_REG(hw, RXCSUM); if(adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; - /* Enable 82573 IPv4 payload checksum for UDP fragments + /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ - if((adapter->hw.mac_type > e1000_82547_rev_2) && - (adapter->rx_ps)) { + if ((hw->mac_type >= e1000_82571) && + (adapter->rx_ps_pages)) { rxcsum |= E1000_RXCSUM_IPPCSE; } } else { rxcsum &= ~E1000_RXCSUM_TUOFL; /* don't need to clear IPPCSE as it defaults to 0 */ } - E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum); + E1000_WRITE_REG(hw, RXCSUM, rxcsum); } +#endif /* CONFIG_E1000_MQ */ - if (adapter->hw.mac_type == e1000_82573) - E1000_WRITE_REG(&adapter->hw, ERT, 0x0100); + if (hw->mac_type == e1000_82573) + E1000_WRITE_REG(hw, ERT, 0x0100); /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + E1000_WRITE_REG(hw, RCTL, rctl); } /** - * e1000_free_tx_resources - Free Tx Resources + * e1000_free_tx_resources - Free Tx Resources per Queue * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue * * Free all transmit software resources **/ void -e1000_free_tx_resources(struct e1000_adapter *adapter) +e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { struct pci_dev *pdev = adapter->pdev; - e1000_clean_tx_ring(adapter); + e1000_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; - vfree(adapter->tx_ring.buffer_info); - adapter->tx_ring.buffer_info = NULL; + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} - pci_free_consistent(pdev, adapter->tx_ring.size, - adapter->tx_ring.desc, adapter->tx_ring.dma); +/** + * e1000_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ + +void +e1000_free_all_tx_resources(struct e1000_adapter *adapter) +{ + int i; - adapter->tx_ring.desc = NULL; + for (i = 0; i < adapter->num_queues; i++) + e1000_free_tx_resources(adapter, &adapter->tx_ring[i]); } static inline void @@ -1414,21 +1798,22 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, /** * e1000_clean_tx_ring - Free Tx Buffers * @adapter: board private structure + * @tx_ring: ring to be cleaned **/ static void -e1000_clean_tx_ring(struct e1000_adapter *adapter) +e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned long size; unsigned int i; /* Free all the Tx ring sk_buffs */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(i = 0; i < tx_ring->count; i++) { @@ -1446,24 +1831,39 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + writel(0, adapter->hw.hw_addr + tx_ring->tdh); + writel(0, adapter->hw.hw_addr + tx_ring->tdt); +} + +/** + * e1000_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_tx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]); } /** * e1000_free_rx_resources - Free Rx Resources * @adapter: board private structure + * @rx_ring: ring to clean the resources from * * Free all receive software resources **/ void -e1000_free_rx_resources(struct e1000_adapter *adapter) +e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; - e1000_clean_rx_ring(adapter); + e1000_clean_rx_ring(adapter, rx_ring); vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; @@ -1478,14 +1878,31 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) } /** - * e1000_clean_rx_ring - Free Rx Buffers + * e1000_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ + +void +e1000_free_all_rx_resources(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue * @adapter: board private structure + * @rx_ring: ring to free buffers from **/ static void -e1000_clean_rx_ring(struct e1000_adapter *adapter) +e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct e1000_buffer *buffer_info; struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; @@ -1508,7 +1925,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!ps_page->ps_page[j]) break; pci_unmap_single(pdev, ps_page_dma->ps_page_dma[j], @@ -1534,8 +1951,22 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); + writel(0, adapter->hw.hw_addr + rx_ring->rdh); + writel(0, adapter->hw.hw_addr + rx_ring->rdt); +} + +/** + * e1000_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_rx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]); } /* The 82542 2.0 (revision 2) needs to have the receive unit in reset @@ -1556,7 +1987,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter) mdelay(5); if(netif_running(netdev)) - e1000_clean_rx_ring(adapter); + e1000_clean_all_rx_rings(adapter); } static void @@ -1576,7 +2007,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter) if(netif_running(netdev)) { e1000_configure_rx(adapter); - e1000_alloc_rx_buffers(adapter); + e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]); } } @@ -1607,6 +2038,22 @@ e1000_set_mac(struct net_device *netdev, void *p) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* With 82571 controllers, LAA may be overwritten (with the default) + * due to controller reset from the other port. */ + if (adapter->hw.mac_type == e1000_82571) { + /* activate the work around */ + adapter->hw.laa_is_present = 1; + + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventaully the LAA will be in RAR[0] and + * RAR[14] */ + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, + E1000_RAR_ENTRIES - 1); + } + if(adapter->hw.mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); @@ -1629,12 +2076,13 @@ e1000_set_multi(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; - unsigned long flags; uint32_t rctl; uint32_t hash_value; - int i; + int i, rar_entries = E1000_RAR_ENTRIES; - spin_lock_irqsave(&adapter->tx_lock, flags); + /* reserve RAR[14] for LAA over-write work-around */ + if (adapter->hw.mac_type == e1000_82571) + rar_entries--; /* Check for Promiscuous and All Multicast modes */ @@ -1659,11 +2107,12 @@ e1000_set_multi(struct net_device *netdev) /* load the first 14 multicast address into the exact filters 1-14 * RAR 0 is used for the station MAC adddress * if there are not 14 addresses, go ahead and clear the filters + * -- with 82571 controllers only 0-13 entries are filled here */ mc_ptr = netdev->mc_list; - for(i = 1; i < E1000_RAR_ENTRIES; i++) { - if(mc_ptr) { + for(i = 1; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->dmi_addr, i); mc_ptr = mc_ptr->next; } else { @@ -1686,8 +2135,6 @@ e1000_set_multi(struct net_device *netdev) if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); - - spin_unlock_irqrestore(&adapter->tx_lock, flags); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -1759,7 +2206,7 @@ static void e1000_watchdog_task(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_tx_ring *txdr = &adapter->tx_ring[0]; uint32_t link; e1000_check_for_link(&adapter->hw); @@ -1818,8 +2265,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_update_adaptive(&adapter->hw); - if(!netif_carrier_ok(netdev)) { - if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { + if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) { + if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, * but we've got queued Tx work that's never going * to get done, so reset controller to flush Tx. @@ -1847,6 +2294,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter) /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = TRUE; + /* With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] */ + if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present) + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* Reset the timer */ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } @@ -1859,7 +2311,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline int -e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; @@ -1910,8 +2363,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; @@ -1923,8 +2376,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; context_desc->cmd_and_length = cpu_to_le32(cmd_length); - if(++i == adapter->tx_ring.count) i = 0; - adapter->tx_ring.next_to_use = i; + if (++i == tx_ring->count) i = 0; + tx_ring->next_to_use = i; return 1; } @@ -1934,7 +2387,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) } static inline boolean_t -e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { struct e1000_context_desc *context_desc; unsigned int i; @@ -1943,8 +2397,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; @@ -1952,8 +2406,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(unlikely(++i == adapter->tx_ring.count)) i = 0; - adapter->tx_ring.next_to_use = i; + if (unlikely(++i == tx_ring->count)) i = 0; + tx_ring->next_to_use = i; return TRUE; } @@ -1965,11 +2419,10 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) #define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) static inline int -e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, - unsigned int first, unsigned int max_per_txd, - unsigned int nr_frags, unsigned int mss) +e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, + unsigned int nr_frags, unsigned int mss) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned int len = skb->len; unsigned int offset = 0, size, count = 0, i; @@ -2065,9 +2518,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, } static inline void -e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) +e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + int tx_flags, int count) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; @@ -2113,7 +2566,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) wmb(); tx_ring->next_to_use = i; - E1000_WRITE_REG(&adapter->hw, TDT, i); + writel(i, adapter->hw.hw_addr + tx_ring->tdt); } /** @@ -2206,6 +2659,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_tx_ring *tx_ring; unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; @@ -2218,7 +2672,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; len -= skb->data_len; - if(unlikely(skb->len <= 0)) { +#ifdef CONFIG_E1000_MQ + tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); +#else + tx_ring = adapter->tx_ring; +#endif + + if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2262,21 +2722,42 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count += nr_frags; - local_irq_save(flags); - if (!spin_trylock(&adapter->tx_lock)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } +#ifdef NETIF_F_TSO + /* TSO Workaround for 82571/2 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + if (skb_shinfo(skb)->tso_size) { + uint8_t hdr_len; + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) && + (adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572)) { + unsigned int pull_size; + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; + } + } + } +#endif + if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); + local_irq_save(flags); + if (!spin_trylock(&tx_ring->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) { + if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) { netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -2284,7 +2765,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } } @@ -2294,37 +2775,37 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } - first = adapter->tx_ring.next_to_use; + first = tx_ring->next_to_use; - tso = e1000_tso(adapter, skb); + tso = e1000_tso(adapter, tx_ring, skb); if (tso < 0) { dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } if (likely(tso)) tx_flags |= E1000_TX_FLAGS_TSO; - else if(likely(e1000_tx_csum(adapter, skb))) + else if (likely(e1000_tx_csum(adapter, tx_ring, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; /* Old method was to assume IPv4 packet by default if TSO was enabled. - * 82573 hardware supports TSO capabilities for IPv6 as well... + * 82571 hardware supports TSO capabilities for IPv6 as well... * no longer assume, we must. */ - if(likely(skb->protocol == ntohs(ETH_P_IP))) + if (likely(skb->protocol == ntohs(ETH_P_IP))) tx_flags |= E1000_TX_FLAGS_IPV4; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), - tx_flags); + e1000_tx_queue(adapter, tx_ring, tx_flags, + e1000_tx_map(adapter, tx_ring, skb, first, + max_per_txd, nr_frags, mss)); netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2)) + if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2)) netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } @@ -2388,9 +2869,18 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } -#define MAX_STD_JUMBO_FRAME_SIZE 9216 +#define MAX_STD_JUMBO_FRAME_SIZE 9234 /* might want this to be bigger enum check... */ - if (adapter->hw.mac_type == e1000_82573 && + /* 82571 controllers limit jumbo frame size to 10500 bytes */ + if ((adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572) && + max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported " + "on 82571 and 82572 controllers.\n"); + return -EINVAL; + } + + if(adapter->hw.mac_type == e1000_82573 && max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported " "on 82573\n"); @@ -2578,6 +3068,29 @@ e1000_update_stats(struct e1000_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } +#ifdef CONFIG_E1000_MQ +void +e1000_rx_schedule(void *data) +{ + struct net_device *poll_dev, *netdev = data; + struct e1000_adapter *adapter = netdev->priv; + int this_cpu = get_cpu(); + + poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu); + if (poll_dev == NULL) { + put_cpu(); + return; + } + + if (likely(netif_rx_schedule_prep(poll_dev))) + __netif_rx_schedule(poll_dev); + else + e1000_irq_enable(adapter); + + put_cpu(); +} +#endif + /** * e1000_intr - Interrupt Handler * @irq: interrupt number @@ -2592,8 +3105,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); -#ifndef CONFIG_E1000_NAPI - unsigned int i; +#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI) + int i; #endif if(unlikely(!icr)) @@ -2605,17 +3118,31 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #ifdef CONFIG_E1000_NAPI - if(likely(netif_rx_schedule_prep(netdev))) { - - /* Disable interrupts and register for poll. The flush - of the posted write is intentionally left out. - */ - - atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(hw, IMC, ~0); - __netif_rx_schedule(netdev); + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(hw, IMC, ~0); + E1000_WRITE_FLUSH(hw); +#ifdef CONFIG_E1000_MQ + if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { + cpu_set(adapter->cpu_for_queue[0], + adapter->rx_sched_call_data.cpumask); + for (i = 1; i < adapter->num_queues; i++) { + cpu_set(adapter->cpu_for_queue[i], + adapter->rx_sched_call_data.cpumask); + atomic_inc(&adapter->irq_sem); + } + atomic_set(&adapter->rx_sched_call_data.count, i); + smp_call_async_mask(&adapter->rx_sched_call_data); + } else { + printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); } -#else +#else /* if !CONFIG_E1000_MQ */ + if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) + __netif_rx_schedule(&adapter->polling_netdev[0]); + else + e1000_irq_enable(adapter); +#endif /* CONFIG_E1000_MQ */ + +#else /* if !CONFIG_E1000_NAPI */ /* Writing IMC and IMS is needed for 82547. Due to Hub Link bus being occupied, an interrupt de-assertion message is not able to be sent. @@ -2632,13 +3159,14 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } for(i = 0; i < E1000_MAX_INTR; i++) - if(unlikely(!adapter->clean_rx(adapter) & - !e1000_clean_tx_irq(adapter))) + if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & + !e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); -#endif + +#endif /* CONFIG_E1000_NAPI */ return IRQ_HANDLED; } @@ -2650,22 +3178,37 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) **/ static int -e1000_clean(struct net_device *netdev, int *budget) +e1000_clean(struct net_device *poll_dev, int *budget) { - struct e1000_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); - int tx_cleaned; - int work_done = 0; + struct e1000_adapter *adapter; + int work_to_do = min(*budget, poll_dev->quota); + int tx_cleaned, i = 0, work_done = 0; - tx_cleaned = e1000_clean_tx_irq(adapter); - adapter->clean_rx(adapter, &work_done, work_to_do); + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + + while (poll_dev != &adapter->polling_netdev[i]) { + i++; + if (unlikely(i == adapter->num_queues)) + BUG(); + } + + tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]); + adapter->clean_rx(adapter, &adapter->rx_ring[i], + &work_done, work_to_do); *budget -= work_done; - netdev->quota -= work_done; + poll_dev->quota -= work_done; - if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { /* If no Tx and not enough Rx work done, exit the polling mode */ - netif_rx_complete(netdev); + if((!tx_cleaned && (work_done == 0)) || + !netif_running(adapter->netdev)) { +quit_polling: + netif_rx_complete(poll_dev); e1000_irq_enable(adapter); return 0; } @@ -2680,9 +3223,9 @@ e1000_clean(struct net_device *netdev, int *budget) **/ static boolean_t -e1000_clean_tx_irq(struct e1000_adapter *adapter) +e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; @@ -2693,12 +3236,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); - while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { /* Premature writeback of Tx descriptors clear (free buffers * and unmap pci_mapping) previous_buffer_info */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(cleaned = FALSE; !cleaned; ) { @@ -2714,7 +3257,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) #ifdef NETIF_F_TSO } else { if (cleaned) { - memcpy(&adapter->previous_buffer_info, + memcpy(&tx_ring->previous_buffer_info, buffer_info, sizeof(struct e1000_buffer)); memset(buffer_info, 0, @@ -2732,6 +3275,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) if(unlikely(++i == tx_ring->count)) i = 0; } + + tx_ring->pkt++; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -2739,15 +3284,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_ring->next_to_clean = i; - spin_lock(&adapter->tx_lock); + spin_lock(&tx_ring->tx_lock); if(unlikely(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))) netif_wake_queue(netdev); - spin_unlock(&adapter->tx_lock); - if(adapter->detect_tx_hung) { + spin_unlock(&tx_ring->tx_lock); + if (adapter->detect_tx_hung) { /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; @@ -2771,8 +3316,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) " next_to_watch <%x>\n" " jiffies <%lx>\n" " next_to_watch.status <%x>\n", - E1000_READ_REG(&adapter->hw, TDH), - E1000_READ_REG(&adapter->hw, TDT), + readl(adapter->hw.hw_addr + tx_ring->tdh), + readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, i, (unsigned long long)tx_ring->buffer_info[i].dma, @@ -2784,12 +3329,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) } } #ifdef NETIF_F_TSO - - if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && - time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ))) + if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && + time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ))) e1000_unmap_and_free_tx_resource( - adapter, &adapter->previous_buffer_info); - + adapter, &tx_ring->previous_buffer_info); #endif return cleaned; } @@ -2852,13 +3395,14 @@ e1000_rx_checksum(struct e1000_adapter *adapter, static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq(struct e1000_adapter *adapter) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -2944,6 +3488,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->status = 0; @@ -2953,7 +3498,7 @@ next_desc: rx_desc = E1000_RX_DESC(*rx_ring, i); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -2965,13 +3510,14 @@ next_desc: static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; union e1000_rx_desc_packet_split *rx_desc; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3027,7 +3573,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) /* Good Receive */ skb_put(skb, length); - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) break; @@ -3048,11 +3594,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); skb->protocol = eth_type_trans(skb, netdev); -#ifdef HAVE_RX_ZERO_COPY if(likely(rx_desc->wb.upper.header_status & - E1000_RXDPS_HDRSTAT_HDRSP)) + E1000_RXDPS_HDRSTAT_HDRSP)) { + adapter->rx_hdr_split++; +#ifdef HAVE_RX_ZERO_COPY skb_shinfo(skb)->zero_copy = TRUE; #endif + } #ifdef CONFIG_E1000_NAPI if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, @@ -3071,6 +3619,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->wb.middle.status_error &= ~0xFF; @@ -3081,7 +3630,7 @@ next_desc: staterr = le32_to_cpu(rx_desc->wb.middle.status_error); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -3092,9 +3641,9 @@ next_desc: **/ static void -e1000_alloc_rx_buffers(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -3178,7 +3727,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); - E1000_WRITE_REG(&adapter->hw, RDT, i); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; @@ -3194,9 +3743,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) **/ static void -e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union e1000_rx_desc_packet_split *rx_desc; @@ -3215,22 +3764,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) rx_desc = E1000_RX_DESC_PS(*rx_ring, i); for(j = 0; j < PS_PAGE_BUFFERS; j++) { - if(unlikely(!ps_page->ps_page[j])) { - ps_page->ps_page[j] = - alloc_page(GFP_ATOMIC); - if(unlikely(!ps_page->ps_page[j])) - goto no_buffers; - ps_page_dma->ps_page_dma[j] = - pci_map_page(pdev, - ps_page->ps_page[j], - 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - } - /* Refresh the desc even if buffer_addrs didn't - * change because each write-back erases this info. - */ - rx_desc->read.buffer_addr[j+1] = - cpu_to_le64(ps_page_dma->ps_page_dma[j]); + if (j < adapter->rx_ps_pages) { + if (likely(!ps_page->ps_page[j])) { + ps_page->ps_page[j] = + alloc_page(GFP_ATOMIC); + if (unlikely(!ps_page->ps_page[j])) + goto no_buffers; + ps_page_dma->ps_page_dma[j] = + pci_map_page(pdev, + ps_page->ps_page[j], + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't + * change because each write-back erases + * this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page_dma->ps_page_dma[j]); + } else + rx_desc->read.buffer_addr[j+1] = ~0; } skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); @@ -3264,7 +3817,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) * descriptors are 32 bytes...so we increment tail * twice as much. */ - E1000_WRITE_REG(&adapter->hw, RDT, i<<1); + writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; @@ -3715,6 +4268,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -3737,6 +4296,7 @@ e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t manc, ret_val, swsm; + uint32_t ctrl_ext; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); @@ -3762,6 +4322,12 @@ e1000_resume(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -3786,7 +4352,7 @@ e1000_netpoll(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); disable_irq(adapter->pdev->irq); e1000_intr(adapter->pdev->irq, netdev, NULL); - e1000_clean_tx_irq(adapter); + e1000_clean_tx_irq(adapter, adapter->tx_ring); enable_irq(adapter->pdev->irq); } #endif diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 676247f9f1cc..38695d5b4637 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -306,7 +306,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_TXD, .arg = { .r = { .min = E1000_MIN_TXD }} }; - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct e1000_tx_ring *tx_ring = adapter->tx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD; @@ -319,6 +320,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { tx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + tx_ring[i].count = tx_ring->count; } { /* Receive Descriptor Count */ struct e1000_option opt = { @@ -329,7 +332,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_RXD, .arg = { .r = { .min = E1000_MIN_RXD }} }; - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct e1000_rx_ring *rx_ring = adapter->rx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -342,6 +346,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { rx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + rx_ring[i].count = rx_ring->count; } { /* Checksum Offload Enable/Disable */ struct e1000_option opt = { diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 87f522738bfc..f119ec4e89ea 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1334,7 +1334,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep) static int epic_poll(struct net_device *dev, int *budget) { struct epic_private *ep = dev->priv; - int work_done, orig_budget; + int work_done = 0, orig_budget; long ioaddr = dev->base_addr; orig_budget = (*budget > dev->quota) ? dev->quota : *budget; @@ -1343,7 +1343,7 @@ rx_action: epic_tx(dev, ep); - work_done = epic_rx(dev, *budget); + work_done += epic_rx(dev, *budget); epic_rx_err(dev, ep); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d6eefdb71c17..22aec6ed80f5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -95,6 +95,8 @@ * of nv_remove * 0.42: 06 Aug 2005: Fix lack of link speed initialization * in the second (and later) nv_open call + * 0.43: 10 Aug 2005: Add support for tx checksum. + * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -106,7 +108,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.41" +#define FORCEDETH_VERSION "0.44" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -145,6 +147,7 @@ #define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ enum { NvRegIrqStatus = 0x000, @@ -241,6 +244,9 @@ enum { #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 +#define NVREG_TXRXCTL_DESC_1 0 +#define NVREG_TXRXCTL_DESC_2 0x02100 +#define NVREG_TXRXCTL_DESC_3 0x02200 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -335,6 +341,10 @@ typedef union _ring_type { /* error and valid are the same for both */ #define NV_TX2_ERROR (1<<30) #define NV_TX2_VALID (1<<31) +#define NV_TX2_TSO (1<<28) +#define NV_TX2_TSO_SHIFT 14 +#define NV_TX2_CHECKSUM_L3 (1<<27) +#define NV_TX2_CHECKSUM_L4 (1<<26) #define NV_RX_DESCRIPTORVALID (1<<16) #define NV_RX_MISSEDFRAME (1<<17) @@ -417,14 +427,14 @@ typedef union _ring_type { /* * desc_ver values: - * This field has two purposes: - * - Newer nics uses a different ring layout. The layout is selected by - * comparing np->desc_ver with DESC_VER_xy. - * - It contains bits that are forced on when writing to NvRegTxRxControl. + * The nic supports three different descriptor types: + * - DESC_VER_1: Original + * - DESC_VER_2: support for jumbo frames. + * - DESC_VER_3: 64-bit format. */ -#define DESC_VER_1 0x0 -#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) -#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_1 1 +#define DESC_VER_2 2 +#define DESC_VER_3 3 /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -491,6 +501,7 @@ struct fe_priv { u32 orig_mac[2]; u32 irqmask; u32 desc_ver; + u32 txrxctl_bits; void __iomem *base; @@ -534,7 +545,7 @@ static inline struct fe_priv *get_nvpriv(struct net_device *dev) static inline u8 __iomem *get_hwbase(struct net_device *dev) { - return get_nvpriv(dev)->base; + return ((struct fe_priv *)netdev_priv(dev))->base; } static inline void pci_push(u8 __iomem *base) @@ -623,7 +634,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) static int phy_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 miicontrol; unsigned int tries = 0; @@ -726,7 +737,7 @@ static int phy_init(struct net_device *dev) static void nv_start_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); @@ -782,14 +793,14 @@ static void nv_stop_tx(struct net_device *dev) static void nv_txrx_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); - writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); - writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); } @@ -801,7 +812,7 @@ static void nv_txrx_reset(struct net_device *dev) */ static struct net_device_stats *nv_get_stats(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); /* It seems that the nic always generates interrupts and doesn't * accumulate errors internally. Thus the current values in np->stats @@ -817,7 +828,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) */ static int nv_alloc_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unsigned int refill_rx = np->refill_rx; int nr; @@ -861,7 +872,7 @@ static int nv_alloc_rx(struct net_device *dev) static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); disable_irq(dev->irq); if (nv_alloc_rx(dev)) { @@ -875,7 +886,7 @@ static void nv_do_rx_refill(unsigned long data) static void nv_init_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->cur_rx = RX_RING; @@ -889,15 +900,17 @@ static void nv_init_rx(struct net_device *dev) static void nv_init_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; + np->tx_skbuff[i] = NULL; + } } static int nv_init_ring(struct net_device *dev) @@ -907,21 +920,44 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx(dev); } +static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) +{ + struct fe_priv *np = netdev_priv(dev); + struct sk_buff *skb = np->tx_skbuff[skbnr]; + unsigned int j, entry, fragments; + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", + dev->name, skbnr, np->tx_skbuff[skbnr]); + + entry = skbnr; + if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { + for (j = fragments; j >= 1; j--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; + pci_unmap_page(np->pci_dev, np->tx_dma[entry], + frag->size, + PCI_DMA_TODEVICE); + entry = (entry - 1) % TX_RING; + } + } + pci_unmap_single(np->pci_dev, np->tx_dma[entry], + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + np->tx_skbuff[skbnr] = NULL; +} + static void nv_drain_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int i; + struct fe_priv *np = netdev_priv(dev); + unsigned int i; + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; + nv_release_txskb(dev, i); np->stats.tx_dropped++; } } @@ -929,7 +965,7 @@ static void nv_drain_tx(struct net_device *dev) static void nv_drain_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; for (i = 0; i < RX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) @@ -959,28 +995,69 @@ static void drain_ring(struct net_device *dev) */ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int nr = np->next_tx % TX_RING; + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int nr = (np->next_tx + fragments) % TX_RING; + unsigned int i; + + spin_lock_irq(&np->lock); + + if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { + spin_unlock_irq(&np->lock); + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } np->tx_skbuff[nr] = skb; - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, - PCI_DMA_TODEVICE); + + if (fragments) { + dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); + /* setup descriptors in reverse order */ + for (i = fragments; i >= 1; i--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, + PCI_DMA_TODEVICE); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } + + nr = (nr - 1) % TX_RING; + + if (np->desc_ver == DESC_VER_1) + tx_flags_extra &= ~NV_TX_LASTPACKET; + else + tx_flags_extra &= ~NV_TX2_LASTPACKET; + } + } + +#ifdef NETIF_F_TSO + if (skb_shinfo(skb)->tso_size) + tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + else +#endif + tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, + PCI_DMA_TODEVICE); + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - else { + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } else { np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - } + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } - spin_lock_irq(&np->lock); - wmb(); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - else - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", - dev->name, np->next_tx); + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -991,15 +1068,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx++; + np->next_tx += 1 + fragments; dev->trans_start = jiffies; - if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) - netif_stop_queue(dev); spin_unlock_irq(&np->lock); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); - return 0; + return NETDEV_TX_OK; } /* @@ -1009,9 +1084,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static void nv_tx_done(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; - int i; + unsigned int i; + struct sk_buff *skb; while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; @@ -1026,35 +1102,38 @@ static void nv_tx_done(struct net_device *dev) if (Flags & NV_TX_VALID) break; if (np->desc_ver == DESC_VER_1) { - if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (Flags & NV_TX_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (Flags & NV_TX_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } else { - if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (Flags & NV_TX2_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX2_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX2_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (Flags & NV_TX2_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX2_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -1067,7 +1146,7 @@ static void nv_tx_done(struct net_device *dev) */ static void nv_tx_timeout(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, @@ -1200,7 +1279,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen) static void nv_rx_process(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; for (;;) { @@ -1355,7 +1434,7 @@ static void set_bufsize(struct net_device *dev) */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int old_mtu; if (new_mtu < 64 || new_mtu > np->pkt_limit) @@ -1408,7 +1487,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); pci_push(base); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(base); /* restart rx engine */ @@ -1440,7 +1519,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev) */ static int nv_set_mac_address(struct net_device *dev, void *addr) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); struct sockaddr *macaddr = (struct sockaddr*)addr; if(!is_valid_ether_addr(macaddr->sa_data)) @@ -1475,7 +1554,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) */ static void nv_set_multicast(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; @@ -1535,7 +1614,7 @@ static void nv_set_multicast(struct net_device *dev) static int nv_update_linkspeed(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int adv, lpa; int newls = np->linkspeed; @@ -1705,7 +1784,7 @@ static void nv_link_irq(struct net_device *dev) static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 events; int i; @@ -1777,7 +1856,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); disable_irq(dev->irq); @@ -1801,7 +1880,7 @@ static void nv_poll_controller(struct net_device *dev) static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); strcpy(info->driver, "forcedeth"); strcpy(info->version, FORCEDETH_VERSION); strcpy(info->bus_info, pci_name(np->pci_dev)); @@ -1809,7 +1888,7 @@ static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); wolinfo->supported = WAKE_MAGIC; spin_lock_irq(&np->lock); @@ -1820,7 +1899,7 @@ static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); spin_lock_irq(&np->lock); @@ -2021,7 +2100,7 @@ static int nv_get_regs_len(struct net_device *dev) static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 *rbuf = buf; int i; @@ -2035,7 +2114,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void static int nv_nway_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int ret; spin_lock_irq(&np->lock); @@ -2065,11 +2144,12 @@ static struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int nv_open(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int ret, oom, i; @@ -2114,9 +2194,9 @@ static int nv_open(struct net_device *dev) /* 5) continue setup */ writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); - writel(np->desc_ver, base + NvRegTxRxControl); + writel(np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); - writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); @@ -2205,7 +2285,7 @@ out_drain: static int nv_close(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base; spin_lock_irq(&np->lock); @@ -2261,7 +2341,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!dev) goto out; - np = get_nvpriv(dev); + np = netdev_priv(dev); np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -2313,19 +2393,32 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); + } else { + dev->features |= NETIF_F_HIGHDMA; } + np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_2; } else { /* original packet format */ np->desc_ver = DESC_VER_1; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_1; } np->pkt_limit = NV_PKTLIMIT_1; if (id->driver_data & DEV_HAS_LARGEDESC) np->pkt_limit = NV_PKTLIMIT_2; + if (id->driver_data & DEV_HAS_CHECKSUM) { + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; +#ifdef NETIF_F_TSO + dev->features |= NETIF_F_TSO; +#endif + } + err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) @@ -2377,8 +2470,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { /* * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab @@ -2403,9 +2497,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->wolenabled = 0; if (np->desc_ver == DESC_VER_1) { - np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; + np->tx_flags = NV_TX_VALID; } else { - np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; + np->tx_flags = NV_TX2_VALID; } np->irqmask = NVREG_IRQMASK_WANTED; if (id->driver_data & DEV_NEED_TIMERIRQ) @@ -2494,7 +2588,7 @@ out: static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unregister_netdev(dev); @@ -2525,35 +2619,35 @@ static struct pci_device_id pci_tbl[] = { }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), @@ -2565,11 +2659,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, {0,}, }; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6518334b9280..ae5a2ed3b264 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -29,12 +29,7 @@ * define the configuration needed by the board are defined in a * board structure in arch/ppc/platforms (though I do not * discount the possibility that other architectures could one - * day be supported. One assumption the driver currently makes - * is that the PHY is configured in such a way to advertise all - * capabilities. This is a sensible default, and on certain - * PHYs, changing this default encounters substantial errata - * issues. Future versions may remove this requirement, but for - * now, it is best for the firmware to ensure this is the case. + * day be supported. * * The Gianfar Ethernet Controller uses a ring of buffer * descriptors. The beginning is indicated by a register @@ -47,7 +42,7 @@ * corresponding bit in the IMASK register is also set (if * interrupt coalescing is active, then the interrupt may not * happen immediately, but will wait until either a set number - * of frames or amount of time have passed.). In NAPI, the + * of frames or amount of time have passed). In NAPI, the * interrupt handler will signal there is work to be done, and * exit. Without NAPI, the packet(s) will be handled * immediately. Both methods will start at the last known empty @@ -75,6 +70,7 @@ #include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/unistd.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -97,9 +93,11 @@ #include <linux/version.h> #include <linux/dma-mapping.h> #include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/phy.h> #include "gianfar.h" -#include "gianfar_phy.h" +#include "gianfar_mii.h" #define TX_TIMEOUT (1*HZ) #define SKB_ALLOC_TIMEOUT 1000000 @@ -113,9 +111,8 @@ #endif const char gfar_driver_name[] = "Gianfar Ethernet"; -const char gfar_driver_version[] = "1.1"; +const char gfar_driver_version[] = "1.2"; -int startup_gfar(struct net_device *dev); static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_timeout(struct net_device *dev); @@ -126,17 +123,13 @@ static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void gfar_phy_change(void *data); -static void gfar_phy_timer(unsigned long data); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); static int gfar_probe(struct device *device); static int gfar_remove(struct device *device); -void free_skb_resources(struct gfar_private *priv); +static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); #ifdef CONFIG_GFAR_NAPI @@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); -static void gfar_phy_startup_timer(unsigned long data); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); @@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv) else return 0; } + +/* Set up the ethernet device structure, private data, + * and anything else we need before we start */ static int gfar_probe(struct device *device) { u32 tempval; @@ -175,7 +170,7 @@ static int gfar_probe(struct device *device) einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; - if (einfo == NULL) { + if (NULL == einfo) { printk(KERN_ERR "gfar %d: Missing additional data!\n", pdev->id); @@ -185,7 +180,7 @@ static int gfar_probe(struct device *device) /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof (*priv)); - if (dev == NULL) + if (NULL == dev) return -ENOMEM; priv = netdev_priv(dev); @@ -207,20 +202,11 @@ static int gfar_probe(struct device *device) priv->regs = (struct gfar *) ioremap(r->start, sizeof (struct gfar)); - if (priv->regs == NULL) { + if (NULL == priv->regs) { err = -ENOMEM; goto regs_fail; } - /* Set the PHY base address */ - priv->phyregs = (struct gfar *) - ioremap(einfo->phy_reg_addr, sizeof (struct gfar)); - - if (priv->phyregs == NULL) { - err = -ENOMEM; - goto phy_regs_fail; - } - spin_lock_init(&priv->lock); dev_set_drvdata(device, dev); @@ -386,12 +372,10 @@ static int gfar_probe(struct device *device) return 0; register_fail: - iounmap((void *) priv->phyregs); -phy_regs_fail: iounmap((void *) priv->regs); regs_fail: free_netdev(dev); - return -ENOMEM; + return err; } static int gfar_remove(struct device *device) @@ -402,108 +386,41 @@ static int gfar_remove(struct device *device) dev_set_drvdata(device, NULL); iounmap((void *) priv->regs); - iounmap((void *) priv->phyregs); free_netdev(dev); return 0; } -/* Configure the PHY for dev. - * returns 0 if success. -1 if failure +/* Initializes driver's PHY state, and attaches to the PHY. + * Returns 0 on success. */ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct phy_info *curphy; - unsigned int timeout = PHY_INIT_TIMEOUT; - struct gfar *phyregs = priv->phyregs; - struct gfar_mii_info *mii_info; - int err; + uint gigabit_support = + priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? + SUPPORTED_1000baseT_Full : 0; + struct phy_device *phydev; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - mii_info = kmalloc(sizeof(struct gfar_mii_info), - GFP_KERNEL); - - if(NULL == mii_info) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate mii_info\n", - dev->name); - return -ENOMEM; - } - - mii_info->speed = SPEED_1000; - mii_info->duplex = DUPLEX_FULL; - mii_info->pause = 0; - mii_info->link = 1; - - mii_info->advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full); - mii_info->autoneg = 1; + phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0); - spin_lock_init(&mii_info->mdio_lock); - - mii_info->mii_id = priv->einfo->phyid; - - mii_info->dev = dev; - - mii_info->mdio_read = &read_phy_reg; - mii_info->mdio_write = &write_phy_reg; - - priv->mii_info = mii_info; - - /* Reset the management interface */ - gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); - - /* Setup the MII Mgmt clock speed */ - gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - - /* Wait until the bus is free */ - while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && - timeout--) - cpu_relax(); - - if(timeout <= 0) { - printk(KERN_ERR "%s: The MII Bus is stuck!\n", - dev->name); - err = -1; - goto bus_fail; - } - - /* get info for this PHY */ - curphy = get_phy_info(priv->mii_info); - - if (curphy == NULL) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: No PHY found\n", dev->name); - err = -1; - goto no_phy; + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); } - mii_info->phyinfo = curphy; + /* Remove any features not supported by the controller */ + phydev->supported &= (GFAR_SUPPORTED | gigabit_support); + phydev->advertising = phydev->supported; - /* Run the commands which initialize the PHY */ - if(curphy->init) { - err = curphy->init(priv->mii_info); - - if (err) - goto phy_init_fail; - } + priv->phydev = phydev; return 0; - -phy_init_fail: -no_phy: -bus_fail: - kfree(mii_info); - - return err; } static void init_registers(struct net_device *dev) @@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev) struct gfar *regs = priv->regs; unsigned long flags; + phy_stop(priv->phydev); + /* Lock it down */ spin_lock_irqsave(&priv->lock, flags); - /* Tell the kernel the link is down */ - priv->mii_info->link = 0; - adjust_link(dev); - gfar_halt(dev); - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - /* Clear any pending interrupts */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY Interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - } - spin_unlock_irqrestore(&priv->lock, flags); /* Free the IRQs */ @@ -629,13 +535,7 @@ void stop_gfar(struct net_device *dev) free_irq(priv->interruptTransmit, dev); free_irq(priv->interruptReceive, dev); } else { - free_irq(priv->interruptTransmit, dev); - } - - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - free_irq(priv->einfo->interruptPHY, dev); - } else { - del_timer_sync(&priv->phy_info_timer); + free_irq(priv->interruptTransmit, dev); } free_skb_resources(priv); @@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev) /* If there are any tx skbs or rx skbs still around, free them. * Then free tx_skbuff and rx_skbuff */ -void free_skb_resources(struct gfar_private *priv) +static void free_skb_resources(struct gfar_private *priv) { struct rxbd8 *rxbdp; struct txbd8 *txbdp; @@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->tx_ring_size, GFP_KERNEL); - if (priv->tx_skbuff == NULL) { + if (NULL == priv->tx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", dev->name); @@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->rx_ring_size, GFP_KERNEL); - if (priv->rx_skbuff == NULL) { + if (NULL == priv->rx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", dev->name); @@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev) } } - /* Set up the PHY change work queue */ - INIT_WORK(&priv->tq, gfar_phy_change, dev); - - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_startup_timer; - priv->phy_info_timer.data = (unsigned long) priv->mii_info; - mod_timer(&priv->phy_info_timer, jiffies + HZ); + phy_start(priv->phydev); /* Configure the coalescing support */ if (priv->txcoalescing) @@ -933,11 +827,6 @@ tx_skb_fail: priv->tx_bd_base, gfar_read(®s->tbase0)); - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); - return err; } @@ -1035,7 +924,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp->status &= TXBD_WRAP; /* Set up checksumming */ - if ((dev->features & NETIF_F_IP_CSUM) + if ((dev->features & NETIF_F_IP_CSUM) && (CHECKSUM_HW == skb->ip_summed)) { fcb = gfar_add_fcb(skb, txbdp); gfar_tx_checksum(skb, fcb); @@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); stop_gfar(dev); - /* Shutdown the PHY */ - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); + /* Disconnect from the PHY */ + phy_disconnect(priv->phydev); + priv->phydev = NULL; netif_stop_queue(dev); @@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) while ((!skb) && timeout--) skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (skb == NULL) + if (NULL == skb) return NULL; /* We need the data buffer to be aligned properly. We will reserve @@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; - if (skb == NULL) { + if (NULL == skb) { if (netif_msg_rx_err(priv)) printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); priv->stats.rx_dropped++; @@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); - - /* Clear the interrupt */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - - /* Schedule the phy change */ - schedule_work(&priv->tq); - - return IRQ_HANDLED; -} - -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void gfar_phy_change(void *data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - int result = 0; - - /* Delay to give the PHY a chance to change the - * register state */ - msleep(1); - - /* Update the link, speed, duplex */ - result = priv->mii_info->phyinfo->read_status(priv->mii_info); - - /* Adjust the known status as long as the link - * isn't still coming up */ - if((0 == result) || (priv->mii_info->link == 0)) - adjust_link(dev); - - /* Reenable interrupts, if needed */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); -} - -/* Called every so often on systems that don't interrupt - * the core for PHY changes */ -static void gfar_phy_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - - schedule_work(&priv->tq); - - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - -/* Keep trying aneg for some time - * If, after GFAR_AN_TIMEOUT seconds, it has not - * finished, we switch to forced. - * Either way, once the process has completed, we either - * request the interrupt, or switch the timer over to - * using gfar_phy_timer to check status */ -static void gfar_phy_startup_timer(unsigned long data) -{ - int result; - static int secondary = GFAR_AN_TIMEOUT; - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct gfar_private *priv = netdev_priv(mii_info->dev); - - /* Configure the Auto-negotiation */ - result = mii_info->phyinfo->config_aneg(mii_info); - - /* If autonegotiation failed to start, and - * we haven't timed out, reset the timer, and return */ - if (result && secondary--) { - mod_timer(&priv->phy_info_timer, jiffies + HZ); - return; - } else if (result) { - /* Couldn't start autonegotiation. - * Try switching to forced */ - mii_info->autoneg = 0; - result = mii_info->phyinfo->config_aneg(mii_info); - - /* Forcing failed! Give up */ - if(result) { - if (netif_msg_link(priv)) - printk(KERN_ERR "%s: Forcing failed!\n", - mii_info->dev->name); - return; - } - } - - /* Kill the timer so it can be restarted */ - del_timer_sync(&priv->phy_info_timer); - - /* Grab the PHY interrupt, if necessary/possible */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - if (request_irq(priv->einfo->interruptPHY, - phy_interrupt, - SA_SHIRQ, - "phy_interrupt", - mii_info->dev) < 0) { - if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", - mii_info->dev->name, - priv->einfo->interruptPHY); - } else { - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); - return; - } - } - - /* Start the timer again, this time in order to - * handle a change in status */ - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_timer; - priv->phy_info_timer.data = (unsigned long) mii_info->dev; - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this - * information through variables in the priv structure, and this + * information through variables in the phydev structure, and this * function converts those variables into the appropriate * register values, and can bring down the device if needed. */ @@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar *regs = priv->regs; - u32 tempval; - struct gfar_mii_info *mii_info = priv->mii_info; + unsigned long flags; + struct phy_device *phydev = priv->phydev; + int new_state = 0; + + spin_lock_irqsave(&priv->lock, flags); + if (phydev->link) { + u32 tempval = gfar_read(®s->maccfg2); - if (mii_info->link) { /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (mii_info->duplex != priv->oldduplex) { - if (!(mii_info->duplex)) { - tempval = gfar_read(®s->maccfg2); + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) tempval &= ~(MACCFG2_FULL_DUPLEX); - gfar_write(®s->maccfg2, tempval); - - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Half Duplex\n", - dev->name); - } else { - tempval = gfar_read(®s->maccfg2); + else tempval |= MACCFG2_FULL_DUPLEX; - gfar_write(®s->maccfg2, tempval); - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Full Duplex\n", - dev->name); - } - - priv->oldduplex = mii_info->duplex; + priv->oldduplex = phydev->duplex; } - if (mii_info->speed != priv->oldspeed) { - switch (mii_info->speed) { + if (phydev->speed != priv->oldspeed) { + new_state = 1; + switch (phydev->speed) { case 1000: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); - gfar_write(®s->maccfg2, tempval); break; case 100: case 10: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); - gfar_write(®s->maccfg2, tempval); break; default: if (netif_msg_link(priv)) printk(KERN_WARNING - "%s: Ack! Speed (%d) is not 10/100/1000!\n", - dev->name, mii_info->speed); + "%s: Ack! Speed (%d) is not 10/100/1000!\n", + dev->name, phydev->speed); break; } - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Speed %dBT\n", dev->name, - mii_info->speed); - - priv->oldspeed = mii_info->speed; + priv->oldspeed = phydev->speed; } + gfar_write(®s->maccfg2, tempval); + if (!priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is up\n", dev->name); + new_state = 1; priv->oldlink = 1; - netif_carrier_on(dev); netif_schedule(dev); } - } else { - if (priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is down\n", - dev->name); - priv->oldlink = 0; - priv->oldspeed = 0; - priv->oldduplex = -1; - netif_carrier_off(dev); - } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; } -} + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + spin_unlock_irqrestore(&priv->lock, flags); +} /* Update the hash table based on the current list of multicast * addresses we subscribe to. Also, change the promiscuity of @@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = { static int __init gfar_init(void) { - return driver_register(&gfar_driver); + int err = gfar_mdio_init(); + + if (err) + return err; + + err = driver_register(&gfar_driver); + + if (err) + gfar_mdio_exit(); + + return err; } static void __exit gfar_exit(void) { driver_unregister(&gfar_driver); + gfar_mdio_exit(); } module_init(gfar_init); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 28af087d9fbb..c77ca6c0d04a 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -17,7 +17,6 @@ * * Still left to do: * -Add support for module parameters - * -Add support for ethtool -s * -Add patch for ethtool phys id */ #ifndef __GIANFAR_H @@ -37,7 +36,8 @@ #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/mm.h> -#include <linux/fsl_devices.h> +#include <linux/mii.h> +#include <linux/phy.h> #include <asm/io.h> #include <asm/irq.h> @@ -48,7 +48,8 @@ #include <linux/workqueue.h> #include <linux/ethtool.h> #include <linux/netdevice.h> -#include "gianfar_phy.h" +#include <linux/fsl_devices.h> +#include "gianfar_mii.h" /* The maximum number of packets to be handled in one call of gfar_poll */ #define GFAR_DEV_WEIGHT 64 @@ -73,7 +74,7 @@ #define PHY_INIT_TIMEOUT 100000 #define GFAR_PHY_CHANGE_TIME 2 -#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, " #define DRV_NAME "gfar-enet" extern const char gfar_driver_name[]; extern const char gfar_driver_version[]; @@ -578,12 +579,7 @@ struct gfar { u32 hafdup; /* 0x.50c - Half Duplex Register */ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ u8 res18[12]; - u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ - u32 miimcom; /* 0x.524 - MII Management Command Register */ - u32 miimadd; /* 0x.528 - MII Management Address Register */ - u32 miimcon; /* 0x.52c - MII Management Control Register */ - u32 miimstat; /* 0x.530 - MII Management Status Register */ - u32 miimind; /* 0x.534 - MII Management Indicator Register */ + u8 gfar_mii_regs[24]; /* See gianfar_phy.h */ u8 res19[4]; u32 ifstat; /* 0x.53c - Interface Status Register */ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ @@ -688,9 +684,6 @@ struct gfar_private { struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ u32 *hash_regs[16]; int hash_width; - struct gfar *phyregs; - struct work_struct tq; - struct timer_list phy_info_timer; struct net_device_stats stats; /* linux network statistics */ struct gfar_extra_stats extra_stats; spinlock_t lock; @@ -710,7 +703,8 @@ struct gfar_private { unsigned int interruptError; struct gianfar_platform_data *einfo; - struct gfar_mii_info *mii_info; + struct phy_device *phydev; + struct mii_bus *mii_bus; int oldspeed; int oldduplex; int oldlink; @@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val) extern struct ethtool_ops *gfar_op_array[]; +extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +extern int startup_gfar(struct net_device *dev); +extern void stop_gfar(struct net_device *dev); +extern void gfar_halt(struct net_device *dev); +extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, + int enable, u32 regnum, u32 read); +void gfar_setup_stashing(struct net_device *dev); + #endif /* __GIANFAR_H */ diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index a451de629197..68e3578e7613 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -39,17 +39,18 @@ #include <asm/types.h> #include <asm/uaccess.h> #include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/phy.h> #include "gianfar.h" #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) -extern int startup_gfar(struct net_device *dev); -extern void stop_gfar(struct net_device *dev); -extern void gfar_halt(struct net_device *dev); extern void gfar_start(struct net_device *dev); extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +#define GFAR_MAX_COAL_USECS 0xffff +#define GFAR_MAX_COAL_FRAMES 0xff static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf); static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); @@ -182,38 +183,32 @@ static void gfar_gdrvinfo(struct net_device *dev, struct drvinfo->eedump_len = 0; } + +static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + + if (NULL == phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); +} + + /* Return the current settings in the ethtool_cmd structure */ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gfar_private *priv = netdev_priv(dev); - uint gigabit_support = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - SUPPORTED_1000baseT_Full : 0; - uint gigabit_advert = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - ADVERTISED_1000baseT_Full: 0; - - cmd->supported = (SUPPORTED_10baseT_Half - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | gigabit_support | SUPPORTED_Autoneg); - - /* For now, we always advertise everything */ - cmd->advertising = (ADVERTISED_10baseT_Half - | ADVERTISED_100baseT_Half - | ADVERTISED_100baseT_Full - | gigabit_advert | ADVERTISED_Autoneg); - - cmd->speed = priv->mii_info->speed; - cmd->duplex = priv->mii_info->duplex; - cmd->port = PORT_MII; - cmd->phy_address = priv->mii_info->mii_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = AUTONEG_ENABLE; + struct phy_device *phydev = priv->phydev; + + if (NULL == phydev) + return -ENODEV; + cmd->maxtxpkt = priv->txcount; cmd->maxrxpkt = priv->rxcount; - return 0; + return phy_ethtool_gset(phydev, cmd); } /* Return the length of the register structure */ @@ -241,14 +236,14 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -265,14 +260,14 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -292,6 +287,9 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; + if (NULL == priv->phydev) + return -ENODEV; + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); cvals->rx_max_coalesced_frames = priv->rxcount; @@ -348,6 +346,22 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->rxcoalescing = 1; + if (NULL == priv->phydev) + return -ENODEV; + + /* Check the bounds of the values */ + if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); priv->rxcount = cvals->rx_max_coalesced_frames; @@ -358,6 +372,19 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->txcoalescing = 1; + /* Check the bounds of the values */ + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); priv->txcount = cvals->tx_max_coalesced_frames; @@ -536,6 +563,7 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data) struct ethtool_ops gfar_ethtool_ops = { .get_settings = gfar_gsettings, + .set_settings = gfar_ssettings, .get_drvinfo = gfar_gdrvinfo, .get_regs_len = gfar_reglen, .get_regs = gfar_get_regs, diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c new file mode 100644 index 000000000000..1eca1dbca7f1 --- /dev/null +++ b/drivers/net/gianfar_mii.c @@ -0,0 +1,219 @@ +/* + * drivers/net/gianfar_mii.c + * + * Gianfar Ethernet Driver -- MIIM bus implementation + * Provides Bus interface for MIIM regs + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <asm/ocp.h> +#include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "gianfar.h" +#include "gianfar_mii.h" + +/* Write value to the PHY at mii_id at register regnum, + * on the bus, waiting until the write is done before returning. + * All PHY configuration is done through the TSEC1 MIIM regs */ +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) +{ + struct gfar_mii *regs = bus->priv; + + /* Set the PHY address and the register address we want to write */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Write out the value we want */ + gfar_write(®s->miimcon, value); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & MIIMIND_BUSY) + cpu_relax(); + + return 0; +} + +/* Read the bus for PHY at addr mii_id, register regnum, and + * return the value. Clears miimcom first. All PHY + * configuration has to be done through the TSEC1 MIIM regs */ +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct gfar_mii *regs = bus->priv; + u16 value; + + /* Set the PHY address and the register address we want to read */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Clear miimcom, and then initiate a read */ + gfar_write(®s->miimcom, 0); + gfar_write(®s->miimcom, MII_READ_COMMAND); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + cpu_relax(); + + /* Grab the value of the register from miimstat */ + value = gfar_read(®s->miimstat); + + return value; +} + + +/* Reset the MIIM registers, and wait for the bus to free */ +int gfar_mdio_reset(struct mii_bus *bus) +{ + struct gfar_mii *regs = bus->priv; + unsigned int timeout = PHY_INIT_TIMEOUT; + + spin_lock_bh(&bus->mdio_lock); + + /* Reset the management interface */ + gfar_write(®s->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while ((gfar_read(®s->miimind) & MIIMIND_BUSY) && + timeout--) + cpu_relax(); + + spin_unlock_bh(&bus->mdio_lock); + + if(timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", + bus->name); + return -EBUSY; + } + + return 0; +} + + +int gfar_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gianfar_mdio_data *pdata; + struct gfar_mii *regs; + struct mii_bus *new_bus; + int err = 0; + + if (NULL == dev) + return -EINVAL; + + new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + new_bus->name = "Gianfar MII Bus", + new_bus->read = &gfar_mdio_read, + new_bus->write = &gfar_mdio_write, + new_bus->reset = &gfar_mdio_reset, + new_bus->id = pdev->id; + + pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /* Set the PHY base address */ + regs = (struct gfar_mii *) ioremap(pdata->paddr, + sizeof (struct gfar_mii)); + + if (NULL == regs) { + err = -ENOMEM; + goto reg_map_fail; + } + + new_bus->priv = regs; + + new_bus->irq = pdata->irq; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + iounmap((void *) regs); +reg_map_fail: + kfree(new_bus); + + return err; +} + + +int gfar_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + + iounmap((void *) (&bus->priv)); + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver gianfar_mdio_driver = { + .name = "fsl-gianfar_mdio", + .bus = &platform_bus_type, + .probe = gfar_mdio_probe, + .remove = gfar_mdio_remove, +}; + +int __init gfar_mdio_init(void) +{ + return driver_register(&gianfar_mdio_driver); +} + +void __exit gfar_mdio_exit(void) +{ + driver_unregister(&gianfar_mdio_driver); +} diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h new file mode 100644 index 000000000000..56e5665d5c9b --- /dev/null +++ b/drivers/net/gianfar_mii.h @@ -0,0 +1,45 @@ +/* + * drivers/net/gianfar_mii.h + * + * Gianfar Ethernet Driver -- MII Management Bus Implementation + * Driver for the MDIO bus controller in the Gianfar register space + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __GIANFAR_MII_H +#define __GIANFAR_MII_H + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define MII_READ_COMMAND 0x00000001 + +#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ + | SUPPORTED_100baseT_Half \ + | SUPPORTED_100baseT_Full \ + | SUPPORTED_Autoneg \ + | SUPPORTED_MII) + +struct gfar_mii { + u32 miimcfg; /* 0x.520 - MII Management Config Register */ + u32 miimcom; /* 0x.524 - MII Management Command Register */ + u32 miimadd; /* 0x.528 - MII Management Address Register */ + u32 miimcon; /* 0x.52c - MII Management Control Register */ + u32 miimstat; /* 0x.530 - MII Management Status Register */ + u32 miimind; /* 0x.534 - MII Management Indicator Register */ +}; + +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum); +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); +int __init gfar_mdio_init(void); +void __exit gfar_mdio_exit(void); +#endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c deleted file mode 100644 index 7c965f268a82..000000000000 --- a/drivers/net/gianfar_phy.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * drivers/net/gianfar_phy.c - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/mm.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/crc32.h> -#include <linux/mii.h> - -#include "gianfar.h" -#include "gianfar_phy.h" - -static void config_genmii_advert(struct gfar_mii_info *mii_info); -static void genmii_setup_forced(struct gfar_mii_info *mii_info); -static void genmii_restart_aneg(struct gfar_mii_info *mii_info); -static int gbit_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_update_link(struct gfar_mii_info *mii_info); -static int genmii_read_status(struct gfar_mii_info *mii_info); -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - - /* Set the PHY address and the register address we want to write */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Write out the value we want */ - gfar_write(®base->miimcon, value); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & MIIMIND_BUSY) - cpu_relax(); -} - -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int read_phy_reg(struct net_device *dev, int mii_id, int regnum) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - u16 value; - - /* Set the PHY address and the register address we want to read */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Clear miimcom, and then initiate a read */ - gfar_write(®base->miimcom, 0); - gfar_write(®base->miimcom, MII_READ_COMMAND); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) - cpu_relax(); - - /* Grab the value of the register from miimstat */ - value = gfar_read(®base->miimstat); - - return value; -} - -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) -{ - if(mii_info->phyinfo->ack_interrupt) - mii_info->phyinfo->ack_interrupt(mii_info); -} - - -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) -{ - mii_info->interrupts = interrupts; - if(mii_info->phyinfo->config_intr) - mii_info->phyinfo->config_intr(mii_info); -} - - -/* Writes MII_ADVERTISE with the appropriate values, after - * sanitizing advertise to make sure only supported features - * are advertised - */ -static void config_genmii_advert(struct gfar_mii_info *mii_info) -{ - u32 advertise; - u16 adv; - - /* Only allow advertising what this PHY supports */ - mii_info->advertising &= mii_info->phyinfo->features; - advertise = mii_info->advertising; - - /* Setup standard advertisement */ - adv = phy_read(mii_info, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - phy_write(mii_info, MII_ADVERTISE, adv); -} - -static void genmii_setup_forced(struct gfar_mii_info *mii_info) -{ - u16 ctrl; - u32 features = mii_info->phyinfo->features; - - ctrl = phy_read(mii_info, MII_BMCR); - - ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); - ctrl |= BMCR_RESET; - - switch(mii_info->speed) { - case SPEED_1000: - if(features & (SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full)) { - ctrl |= BMCR_SPEED1000; - break; - } - mii_info->speed = SPEED_100; - case SPEED_100: - if (features & (SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full)) { - ctrl |= BMCR_SPEED100; - break; - } - mii_info->speed = SPEED_10; - case SPEED_10: - if (features & (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full)) - break; - default: /* Unsupported speed! */ - printk(KERN_ERR "%s: Bad speed!\n", - mii_info->dev->name); - break; - } - - phy_write(mii_info, MII_BMCR, ctrl); -} - - -/* Enable and Restart Autonegotiation */ -static void genmii_restart_aneg(struct gfar_mii_info *mii_info) -{ - u16 ctl; - - ctl = phy_read(mii_info, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(mii_info, MII_BMCR, ctl); -} - - -static int gbit_config_aneg(struct gfar_mii_info *mii_info) -{ - u16 adv; - u32 advertise; - - if(mii_info->autoneg) { - /* Configure the ADVERTISE register */ - config_genmii_advert(mii_info); - advertise = mii_info->advertising; - - adv = phy_read(mii_info, MII_1000BASETCONTROL); - adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | - MII_1000BASETCONTROL_HALFDUPLEXCAP); - if (advertise & SUPPORTED_1000baseT_Half) - adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; - if (advertise & SUPPORTED_1000baseT_Full) - adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; - phy_write(mii_info, MII_1000BASETCONTROL, adv); - - /* Start/Restart aneg */ - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - -static int marvell_config_aneg(struct gfar_mii_info *mii_info) -{ - /* The Marvell PHY has an errata which requires - * that certain registers get written in order - * to restart autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_RESET); - - phy_write(mii_info, 0x1d, 0x1f); - phy_write(mii_info, 0x1e, 0x200c); - phy_write(mii_info, 0x1d, 0x5); - phy_write(mii_info, 0x1e, 0); - phy_write(mii_info, 0x1e, 0x100); - - gbit_config_aneg(mii_info); - - return 0; -} -static int genmii_config_aneg(struct gfar_mii_info *mii_info) -{ - if (mii_info->autoneg) { - config_genmii_advert(mii_info); - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - - -static int genmii_update_link(struct gfar_mii_info *mii_info) -{ - u16 status; - - /* Do a fake read */ - phy_read(mii_info, MII_BMSR); - - /* Read link and autonegotiation status */ - status = phy_read(mii_info, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - mii_info->link = 0; - else - mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return -EAGAIN; - - return 0; -} - -static int genmii_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - if (mii_info->autoneg) { - status = phy_read(mii_info, MII_LPA); - - if (status & (LPA_10FULL | LPA_100FULL)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - if (status & (LPA_100FULL | LPA_100HALF)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - mii_info->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} -static int marvell_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); - -#if 0 - /* If speed and duplex aren't resolved, - * return an error. Isn't this handled - * by checking aneg? - */ - if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) - return -EAGAIN; -#endif - - /* Get the duplexity */ - if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - /* Get the speed */ - speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; - switch(speed) { - case MII_M1011_PHY_SPEC_STATUS_1000: - mii_info->speed = SPEED_1000; - break; - case MII_M1011_PHY_SPEC_STATUS_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - mii_info->pause = 0; - } - - return 0; -} - - -static int cis820x_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - - status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); - if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - speed = status & MII_CIS8201_AUXCONSTAT_SPEED; - - switch (speed) { - case MII_CIS8201_AUXCONSTAT_GBIT: - mii_info->speed = SPEED_1000; - break; - case MII_CIS8201_AUXCONSTAT_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - } - - return 0; -} - -static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) -{ - /* Clear the interrupts by reading the reg */ - phy_read(mii_info, MII_M1011_IEVENT); - - return 0; -} - -static int marvell_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); - else - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); - - return 0; -} - -static int cis820x_init(struct gfar_mii_info *mii_info) -{ - phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, - MII_CIS8201_AUXCONSTAT_INIT); - phy_write(mii_info, MII_CIS8201_EXT_CON1, - MII_CIS8201_EXTCON1_INIT); - - return 0; -} - -static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_CIS8201_ISTAT); - - return 0; -} - -static int cis820x_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); - else - phy_write(mii_info, MII_CIS8201_IMASK, 0); - - return 0; -} - -#define DM9161_DELAY 10 - -static int dm9161_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - status = phy_read(mii_info, MII_DM9161_SCSR); - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - } - - return 0; -} - - -static int dm9161_config_aneg(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - if(0 == priv->resetdone) - return -EAGAIN; - - return 0; -} - -static void dm9161_timer(unsigned long data) -{ - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct dm9161_private *priv = mii_info->priv; - u16 status = phy_read(mii_info, MII_BMSR); - - if (status & BMSR_ANEGCOMPLETE) { - priv->resetdone = 1; - } else - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); -} - -static int dm9161_init(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv; - - /* Allocate the private data structure */ - priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); - - if (NULL == priv) - return -ENOMEM; - - mii_info->priv = priv; - - /* Reset is not done yet */ - priv->resetdone = 0; - - /* Isolate the PHY */ - phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); - - /* Do not bypass the scrambler/descrambler */ - phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); - - /* Clear 10BTCSR to default */ - phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); - - /* Reconnect the PHY, and enable Autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); - - /* Start a timer for DM9161_DELAY seconds to wait - * for the PHY to be ready */ - init_timer(&priv->timer); - priv->timer.function = &dm9161_timer; - priv->timer.data = (unsigned long) mii_info; - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); - - return 0; -} - -static void dm9161_close(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - del_timer_sync(&priv->timer); - kfree(priv); -} - -#if 0 -static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_DM9161_INTR); - - return 0; -} -#endif - -/* Cicada 820x */ -static struct phy_info phy_info_cis820x = { - 0x000fc440, - "Cicada Cis8204", - 0x000fffc0, - .features = MII_GBIT_FEATURES, - .init = &cis820x_init, - .config_aneg = &gbit_config_aneg, - .read_status = &cis820x_read_status, - .ack_interrupt = &cis820x_ack_interrupt, - .config_intr = &cis820x_config_intr, -}; - -static struct phy_info phy_info_dm9161 = { - .phy_id = 0x0181b880, - .name = "Davicom DM9161E", - .phy_id_mask = 0x0ffffff0, - .init = dm9161_init, - .config_aneg = dm9161_config_aneg, - .read_status = dm9161_read_status, - .close = dm9161_close, -}; - -static struct phy_info phy_info_marvell = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101/88E1111", - .features = MII_GBIT_FEATURES, - .config_aneg = &marvell_config_aneg, - .read_status = &marvell_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, -}; - -static struct phy_info phy_info_genmii= { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .features = MII_BASIC_FEATURES, - .config_aneg = genmii_config_aneg, - .read_status = genmii_read_status, -}; - -static struct phy_info *phy_info[] = { - &phy_info_cis820x, - &phy_info_marvell, - &phy_info_dm9161, - &phy_info_genmii, - NULL -}; - -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) -{ - u16 retval; - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); - - return retval; -} - -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) -{ - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - mii_info->mdio_write(mii_info->dev, - mii_info->mii_id, - regnum, val); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); -} - -/* Use the PHY ID registers to determine what type of PHY is attached - * to device dev. return a struct phy_info structure describing that PHY - */ -struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) -{ - u16 phy_reg; - u32 phy_ID; - int i; - struct phy_info *theInfo = NULL; - struct net_device *dev = mii_info->dev; - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read(mii_info, MII_PHYSID1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read(mii_info, MII_PHYSID2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) - if (phy_info[i]->phy_id == - (phy_ID & phy_info[i]->phy_id_mask)) { - theInfo = phy_info[i]; - break; - } - - /* This shouldn't happen, as we have generic PHY support */ - if (theInfo == NULL) { - printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); - return NULL; - } else { - printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, - phy_ID); - } - - return theInfo; -} diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h deleted file mode 100644 index 1e9b3abf1e6d..000000000000 --- a/drivers/net/gianfar_phy.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * drivers/net/gianfar_phy.h - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#ifndef __GIANFAR_PHY_H -#define __GIANFAR_PHY_H - -#define MII_end ((u32)-2) -#define MII_read ((u32)-1) - -#define MIIMIND_BUSY 0x00000001 -#define MIIMIND_NOTVALID 0x00000004 - -#define GFAR_AN_TIMEOUT 2000 - -/* 1000BT control (Marvell & BCM54xx at least) */ -#define MII_1000BASETCONTROL 0x09 -#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 -#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 - -/* Cicada Extended Control Register 1 */ -#define MII_CIS8201_EXT_CON1 0x17 -#define MII_CIS8201_EXTCON1_INIT 0x0000 - -/* Cicada Interrupt Mask Register */ -#define MII_CIS8201_IMASK 0x19 -#define MII_CIS8201_IMASK_IEN 0x8000 -#define MII_CIS8201_IMASK_SPEED 0x4000 -#define MII_CIS8201_IMASK_LINK 0x2000 -#define MII_CIS8201_IMASK_DUPLEX 0x1000 -#define MII_CIS8201_IMASK_MASK 0xf000 - -/* Cicada Interrupt Status Register */ -#define MII_CIS8201_ISTAT 0x1a -#define MII_CIS8201_ISTAT_STATUS 0x8000 -#define MII_CIS8201_ISTAT_SPEED 0x4000 -#define MII_CIS8201_ISTAT_LINK 0x2000 -#define MII_CIS8201_ISTAT_DUPLEX 0x1000 - -/* Cicada Auxiliary Control/Status Register */ -#define MII_CIS8201_AUX_CONSTAT 0x1c -#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MII_CIS8201_AUXCONSTAT_100 0x0008 - -/* 88E1011 PHY Status Register */ -#define MII_M1011_PHY_SPEC_STATUS 0x11 -#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 -#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 -#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 -#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 -#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 -#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 - -#define MII_M1011_IEVENT 0x13 -#define MII_M1011_IEVENT_CLEAR 0x0000 - -#define MII_M1011_IMASK 0x12 -#define MII_M1011_IMASK_INIT 0x6400 -#define MII_M1011_IMASK_CLEAR 0x0000 - -#define MII_DM9161_SCR 0x10 -#define MII_DM9161_SCR_INIT 0x0610 - -/* DM9161 Specified Configuration and Status Register */ -#define MII_DM9161_SCSR 0x11 -#define MII_DM9161_SCSR_100F 0x8000 -#define MII_DM9161_SCSR_100H 0x4000 -#define MII_DM9161_SCSR_10F 0x2000 -#define MII_DM9161_SCSR_10H 0x1000 - -/* DM9161 Interrupt Register */ -#define MII_DM9161_INTR 0x15 -#define MII_DM9161_INTR_PEND 0x8000 -#define MII_DM9161_INTR_DPLX_MASK 0x0800 -#define MII_DM9161_INTR_SPD_MASK 0x0400 -#define MII_DM9161_INTR_LINK_MASK 0x0200 -#define MII_DM9161_INTR_MASK 0x0100 -#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 -#define MII_DM9161_INTR_SPD_CHANGE 0x0008 -#define MII_DM9161_INTR_LINK_CHANGE 0x0004 -#define MII_DM9161_INTR_INIT 0x0000 -#define MII_DM9161_INTR_STOP \ -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) - -/* DM9161 10BT Configuration/Status */ -#define MII_DM9161_10BTCSR 0x12 -#define MII_DM9161_10BTCSR_INIT 0x7800 - -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ - SUPPORTED_TP | \ - SUPPORTED_MII) - -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ - SUPPORTED_1000baseT_Full) - -#define MII_READ_COMMAND 0x00000001 - -#define MII_INTERRUPT_DISABLED 0x0 -#define MII_INTERRUPT_ENABLED 0x1 -/* Taken from mii_if_info and sungem_phy.h */ -struct gfar_mii_info { - /* Information about the PHY type */ - /* And management functions */ - struct phy_info *phyinfo; - - /* forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - - /* The most recently read link state */ - int link; - - /* Enabled Interrupts */ - u32 interrupts; - - u32 advertising; - int autoneg; - int mii_id; - - /* private data pointer */ - /* For use by PHYs to maintain extra state */ - void *priv; - - /* Provided by host chip */ - struct net_device *dev; - - /* A lock to ensure that only one thing can read/write - * the MDIO bus at a time */ - spinlock_t mdio_lock; - - /* Provided by ethernet driver */ - int (*mdio_read) (struct net_device *dev, int mii_id, int reg); - void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); -}; - -/* struct phy_info: a structure which defines attributes for a PHY - * - * id will contain a number which represents the PHY. During - * startup, the driver will poll the PHY to find out what its - * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be ANDed with phy_id_mask to - * discard any bits which may change based on revision numbers - * unimportant to functionality - * - * There are 6 commands which take a gfar_mii_info structure. - * Each PHY must declare config_aneg, and read_status. - */ -struct phy_info { - u32 phy_id; - char *name; - unsigned int phy_id_mask; - u32 features; - - /* Called to initialize the PHY */ - int (*init)(struct gfar_mii_info *mii_info); - - /* Called to suspend the PHY for power */ - int (*suspend)(struct gfar_mii_info *mii_info); - - /* Reconfigures autonegotiation (or disables it) */ - int (*config_aneg)(struct gfar_mii_info *mii_info); - - /* Determines the negotiated speed and duplex */ - int (*read_status)(struct gfar_mii_info *mii_info); - - /* Clears any pending interrupts */ - int (*ack_interrupt)(struct gfar_mii_info *mii_info); - - /* Enables or disables interrupts */ - int (*config_intr)(struct gfar_mii_info *mii_info); - - /* Clears up any memory if needed */ - void (*close)(struct gfar_mii_info *mii_info); -}; - -struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); -int read_phy_reg(struct net_device *dev, int mii_id, int regnum); -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); - -struct dm9161_private { - struct timer_list timer; - int resetdone; -}; - -#endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index de087cd609d9..896aa02000d7 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -1,6 +1,7 @@ config MKISS tristate "Serial port KISS driver" depends on AX25 + select CRC16 ---help--- KISS is a protocol used for the exchange of data between a computer and a Terminal Node Controller (a small embedded system commonly diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1756f0ed54cc..cb43a9d28774 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) { struct bpqdev *bpq; - list_for_each_entry(bpq, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) { if (bpq->ethdev == dev) return bpq->axdev; } @@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - list_for_each_entry(bpqdev, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) { if (i == *pos) return bpqdev; } @@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) p = ((struct bpqdev *)v)->bpq_list.next; return (p == &bpq_devices) ? NULL - : list_entry(p, struct bpqdev, bpq_list); + : rcu_dereference(list_entry(p, struct bpqdev, bpq_list)); } static void bpq_seq_stop(struct seq_file *seq, void *v) @@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi if (!dev_is_ethdev(dev)) return NOTIFY_DONE; - rcu_read_lock(); - switch (event) { case NETDEV_UP: /* new ethernet device -> new BPQ interface */ if (bpq_get_ax25_dev(dev) == NULL) @@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi default: break; } - rcu_read_unlock(); return NOTIFY_DONE; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d9fe64b46f4b..85d6dc005be0 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -14,13 +14,14 @@ * * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl> * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org> + * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de> */ - #include <linux/config.h> #include <linux/module.h> #include <asm/system.h> #include <linux/bitops.h> #include <asm/uaccess.h> +#include <linux/crc16.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -39,11 +40,6 @@ #include <net/ax25.h> -#ifdef CONFIG_INET -#include <linux/ip.h> -#include <linux/tcp.h> -#endif - #define AX_MTU 236 /* SLIP/KISS protocol characters. */ @@ -80,9 +76,13 @@ struct mkiss { int mode; int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 + int crcauto; /* CRC auto mode */ + +#define CRC_MODE_NONE 0 +#define CRC_MODE_FLEX 1 +#define CRC_MODE_SMACK 2 +#define CRC_MODE_FLEX_TEST 3 +#define CRC_MODE_SMACK_TEST 4 atomic_t refcnt; struct semaphore dead_sem; @@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size) return 0; } +static int check_crc_16(unsigned char *cp, int size) +{ + unsigned short crc = 0x0000; + + if (size < 3) + return -1; + + crc = crc16(0, cp, size); + + if (crc != 0x0000) + return -1; + + return 0; +} + /* * Standard encapsulation */ @@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax) spin_lock_bh(&ax->buflock); if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x20) { - ax->crcmode = CRC_MODE_FLEX; + if (ax->rbuff[0] & 0x80) { + if (check_crc_16(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); + + return; + } + if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-smack\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK; + } + ax->rcount -= 2; + *ax->rbuff &= ~0x80; + } else if (ax->rbuff[0] & 0x20) { if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->stats.rx_errors++; + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); return; } + if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-flexnet\n", + ax->dev->name); + ax->crcmode = CRC_MODE_FLEX; + } ax->rcount -= 2; - /* dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have - * to correct the kissparm signature, because it - * indicates a crc but there's none + + /* + * dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have to + * correct the kissparm signature, because it indicates + * a crc but there's none */ - *ax->rbuff &= ~0x20; + *ax->rbuff &= ~0x20; } } spin_unlock_bh(&ax->buflock); @@ -417,20 +455,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) p = icp; spin_lock_bh(&ax->buflock); - switch (ax->crcmode) { - unsigned short crc; + if ((*p & 0x0f) != 0) { + /* Configuration Command (kissparms(1). + * Protocol spec says: never append CRC. + * This fixes a very old bug in the linux + * kiss driver. -- dl9sau */ + switch (*p & 0xff) { + case 0x85: + /* command from userspace especially for us, + * not for delivery to the tnc */ + if (len > 1) { + int cmd = (p[1] & 0xff); + switch(cmd) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + break; + case 0: + default: + ax->crcmode = CRC_MODE_SMACK_TEST; + cmd = 0; + } + ax->crcauto = (cmd ? 0 : 1); + printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); + } + spin_unlock_bh(&ax->buflock); + netif_start_queue(dev); - case CRC_MODE_FLEX: - *p |= 0x20; - crc = calc_crc_flex(p, len); - count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); - break; + return; + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } else { + unsigned short crc; + switch (ax->crcmode) { + case CRC_MODE_SMACK_TEST: + ax->crcmode = CRC_MODE_FLEX_TEST; + printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name); + // fall through + case CRC_MODE_SMACK: + *p |= 0x80; + crc = swab16(crc16(0, p, len)); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + case CRC_MODE_FLEX_TEST: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name); + // fall through + case CRC_MODE_FLEX: + *p |= 0x20; + crc = calc_crc_flex(p, len); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } - default: - count = kiss_esc(p, (unsigned char *)ax->xbuff, len); - break; - } - set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); ax->stats.tx_packets++; @@ -439,8 +526,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; - - spin_unlock_bh(&ax->buflock); } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ @@ -622,7 +707,7 @@ static void ax_setup(struct net_device *dev) * best way to fix this is to use a rwlock in the tty struct, but for now we * use a single global rwlock for all ttys in ppp line discipline. */ -static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(disc_data_lock); static struct mkiss *mkiss_get(struct tty_struct *tty) { @@ -643,6 +728,8 @@ static void mkiss_put(struct mkiss *ax) up(&ax->dead_sem); } +static int crc_force = 0; /* Can be overridden with insmod */ + static int mkiss_open(struct tty_struct *tty) { struct net_device *dev; @@ -682,6 +769,33 @@ static int mkiss_open(struct tty_struct *tty) if (register_netdev(dev)) goto out_free_buffers; + /* after register_netdev() - because else printk smashes the kernel */ + switch (crc_force) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n", + ax->dev->name); + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n", + ax->dev->name); + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: crc mode disabled.\n", + ax->dev->name); + break; + case 0: + /* fall through */ + default: + crc_force = 0; + printk(KERN_INFO "mkiss: %s: crc mode is auto.\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK_TEST; + } + ax->crcauto = (crc_force ? 0 : 1); + netif_start_queue(dev); /* Done. We have linked the TTY line to a channel. */ @@ -765,7 +879,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, case SIOCSIFHWADDR: { char addr[AX25_ADDR_LEN]; -printk(KERN_INFO "In SIOCSIFHWADDR"); if (copy_from_user(&addr, (void __user *) arg, AX25_ADDR_LEN)) { @@ -864,6 +977,7 @@ out: } static struct tty_ldisc ax_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, @@ -904,6 +1018,8 @@ static void __exit mkiss_exit_driver(void) MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); +MODULE_PARM(crc_force, "i"); +MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h deleted file mode 100644 index 4ab700478598..000000000000 --- a/drivers/net/hamradio/mkiss.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** - * Defines for the Multi-KISS driver. - ****************************************************************************/ - -#define AX25_MAXDEV 16 /* MAX number of AX25 channels; - This can be overridden with - insmod -oax25_maxdev=nnn */ -#define AX_MTU 236 - -/* SLIP/KISS protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -struct ax_disp { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* SLIP interface statistics. */ - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_bytes; /* inbound bytes counter */ - unsigned long tx_bytes; /* outbound bytes counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ - - /* Detailed SLIP statistics. */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - - unsigned long flags; /* Flag values/ mode etc */ - /* long req'd: used by set_bit --RR */ -#define AXF_INUSE 0 /* Channel in use */ -#define AXF_ESCAPE 1 /* ESC received */ -#define AXF_ERROR 2 /* Parity, etc. error */ -#define AXF_KEEPTEST 3 /* Keepalive test flag */ -#define AXF_OUTWAIT 4 /* is outpacket was flag */ - - int mode; - int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 - spinlock_t buflock; /* lock for rbuf and xbuf */ -}; - -#define AX25_MAGIC 0x5316 diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index cf0ac6fda1a1..b71fab6e34f4 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2517,10 +2517,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_after_eq(jiffies, time)) /* no signal->no logout */ @@ -2536,10 +2534,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); #ifdef HP100_DEBUG @@ -2577,10 +2573,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ @@ -2591,10 +2585,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_before_eq(time, jiffies)) { @@ -2606,10 +2598,8 @@ static int hp100_down_vg_link(struct net_device *dev) time = jiffies + (2 * HZ); /* This seems to take a while.... */ do { - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); return 0; @@ -2659,10 +2649,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); /* Start an addressed training and optionally request promiscuous port */ @@ -2697,10 +2685,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_before(jiffies, time)); if (time_after_eq(jiffies, time)) { @@ -2723,10 +2709,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) #endif break; } - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); } diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index ca5914091d3a..d54156f11e61 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -400,5 +400,15 @@ config VIA_FIR To compile it as a module, choose M here: the module will be called via-ircc. +config PXA_FICP + tristate "Intel PXA2xx Internal FICP" + depends on ARCH_PXA && IRDA + help + Say Y or M here if you want to build support for the PXA2xx + built-in IRDA interface which can support both SIR and FIR. + This driver relies on platform specific helper routines so + available capabilities may vary from one PXA2xx target to + another. + endmenu diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 29a8bd812b21..e7a8b7f7f5dd 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o obj-$(CONFIG_VIA_FIR) += via-ircc.o +obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o # Old dongle drivers for old SIR drivers obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c new file mode 100644 index 000000000000..aef80f5e7c9c --- /dev/null +++ b/drivers/net/irda/pxaficp_ir.c @@ -0,0 +1,871 @@ +/* + * linux/drivers/net/irda/pxaficp_ir.c + * + * Based on sa1100_ir.c by Russell King + * + * Changes copyright (C) 2003-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/rtnetlink.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/pm.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/delay.h> +#include <asm/hardware.h> +#include <asm/arch/irda.h> +#include <asm/arch/pxa-regs.h> + +#ifdef CONFIG_MACH_MAINSTONE +#include <asm/arch/mainstone.h> +#endif + +#define IrSR_RXPL_NEG_IS_ZERO (1<<4) +#define IrSR_RXPL_POS_IS_ZERO 0x0 +#define IrSR_TXPL_NEG_IS_ZERO (1<<3) +#define IrSR_TXPL_POS_IS_ZERO 0x0 +#define IrSR_XMODE_PULSE_1_6 (1<<2) +#define IrSR_XMODE_PULSE_3_16 0x0 +#define IrSR_RCVEIR_IR_MODE (1<<1) +#define IrSR_RCVEIR_UART_MODE 0x0 +#define IrSR_XMITIR_IR_MODE (1<<0) +#define IrSR_XMITIR_UART_MODE 0x0 + +#define IrSR_IR_RECEIVE_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_IR_MODE | \ + IrSR_XMITIR_UART_MODE) + +#define IrSR_IR_TRANSMIT_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_UART_MODE | \ + IrSR_XMITIR_IR_MODE) + +struct pxa_irda { + int speed; + int newspeed; + unsigned long last_oscr; + + unsigned char *dma_rx_buff; + unsigned char *dma_tx_buff; + dma_addr_t dma_rx_buff_phy; + dma_addr_t dma_tx_buff_phy; + unsigned int dma_tx_buff_len; + int txdma; + int rxdma; + + struct net_device_stats stats; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct device *dev; + struct pxaficp_platform_data *pdata; +}; + + +#define IS_FIR(si) ((si)->speed >= 4000000) +#define IRDA_FRAME_SIZE_LIMIT 2047 + +inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) +{ + DCSR(si->rxdma) = DCSR_NODESC; + DSADR(si->rxdma) = __PREG(ICDR); + DTADR(si->rxdma) = si->dma_rx_buff_phy; + DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT; + DCSR(si->rxdma) |= DCSR_RUN; +} + +inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) +{ + DCSR(si->txdma) = DCSR_NODESC; + DSADR(si->txdma) = si->dma_tx_buff_phy; + DTADR(si->txdma) = __PREG(ICDR); + DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len; + DCSR(si->txdma) |= DCSR_RUN; +} + +/* + * Set the IrDA communications speed. + */ +static int pxa_irda_set_speed(struct pxa_irda *si, int speed) +{ + unsigned long flags; + unsigned int divisor; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + + /* refer to PXA250/210 Developer's Manual 10-7 */ + /* BaudRate = 14.7456 MHz / (16*Divisor) */ + divisor = 14745600 / (16 * speed); + + local_irq_save(flags); + + if (IS_FIR(si)) { + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + pxa_set_cken(CKEN13_FICP, 0); + + /* set board transceiver to SIR mode */ + si->pdata->transceiver_mode(si->dev, IR_SIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* enable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 1); + } + + /* disable STUART first */ + STIER = 0; + + /* access DLL & DLH */ + STLCR |= LCR_DLAB; + STDLL = divisor & 0xff; + STDLH = divisor >> 8; + STLCR &= ~LCR_DLAB; + + si->speed = speed; + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + + local_irq_restore(flags); + break; + + case 4000000: + local_irq_save(flags); + + /* disable STUART */ + STIER = 0; + STISR = 0; + pxa_set_cken(CKEN5_STUART, 0); + + /* disable FICP first */ + ICCR0 = 0; + + /* set board transceiver to FIR mode */ + si->pdata->transceiver_mode(si->dev, IR_FIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_ICPRXD_MD); + pxa_gpio_mode(GPIO47_ICPTXD_MD); + + /* enable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 1); + + si->speed = speed; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + local_irq_restore(flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* SIR interrupt service routine. */ +static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int iir, lsr, data; + + iir = STIIR; + + switch (iir & 0x0F) { + case 0x06: /* Receiver Line Status */ + lsr = STLSR; + while (lsr & LSR_FIFOE) { + data = STRBR; + if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { + printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); + si->stats.rx_errors++; + if (lsr & LSR_FE) + si->stats.rx_frame_errors++; + if (lsr & LSR_OE) + si->stats.rx_fifo_errors++; + } else { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, data); + } + lsr = STLSR; + } + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x04: /* Received Data Available */ + /* forth through */ + + case 0x0C: /* Character Timeout Indication */ + do { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); + } while (STLSR & LSR_DR); + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x02: /* Transmit FIFO Data Request */ + while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { + STTHR = *si->tx_buff.data++; + si->tx_buff.len -= 1; + } + + if (si->tx_buff.len == 0) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->tx_buff.data - + si->tx_buff.head; + + /* We need to ensure that the transmitter has finished. */ + while ((STLSR & LSR_TEMT) == 0) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * Ok, we've finished transmitting. Now enable + * the receiver. Sometimes we get a receive IRQ + * immediately after a transmit... + */ + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + /* enable IR Receiver, disable IR Transmitter */ + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + /* enable STUART and receive interrupts */ + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + } + /* I'm hungry! */ + netif_wake_queue(dev); + } + break; + } + + return IRQ_HANDLED; +} + +/* FIR Receive DMA interrupt handler */ +static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs) +{ + int dcsr = DCSR(channel); + + DCSR(channel) = dcsr & ~DCSR_RUN; + + printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr); +} + +/* FIR Transmit DMA interrupt handler */ +static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs) +{ + struct net_device *dev = data; + struct pxa_irda *si = netdev_priv(dev); + int dcsr; + + dcsr = DCSR(channel); + DCSR(channel) = dcsr & ~DCSR_RUN; + + if (dcsr & DCSR_ENDINTR) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->dma_tx_buff_len; + } else { + si->stats.tx_errors++; + } + + while (ICSR1 & ICSR1_TBY) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * HACK: It looks like the TBY bit is dropped too soon. + * Without this delay things break. + */ + udelay(120); + + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + } + netif_wake_queue(dev); +} + +/* EIF(Error in FIFO/End in Frame) handler for FIR */ +static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) +{ + unsigned int len, stat, data; + + /* Get the current data position. */ + len = DTADR(si->rxdma) - si->dma_rx_buff_phy; + + do { + /* Read Status, and then Data. */ + stat = ICSR1; + rmb(); + data = ICDR; + + if (stat & (ICSR1_CRE | ICSR1_ROR)) { + si->stats.rx_errors++; + if (stat & ICSR1_CRE) { + printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); + si->stats.rx_crc_errors++; + } + if (stat & ICSR1_ROR) { + printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); + si->stats.rx_frame_errors++; + } + } else { + si->dma_rx_buff[len++] = data; + } + /* If we hit the end of frame, there's no point in continuing. */ + if (stat & ICSR1_EOF) + break; + } while (ICSR0 & ICSR0_EIF); + + if (stat & ICSR1_EOF) { + /* end of frame. */ + struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); + si->stats.rx_dropped++; + return; + } + + /* Align IP header to 20 bytes */ + skb_reserve(skb, 1); + memcpy(skb->data, si->dma_rx_buff, len); + skb_put(skb, len); + + /* Feed it to IrLAP */ + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + + si->stats.rx_packets++; + si->stats.rx_bytes += len; + + dev->last_rx = jiffies; + } +} + +/* FIR interrupt handler */ +static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int icsr0; + + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + si->last_oscr = OSCR; + icsr0 = ICSR0; + + if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { + if (icsr0 & ICSR0_FRE) { + printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); + si->stats.rx_frame_errors++; + } else { + printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); + si->stats.rx_errors++; + } + ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB); + } + + if (icsr0 & ICSR0_EIF) { + /* An error in FIFO occured, or there is a end of frame */ + pxa_irda_fir_irq_eif(si, dev); + } + + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + return IRQ_HANDLED; +} + +/* hard_xmit interface of irda device */ +static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + /* + * Does this packet contain a request to change the interface + * speed? If so, remember it until we complete the transmission + * of this frame. + */ + if (speed != si->speed && speed != -1) + si->newspeed = speed; + + /* + * If this is an empty frame, we can bypass a lot. + */ + if (skb->len == 0) { + if (si->newspeed) { + si->newspeed = 0; + pxa_irda_set_speed(si, speed); + } + dev_kfree_skb(skb); + return 0; + } + + netif_stop_queue(dev); + + if (!IS_FIR(si)) { + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); + + /* Disable STUART interrupts and switch to transmit mode. */ + STIER = 0; + STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6; + + /* enable STUART and transmit interrupts */ + STIER = IER_UUE | IER_TIE; + } else { + unsigned long mtt = irda_get_mtt(skb); + + si->dma_tx_buff_len = skb->len; + memcpy(si->dma_tx_buff, skb->data, skb->len); + + if (mtt) + while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) + cpu_relax(); + + /* stop RX DMA, disable FICP */ + DCSR(si->rxdma) &= ~DCSR_RUN; + ICCR0 = 0; + + pxa_irda_fir_dma_tx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_TXE; + } + + dev_kfree_skb(skb); + dev->trans_start = jiffies; + return 0; +} + +static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct pxa_irda *si = netdev_priv(dev); + int ret; + + switch (cmd) { + case SIOCSBANDWIDTH: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (netif_running(dev)) { + ret = pxa_irda_set_speed(si, + rq->ifr_baudrate); + } else { + printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + ret = 0; + rq->ifr_receiving = IS_FIR(si) ? 0 + : si->rx_buff.state != OUTSIDE_FRAME; + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *pxa_irda_stats(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + return &si->stats; +} + +static void pxa_irda_startup(struct pxa_irda *si) +{ + /* Disable STUART interrupts */ + STIER = 0; + /* enable STUART interrupt to the processor */ + STMCR = MCR_OUT2; + /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ + STLCR = LCR_WLS0 | LCR_WLS1; + /* enable FIFO, we use FIFO to improve performance */ + STFCR = FCR_TRFIFOE | FCR_ITL_32; + + /* disable FICP */ + ICCR0 = 0; + /* configure FICP ICCR2 */ + ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; + + /* configure DMAC */ + DRCMR17 = si->rxdma | DRCMR_MAPVLD; + DRCMR18 = si->txdma | DRCMR_MAPVLD; + + /* force SIR reinitialization */ + si->speed = 4000000; + pxa_irda_set_speed(si, 9600); + + printk(KERN_DEBUG "pxa_ir: irda startup\n"); +} + +static void pxa_irda_shutdown(struct pxa_irda *si) +{ + unsigned long flags; + + local_irq_save(flags); + + /* disable STUART and interrupt */ + STIER = 0; + /* disable STUART SIR mode */ + STISR = 0; + /* disable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 0); + + /* disable DMA */ + DCSR(si->txdma) &= ~DCSR_RUN; + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + /* disable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 0); + + DRCMR17 = 0; + DRCMR18 = 0; + + local_irq_restore(flags); + + /* power off board transceiver */ + si->pdata->transceiver_mode(si->dev, IR_OFF); + + printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); +} + +static int pxa_irda_start(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int err; + + si->speed = 9600; + + err = request_irq(IRQ_STUART, pxa_irda_sir_irq, 0, dev->name, dev); + if (err) + goto err_irq1; + + err = request_irq(IRQ_ICP, pxa_irda_fir_irq, 0, dev->name, dev); + if (err) + goto err_irq2; + + /* + * The interrupt must remain disabled for now. + */ + disable_irq(IRQ_STUART); + disable_irq(IRQ_ICP); + + err = -EBUSY; + si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev); + if (si->rxdma < 0) + goto err_rx_dma; + + si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev); + if (si->txdma < 0) + goto err_tx_dma; + + err = -ENOMEM; + si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_rx_buff_phy, GFP_KERNEL ); + if (!si->dma_rx_buff) + goto err_dma_rx_buff; + + si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_tx_buff_phy, GFP_KERNEL ); + if (!si->dma_tx_buff) + goto err_dma_tx_buff; + + /* Setup the serial port for the initial speed. */ + pxa_irda_startup(si); + + /* + * Open a new IrLAP layer instance. + */ + si->irlap = irlap_open(dev, &si->qos, "pxa"); + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + /* + * Now enable the interrupt and start the queue + */ + enable_irq(IRQ_STUART); + enable_irq(IRQ_ICP); + netif_start_queue(dev); + + printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); + + return 0; + +err_irlap: + pxa_irda_shutdown(si); + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); +err_dma_tx_buff: + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); +err_dma_rx_buff: + pxa_free_dma(si->txdma); +err_tx_dma: + pxa_free_dma(si->rxdma); +err_rx_dma: + free_irq(IRQ_ICP, dev); +err_irq2: + free_irq(IRQ_STUART, dev); +err_irq1: + + return err; +} + +static int pxa_irda_stop(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + + netif_stop_queue(dev); + + pxa_irda_shutdown(si); + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + free_irq(IRQ_STUART, dev); + free_irq(IRQ_ICP, dev); + + pxa_free_dma(si->rxdma); + pxa_free_dma(si->txdma); + + if (si->dma_rx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); + if (si->dma_tx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); + + printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); + return 0; +} + +static int pxa_irda_suspend(struct device *_dev, pm_message_t state, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; + + if (netif_running(dev)) { + si = netdev_priv(dev); + netif_device_detach(dev); + pxa_irda_shutdown(si); + } + + return 0; +} + +static int pxa_irda_resume(struct device *_dev, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (!dev || level != RESUME_ENABLE) + return 0; + + if (netif_running(dev)) { + si = netdev_priv(dev); + pxa_irda_startup(si); + netif_device_attach(dev); + netif_wake_queue(dev); + } + + return 0; +} + + +static int pxa_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int pxa_irda_probe(struct device *_dev) +{ + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct pxa_irda *si; + unsigned int baudrate_mask; + int err; + + if (!pdev->dev.platform_data) + return -ENODEV; + + err = request_mem_region(__PREG(STUART), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + + err = request_mem_region(__PREG(FICP), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + + dev = alloc_irdadev(sizeof(struct pxa_irda)); + if (!dev) + goto err_mem_3; + + si = netdev_priv(dev); + si->dev = &pdev->dev; + si->pdata = pdev->dev.platform_data; + + /* + * Initialise the SIR buffers + */ + err = pxa_irda_init_iobuf(&si->rx_buff, 14384); + if (err) + goto err_mem_4; + err = pxa_irda_init_iobuf(&si->tx_buff, 4000); + if (err) + goto err_mem_5; + + dev->hard_start_xmit = pxa_irda_hard_xmit; + dev->open = pxa_irda_start; + dev->stop = pxa_irda_stop; + dev->do_ioctl = pxa_irda_ioctl; + dev->get_stats = pxa_irda_stats; + + irda_init_max_qos_capabilies(&si->qos); + + baudrate_mask = 0; + if (si->pdata->transceiver_cap & IR_SIRMODE) + baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + if (si->pdata->transceiver_cap & IR_FIRMODE) + baudrate_mask |= IR_4000000 << 8; + + si->qos.baud_rate.bits &= baudrate_mask; + si->qos.min_turn_time.bits = 7; /* 1ms or more */ + + irda_qos_bits_to_value(&si->qos); + + err = register_netdev(dev); + + if (err == 0) + dev_set_drvdata(&pdev->dev, dev); + + if (err) { + kfree(si->tx_buff.head); +err_mem_5: + kfree(si->rx_buff.head); +err_mem_4: + free_netdev(dev); +err_mem_3: + release_mem_region(__PREG(FICP), 0x1c); +err_mem_2: + release_mem_region(__PREG(STUART), 0x24); + } +err_mem_1: + return err; +} + +static int pxa_irda_remove(struct device *_dev) +{ + struct net_device *dev = dev_get_drvdata(_dev); + + if (dev) { + struct pxa_irda *si = netdev_priv(dev); + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(STUART), 0x24); + release_mem_region(__PREG(FICP), 0x1c); + + return 0; +} + +static struct device_driver pxa_ir_driver = { + .name = "pxa2xx-ir", + .bus = &platform_bus_type, + .probe = pxa_irda_probe, + .remove = pxa_irda_remove, + .suspend = pxa_irda_suspend, + .resume = pxa_irda_resume, +}; + +static int __init pxa_irda_init(void) +{ + return driver_register(&pxa_ir_driver); +} + +static void __exit pxa_irda_exit(void) +{ + driver_unregister(&pxa_ir_driver); +} + +module_init(pxa_irda_init); +module_exit(pxa_irda_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 15f207323d97..3961a754e920 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -678,10 +678,9 @@ static void turnaround_delay(const struct stir_cb *stir, long us) return; ticks = us / (1000000 / HZ); - if (ticks > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1 + ticks); - } else + if (ticks > 0) + schedule_timeout_interruptible(1 + ticks); + else udelay(us); } diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 9d026ed77ddd..04e47189d830 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -645,11 +645,10 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - if(data) - schedule_timeout(data * HZ); + if (data) + schedule_timeout_interruptible(data * HZ); else - schedule_timeout(MAX_SCHEDULE_TIMEOUT); + schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); del_timer_sync(&adapter->blink_timer); ixgb_led_off(&adapter->hw); @@ -723,6 +722,7 @@ struct ethtool_ops ixgb_ethtool_ops = { .phys_id = ixgb_phys_id, .get_stats_count = ixgb_get_stats_count, .get_ethtool_stats = ixgb_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void ixgb_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 89d6d69be382..176680cb153e 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -460,8 +460,9 @@ ixgb_probe(struct pci_dev *pdev, } ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); + memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { err = -EIO; goto err_eeprom; } diff --git a/drivers/net/lance.c b/drivers/net/lance.c index b4929beb33b2..1d75ca0bb939 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -298,7 +298,7 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static void lance_init_ring(struct net_device *dev, int mode); +static void lance_init_ring(struct net_device *dev, gfp_t mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -846,7 +846,7 @@ lance_purge_ring(struct net_device *dev) /* Initialize the LANCE Rx and Tx rings. */ static void -lance_init_ring(struct net_device *dev, int gfp) +lance_init_ring(struct net_device *dev, gfp_t gfp) { struct lance_private *lp = dev->priv; int i; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 27f0d8ac4c40..309d254842cf 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -298,7 +298,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) return 0; unmap: if (ei_status.reg0) - iounmap((void *)dev->mem_start); + iounmap(ei_status.mem); cleanup: free_irq(dev->irq, dev); return ret; diff --git a/drivers/net/mii.c b/drivers/net/mii.c index c33cb3dc942b..e42aa797f08b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -207,6 +207,20 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } +int mii_check_gmii_support(struct mii_if_info *mii) +{ + int reg; + + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (reg & BMSR_ESTATEN) { + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS); + if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) + return 1; + } + + return 0; +} + int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -394,5 +408,6 @@ EXPORT_SYMBOL(mii_ethtool_gset); EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_media); +EXPORT_SYMBOL(mii_check_gmii_support); EXPORT_SYMBOL(generic_mii_ioctl); diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c new file mode 100644 index 000000000000..f79f7ee72ab8 --- /dev/null +++ b/drivers/net/mipsnet.c @@ -0,0 +1,371 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define DEBUG + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/sched.h> +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <asm/io.h> +#include <asm/mips-boards/simint.h> + +#include "mipsnet.h" /* actual device IO mapping */ + +#define MIPSNET_VERSION "2005-06-20" + +#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) + +struct mipsnet_priv { + struct net_device_stats stats; +}; + +static struct platform_device *mips_plat_dev; + +static char mipsnet_string[] = "mipsnet"; + +/* + * Copy data from the MIPSNET rx data port + */ +static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, + int len) +{ + uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount)); + if (available_len < len) + return -EFAULT; + + for (; len > 0; len--, kdata++) { + *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); + } + + return inl(mipsnet_reg_address(dev, rxDataCount)); +} + +static inline ssize_t mipsnet_put_todevice(struct net_device *dev, + struct sk_buff *skb) +{ + int count_to_go = skb->len; + char *buf_ptr = skb->data; + struct mipsnet_priv *mp = netdev_priv(dev); + + pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", + dev->name, __FUNCTION__, skb->len); + + outl(skb->len, mipsnet_reg_address(dev, txDataCount)); + + pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", + dev->name, __FUNCTION__, skb->len); + + for (; count_to_go; buf_ptr++, count_to_go--) { + outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); + } + + mp->stats.tx_packets++; + mp->stats.tx_bytes += skb->len; + + return skb->len; +} + +static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pr_debug("%s:%s(): transmitting %d bytes\n", + dev->name, __FUNCTION__, skb->len); + + /* Only one packet at a time. Once TXDONE interrupt is serviced, the + * queue will be restarted. + */ + netif_stop_queue(dev); + mipsnet_put_todevice(dev, skb); + + return 0; +} + +static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) +{ + struct sk_buff *skb; + size_t len = count; + struct mipsnet_priv *mp = netdev_priv(dev); + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + mp->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) + return -EFAULT; + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + pr_debug("%s:%s(): pushing RXed data to kernel\n", + dev->name, __FUNCTION__); + netif_rx(skb); + + mp->stats.rx_packets++; + mp->stats.rx_bytes += len; + + return count; +} + +static irqreturn_t +mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + + irqreturn_t retval = IRQ_NONE; + uint64_t interruptFlags; + + if (irq == dev->irq) { + pr_debug("%s:%s(): irq %d for device\n", + dev->name, __FUNCTION__, irq); + + retval = IRQ_HANDLED; + + interruptFlags = + inl(mipsnet_reg_address(dev, interruptControl)); + pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, + __FUNCTION__, interruptFlags); + + if (interruptFlags & MIPSNET_INTCTL_TXDONE) { + pr_debug("%s:%s(): got TXDone\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_TXDONE, + mipsnet_reg_address(dev, interruptControl)); + // only one packet at a time, we are done. + netif_wake_queue(dev); + } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { + pr_debug("%s:%s(): got RX data\n", + dev->name, __FUNCTION__); + mipsnet_get_fromdev(dev, + inl(mipsnet_reg_address(dev, rxDataCount))); + pr_debug("%s:%s(): clearing RX int\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_RXDONE, + mipsnet_reg_address(dev, interruptControl)); + + } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { + pr_debug("%s:%s(): got test interrupt\n", + dev->name, __FUNCTION__); + // TESTBIT is cleared on read. + // And takes effect after a write with 0 + outl(0, mipsnet_reg_address(dev, interruptControl)); + } else { + pr_debug("%s:%s(): no valid fags 0x%016llx\n", + dev->name, __FUNCTION__, interruptFlags); + // Maybe shared IRQ, just ignore, no clearing. + retval = IRQ_NONE; + } + + } else { + printk(KERN_INFO "%s: %s(): irq %d for unknown device\n", + dev->name, __FUNCTION__, irq); + retval = IRQ_NONE; + } + return retval; +} //mipsnet_interrupt() + +static int mipsnet_open(struct net_device *dev) +{ + int err; + pr_debug("%s: mipsnet_open\n", dev->name); + + err = request_irq(dev->irq, &mipsnet_interrupt, + SA_SHIRQ, dev->name, (void *) dev); + + if (err) { + pr_debug("%s: %s(): can't get irq %d\n", + dev->name, __FUNCTION__, dev->irq); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + return err; + } + + pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", + dev->name, __FUNCTION__, dev->base_addr, dev->irq); + + + netif_start_queue(dev); + + // test interrupt handler + outl(MIPSNET_INTCTL_TESTBIT, + mipsnet_reg_address(dev, interruptControl)); + + + return 0; +} + +static int mipsnet_close(struct net_device *dev) +{ + pr_debug("%s: %s()\n", dev->name, __FUNCTION__); + netif_stop_queue(dev); + return 0; +} + +static struct net_device_stats *mipsnet_get_stats(struct net_device *dev) +{ + struct mipsnet_priv *mp = netdev_priv(dev); + + return &mp->stats; +} + +static void mipsnet_set_mclist(struct net_device *dev) +{ + // we don't do anything + return; +} + +static int __init mipsnet_probe(struct device *dev) +{ + struct net_device *netdev; + int err; + + netdev = alloc_etherdev(sizeof(struct mipsnet_priv)); + if (!netdev) { + err = -ENOMEM; + goto out; + } + + dev_set_drvdata(dev, netdev); + + netdev->open = mipsnet_open; + netdev->stop = mipsnet_close; + netdev->hard_start_xmit = mipsnet_xmit; + netdev->get_stats = mipsnet_get_stats; + netdev->set_multicast_list = mipsnet_set_mclist; + + /* + * TODO: probe for these or load them from PARAM + */ + netdev->base_addr = 0x4200; + netdev->irq = MIPSCPU_INT_BASE + MIPSCPU_INT_MB0 + + inl(mipsnet_reg_address(netdev, interruptInfo)); + + // Get the io region now, get irq on open() + if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { + pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " + "for dev is not availble.\n", netdev->name, + __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); + err = -EBUSY; + goto out_free_netdev; + } + + /* + * Lacking any better mechanism to allocate a MAC address we use a + * random one ... + */ + random_ether_addr(netdev->dev_addr); + + err = register_netdev(netdev); + if (err) { + printk(KERN_ERR "MIPSNet: failed to register netdev.\n"); + goto out_free_region; + } + + return 0; + +out_free_region: + release_region(netdev->base_addr, MIPSNET_IO_EXTENT); + +out_free_netdev: + free_netdev(netdev); + +out: + return err; +} + +static int __devexit mipsnet_device_remove(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + + unregister_netdev(dev); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + free_netdev(dev); + dev_set_drvdata(device, NULL); + + return 0; +} + +static struct device_driver mipsnet_driver = { + .name = mipsnet_string, + .bus = &platform_bus_type, + .probe = mipsnet_probe, + .remove = __devexit_p(mipsnet_device_remove), +}; + +static void mipsnet_platform_release(struct device *device) +{ + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device(device); + kfree(pldev); +} + +static int __init mipsnet_init_module(void) +{ + struct platform_device *pldev; + int err; + + printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " + "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); + + if (driver_register(&mipsnet_driver)) { + printk(KERN_ERR "Driver registration failed\n"); + err = -ENODEV; + goto out; + } + + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unregister_driver; + } + + memset (pldev, 0, sizeof (*pldev)); + pldev->name = mipsnet_string; + pldev->id = 0; + pldev->dev.release = mipsnet_platform_release; + + if (platform_device_register(pldev)) { + err = -ENODEV; + goto out_free_pldev; + } + + if (!pldev->dev.driver) { + /* + * The driver was not bound to this device, there was + * no hardware at this address. Unregister it, as the + * release fuction will take care of freeing the + * allocated structure + */ + platform_device_unregister (pldev); + } + + mips_plat_dev = pldev; + + return 0; + +out_free_pldev: + kfree(pldev); + +out_unregister_driver: + driver_unregister(&mipsnet_driver); +out: + return err; +} + +static void __exit mipsnet_exit_module(void) +{ + pr_debug("MIPSNet Ethernet driver exiting\n"); + + driver_unregister(&mipsnet_driver); +} + +module_init(mipsnet_init_module); +module_exit(mipsnet_exit_module); diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h new file mode 100644 index 000000000000..878535953cb1 --- /dev/null +++ b/drivers/net/mipsnet.h @@ -0,0 +1,127 @@ +// +// <COPYRIGHT CLASS="1B" YEAR="2005"> +// Unpublished work (c) MIPS Technologies, Inc. All rights reserved. +// Unpublished rights reserved under the copyright laws of the U.S.A. and +// other countries. +// +// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC. +// FOR INTERNAL USE ONLY. +// +// Under no circumstances (contract or otherwise) may this information be +// disclosed to, or copied, modified or used by anyone other than employees +// or contractors of MIPS Technologies having a need to know. +// </COPYRIGHT> +// +//++ +// File: MIPS_Net.h +// +// Description: +// The definition of the emulated MIPSNET device's interface. +// +// Notes: This include file needs to work from a Linux device drivers. +// +//-- +// + +#ifndef __MIPSNET_H +#define __MIPSNET_H + +/* + * Id of this Net device, as seen by the core. + */ +#define MIPS_NET_DEV_ID ((uint64_t) \ + ((uint64_t)'M'<< 0)| \ + ((uint64_t)'I'<< 8)| \ + ((uint64_t)'P'<<16)| \ + ((uint64_t)'S'<<24)| \ + ((uint64_t)'N'<<32)| \ + ((uint64_t)'E'<<40)| \ + ((uint64_t)'T'<<48)| \ + ((uint64_t)'0'<<56)) + +/* + * Net status/control block as seen by sw in the core. + * (Why not use bit fields? can't be bothered with cross-platform struct + * packing.) + */ +typedef struct _net_control_block { + /// dev info for probing + /// reads as MIPSNET%d where %d is some form of version + uint64_t devId; /*0x00 */ + + /* + * read only busy flag. + * Set and cleared by the Net Device to indicate that an rx or a tx + * is in progress. + */ + uint32_t busy; /*0x08 */ + + /* + * Set by the Net Device. + * The device will set it once data has been received. + * The value is the number of bytes that should be read from + * rxDataBuffer. The value will decrease till 0 until all the data + * from rxDataBuffer has been read. + */ + uint32_t rxDataCount; /*0x0c */ +#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) + + /* + * Settable from the MIPS core, cleared by the Net Device. + * The core should set the number of bytes it wants to send, + * then it should write those bytes of data to txDataBuffer. + * The device will clear txDataCount has been processed (not necessarily sent). + */ + uint32_t txDataCount; /*0x10 */ + + /* + * Interrupt control + * + * Used to clear the interrupted generated by this dev. + * Write a 1 to clear the interrupt. (except bit31). + * + * Bit0 is set if it was a tx-done interrupt. + * Bit1 is set when new rx-data is available. + * Until this bit is cleared there will be no other RXs. + * + * Bit31 is used for testing, it clears after a read. + * Writing 1 to this bit will cause an interrupt to be generated. + * To clear the test interrupt, write 0 to this register. + */ + uint32_t interruptControl; /*0x14 */ +#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0)) +#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1)) +#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31)) +#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT) + + /* + * Readonly core-specific interrupt info for the device to signal the core. + * The meaning of the contents of this field might change. + */ + /*###\todo: the whole memIntf interrupt scheme is messy: the device should have + * no control what so ever of what VPE/register set is being used. + * The MemIntf should only expose interrupt lines, and something in the + * config should be responsible for the line<->core/vpe bindings. + */ + uint32_t interruptInfo; /*0x18 */ + + /* + * This is where the received data is read out. + * There is more data to read until rxDataReady is 0. + * Only 1 byte at this regs offset is used. + */ + uint32_t rxDataBuffer; /*0x1c */ + + /* + * This is where the data to transmit is written. + * Data should be written for the amount specified in the txDataCount register. + * Only 1 byte at this regs offset is used. + */ + uint32_t txDataBuffer; /*0x20 */ +} MIPS_T_NetControl; + +#define MIPSNET_IO_EXTENT 0x40 /* being generous */ + +#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field) + +#endif /* __MIPSNET_H */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index f0996ce5c268..6c86dca62e2a 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -277,7 +277,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) struct recvq __iomem *rq = mp->rq; struct myri_rxd __iomem *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; - int gfp_flags = GFP_KERNEL; + gfp_t gfp_flags = GFP_KERNEL; int i; if (from_irq || in_interrupt()) diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 9391e55a5e92..47722f708a41 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -296,7 +296,7 @@ struct myri_eth { /* We use this to acquire receive skb's that we can DMA directly into. */ #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *myri_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *myri_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; diff --git a/drivers/net/ne.c b/drivers/net/ne.c index d209a1556b2e..0de8fdd2aa86 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -54,6 +54,10 @@ static const char version2[] = #include <asm/system.h> #include <asm/io.h> +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) +#include <asm/tx4938/rbtx4938.h> +#endif + #include "8390.h" #define DRV_NAME "ne" @@ -111,6 +115,9 @@ bad_clone_list[] __initdata = { {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ +#endif {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ {NULL,} }; @@ -226,6 +233,10 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); +#ifdef CONFIG_TOSHIBA_RBTX4938 + dev->base_addr = 0x07f20280; + dev->irq = RBTX4938_RTL_8019_IRQ; +#endif err = do_ne_probe(dev); if (err) goto out; @@ -506,6 +517,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + wordlength = 1; +#endif + #ifdef CONFIG_PLAT_OAKS32R ei_status.word16 = 0; #else diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f1c01ac29102..e531a4eedfee 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -372,6 +372,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); dev->dev_addr[i] = SA_prom[i]; } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); return 0; @@ -637,6 +638,7 @@ static struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index e4811b42a6b7..a3c3fc9c0d8a 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1632,8 +1632,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab timed_out = 1; break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (status & fail) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 113b68099216..70fe81a89df9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.30j" -#define DRV_RELDATE "29.04.2005" +#define DRV_VERSION "1.31a" +#define DRV_RELDATE "12.Sep.2005" #define PFX DRV_NAME ": " static const char *version = @@ -257,6 +257,9 @@ static int homepna[MAX_UNITS]; * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. * v1.30i 28 Jun 2004 Don Fry change to use module_param. * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. + * v1.31 02 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> added set_ringparam(). + * v1.31a 12 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> set min ring size to 4 + * to allow loopback test to work unchanged. */ @@ -266,17 +269,17 @@ static int homepna[MAX_UNITS]; * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ #ifndef PCNET32_LOG_TX_BUFFERS -#define PCNET32_LOG_TX_BUFFERS 4 -#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_TX_BUFFERS 4 +#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */ +#define PCNET32_LOG_MAX_RX_BUFFERS 9 #endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) +#define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS)) #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) +#define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) #define PKT_BUF_SZ 1544 @@ -334,14 +337,14 @@ struct pcnet32_access { }; /* - * The first three fields of pcnet32_private are read by the ethernet device - * so we allocate the structure should be allocated by pci_alloc_consistent(). + * The first field of pcnet32_private is read by the ethernet device + * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { - /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; struct pcnet32_init_block init_block; + /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ + struct pcnet32_rx_head *rx_ring; + struct pcnet32_tx_head *tx_ring; dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by pci_alloc_consistent */ @@ -349,13 +352,21 @@ struct pcnet32_private { structure */ const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t tx_dma_addr[TX_RING_SIZE]; - dma_addr_t rx_dma_addr[RX_RING_SIZE]; + struct sk_buff **tx_skbuff; + struct sk_buff **rx_skbuff; + dma_addr_t *tx_dma_addr; + dma_addr_t *rx_dma_addr; struct pcnet32_access a; spinlock_t lock; /* Guard lock */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int rx_ring_size; /* current rx ring size */ + unsigned int tx_ring_size; /* current tx ring size */ + unsigned int rx_mod_mask; /* rx ring modular mask */ + unsigned int tx_mod_mask; /* tx ring modular mask */ + unsigned short rx_len_bits; + unsigned short tx_len_bits; + dma_addr_t rx_ring_dma_addr; + dma_addr_t tx_ring_dma_addr; unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; @@ -397,6 +408,9 @@ static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); static void pcnet32_purge_tx_ring(struct net_device *dev); +static int pcnet32_alloc_ring(struct net_device *dev); +static void pcnet32_free_ring(struct net_device *dev); + enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -613,10 +627,62 @@ static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringpar { struct pcnet32_private *lp = dev->priv; - ering->tx_max_pending = TX_RING_SIZE - 1; - ering->tx_pending = lp->cur_tx - lp->dirty_tx; - ering->rx_max_pending = RX_RING_SIZE - 1; - ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK; + ering->tx_max_pending = TX_MAX_RING_SIZE - 1; + ering->tx_pending = lp->tx_ring_size - 1; + ering->rx_max_pending = RX_MAX_RING_SIZE - 1; + ering->rx_pending = lp->rx_ring_size - 1; +} + +static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int i; + + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + if (netif_running(dev)) + pcnet32_close(dev); + + spin_lock_irqsave(&lp->lock, flags); + pcnet32_free_ring(dev); + lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE); + lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE); + + /* set the minimum ring size to 4, to allow the loopback test to work + * unchanged. + */ + for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { + if (lp->tx_ring_size <= (1 << i)) + break; + } + lp->tx_ring_size = (1 << i); + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->tx_len_bits = (i << 12); + + for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { + if (lp->rx_ring_size <= (1 << i)) + break; + } + lp->rx_ring_size = (1 << i); + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->rx_len_bits = (i << 4); + + if (pcnet32_alloc_ring(dev)) { + pcnet32_free_ring(dev); + return -ENOMEM; + } + + spin_unlock_irqrestore(&lp->lock, flags); + + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_INFO PFX "Ring Param Settings: RX: %d, TX: %d\n", lp->rx_ring_size, lp->tx_ring_size); + + if (netif_running(dev)) + pcnet32_open(dev); + + return 0; } static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -948,6 +1014,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .nway_reset = pcnet32_nway_reset, .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, + .set_ringparam = pcnet32_set_ringparam, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, .get_tso = ethtool_op_get_tso, @@ -957,6 +1024,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* only probes for non-PCI devices, the rest are handled by @@ -1185,9 +1253,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memcpy(dev->dev_addr, promaddr, 6); } } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if (!is_valid_ether_addr(dev->dev_addr)) + if (!is_valid_ether_addr(dev->perm_addr)) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { @@ -1239,6 +1308,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; + lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ + lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); + lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); lp->mii_if.full_duplex = fdx; lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; @@ -1265,21 +1340,23 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } lp->a = *a; + if (pcnet32_alloc_ring(dev)) { + ret = -ENOMEM; + goto err_free_ring; + } /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); @@ -1310,7 +1387,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) if (pcnet32_debug & NETIF_MSG_PROBE) printk(", failed to detect IRQ line.\n"); ret = -ENODEV; - goto err_free_consistent; + goto err_free_ring; } if (pcnet32_debug & NETIF_MSG_PROBE) printk(", probed IRQ %d.\n", dev->irq); @@ -1341,7 +1418,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) - goto err_free_consistent; + goto err_free_ring; if (pdev) { pci_set_drvdata(pdev, dev); @@ -1359,6 +1436,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) return 0; +err_free_ring: + pcnet32_free_ring(dev); err_free_consistent: pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); err_free_netdev: @@ -1369,6 +1448,86 @@ err_release_region: } +static int pcnet32_alloc_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + if ((lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + &lp->tx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if ((lp->rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + &lp->rx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if (!(lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); + + if (!(lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); + + if (!(lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); + + if (!(lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); + + return 0; +} + + +static void pcnet32_free_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + kfree(lp->tx_skbuff); + lp->tx_skbuff = NULL; + + kfree(lp->rx_skbuff); + lp->rx_skbuff = NULL; + + kfree(lp->tx_dma_addr); + lp->tx_dma_addr = NULL; + + kfree(lp->rx_dma_addr); + lp->rx_dma_addr = NULL; + + if (lp->tx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + lp->tx_ring, lp->tx_ring_dma_addr); + lp->tx_ring = NULL; + } + + if (lp->rx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + lp->rx_ring, lp->rx_ring_dma_addr); + lp->rx_ring = NULL; + } +} + + static int pcnet32_open(struct net_device *dev) { @@ -1400,8 +1559,8 @@ pcnet32_open(struct net_device *dev) if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)), - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)), + (u32) (lp->tx_ring_dma_addr), + (u32) (lp->rx_ring_dma_addr), (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block))); /* set/reset autoselect bit */ @@ -1521,7 +1680,7 @@ pcnet32_open(struct net_device *dev) err_free_ring: /* free any allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, @@ -1531,6 +1690,9 @@ err_free_ring: lp->rx_skbuff[i] = NULL; lp->rx_dma_addr[i] = 0; } + + pcnet32_free_ring(dev); + /* * Switch back to 16bit mode to avoid problems with dumb * DOS packet driver after a warm reboot @@ -1562,7 +1724,7 @@ pcnet32_purge_tx_ring(struct net_device *dev) struct pcnet32_private *lp = dev->priv; int i; - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -1587,7 +1749,7 @@ pcnet32_init_ring(struct net_device *dev) lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; if (rx_skbuff == NULL) { if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { @@ -1611,20 +1773,18 @@ pcnet32_init_ring(struct net_device *dev) } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ lp->tx_ring[i].base = 0; lp->tx_dma_addr[i] = 0; } - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -1682,13 +1842,13 @@ pcnet32_tx_timeout (struct net_device *dev) printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) + for (i = 0 ; i < lp->rx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->rx_ring[i].base), (-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff, le32_to_cpu(lp->rx_ring[i].msg_length), le16_to_cpu(lp->rx_ring[i].status)); - for (i = 0 ; i < TX_RING_SIZE; i++) + for (i = 0 ; i < lp->tx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->tx_ring[i].base), (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, @@ -1729,7 +1889,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; + entry = lp->cur_tx & lp->tx_mod_mask; /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ @@ -1753,7 +1913,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) { + if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) { lp->tx_full = 1; netif_stop_queue(dev); } @@ -1806,7 +1966,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) int delta; while (dirty_tx != lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; + int entry = dirty_tx & lp->tx_mod_mask; int status = (short)le16_to_cpu(lp->tx_ring[entry].status); if (status < 0) @@ -1864,18 +2024,18 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) dirty_tx++; } - delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE); - if (delta > TX_RING_SIZE) { + delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size); + if (delta > lp->tx_ring_size) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += TX_RING_SIZE; - delta -= TX_RING_SIZE; + dirty_tx += lp->tx_ring_size; + delta -= lp->tx_ring_size; } if (lp->tx_full && netif_queue_stopped(dev) && - delta < TX_RING_SIZE - 2) { + delta < lp->tx_ring_size - 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); @@ -1932,8 +2092,8 @@ static int pcnet32_rx(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int boguscnt = RX_RING_SIZE / 2; + int entry = lp->cur_rx & lp->rx_mod_mask; + int boguscnt = lp->rx_ring_size / 2; /* If we own the next entry, it's a new packet. Send it up. */ while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { @@ -1998,12 +2158,12 @@ pcnet32_rx(struct net_device *dev) if (netif_msg_drv(lp)) printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) + for (i = 0; i < lp->rx_ring_size; i++) if ((short)le16_to_cpu(lp->rx_ring[(entry+i) - & RX_RING_MOD_MASK].status) < 0) + & lp->rx_mod_mask].status) < 0) break; - if (i > RX_RING_SIZE -2) { + if (i > lp->rx_ring_size -2) { lp->stats.rx_dropped++; lp->rx_ring[entry].status |= le16_to_cpu(0x8000); wmb(); /* Make sure adapter sees owner change */ @@ -2041,7 +2201,7 @@ pcnet32_rx(struct net_device *dev) lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + entry = (++lp->cur_rx) & lp->rx_mod_mask; if (--boguscnt <= 0) break; /* don't stay in loop forever */ } @@ -2084,7 +2244,7 @@ pcnet32_close(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); /* free all allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { @@ -2096,7 +2256,7 @@ pcnet32_close(struct net_device *dev) lp->rx_dma_addr[i] = 0; } - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -2265,6 +2425,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) struct pcnet32_private *lp = dev->priv; unregister_netdev(dev); + pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(dev); @@ -2340,6 +2501,7 @@ static void __exit pcnet32_cleanup_module(void) struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); + pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(pcnet32_dev); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 14f4de1a8180..c782a6329805 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -12,14 +12,6 @@ config PHYLIB devices. This option provides infrastructure for managing PHY devices. -config PHYCONTROL - bool " Support for automatically handling PHY state changes" - depends on PHYLIB - help - Adds code to perform all the work for keeping PHY link - state (speed/duplex/etc) up-to-date. Also handles - interrupts. - comment "MII PHY device drivers" depends on PHYLIB diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d9e11f93bf3a..9209da9dde0d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -242,10 +242,6 @@ EXPORT_SYMBOL(phy_sanitize_settings); * choose the next best ones from the ones selected, so we don't * care if ethtool tries to give us bad values * - * A note about the PHYCONTROL Layer. If you turn off - * CONFIG_PHYCONTROL, you will need to read the PHY status - * registers after this function completes, and update your - * controller manually. */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -380,7 +376,6 @@ int phy_start_aneg(struct phy_device *phydev) err = phydev->drv->config_aneg(phydev); -#ifdef CONFIG_PHYCONTROL if (err < 0) goto out_unlock; @@ -395,14 +390,12 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: -#endif spin_unlock(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); -#ifdef CONFIG_PHYCONTROL static void phy_change(void *data); static void phy_timer(unsigned long data); @@ -868,4 +861,3 @@ static void phy_timer(unsigned long data) mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); } -#endif /* CONFIG_PHYCONTROL */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 33f7bdb5857c..6da1aa0706a1 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -101,7 +101,6 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } -#ifdef CONFIG_PHYCONTROL /* phy_prepare_link: * * description: Tells the PHY infrastructure to handle the @@ -160,8 +159,6 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -#endif /* CONFIG_PHYCONTROL */ - /* phy_attach: * * description: Called by drivers to attach to a particular PHY diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index afb3f186b884..159b56a56ef4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1027,6 +1027,7 @@ static struct ethtool_ops rtl8169_ethtool_ops = { .get_strings = rtl8169_get_strings, .get_stats_count = rtl8169_get_stats_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, @@ -1511,6 +1512,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c new file mode 100644 index 000000000000..12cde0604580 --- /dev/null +++ b/drivers/net/rionet.c @@ -0,0 +1,574 @@ +/* + * rionet - Ethernet driver over RapidIO messaging services + * + * Copyright 2005 MontaVista Software, Inc. + * Matt Porter <mporter@kernel.crashing.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/crc32.h> +#include <linux/ethtool.h> + +#define DRV_NAME "rionet" +#define DRV_VERSION "0.2" +#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" +#define DRV_DESC "Ethernet over RapidIO" + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); + +#define RIONET_DEFAULT_MSGLEVEL \ + (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + +#define RIONET_DOORBELL_JOIN 0x1000 +#define RIONET_DOORBELL_LEAVE 0x1001 + +#define RIONET_MAILBOX 0 + +#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE +#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE + +static LIST_HEAD(rionet_peers); + +struct rionet_private { + struct rio_mport *mport; + struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; + struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; + struct net_device_stats stats; + int rx_slot; + int tx_slot; + int tx_cnt; + int ack_slot; + spinlock_t lock; + spinlock_t tx_lock; + u32 msg_enable; +}; + +struct rionet_peer { + struct list_head node; + struct rio_dev *rdev; + struct resource *res; +}; + +static int rionet_check = 0; +static int rionet_capable = 1; + +/* + * This is a fast lookup table for for translating TX + * Ethernet packets into a destination RIO device. It + * could be made into a hash table to save memory depending + * on system trade-offs. + */ +static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; + +#define is_rionet_capable(pef, src_ops, dst_ops) \ + ((pef & RIO_PEF_INB_MBOX) && \ + (pef & RIO_PEF_INB_DOORBELL) && \ + (src_ops & RIO_SRC_OPS_DOORBELL) && \ + (dst_ops & RIO_DST_OPS_DOORBELL)) +#define dev_rionet_capable(dev) \ + is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops) + +#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) +#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) + +static struct net_device_stats *rionet_stats(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + return &rnet->stats; +} + +static int rionet_rx_clean(struct net_device *ndev) +{ + int i; + int error = 0; + struct rionet_private *rnet = ndev->priv; + void *data; + + i = rnet->rx_slot; + + do { + if (!rnet->rx_skb[i]) + continue; + + if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX))) + break; + + rnet->rx_skb[i]->data = data; + skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); + rnet->rx_skb[i]->dev = ndev; + rnet->rx_skb[i]->protocol = + eth_type_trans(rnet->rx_skb[i], ndev); + error = netif_rx(rnet->rx_skb[i]); + + if (error == NET_RX_DROP) { + rnet->stats.rx_dropped++; + } else if (error == NET_RX_BAD) { + if (netif_msg_rx_err(rnet)) + printk(KERN_WARNING "%s: bad rx packet\n", + DRV_NAME); + rnet->stats.rx_errors++; + } else { + rnet->stats.rx_packets++; + rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; + } + + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); + + return i; +} + +static void rionet_rx_fill(struct net_device *ndev, int end) +{ + int i; + struct rionet_private *rnet = ndev->priv; + + i = rnet->rx_slot; + do { + rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE); + + if (!rnet->rx_skb[i]) + break; + + rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX, + rnet->rx_skb[i]->data); + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end); + + rnet->rx_slot = i; +} + +static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, + struct rio_dev *rdev) +{ + struct rionet_private *rnet = ndev->priv; + + rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); + rnet->tx_skb[rnet->tx_slot] = skb; + + rnet->stats.tx_packets++; + rnet->stats.tx_bytes += skb->len; + + if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) + netif_stop_queue(ndev); + + ++rnet->tx_slot; + rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1); + + if (netif_msg_tx_queued(rnet)) + printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME, + (u32) skb, skb->len); + + return 0; +} + +static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int i; + struct rionet_private *rnet = ndev->priv; + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 destid; + unsigned long flags; + + local_irq_save(flags); + if (!spin_trylock(&rnet->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { + netif_stop_queue(ndev); + spin_unlock_irqrestore(&rnet->tx_lock, flags); + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", + ndev->name); + return NETDEV_TX_BUSY; + } + + if (eth->h_dest[0] & 0x01) { + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) + if (rionet_active[i]) + rionet_queue_tx_msg(skb, ndev, + rionet_active[i]); + } else if (RIONET_MAC_MATCH(eth->h_dest)) { + destid = RIONET_GET_DESTID(eth->h_dest); + if (rionet_active[destid]) + rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); + } + + spin_unlock_irqrestore(&rnet->tx_lock, flags); + + return 0; +} + +static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, + u16 info) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + struct rionet_peer *peer; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", + DRV_NAME, sid, tid, info); + if (info == RIONET_DOORBELL_JOIN) { + if (!rionet_active[sid]) { + list_for_each_entry(peer, &rionet_peers, node) { + if (peer->rdev->destid == sid) + rionet_active[sid] = peer->rdev; + } + rio_mport_send_doorbell(mport, sid, + RIONET_DOORBELL_JOIN); + } + } else if (info == RIONET_DOORBELL_LEAVE) { + rionet_active[sid] = NULL; + } else { + if (netif_msg_intr(rnet)) + printk(KERN_WARNING "%s: unhandled doorbell\n", + DRV_NAME); + } +} + +static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + int n; + struct net_device *ndev = dev_id; + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + spin_lock(&rnet->lock); + if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot) + rionet_rx_fill(ndev, n); + spin_unlock(&rnet->lock); +} + +static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + + spin_lock(&rnet->lock); + + if (netif_msg_intr(rnet)) + printk(KERN_INFO + "%s: outbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + while (rnet->tx_cnt && (rnet->ack_slot != slot)) { + /* dma unmap single */ + dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]); + rnet->tx_skb[rnet->ack_slot] = NULL; + ++rnet->ack_slot; + rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1); + rnet->tx_cnt--; + } + + if (rnet->tx_cnt < RIONET_TX_RING_SIZE) + netif_wake_queue(ndev); + + spin_unlock(&rnet->lock); +} + +static int rionet_open(struct net_device *ndev) +{ + int i, rc = 0; + struct rionet_peer *peer, *tmp; + u32 pwdcsr; + struct rionet_private *rnet = ndev->priv; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: open\n", DRV_NAME); + + if ((rc = rio_request_inb_dbell(rnet->mport, + (void *)ndev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE, + rionet_dbell_event)) < 0) + goto out; + + if ((rc = rio_request_inb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_RX_RING_SIZE, + rionet_inb_msg_event)) < 0) + goto out; + + if ((rc = rio_request_outb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_TX_RING_SIZE, + rionet_outb_msg_event)) < 0) + goto out; + + /* Initialize inbound message ring */ + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + rnet->rx_skb[i] = NULL; + rnet->rx_slot = 0; + rionet_rx_fill(ndev, 0); + + rnet->tx_slot = 0; + rnet->tx_cnt = 0; + rnet->ack_slot = 0; + + netif_carrier_on(ndev); + netif_start_queue(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (!(peer->res = rio_request_outb_dbell(peer->rdev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE))) + { + printk(KERN_ERR "%s: error requesting doorbells\n", + DRV_NAME); + continue; + } + + /* + * If device has initialized inbound doorbells, + * send a join message + */ + rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr); + if (pwdcsr & RIO_DOORBELL_AVAIL) + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); + } + + out: + return rc; +} + +static int rionet_close(struct net_device *ndev) +{ + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_peer *peer, *tmp; + int i; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: close\n", DRV_NAME); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + if (rnet->rx_skb[i]) + kfree_skb(rnet->rx_skb[i]); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (rionet_active[peer->rdev->destid]) { + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); + rionet_active[peer->rdev->destid] = NULL; + } + rio_release_outb_dbell(peer->rdev, peer->res); + } + + rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE); + rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX); + rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX); + + return 0; +} + +static void rionet_remove(struct rio_dev *rdev) +{ + struct net_device *ndev = NULL; + struct rionet_peer *peer, *tmp; + + unregister_netdev(ndev); + kfree(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + list_del(&peer->node); + kfree(peer); + } +} + +static void rionet_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct rionet_private *rnet = ndev->priv; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "n/a"); + strcpy(info->bus_info, rnet->mport->name); +} + +static u32 rionet_get_msglevel(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + + return rnet->msg_enable; +} + +static void rionet_set_msglevel(struct net_device *ndev, u32 value) +{ + struct rionet_private *rnet = ndev->priv; + + rnet->msg_enable = value; +} + +static struct ethtool_ops rionet_ethtool_ops = { + .get_drvinfo = rionet_get_drvinfo, + .get_msglevel = rionet_get_msglevel, + .set_msglevel = rionet_set_msglevel, + .get_link = ethtool_op_get_link, +}; + +static int rionet_setup_netdev(struct rio_mport *mport) +{ + int rc = 0; + struct net_device *ndev = NULL; + struct rionet_private *rnet; + u16 device_id; + + /* Allocate our net_device structure */ + ndev = alloc_etherdev(sizeof(struct rionet_private)); + if (ndev == NULL) { + printk(KERN_INFO "%s: could not allocate ethernet device.\n", + DRV_NAME); + rc = -ENOMEM; + goto out; + } + + /* Set up private area */ + rnet = (struct rionet_private *)ndev->priv; + rnet->mport = mport; + + /* Set the default MAC address */ + device_id = rio_local_get_device_id(mport); + ndev->dev_addr[0] = 0x00; + ndev->dev_addr[1] = 0x01; + ndev->dev_addr[2] = 0x00; + ndev->dev_addr[3] = 0x01; + ndev->dev_addr[4] = device_id >> 8; + ndev->dev_addr[5] = device_id & 0xff; + + /* Fill in the driver function table */ + ndev->open = &rionet_open; + ndev->hard_start_xmit = &rionet_start_xmit; + ndev->stop = &rionet_close; + ndev->get_stats = &rionet_stats; + ndev->mtu = RIO_MAX_MSG_SIZE - 14; + ndev->features = NETIF_F_LLTX; + SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); + + SET_MODULE_OWNER(ndev); + + spin_lock_init(&rnet->lock); + spin_lock_init(&rnet->tx_lock); + + rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; + + rc = register_netdev(ndev); + if (rc != 0) + goto out; + + printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, + DRV_NAME, + DRV_DESC, + DRV_VERSION, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + out: + return rc; +} + +/* + * XXX Make multi-net safe + */ +static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + int rc = -ENODEV; + u32 lpef, lsrc_ops, ldst_ops; + struct rionet_peer *peer; + + /* If local device is not rionet capable, give up quickly */ + if (!rionet_capable) + goto out; + + /* + * First time through, make sure local device is rionet + * capable, setup netdev, and set flags so this is skipped + * on later probes + */ + if (!rionet_check) { + rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef); + rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, + &lsrc_ops); + rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, + &ldst_ops); + if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) { + printk(KERN_ERR + "%s: local device is not network capable\n", + DRV_NAME); + rionet_check = 1; + rionet_capable = 0; + goto out; + } + + rc = rionet_setup_netdev(rdev->net->hport); + rionet_check = 1; + } + + /* + * If the remote device has mailbox/doorbell capabilities, + * add it to the peer list. + */ + if (dev_rionet_capable(rdev)) { + if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) { + rc = -ENOMEM; + goto out; + } + peer->rdev = rdev; + list_add_tail(&peer->node, &rionet_peers); + } + + out: + return rc; +} + +static struct rio_device_id rionet_id_table[] = { + {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)} +}; + +static struct rio_driver rionet_driver = { + .name = "rionet", + .id_table = rionet_id_table, + .probe = rionet_probe, + .remove = rionet_remove, +}; + +static int __init rionet_init(void) +{ + return rio_register_driver(&rionet_driver); +} + +static void __exit rionet_exit(void) +{ + rio_unregister_driver(&rionet_driver); +} + +module_init(rionet_init); +module_exit(rionet_exit); diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 7cefe5507b9e..00179bc3437f 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -814,6 +814,17 @@ typedef struct _XENA_dev_config { u64 rxgxs_ber_0; /* CHANGED */ u64 rxgxs_ber_1; /* CHANGED */ + u64 spi_control; +#define SPI_CONTROL_KEY(key) vBIT(key,0,4) +#define SPI_CONTROL_BYTECNT(cnt) vBIT(cnt,29,3) +#define SPI_CONTROL_CMD(cmd) vBIT(cmd,32,8) +#define SPI_CONTROL_ADDR(addr) vBIT(addr,40,24) +#define SPI_CONTROL_SEL1 BIT(4) +#define SPI_CONTROL_REQ BIT(7) +#define SPI_CONTROL_NACK BIT(5) +#define SPI_CONTROL_DONE BIT(6) + u64 spi_data; +#define SPI_DATA_WRITE(data,len) vBIT(data,0,len) } XENA_dev_config_t; #define XENA_REG_SPACE sizeof(XENA_dev_config_t) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd451e099a4c..d303d162974f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -65,9 +65,11 @@ #include "s2io.h" #include "s2io-regs.h" +#define DRV_VERSION "Version 2.0.9.1" + /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; -static char s2io_driver_version[] = "Version 2.0.8.1"; +static char s2io_driver_version[] = DRV_VERSION; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -307,6 +309,8 @@ static unsigned int indicate_max_pkts; #endif /* Frequency of Rx desc syncs expressed as power of 2 */ static unsigned int rxsync_frequency = 3; +/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ +static unsigned int intr_type = 0; /* * S2IO device table. @@ -1396,8 +1400,13 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->rti_data1_mem); val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) | - RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); + RTI_DATA2_MEM_RX_UFC_B(0x2) ; + if (nic->intr_type == MSI_X) + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ + RTI_DATA2_MEM_RX_UFC_D(0x40)); + else + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ + RTI_DATA2_MEM_RX_UFC_D(0x80)); writeq(val64, &bar0->rti_data2_mem); for (i = 0; i < config->rx_ring_num; i++) { @@ -1507,17 +1516,15 @@ static int init_nic(struct s2io_nic *nic) #define LINK_UP_DOWN_INTERRUPT 1 #define MAC_RMAC_ERR_TIMER 2 -#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) -#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER -#else int s2io_link_fault_indication(nic_t *nic) { + if (nic->intr_type != INTA) + return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; else return MAC_RMAC_ERR_TIMER; } -#endif /** * en_dis_able_nic_intrs - Enable or Disable the interrupts @@ -1941,11 +1948,14 @@ static int start_nic(struct s2io_nic *nic) } /* Enable select interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; - - en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + if (nic->intr_type != INTA) + en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS); + else { + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; + en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + } /* * With some switches, link might be already up at this point. @@ -2633,11 +2643,11 @@ static void tx_intr_handler(fifo_info_t *fifo_data) err = txdlp->Control_1 & TXD_T_CODE; if ((err >> 48) == 0xA) { DBG_PRINT(TX_DBG, "TxD returned due \ - to loss of link\n"); +to loss of link\n"); } else { DBG_PRINT(ERR_DBG, "***TxD error \ - %llx\n", err); +%llx\n", err); } } @@ -2854,6 +2864,9 @@ void s2io_reset(nic_t * sp) /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); + /* Restore the MSIX table entries from local variables */ + restore_xmsi_data(sp); + /* Clear certain PCI/PCI-X fields after reset */ if (sp->device_type == XFRAME_II_DEVICE) { /* Clear parity err detect bit */ @@ -2983,8 +2996,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_FE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (sp->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else /* @@ -3005,8 +3019,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_SE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (sp->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #endif val64 = readq(&bar0->swapper_ctrl); @@ -3028,6 +3043,201 @@ int s2io_set_swapper(nic_t * sp) return SUCCESS; } +int wait_for_msix_trans(nic_t *nic, int i) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int ret = 0, cnt = 0; + + do { + val64 = readq(&bar0->xmsi_access); + if (!(val64 & BIT(15))) + break; + mdelay(1); + cnt++; + } while(cnt < 5); + if (cnt == 5) { + DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); + ret = 1; + } + + return ret; +} + +void restore_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int i; + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + writeq(nic->msix_info[i].addr, &bar0->xmsi_address); + writeq(nic->msix_info[i].data, &bar0->xmsi_data); + val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + } +} + +void store_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64, addr, data; + int i; + + /* Store and display */ + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + val64 = (BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + addr = readq(&bar0->xmsi_address); + data = readq(&bar0->xmsi_data); + if (addr && data) { + nic->msix_info[i].addr = addr; + nic->msix_info[i].data = data; + } + } +} + +int s2io_enable_msi(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u16 msi_ctrl, msg_val; + struct config_param *config = &nic->config; + struct net_device *dev = nic->dev; + u64 val64, tx_mat, rx_mat; + int i, err; + + val64 = readq(&bar0->pic_control); + val64 &= ~BIT(1); + writeq(val64, &bar0->pic_control); + + err = pci_enable_msi(nic->pdev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n", + nic->dev->name); + return err; + } + + /* + * Enable MSI and use MSI-1 in stead of the standard MSI-0 + * for interrupt handling. + */ + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + msg_val ^= 0x1; + pci_write_config_word(nic->pdev, 0x4c, msg_val); + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + + pci_read_config_word(nic->pdev, 0x42, &msi_ctrl); + msi_ctrl |= 0x10; + pci_write_config_word(nic->pdev, 0x42, msi_ctrl); + + /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */ + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; i<config->tx_fifo_num; i++) { + tx_mat |= TX_MAT_SET(i, 1); + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + rx_mat = readq(&bar0->rx_mat); + for (i=0; i<config->rx_ring_num; i++) { + rx_mat |= RX_MAT_SET(i, 1); + } + writeq(rx_mat, &bar0->rx_mat); + + dev->irq = nic->pdev->irq; + return 0; +} + +int s2io_enable_msi_x(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 tx_mat, rx_mat; + u16 msi_control; /* Temp variable */ + int ret, i, j, msix_indx = 1; + + nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), + GFP_KERNEL); + if (nic->entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + return -ENOMEM; + } + memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); + + nic->s2io_entries = + kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), + GFP_KERNEL); + if (nic->s2io_entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + kfree(nic->entries); + return -ENOMEM; + } + memset(nic->s2io_entries, 0, + MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + nic->entries[i].entry = i; + nic->s2io_entries[i].entry = i; + nic->s2io_entries[i].arg = NULL; + nic->s2io_entries[i].in_use = 0; + } + + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i]; + nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + if (!nic->config.bimodal) { + rx_mat = readq(&bar0->rx_mat); + for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { + rx_mat |= RX_MAT_SET(j, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(rx_mat, &bar0->rx_mat); + } else { + tx_mat = readq(&bar0->tx_mat0_n[7]); + for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[7]); + } + + ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); + kfree(nic->entries); + kfree(nic->s2io_entries); + nic->entries = NULL; + nic->s2io_entries = NULL; + return -ENOMEM; + } + + /* + * To enable MSI-X, MSI also needs to be enabled, due to a bug + * in the herc NIC. (Temp change, needs to be removed later) + */ + pci_read_config_word(nic->pdev, 0x42, &msi_control); + msi_control |= 0x1; /* Enable MSI */ + pci_write_config_word(nic->pdev, 0x42, msi_control); + + return 0; +} + /* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* */ @@ -3048,6 +3258,8 @@ int s2io_open(struct net_device *dev) { nic_t *sp = dev->priv; int err = 0; + int i; + u16 msi_control; /* Temp variable */ /* * Make sure you have link off by default every time @@ -3064,13 +3276,55 @@ int s2io_open(struct net_device *dev) goto hw_init_failed; } + /* Store the values of the MSIX table in the nic_t structure */ + store_xmsi_data(sp); + /* After proper initialization of H/W, register ISR */ - err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, - sp->name, dev); - if (err) { - DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", - dev->name); - goto isr_registration_failed; + if (sp->intr_type == MSI) { + err = request_irq((int) sp->pdev->irq, s2io_msi_handle, + SA_SHIRQ, sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI registration \ +failed\n", dev->name); + goto isr_registration_failed; + } + } + if (sp->intr_type == MSI_X) { + for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { + if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) { + sprintf(sp->desc1, "%s:MSI-X-%d-TX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_fifo_handle, 0, sp->desc1, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1, + sp->msix_info[i].addr); + } else { + sprintf(sp->desc2, "%s:MSI-X-%d-RX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_ring_handle, 0, sp->desc2, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2, + sp->msix_info[i].addr); + } + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \ +failed\n", dev->name, i); + DBG_PRINT(ERR_DBG, "Returned: %d\n", err); + goto isr_registration_failed; + } + sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; + } + } + if (sp->intr_type == INTA) { + err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, + sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", + dev->name); + goto isr_registration_failed; + } } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { @@ -3083,11 +3337,37 @@ int s2io_open(struct net_device *dev) return 0; setting_mac_address_failed: - free_irq(sp->pdev->irq, dev); + if (sp->intr_type != MSI_X) + free_irq(sp->pdev->irq, dev); isr_registration_failed: del_timer_sync(&sp->alarm_timer); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_disable_msix(sp->pdev); + + /* Temp */ + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + } + } + else if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); s2io_reset(sp); hw_init_failed: + if (sp->intr_type == MSI_X) { + if (sp->entries) + kfree(sp->entries); + if (sp->s2io_entries) + kfree(sp->s2io_entries); + } return err; } @@ -3107,12 +3387,35 @@ hw_init_failed: int s2io_close(struct net_device *dev) { nic_t *sp = dev->priv; + int i; + u16 msi_control; + flush_scheduled_work(); netif_stop_queue(dev); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); - free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + + pci_disable_msix(sp->pdev); + } + } + else { + free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); + } sp->device_close_flag = TRUE; /* Device is shut down. */ return 0; } @@ -3278,6 +3581,104 @@ s2io_alarm_handle(unsigned long data) mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } +static irqreturn_t +s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + nic_t *sp = dev->priv; + int i; + int ret; + mac_info_t *mac_control; + struct config_param *config; + + atomic_inc(&sp->isr_cnt); + mac_control = &sp->mac_control; + config = &sp->config; + DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__); + + /* If Intr is because of Rx Traffic */ + for (i = 0; i < config->rx_ring_num; i++) + rx_intr_handler(&mac_control->rings[i]); + + /* If Intr is because of Tx Traffic */ + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + + /* + * If the Rx buffer count is below the panic threshold then + * reallocate the buffers from the interrupt handler itself, + * else schedule a tasklet to reallocate the buffers. + */ + for (i = 0; i < config->rx_ring_num; i++) { + int rxb_size = atomic_read(&sp->rx_bufs_left[i]); + int level = rx_buffer_level(sp, rxb_size, i); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in ISR!!\n"); + clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + } + + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + ring_info_t *ring = (ring_info_t *)dev_id; + nic_t *sp = ring->nic; + int rxb_size, level, rng_n; + + atomic_inc(&sp->isr_cnt); + rx_intr_handler(ring); + + rng_n = ring->ring_no; + rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); + level = rx_buffer_level(sp, rxb_size, rng_n); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + int ret; + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "Out of memory in %s", + __FUNCTION__); + clear_bit(0, (&sp->tasklet_status)); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + atomic_dec(&sp->isr_cnt); + + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + fifo_info_t *fifo = (fifo_info_t *)dev_id; + nic_t *sp = fifo->nic; + + atomic_inc(&sp->isr_cnt); + tx_intr_handler(fifo); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + static void s2io_txpic_intr_handle(nic_t *sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; @@ -3778,11 +4179,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, { nic_t *sp = dev->priv; - strncpy(info->driver, s2io_driver_name, sizeof(s2io_driver_name)); - strncpy(info->version, s2io_driver_version, - sizeof(s2io_driver_version)); - strncpy(info->fw_version, "", 32); - strncpy(info->bus_info, pci_name(sp->pdev), 32); + strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); + strncpy(info->version, s2io_driver_version, sizeof(info->version)); + strncpy(info->fw_version, "", sizeof(info->fw_version)); + strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; info->testinfo_len = S2IO_TEST_LEN; @@ -3978,29 +4378,53 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(nic_t * sp, int off, u32 * data) +static int read_eeprom(nic_t * sp, int off, u64 * data) { int ret = -1; u32 exit_cnt = 0; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - *data = I2C_CONTROL_GET_DATA(val64); - ret = 0; - break; + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + *data = I2C_CONTROL_GET_DATA(val64); + ret = 0; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(0x3) | + SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { + *data = readq(&bar0->spi_data); + *data &= 0xffffff; + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } return ret; } @@ -4019,28 +4443,53 @@ static int read_eeprom(nic_t * sp, int off, u32 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) +static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + if (!(val64 & I2C_CONTROL_NACK)) + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - if (!(val64 & I2C_CONTROL_NACK)) + if (sp->device_type == XFRAME_II_DEVICE) { + int write_cnt = (cnt == 8) ? 0 : cnt; + writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data); + + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(write_cnt) | + SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { ret = 0; - break; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } - return ret; } @@ -4060,7 +4509,8 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) static int s2io_ethtool_geeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * data_buf) { - u32 data, i, valid; + u32 i, valid; + u64 data; nic_t *sp = dev->priv; eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -4098,7 +4548,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, u8 * data_buf) { int len = eeprom->len, cnt = 0; - u32 valid = 0, data; + u64 valid = 0, data; nic_t *sp = dev->priv; if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { @@ -4146,7 +4596,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, static int s2io_register_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; - u64 val64 = 0; + u64 val64 = 0, exp_val; int fail = 0; val64 = readq(&bar0->pif_rd_swapper_fb); @@ -4162,7 +4612,11 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } val64 = readq(&bar0->rx_queue_cfg); - if (val64 != 0x0808080808080808ULL) { + if (sp->device_type == XFRAME_II_DEVICE) + exp_val = 0x0404040404040404ULL; + else + exp_val = 0x0808080808080808ULL; + if (val64 != exp_val) { fail = 1; DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n"); } @@ -4190,7 +4644,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } *data = fail; - return 0; + return fail; } /** @@ -4209,58 +4663,83 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) static int s2io_eeprom_test(nic_t * sp, uint64_t * data) { int fail = 0; - u32 ret_data; + u64 ret_data, org_4F0, org_7F0; + u8 saved_4F0 = 0, saved_7F0 = 0; + struct net_device *dev = sp->dev; /* Test Write Error at offset 0 */ - if (!write_eeprom(sp, 0, 0, 3)) - fail = 1; + /* Note that SPI interface allows write access to all areas + * of EEPROM. Hence doing all negative testing only for Xframe I. + */ + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0, 0, 3)) + fail = 1; + + /* Save current values at offsets 0x4F0 and 0x7F0 */ + if (!read_eeprom(sp, 0x4F0, &org_4F0)) + saved_4F0 = 1; + if (!read_eeprom(sp, 0x7F0, &org_7F0)) + saved_7F0 = 1; /* Test Write at offset 4f0 */ - if (write_eeprom(sp, 0x4F0, 0x01234567, 3)) + if (write_eeprom(sp, 0x4F0, 0x012345, 3)) fail = 1; if (read_eeprom(sp, 0x4F0, &ret_data)) fail = 1; - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x4F0, 0xFFFFFF, 3); /* Test Write Request Error at offset 0x7c */ - if (!write_eeprom(sp, 0x07C, 0, 3)) - fail = 1; + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0x07C, 0, 3)) + fail = 1; - /* Test Write Request at offset 0x7fc */ - if (write_eeprom(sp, 0x7FC, 0x01234567, 3)) + /* Test Write Request at offset 0x7f0 */ + if (write_eeprom(sp, 0x7F0, 0x012345, 3)) fail = 1; - if (read_eeprom(sp, 0x7FC, &ret_data)) + if (read_eeprom(sp, 0x7F0, &ret_data)) fail = 1; - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x7F0, 0xFFFFFF, 3); - /* Test Write Error at offset 0x80 */ - if (!write_eeprom(sp, 0x080, 0, 3)) - fail = 1; + if (sp->device_type == XFRAME_I_DEVICE) { + /* Test Write Error at offset 0x80 */ + if (!write_eeprom(sp, 0x080, 0, 3)) + fail = 1; - /* Test Write Error at offset 0xfc */ - if (!write_eeprom(sp, 0x0FC, 0, 3)) - fail = 1; + /* Test Write Error at offset 0xfc */ + if (!write_eeprom(sp, 0x0FC, 0, 3)) + fail = 1; - /* Test Write Error at offset 0x100 */ - if (!write_eeprom(sp, 0x100, 0, 3)) - fail = 1; + /* Test Write Error at offset 0x100 */ + if (!write_eeprom(sp, 0x100, 0, 3)) + fail = 1; - /* Test Write Error at offset 4ec */ - if (!write_eeprom(sp, 0x4EC, 0, 3)) - fail = 1; + /* Test Write Error at offset 4ec */ + if (!write_eeprom(sp, 0x4EC, 0, 3)) + fail = 1; + } + + /* Restore values at offsets 0x4F0 and 0x7F0 */ + if (saved_4F0) + write_eeprom(sp, 0x4F0, org_4F0, 3); + if (saved_7F0) + write_eeprom(sp, 0x7F0, org_7F0, 3); *data = fail; - return 0; + return fail; } /** @@ -4342,7 +4821,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; - int cnt, iteration = 0, test_pass = 0; + int cnt, iteration = 0, test_fail = 0; val64 = readq(&bar0->adapter_control); val64 &= ~ADAPTER_ECC_EN; @@ -4350,7 +4829,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) val64 = readq(&bar0->mc_rldram_test_ctrl); val64 |= MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); val64 = readq(&bar0->mc_rldram_mrs); val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE; @@ -4378,17 +4857,12 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) } writeq(val64, &bar0->mc_rldram_test_d2); - val64 = (u64) (0x0000003fffff0000ULL); + val64 = (u64) (0x0000003ffffe0100ULL); writeq(val64, &bar0->mc_rldram_test_add); - - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= - MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | - MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | + MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4400,11 +4874,8 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) if (cnt == 5) break; - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4417,18 +4888,18 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) break; val64 = readq(&bar0->mc_rldram_test_ctrl); - if (val64 & MC_RLDRAM_TEST_PASS) - test_pass = 1; + if (!(val64 & MC_RLDRAM_TEST_PASS)) + test_fail = 1; iteration++; } - if (!test_pass) - *data = 1; - else - *data = 0; + *data = test_fail; - return 0; + /* Bring the adapter out of test mode */ + SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF); + + return test_fail; } /** @@ -4932,7 +5403,7 @@ static void s2io_card_down(nic_t * sp) static int s2io_card_up(nic_t * sp) { - int i, ret; + int i, ret = 0; mac_info_t *mac_control; struct config_param *config; struct net_device *dev = (struct net_device *) sp->dev; @@ -4944,6 +5415,15 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } + if (sp->intr_type == MSI) + ret = s2io_enable_msi(sp); + else if (sp->intr_type == MSI_X) + ret = s2io_enable_msi_x(sp); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); + sp->intr_type = INTA; + } + /* * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks @@ -5228,6 +5708,8 @@ static void s2io_init_pci(nic_t * sp) MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>"); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + module_param(tx_fifo_num, int, 0); module_param(rx_ring_num, int, 0); module_param_array(tx_fifo_len, uint, NULL, 0); @@ -5245,6 +5727,7 @@ module_param(bimodal, bool, 0); module_param(indicate_max_pkts, int, 0); #endif module_param(rxsync_frequency, int, 0); +module_param(intr_type, int, 0); /** * s2io_init_nic - Initialization of the adapter . @@ -5274,9 +5757,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mac_info_t *mac_control; struct config_param *config; int mode; + u8 dev_intr_type = intr_type; #ifdef CONFIG_S2IO_NAPI - DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); + if (dev_intr_type != INTA) { + DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \ +is enabled. Defaulting to INTA\n"); + dev_intr_type = INTA; + } + else + DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); #endif if ((ret = pci_enable_device(pdev))) { @@ -5303,10 +5793,35 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } - if (pci_request_regions(pdev, s2io_driver_name)) { - DBG_PRINT(ERR_DBG, "Request Regions failed\n"), - pci_disable_device(pdev); - return -ENODEV; + if ((dev_intr_type == MSI_X) && + ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && + (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { + DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \ +Defaulting to INTA\n"); + dev_intr_type = INTA; + } + if (dev_intr_type != MSI_X) { + if (pci_request_regions(pdev, s2io_driver_name)) { + DBG_PRINT(ERR_DBG, "Request Regions failed\n"), + pci_disable_device(pdev); + return -ENODEV; + } + } + else { + if (!(request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n"); + pci_disable_device(pdev); + return -ENODEV; + } + if (!(request_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n"); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + pci_disable_device(pdev); + return -ENODEV; + } } dev = alloc_etherdev(sizeof(nic_t)); @@ -5329,6 +5844,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->pdev = pdev; sp->high_dma_flag = dma_flag; sp->device_enabled_once = FALSE; + sp->intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || (pdev->device == PCI_DEVICE_ID_HERC_UNI)) @@ -5336,6 +5852,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) else sp->device_type = XFRAME_I_DEVICE; + /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -5571,12 +6088,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -5595,12 +6123,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } else { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", sp->def_mac_addr[0].mac_addr[0], @@ -5644,7 +6183,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mem_alloc_failed: free_shared_mem(sp); pci_disable_device(pdev); - pci_release_regions(pdev); + if (dev_intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); @@ -5678,7 +6224,14 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) iounmap(sp->bar0); iounmap(sp->bar1); pci_disable_device(pdev); - pci_release_regions(pdev); + if (sp->intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 89151cb52181..1cc24b56760e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -652,6 +652,30 @@ typedef struct { #define SMALL_BLK_CNT 30 #define LARGE_BLK_CNT 100 +/* + * Structure to keep track of the MSI-X vectors and the corresponding + * argument registered against each vector + */ +#define MAX_REQUESTED_MSI_X 17 +struct s2io_msix_entry +{ + u16 vector; + u16 entry; + void *arg; + + u8 type; +#define MSIX_FIFO_TYPE 1 +#define MSIX_RING_TYPE 2 + + u8 in_use; +#define MSIX_REGISTERED_SUCCESS 0xAA +}; + +struct msix_info_st { + u64 addr; + u64 data; +}; + /* Structure representing one instance of the NIC */ struct s2io_nic { #ifdef CONFIG_S2IO_NAPI @@ -719,13 +743,8 @@ struct s2io_nic { * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. */ -#ifdef INIT_TQUEUE - struct tq_struct rst_timer_task; - struct tq_struct set_link_task; -#else struct work_struct rst_timer_task; struct work_struct set_link_task; -#endif /* Flag that can be used to turn on or turn off the Rx checksum * offload feature. @@ -748,10 +767,23 @@ struct s2io_nic { atomic_t card_state; volatile unsigned long link_state; struct vlan_group *vlgrp; +#define MSIX_FLG 0xA5 + struct msix_entry *entries; + struct s2io_msix_entry *s2io_entries; + char desc1[35]; + char desc2[35]; + + struct msix_info_st msix_info[0x3f]; + #define XFRAME_I_DEVICE 1 #define XFRAME_II_DEVICE 2 u8 device_type; +#define INTA 0 +#define MSI 1 +#define MSI_X 2 + u8 intr_type; + spinlock_t rx_lock; atomic_t isr_cnt; }; @@ -886,6 +918,13 @@ static int s2io_poll(struct net_device *dev, int *budget); static void s2io_init_pci(nic_t * sp); int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); +static int s2io_enable_msi(nic_t *nic); +static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs); +int s2io_enable_msi_x(nic_t *nic); static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; @@ -894,4 +933,5 @@ int s2io_set_swapper(nic_t * sp); static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); int get_xena_rev_id(struct pci_dev *pdev); +void restore_xmsi_data(nic_t *nic); #endif /* _S2IO_H */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7abd55a4fb21..aa4ca1821759 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -118,8 +118,6 @@ MODULE_PARM_DESC(int_timeout, "Timeout value"); ********************************************************************* */ -typedef unsigned long sbmac_port_t; - typedef enum { sbmac_speed_auto, sbmac_speed_10, sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; @@ -129,7 +127,7 @@ typedef enum { sbmac_duplex_auto, sbmac_duplex_half, typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; -typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, +typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, sbmac_state_broken } sbmac_state_t; @@ -144,17 +142,13 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) -#define SBMAC_READCSR(t) __raw_readq((unsigned long)t) -#define SBMAC_WRITECSR(t,v) __raw_writeq(v, (unsigned long)t) - - #define SBMAC_MAX_TXDESCR 32 #define SBMAC_MAX_RXDESCR 32 #define ETHER_ALIGN 2 #define ETHER_ADDR_LEN 6 -#define ENET_PACKET_SIZE 1518 -/*#define ENET_PACKET_SIZE 9216 */ +#define ENET_PACKET_SIZE 1518 +/*#define ENET_PACKET_SIZE 9216 */ /********************************************************************** * DMA Descriptor structure @@ -172,12 +166,12 @@ typedef unsigned long paddr_t; ********************************************************************* */ typedef struct sbmacdma_s { - - /* + + /* * This stuff is used to identify the channel and the registers * associated with it. */ - + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ int sbdma_channel; /* channel number */ int sbdma_txdir; /* direction (1=transmit) */ @@ -187,21 +181,21 @@ typedef struct sbmacdma_s { int sbdma_int_timeout; /* # usec rx/tx interrupt */ #endif - sbmac_port_t sbdma_config0; /* DMA config register 0 */ - sbmac_port_t sbdma_config1; /* DMA config register 1 */ - sbmac_port_t sbdma_dscrbase; /* Descriptor base address */ - sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */ - sbmac_port_t sbdma_curdscr; /* current descriptor address */ - + volatile void __iomem *sbdma_config0; /* DMA config register 0 */ + volatile void __iomem *sbdma_config1; /* DMA config register 1 */ + volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ + volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ + volatile void __iomem *sbdma_curdscr; /* current descriptor address */ + /* * This stuff is for maintenance of the ring */ - + sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ - + struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ - + paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ @@ -213,15 +207,15 @@ typedef struct sbmacdma_s { ********************************************************************* */ struct sbmac_softc { - + /* * Linux-specific things */ - + struct net_device *sbm_dev; /* pointer to linux device */ spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ - struct net_device_stats sbm_stats; + struct net_device_stats sbm_stats; int sbm_devflags; /* current device flags */ int sbm_phy_oldbmsr; @@ -229,31 +223,31 @@ struct sbmac_softc { int sbm_phy_oldk1stsr; int sbm_phy_oldlinkstat; int sbm_buffersize; - + unsigned char sbm_phys[2]; - + /* * Controller-specific things */ - - unsigned long sbm_base; /* MAC's base address */ + + volatile void __iomem *sbm_base; /* MAC's base address */ sbmac_state_t sbm_state; /* current state */ - - sbmac_port_t sbm_macenable; /* MAC Enable Register */ - sbmac_port_t sbm_maccfg; /* MAC Configuration Register */ - sbmac_port_t sbm_fifocfg; /* FIFO configuration register */ - sbmac_port_t sbm_framecfg; /* Frame configuration register */ - sbmac_port_t sbm_rxfilter; /* receive filter register */ - sbmac_port_t sbm_isr; /* Interrupt status register */ - sbmac_port_t sbm_imr; /* Interrupt mask register */ - sbmac_port_t sbm_mdio; /* MDIO register */ - + + volatile void __iomem *sbm_macenable; /* MAC Enable Register */ + volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ + volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ + volatile void __iomem *sbm_framecfg; /* Frame configuration register */ + volatile void __iomem *sbm_rxfilter; /* receive filter register */ + volatile void __iomem *sbm_isr; /* Interrupt status register */ + volatile void __iomem *sbm_imr; /* Interrupt mask register */ + volatile void __iomem *sbm_mdio; /* MDIO register */ + sbmac_speed_t sbm_speed; /* current speed */ sbmac_duplex_t sbm_duplex; /* current duplex */ sbmac_fc_t sbm_fc; /* current flow control setting */ - + unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - + sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ sbmacdma_t sbm_rxdma; int rx_hw_checksum; @@ -302,6 +296,7 @@ static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); +static int sbmac_mii_probe(struct net_device *dev); static void sbmac_mii_sync(struct sbmac_softc *s); static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); @@ -439,6 +434,9 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; #define MII_BMCR 0x00 /* Basic mode control register (rw) */ #define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define MII_PHYIDR1 0x02 +#define MII_PHYIDR2 0x03 + #define MII_K1STSR 0x0A /* 1K Status Register (ro) */ #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ @@ -450,13 +448,13 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; /********************************************************************** * SBMAC_MII_SYNC(s) - * + * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -467,25 +465,25 @@ static void sbmac_mii_sync(struct sbmac_softc *s) uint64_t bits; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - + + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + for (cnt = 0; cnt < 32; cnt++) { - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); } } /********************************************************************** * SBMAC_MII_SENDDATA(s,data,bitcnt) - * + * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * data - data to send * bitcnt - number of bits to send @@ -498,20 +496,20 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc unsigned int curmask; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + bits = M_MAC_MDIO_DIR_OUTPUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + curmask = 1 << (bitcnt - 1); - + for (i = 0; i < bitcnt; i++) { if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); curmask >>= 1; } } @@ -520,14 +518,14 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc /********************************************************************** * SBMAC_MII_READ(s,phyaddr,regidx) - * + * * Read a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY's address * regidx = index of register to read - * + * * Return value: * value read, or 0 if an error occurred. ********************************************************************* */ @@ -543,9 +541,9 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ - + sbmac_mii_sync(s); - + /* * Send the data to the PHY. The sequence is * a "start" command (2 bits) @@ -553,59 +551,55 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * the PHY addr (5 bits) * the register index (5 bits) */ - + sbmac_mii_senddata(s,MII_COMMAND_START, 2); sbmac_mii_senddata(s,MII_COMMAND_READ, 2); sbmac_mii_senddata(s,phyaddr, 5); sbmac_mii_senddata(s,regidx, 5); - - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - - /* + + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + + /* * Switch the port around without a clock transition. */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + /* * Send out a clock pulse to signal we want the status */ - - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - - /* + + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + + /* * If an error occurred, the PHY will signal '1' back */ - error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN; - - /* + error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; + + /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + regval = 0; - + for (idx = 0; idx < 16; idx++) { regval <<= 1; - + if (error == 0) { - if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) + if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + + __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); } - + /* Switch back to output */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + if (error == 0) return regval; return 0; @@ -614,15 +608,15 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) /********************************************************************** * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) - * + * * Write a value to a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY to use * regidx - register within the PHY * regval - data to write to register - * + * * Return value: * nothing ********************************************************************* */ @@ -633,7 +627,7 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, int mac_mdio_genc; sbmac_mii_sync(s); - + sbmac_mii_senddata(s,MII_COMMAND_START,2); sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); sbmac_mii_senddata(s,phyaddr, 5); @@ -641,27 +635,27 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, sbmac_mii_senddata(s,MII_COMMAND_ACK,2); sbmac_mii_senddata(s,regval,16); - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); } /********************************************************************** * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) - * + * * Initialize a DMA channel context. Since there are potentially * eight DMA channels per MAC, it's nice to do this in a standard - * way. - * - * Input parameters: + * way. + * + * Input parameters: * d - sbmacdma_t structure (DMA channel context) * s - sbmac_softc structure (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors - * + * * Return value: * nothing ********************************************************************* */ @@ -672,101 +666,87 @@ static void sbdma_initctx(sbmacdma_t *d, int txrx, int maxdescr) { - /* - * Save away interesting stuff in the structure + /* + * Save away interesting stuff in the structure */ - + d->sbdma_eth = s; d->sbdma_channel = chan; d->sbdma_txdir = txrx; - + #if 0 /* RMON clearing */ s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0); - - /* - * initialize register pointers - */ - - d->sbdma_config0 = + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); + + /* + * initialize register pointers + */ + + d->sbdma_config0 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0); - d->sbdma_config1 = + d->sbdma_config1 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1); - d->sbdma_dscrbase = + d->sbdma_dscrbase = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE); - d->sbdma_dscrcnt = + d->sbdma_dscrcnt = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); - d->sbdma_curdscr = + d->sbdma_curdscr = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); - + /* * Allocate memory for the ring */ - + d->sbdma_maxdescr = maxdescr; - - d->sbdma_dscrtable = (sbdmadscr_t *) - kmalloc(d->sbdma_maxdescr*sizeof(sbdmadscr_t), GFP_KERNEL); - + + d->sbdma_dscrtable = (sbdmadscr_t *) + kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); + + /* + * The descriptor table must be aligned to at least 16 bytes or the + * MAC will corrupt it. + */ + d->sbdma_dscrtable = (sbdmadscr_t *) + ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); + memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); - + d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; - + d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable); - + /* * And context table */ - - d->sbdma_ctxtable = (struct sk_buff **) + + d->sbdma_ctxtable = (struct sk_buff **) kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL); - + memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); - + #ifdef CONFIG_SBMAC_COALESCE /* * Setup Rx/Tx DMA coalescing defaults @@ -777,7 +757,7 @@ static void sbdma_initctx(sbmacdma_t *d, } else { d->sbdma_int_pktcnt = 1; } - + if ( int_timeout ) { d->sbdma_int_timeout = int_timeout; } else { @@ -789,13 +769,13 @@ static void sbdma_initctx(sbmacdma_t *d, /********************************************************************** * SBDMA_CHANNEL_START(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd * rxtx - DMA_RX or DMA_TX depending on what type of channel - * + * * Return value: * nothing ********************************************************************* */ @@ -805,24 +785,21 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /* * Turn on the DMA channel */ - + #ifdef CONFIG_SBMAC_COALESCE - SBMAC_WRITECSR(d->sbdma_config1, - V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | - 0); - SBMAC_WRITECSR(d->sbdma_config0, - M_DMA_EOP_INT_EN | + __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | + 0, d->sbdma_config1); + __raw_writeq(M_DMA_EOP_INT_EN | V_DMA_RINGSZ(d->sbdma_maxdescr) | V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) | - 0); + 0, d->sbdma_config0); #else - SBMAC_WRITECSR(d->sbdma_config1,0); - SBMAC_WRITECSR(d->sbdma_config0, - V_DMA_RINGSZ(d->sbdma_maxdescr) | - 0); + __raw_writeq(0, d->sbdma_config1); + __raw_writeq(V_DMA_RINGSZ(d->sbdma_maxdescr) | + 0, d->sbdma_config0); #endif - SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys); + __raw_writeq(d->sbdma_dscrtable_phys, d->sbdma_dscrbase); /* * Initialize ring pointers @@ -834,12 +811,12 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /********************************************************************** * SBDMA_CHANNEL_STOP(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd - * + * * Return value: * nothing ********************************************************************* */ @@ -849,44 +826,44 @@ static void sbdma_channel_stop(sbmacdma_t *d) /* * Turn off the DMA channel */ - - SBMAC_WRITECSR(d->sbdma_config1,0); - - SBMAC_WRITECSR(d->sbdma_dscrbase,0); - - SBMAC_WRITECSR(d->sbdma_config0,0); - + + __raw_writeq(0, d->sbdma_config1); + + __raw_writeq(0, d->sbdma_dscrbase); + + __raw_writeq(0, d->sbdma_config0); + /* * Zero ring pointers */ - - d->sbdma_addptr = 0; - d->sbdma_remptr = 0; + + d->sbdma_addptr = NULL; + d->sbdma_remptr = NULL; } static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) { unsigned long addr; unsigned long newaddr; - + addr = (unsigned long) skb->data; - + newaddr = (addr + power2 - 1) & ~(power2 - 1); - + skb_reserve(skb,newaddr-addr+offset); } /********************************************************************** * SBDMA_ADD_RCVBUFFER(d,sb) - * + * * Add a buffer to the specified DMA channel. For receive channels, * this queues a buffer for inbound packets. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add, or NULL if we should allocate one - * + * * Return value: * 0 if buffer could not be added (ring is full) * 1 if buffer added successfully @@ -899,24 +876,24 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) sbdmadscr_t *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - /* - * Allocate a sk_buff if we don't already have one. + /* + * Allocate a sk_buff if we don't already have one. * If we do have an sk_buff, reset it so that it's empty. * * Note: sk_buffs don't seem to be guaranteed to have any sort @@ -925,7 +902,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * * 1. the data does not start in the middle of a cache line. * 2. The data does not end in the middle of a cache line - * 3. The buffer can be aligned such that the IP addresses are + * 3. The buffer can be aligned such that the IP addresses are * naturally aligned. * * Remember, the SOCs MAC writes whole cache lines at a time, @@ -933,7 +910,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * data portion starts in the middle of a cache line, the SOC * DMA will trash the beginning (and ending) portions. */ - + if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { @@ -949,23 +926,22 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) } else { sb_new = sb; - /* + /* * nothing special to reinit buffer, it's already aligned * and sb->data already points to a good place. */ } - + /* - * fill in the descriptor + * fill in the descriptor */ - + #ifdef CONFIG_SBMAC_COALESCE /* * Do not interrupt per DMA transfer. */ dsc->dscr_a = virt_to_phys(sb_new->data) | - V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | - 0; + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; #else dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | @@ -974,38 +950,38 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) /* receiving: no options */ dsc->dscr_b = 0; - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); - + + __raw_writeq(1, d->sbdma_dscrcnt); + return 0; /* we did it */ } /********************************************************************** * SBDMA_ADD_TXBUFFER(d,sb) - * + * * Add a transmit buffer to the specified DMA channel, causing a * transmit to start. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add - * + * * Return value: * 0 transmit queued successfully * otherwise error code @@ -1019,70 +995,70 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) uint64_t phys; uint64_t ncb; int length; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - + /* * Under Linux, it's not necessary to copy/coalesce buffers * like it is on NetBSD. We think they're all contiguous, * but that may not be true for GBE. */ - + length = sb->len; - + /* * fill in the descriptor. Note that the number of cache * blocks in the descriptor is the number of blocks * *spanned*, so we need to add in the offset (if any) * while doing the calculation. */ - + phys = virt_to_phys(sb->data); ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1))); - dsc->dscr_a = phys | + dsc->dscr_a = phys | V_DMA_DSCRA_A_SIZE(ncb) | #ifndef CONFIG_SBMAC_COALESCE M_DMA_DSCRA_INTERRUPT | #endif M_DMA_ETHTX_SOP; - + /* transmitting: set outbound options and length */ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | V_DMA_DSCRB_PKT_SIZE(length); - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); - + + __raw_writeq(1, d->sbdma_dscrcnt); + return 0; /* we did it */ } @@ -1091,12 +1067,12 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) /********************************************************************** * SBDMA_EMPTYRING(d) - * + * * Free all allocated sk_buffs on the specified DMA channel; - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1105,7 +1081,7 @@ static void sbdma_emptyring(sbmacdma_t *d) { int idx; struct sk_buff *sb; - + for (idx = 0; idx < d->sbdma_maxdescr; idx++) { sb = d->sbdma_ctxtable[idx]; if (sb) { @@ -1118,13 +1094,13 @@ static void sbdma_emptyring(sbmacdma_t *d) /********************************************************************** * SBDMA_FILLRING(d) - * + * * Fill the specified DMA channel (must be receive channel) * with sk_buffs - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1132,7 +1108,7 @@ static void sbdma_emptyring(sbmacdma_t *d) static void sbdma_fillring(sbmacdma_t *d) { int idx; - + for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { if (sbdma_add_rcvbuffer(d,NULL) != 0) break; @@ -1142,16 +1118,16 @@ static void sbdma_fillring(sbmacdma_t *d) /********************************************************************** * SBDMA_RX_PROCESS(sc,d) - * - * Process "completed" receive buffers on the specified DMA channel. + * + * Process "completed" receive buffers on the specified DMA channel. * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. + * it processes all of the packets on a given channel before + * returning. * - * Input parameters: + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1163,56 +1139,56 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sbdmadscr_t *dsc; struct sk_buff *sb; int len; - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - + /* * If they're the same, that means we've processed all * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4; - + /* * Check packet status. If good, process it. * If not, silently drop it and put it back on the * receive ring. */ - + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { - + /* * Add a new buffer to replace the old one. If we fail * to allocate a buffer, we're going to drop this * packet and put it right back on the receive ring. */ - + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { sc->sbm_stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ @@ -1221,7 +1197,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) * Set length into the packet */ skb_put(sb,len); - + /* * Buffer has been replaced on the * receive ring. Pass the buffer to @@ -1240,7 +1216,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sb->ip_summed = CHECKSUM_NONE; } } - + netif_rx(sb); } } else { @@ -1251,14 +1227,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sc->sbm_stats.rx_errors++; sbdma_add_rcvbuffer(d,sb); } - - - /* + + + /* * .. and advance to the next buffer. */ - + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } } @@ -1266,17 +1242,17 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) /********************************************************************** * SBDMA_TX_PROCESS(sc,d) - * - * Process "completed" transmit buffers on the specified DMA channel. + * + * Process "completed" transmit buffers on the specified DMA channel. * This is normally called within the interrupt service routine. * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. + * it processes all of the packets on a given channel before + * returning. * - * Input parameters: + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1290,21 +1266,21 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) unsigned long flags; spin_lock_irqsave(&(sc->sbm_lock), flags); - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); /* @@ -1312,75 +1288,75 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + /* * Stats */ - + sc->sbm_stats.tx_bytes += sb->len; sc->sbm_stats.tx_packets++; - + /* * for transmits, we just free buffers. */ - + dev_kfree_skb_irq(sb); - - /* + + /* * .. and advance to the next buffer. */ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } - + /* * Decide if we should wake up the protocol or not. * Other drivers seem to do this when we reach a low * watermark on the transmit queue. */ - + netif_wake_queue(d->sbdma_eth->sbm_dev); - + spin_unlock_irqrestore(&(sc->sbm_lock), flags); - + } /********************************************************************** * SBMAC_INITCTX(s) - * + * * Initialize an Ethernet context structure - this is called * once per MAC on the 1250. Memory is allocated here, so don't * call it again from inside the ioctl routines that bring the * interface up/down - * - * Input parameters: + * + * Input parameters: * s - sbmac context structure - * + * * Return value: * 0 ********************************************************************* */ static int sbmac_initctx(struct sbmac_softc *s) { - - /* - * figure out the addresses of some ports + + /* + * figure out the addresses of some ports */ - + s->sbm_macenable = s->sbm_base + R_MAC_ENABLE; s->sbm_maccfg = s->sbm_base + R_MAC_CFG; s->sbm_fifocfg = s->sbm_base + R_MAC_THRSH_CFG; @@ -1397,29 +1373,29 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_phy_oldanlpar = 0; s->sbm_phy_oldk1stsr = 0; s->sbm_phy_oldlinkstat = 0; - + /* * Initialize the DMA channels. Right now, only one per MAC is used * Note: Only do this _once_, as it allocates memory from the kernel! */ - + sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR); sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR); - + /* * initial state is OFF */ - + s->sbm_state = sbmac_state_off; - + /* * Initial speed is (XXX TEMP) 10MBit/s HDX no FC */ - + s->sbm_speed = sbmac_speed_10; s->sbm_duplex = sbmac_duplex_half; s->sbm_fc = sbmac_fc_disabled; - + return 0; } @@ -1430,7 +1406,7 @@ static void sbdma_uninitctx(struct sbmacdma_s *d) kfree(d->sbdma_dscrtable); d->sbdma_dscrtable = NULL; } - + if (d->sbdma_ctxtable) { kfree(d->sbdma_ctxtable); d->sbdma_ctxtable = NULL; @@ -1447,12 +1423,12 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) /********************************************************************** * SBMAC_CHANNEL_START(s) - * + * * Start packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1460,49 +1436,49 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) static void sbmac_channel_start(struct sbmac_softc *s) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; - + /* * Don't do this if running */ if (s->sbm_state == sbmac_state_on) return; - + /* * Bring the controller out of reset, but leave it off. */ - - SBMAC_WRITECSR(s->sbm_macenable,0); - + + __raw_writeq(0, s->sbm_macenable); + /* * Ignore all received packets */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - - /* + + __raw_writeq(0, s->sbm_rxfilter); + + /* * Calculate values for various control registers. */ - + cfg = M_MAC_RETRY_EN | - M_MAC_TX_HOLD_SOP_EN | + M_MAC_TX_HOLD_SOP_EN | V_MAC_TX_PAUSE_CNT_16K | M_MAC_AP_STAT_EN | M_MAC_FAST_SYNC | M_MAC_SS_EN | 0; - - /* + + /* * Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above * Use a larger RD_THRSH for gigabit */ - if (periph_rev >= 2) + if (periph_rev >= 2) th_value = 64; - else + else th_value = 28; fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ @@ -1520,51 +1496,51 @@ static void sbmac_channel_start(struct sbmac_softc *s) V_MAC_BACKOFF_SEL(1); /* - * Clear out the hash address map + * Clear out the hash address map */ - + port = s->sbm_base + R_MAC_HASH_BASE; for (idx = 0; idx < MAC_HASH_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the exact-match table */ - + port = s->sbm_base + R_MAC_ADDR_BASE; for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the DMA Channel mapping table registers */ - + port = s->sbm_base + R_MAC_CHUP0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } port = s->sbm_base + R_MAC_CHLO0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Program the hardware address. It goes into the hardware-address * register as well as the first filter register. */ - + reg = sbmac_addr2reg(s->sbm_hwaddr); - + port = s->sbm_base + R_MAC_ADDR_BASE; - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); port = s->sbm_base + R_MAC_ETHERNET_ADDR; #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS @@ -1573,108 +1549,105 @@ static void sbmac_channel_start(struct sbmac_softc *s) * destination address in the R_MAC_ETHERNET_ADDR register. * Set the value to zero. */ - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); #else - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); #endif - + /* * Set the receive filter for no packets, and write values * to the various config registers */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_fifocfg,fifo); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(fifo, s->sbm_fifocfg); + __raw_writeq(cfg, s->sbm_maccfg); + /* * Initialize DMA channels (rings should be ok now) */ - + sbdma_channel_start(&(s->sbm_rxdma), DMA_RX); sbdma_channel_start(&(s->sbm_txdma), DMA_TX); - + /* * Configure the speed, duplex, and flow control */ sbmac_set_speed(s,s->sbm_speed); sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc); - + /* * Fill the receive ring */ - + sbdma_fillring(&(s->sbm_rxdma)); - - /* + + /* * Turn on the rest of the bits in the enable register - */ - - SBMAC_WRITECSR(s->sbm_macenable, - M_MAC_RXDMA_EN0 | + */ + + __raw_writeq(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0 | M_MAC_RX_ENABLE | - M_MAC_TX_ENABLE); - - + M_MAC_TX_ENABLE, s->sbm_macenable); + + #ifdef CONFIG_SBMAC_COALESCE /* * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0 */ - SBMAC_WRITECSR(s->sbm_imr, - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0)); + __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | + ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); #else /* * Accept any kind of interrupt on TX and RX DMA channel 0 */ - SBMAC_WRITECSR(s->sbm_imr, - (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | - (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)); + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); #endif - - /* - * Enable receiving unicasts and broadcasts + + /* + * Enable receiving unicasts and broadcasts */ - - SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN); - + + __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter); + /* - * we're running now. + * we're running now. */ - + s->sbm_state = sbmac_state_on; - - /* - * Program multicast addresses + + /* + * Program multicast addresses */ - + sbmac_setmulti(s); - - /* - * If channel was in promiscuous mode before, turn that on + + /* + * If channel was in promiscuous mode before, turn that on */ - + if (s->sbm_devflags & IFF_PROMISC) { sbmac_promiscuous_mode(s,1); } - + } /********************************************************************** * SBMAC_CHANNEL_STOP(s) - * + * * Stop packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1682,49 +1655,49 @@ static void sbmac_channel_start(struct sbmac_softc *s) static void sbmac_channel_stop(struct sbmac_softc *s) { /* don't do this if already stopped */ - + if (s->sbm_state == sbmac_state_off) return; - + /* don't accept any packets, disable all interrupts */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); - + + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); + /* Turn off ticker */ - + /* XXX */ - + /* turn off receiver and transmitter */ - - SBMAC_WRITECSR(s->sbm_macenable,0); - + + __raw_writeq(0, s->sbm_macenable); + /* We're stopped now. */ - + s->sbm_state = sbmac_state_off; - + /* * Stop DMA channels (rings should be ok now) */ - + sbdma_channel_stop(&(s->sbm_rxdma)); sbdma_channel_stop(&(s->sbm_txdma)); - + /* Empty the receive and transmit rings */ - + sbdma_emptyring(&(s->sbm_rxdma)); sbdma_emptyring(&(s->sbm_txdma)); - + } /********************************************************************** * SBMAC_SET_CHANNEL_STATE(state) - * + * * Set the channel's state ON or OFF - * - * Input parameters: + * + * Input parameters: * state - new state - * + * * Return value: * old state ********************************************************************* */ @@ -1732,43 +1705,43 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, sbmac_state_t state) { sbmac_state_t oldstate = sc->sbm_state; - + /* * If same as previous state, return */ - + if (state == oldstate) { return oldstate; } - + /* - * If new state is ON, turn channel on + * If new state is ON, turn channel on */ - + if (state == sbmac_state_on) { sbmac_channel_start(sc); } else { sbmac_channel_stop(sc); } - + /* * Return previous state */ - + return oldstate; } /********************************************************************** * SBMAC_PROMISCUOUS_MODE(sc,onoff) - * + * * Turn on or off promiscuous mode - * - * Input parameters: + * + * Input parameters: * sc - softc * onoff - 1 to turn on, 0 to turn off - * + * * Return value: * nothing ********************************************************************* */ @@ -1776,30 +1749,30 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) { uint64_t reg; - + if (sc->sbm_state != sbmac_state_on) return; - + if (onoff) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - } + __raw_writeq(reg, sc->sbm_rxfilter); + } else { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } /********************************************************************** * SBMAC_SETIPHDR_OFFSET(sc,onoff) - * + * * Set the iphdr offset as 15 assuming ethernet encapsulation - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -1807,12 +1780,12 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) { uint64_t reg; - + /* Hard code the off set to 15 for now */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - + __raw_writeq(reg, sc->sbm_rxfilter); + /* read system identification to determine revision */ if (periph_rev >= 2) { sc->rx_hw_checksum = ENABLE; @@ -1824,13 +1797,13 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) /********************************************************************** * SBMAC_ADDR2REG(ptr) - * + * * Convert six bytes into the 64-bit register value that * we typically write into the SBMAC's address/mcast registers - * - * Input parameters: + * + * Input parameters: * ptr - pointer to 6 bytes - * + * * Return value: * register value ********************************************************************* */ @@ -1838,35 +1811,35 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) static uint64_t sbmac_addr2reg(unsigned char *ptr) { uint64_t reg = 0; - + ptr += 6; - - reg |= (uint64_t) *(--ptr); + + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); - + reg |= (uint64_t) *(--ptr); + return reg; } /********************************************************************** * SBMAC_SET_SPEED(s,speed) - * + * * Configure LAN speed for the specified MAC. * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * speed - speed to set MAC to (see sbmac_speed_t enum) - * + * * Return value: * 1 if successful * 0 indicates invalid parameters @@ -1880,31 +1853,31 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) /* * Save new current values */ - + s->sbm_speed = speed; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ /* - * Read current register values + * Read current register values */ - - cfg = SBMAC_READCSR(s->sbm_maccfg); - framecfg = SBMAC_READCSR(s->sbm_framecfg); - + + cfg = __raw_readq(s->sbm_maccfg); + framecfg = __raw_readq(s->sbm_framecfg); + /* * Mask out the stuff we want to change */ - + cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL); framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH | M_MAC_SLOT_SIZE); - + /* * Now add in the new bits */ - + switch (speed) { case sbmac_speed_10: framecfg |= V_MAC_IFG_RX_10 | @@ -1913,7 +1886,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_10; cfg |= V_MAC_SPEED_SEL_10MBPS; break; - + case sbmac_speed_100: framecfg |= V_MAC_IFG_RX_100 | V_MAC_IFG_TX_100 | @@ -1921,7 +1894,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_100; cfg |= V_MAC_SPEED_SEL_100MBPS ; break; - + case sbmac_speed_1000: framecfg |= V_MAC_IFG_RX_1000 | V_MAC_IFG_TX_1000 | @@ -1929,34 +1902,34 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_1000; cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; break; - + case sbmac_speed_auto: /* XXX not implemented */ /* fall through */ default: return 0; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(cfg, s->sbm_maccfg); + return 1; } /********************************************************************** * SBMAC_SET_DUPLEX(s,duplex,fc) - * + * * Set Ethernet duplex and flow control options for this MAC * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * duplex - duplex setting (see sbmac_duplex_t) * fc - flow control setting (see sbmac_fc_t) - * + * * Return value: * 1 if ok * 0 if an invalid parameter combination was specified @@ -1965,67 +1938,67 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) { uint64_t cfg; - + /* * Save new current values */ - + s->sbm_duplex = duplex; s->sbm_fc = fc; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ - + /* - * Read current register values + * Read current register values */ - - cfg = SBMAC_READCSR(s->sbm_maccfg); - + + cfg = __raw_readq(s->sbm_maccfg); + /* * Mask off the stuff we're about to change */ - + cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN); - - + + switch (duplex) { case sbmac_duplex_half: switch (fc) { case sbmac_fc_disabled: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_collision: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_carrier: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; break; - + case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ case sbmac_fc_frame: /* not valid in half duplex */ default: /* invalid selection */ return 0; } break; - + case sbmac_duplex_full: switch (fc) { case sbmac_fc_disabled: cfg |= V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_frame: cfg |= V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_collision: /* not valid in full duplex */ case sbmac_fc_carrier: /* not valid in full duplex */ case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ default: return 0; } @@ -2034,13 +2007,13 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /* XXX not implemented */ break; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(cfg, s->sbm_maccfg); + return 1; } @@ -2049,12 +2022,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /********************************************************************** * SBMAC_INTR() - * + * * Interrupt handler for MAC interrupts - * - * Input parameters: + * + * Input parameters: * MAC structure - * + * * Return value: * nothing ********************************************************************* */ @@ -2066,27 +2039,27 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) int handled = 0; for (;;) { - + /* * Read the ISR (this clears the bits in the real * register, except for counter addr) */ - - isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; - + + isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; + if (isr == 0) break; handled = 1; - + /* * Transmits on channel 0 */ - + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { sbdma_tx_process(sc,&(sc->sbm_txdma)); } - + /* * Receives on channel 0 */ @@ -2106,8 +2079,8 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) * EOP_SEEN here takes care of this case. * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0) */ - - + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { sbdma_rx_process(sc,&(sc->sbm_rxdma)); } @@ -2118,29 +2091,29 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) /********************************************************************** * SBMAC_START_TX(skb,dev) - * - * Start output on the specified interface. Basically, we + * + * Start output on the specified interface. Basically, we * queue as many buffers as we can until the ring fills up, or * we run off the end of the queue, whichever comes first. - * - * Input parameters: - * - * + * + * Input parameters: + * + * * Return value: * nothing ********************************************************************* */ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + /* lock eth irq */ spin_lock_irq (&sc->sbm_lock); - + /* - * Put the buffer on the transmit ring. If we + * Put the buffer on the transmit ring. If we * don't have room, stop the queue. */ - + if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { /* XXX save skb that we could not send */ netif_stop_queue(dev); @@ -2148,24 +2121,24 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) return 1; } - + dev->trans_start = jiffies; - + spin_unlock_irq (&sc->sbm_lock); - + return 0; } /********************************************************************** * SBMAC_SETMULTI(sc) - * + * * Reprogram the multicast table into the hardware, given * the list of multicasts associated with the interface * structure. - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -2173,75 +2146,75 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) static void sbmac_setmulti(struct sbmac_softc *sc) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; - - /* + + /* * Clear out entire multicast table. We do this by nuking * the entire hash table and all the direct matches except - * the first one, which is used for our station address + * the first one, which is used for our station address */ - + for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } - + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } - + /* * Clear the filter to say we don't want any multicasts. */ - - reg = SBMAC_READCSR(sc->sbm_rxfilter); + + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - + __raw_writeq(reg, sc->sbm_rxfilter); + if (dev->flags & IFF_ALLMULTI) { - /* - * Enable ALL multicasts. Do this by inverting the - * multicast enable bit. + /* + * Enable ALL multicasts. Do this by inverting the + * multicast enable bit. */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); return; } - - /* + + /* * Progam new multicast entries. For now, only use the * perfect filter. In the future we'll need to use the * hash filter if the perfect filter overflows */ - + /* XXX only using perfect filter for now, need to use hash * XXX if the table overflows */ - + idx = 1; /* skip station address */ mclist = dev->mc_list; while (mclist && (idx < MAC_ADDR_COUNT)) { reg = sbmac_addr2reg(mclist->dmi_addr); port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t)); - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); idx++; mclist = mclist->next; } - - /* + + /* * Enable the "accept multicast bits" if we programmed at least one - * multicast. + * multicast. */ - + if (idx > 1) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_MCAST_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } @@ -2250,12 +2223,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc) #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) /********************************************************************** * SBMAC_PARSE_XDIGIT(str) - * + * * Parse a hex digit, returning its value - * - * Input parameters: + * + * Input parameters: * str - character - * + * * Return value: * hex value, or -1 if invalid ********************************************************************* */ @@ -2263,7 +2236,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc) static int sbmac_parse_xdigit(char str) { int digit; - + if ((str >= '0') && (str <= '9')) digit = str - '0'; else if ((str >= 'a') && (str <= 'f')) @@ -2272,20 +2245,20 @@ static int sbmac_parse_xdigit(char str) digit = str - 'A' + 10; else return -1; - + return digit; } /********************************************************************** * SBMAC_PARSE_HWADDR(str,hwaddr) - * + * * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte * Ethernet address. - * - * Input parameters: + * + * Input parameters: * str - string * hwaddr - pointer to hardware address - * + * * Return value: * 0 if ok, else -1 ********************************************************************* */ @@ -2294,7 +2267,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) { int digit1,digit2; int idx = 6; - + while (*str && (idx > 0)) { digit1 = sbmac_parse_xdigit(*str); if (digit1 < 0) @@ -2302,7 +2275,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) str++; if (!*str) return -1; - + if ((*str == ':') || (*str == '-')) { digit2 = digit1; digit1 = 0; @@ -2313,10 +2286,10 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) return -1; str++; } - + *hwaddr++ = (digit1 << 4) | digit2; idx--; - + if (*str == '-') str++; if (*str == ':') @@ -2337,12 +2310,12 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) /********************************************************************** * SBMAC_INIT(dev) - * + * * Attach routine - init hardware and hook ourselves into linux - * - * Input parameters: + * + * Input parameters: * dev - net_device structure - * + * * Return value: * status ********************************************************************* */ @@ -2354,53 +2327,53 @@ static int sbmac_init(struct net_device *dev, int idx) uint64_t ea_reg; int i; int err; - + sc = netdev_priv(dev); - + /* Determine controller base address */ - + sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; - + eaddr = sc->sbm_hwaddr; - - /* + + /* * Read the ethernet address. The firwmare left this programmed * for us in the ethernet address register for each mac. */ - - ea_reg = SBMAC_READCSR(sc->sbm_base + R_MAC_ETHERNET_ADDR); - SBMAC_WRITECSR(sc->sbm_base + R_MAC_ETHERNET_ADDR, 0); + + ea_reg = __raw_readq(sc->sbm_base + R_MAC_ETHERNET_ADDR); + __raw_writeq(0, sc->sbm_base + R_MAC_ETHERNET_ADDR); for (i = 0; i < 6; i++) { eaddr[i] = (uint8_t) (ea_reg & 0xFF); ea_reg >>= 8; } - + for (i = 0; i < 6; i++) { dev->dev_addr[i] = eaddr[i]; } - - + + /* - * Init packet size + * Init packet size */ - + sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN; - /* + /* * Initialize context (get pointers to registers and stuff), then * allocate the memory for the descriptor tables. */ - + sbmac_initctx(sc); - + /* * Set up Linux device callins */ - + spin_lock_init(&(sc->sbm_lock)); - + dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2419,7 +2392,7 @@ static int sbmac_init(struct net_device *dev, int idx) if (err) goto out_uninit; - if (periph_rev >= 2) { + if (sc->rx_hw_checksum == ENABLE) { printk(KERN_INFO "%s: enabling TCP rcv checksum\n", sc->sbm_dev->name); } @@ -2430,10 +2403,10 @@ static int sbmac_init(struct net_device *dev, int idx) * was being displayed) */ printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", + "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, dev->base_addr, eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - + return 0; @@ -2447,54 +2420,86 @@ out_uninit: static int sbmac_open(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + if (debug > 1) { printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); } - - /* + + /* * map/route interrupt (clear status first, in case something * weird is pending; we haven't initialized the mac registers * yet) */ - SBMAC_READCSR(sc->sbm_isr); + __raw_readq(sc->sbm_isr); if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) return -EBUSY; /* - * Configure default speed + * Probe phy address + */ + + if(sbmac_mii_probe(dev) == -1) { + printk("%s: failed to probe PHY.\n", dev->name); + return -EINVAL; + } + + /* + * Configure default speed */ sbmac_mii_poll(sc,noisy_mii); - + /* * Turn on the channel */ sbmac_set_channel_state(sc,sbmac_state_on); - + /* * XXX Station address is in dev->dev_addr */ - + if (dev->if_port == 0) - dev->if_port = 0; - + dev->if_port = 0; + netif_start_queue(dev); - + sbmac_set_rx_mode(dev); - + /* Set the timer to check for link beat. */ init_timer(&sc->sbm_timer); sc->sbm_timer.expires = jiffies + 2 * HZ/100; sc->sbm_timer.data = (unsigned long)dev; sc->sbm_timer.function = &sbmac_timer; add_timer(&sc->sbm_timer); - + return 0; } +static int sbmac_mii_probe(struct net_device *dev) +{ + int i; + struct sbmac_softc *s = netdev_priv(dev); + u16 bmsr, id1, id2; + u32 vendor, device; + + for (i=1; i<31; i++) { + bmsr = sbmac_mii_read(s, i, MII_BMSR); + if (bmsr != 0) { + s->sbm_phys[0] = i; + id1 = sbmac_mii_read(s, i, MII_PHYIDR1); + id2 = sbmac_mii_read(s, i, MII_PHYIDR2); + vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f); + device = (id2 >> 4) & 0x3f; + + printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n", + dev->name, i, vendor, device); + return i; + } + } + return -1; +} static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) @@ -2609,20 +2614,20 @@ static void sbmac_timer(unsigned long data) int mii_status; spin_lock_irq (&sc->sbm_lock); - + /* make IFF_RUNNING follow the MII status bit "Link established" */ mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); - + if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; if (mii_status & BMSR_LINKSTAT) { netif_carrier_on(dev); } else { - netif_carrier_off(dev); + netif_carrier_off(dev); } } - + /* * Poll the PHY to see what speed we should be running at */ @@ -2640,9 +2645,9 @@ static void sbmac_timer(unsigned long data) sbmac_channel_start(sc); } } - + spin_unlock_irq (&sc->sbm_lock); - + sc->sbm_timer.expires = jiffies + next_tick; add_timer(&sc->sbm_timer); } @@ -2651,13 +2656,13 @@ static void sbmac_timer(unsigned long data) static void sbmac_tx_timeout (struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + spin_lock_irq (&sc->sbm_lock); - - + + dev->trans_start = jiffies; sc->sbm_stats.tx_errors++; - + spin_unlock_irq (&sc->sbm_lock); printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); @@ -2670,13 +2675,13 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; - + spin_lock_irqsave(&sc->sbm_lock, flags); - + /* XXX update other stats here */ - + spin_unlock_irqrestore(&sc->sbm_lock, flags); - + return &sc->sbm_stats; } @@ -2693,8 +2698,8 @@ static void sbmac_set_rx_mode(struct net_device *dev) /* * Promiscuous changed. */ - - if (dev->flags & IFF_PROMISC) { + + if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ msg_flag = 1; sbmac_promiscuous_mode(sc,1); @@ -2705,18 +2710,18 @@ static void sbmac_set_rx_mode(struct net_device *dev) } } spin_unlock_irqrestore(&sc->sbm_lock, flags); - + if (msg_flag) { printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis"); } - + /* * Program the multicasts. Do this every time. */ - + sbmac_setmulti(sc); - + } static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -2725,10 +2730,10 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) u16 *data = (u16 *)&rq->ifr_ifru; unsigned long flags; int retval; - + spin_lock_irqsave(&sc->sbm_lock, flags); retval = 0; - + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = sc->sbm_phys[0] & 0x1f; @@ -2750,7 +2755,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) default: retval = -EOPNOTSUPP; } - + spin_unlock_irqrestore(&sc->sbm_lock, flags); return retval; } @@ -2781,7 +2786,7 @@ static int sbmac_close(struct net_device *dev) sbdma_emptyring(&(sc->sbm_txdma)); sbdma_emptyring(&(sc->sbm_rxdma)); - + return 0; } @@ -2793,13 +2798,13 @@ sbmac_setup_hwaddr(int chan,char *addr) { uint8_t eaddr[6]; uint64_t val; - sbmac_port_t port; + unsigned long port; port = A_MAC_CHANNEL_BASE(chan); sbmac_parse_hwaddr(addr,eaddr); val = sbmac_addr2reg(eaddr); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),val); - val = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR)); + val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); } #endif @@ -2810,9 +2815,9 @@ sbmac_init_module(void) { int idx; struct net_device *dev; - sbmac_port_t port; + unsigned long port; int chip_max_units; - + /* * For bringup when not using the firmware, we can pre-fill * the MAC addresses using the environment variables @@ -2858,13 +2863,13 @@ sbmac_init_module(void) port = A_MAC_CHANNEL_BASE(idx); - /* + /* * The R_MAC_ETHERNET_ADDR register will be set to some nonzero * value for us by the firmware if we're going to use this MAC. * If we find a zero, skip this MAC. */ - sbmac_orig_hwaddr[idx] = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); if (sbmac_orig_hwaddr[idx] == 0) { printk(KERN_DEBUG "sbmac: not configuring MAC at " "%lx\n", port); @@ -2876,7 +2881,7 @@ sbmac_init_module(void) */ dev = alloc_etherdev(sizeof(struct sbmac_softc)); - if (!dev) + if (!dev) return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); @@ -2886,8 +2891,7 @@ sbmac_init_module(void) dev->mem_end = 0; if (sbmac_init(dev, idx)) { port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR), - sbmac_orig_hwaddr[idx]); + __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR)); free_netdev(dev); continue; } diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 9bc3b1c0dd6a..a4614df38a90 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -32,8 +32,6 @@ #include "sgiseeq.h" -static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n"; - static char *sgiseeqstr = "SGI Seeq8003"; /* @@ -113,9 +111,9 @@ static struct net_device *root_sgiseeq_dev; static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { - hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ; udelay(20); - hregs->rx_reset = 0; + hregs->reset = 0; } static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs, @@ -252,7 +250,6 @@ void sgiseeq_dump_rings(void) #define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF) #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2) -#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ) static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, struct sgiseeq_regs *sregs) @@ -274,8 +271,6 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, sregs->tstat = TSTAT_INIT_SEEQ; } - hregs->rx_dconfig |= RDMACFG_INIT; - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc); hregs->tx_ndptr = CPHYSADDR(sp->tx_desc); @@ -446,7 +441,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs spin_lock(&sp->tx_lock); /* Ack the IRQ and set software state. */ - hregs->rx_reset = HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CLRIRQ; /* Always check for received packets. */ sgiseeq_rx(dev, sp, hregs, sregs); @@ -493,11 +488,13 @@ static int sgiseeq_close(struct net_device *dev) { struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; + unsigned int irq = dev->irq; netif_stop_queue(dev); /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); + free_irq(irq, dev); return 0; } @@ -644,7 +641,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) -static int sgiseeq_init(struct hpc3_regs* regs, int irq) +static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) { struct sgiseeq_init_block *sr; struct sgiseeq_private *sp; @@ -680,8 +677,8 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) gpriv = sp; gdev = dev; #endif - sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0]; - sp->hregs = &hpc3c0->ethregs; + sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0]; + sp->hregs = &hpcregs->ethregs; sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; @@ -698,6 +695,11 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); + /* Setup PIO and DMA transfer timing */ + sp->hregs->pconfig = 0x161; + sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | + HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; + /* Reset the chip. */ hpc3_eth_reset(sp->hregs); @@ -724,7 +726,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) goto err_out_free_page; } - printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); + printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); @@ -734,7 +736,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) return 0; err_out_free_page: - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); err_out_free_dev: kfree(dev); @@ -744,8 +746,6 @@ err_out: static int __init sgiseeq_probe(void) { - printk(version); - /* On board adapter on 1st HPC is always present */ return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); } @@ -754,15 +754,12 @@ static void __exit sgiseeq_exit(void) { struct net_device *next, *dev; struct sgiseeq_private *sp; - int irq; for (dev = root_sgiseeq_dev; dev; dev = next) { sp = (struct sgiseeq_private *) netdev_priv(dev); next = sp->next_module; - irq = dev->irq; unregister_netdev(dev); - free_irq(irq, dev); - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); free_netdev(dev); } } @@ -770,4 +767,6 @@ static void __exit sgiseeq_exit(void) module_init(sgiseeq_probe); module_exit(sgiseeq_exit); +MODULE_DESCRIPTION("SGI Seeq 8003 driver"); +MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c2e6484ef138..572f121b1f4e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -730,6 +730,7 @@ static struct ethtool_ops skge_ethtool_ops = { .phys_id = skge_phys_id, .get_stats_count = skge_get_stats_count, .get_ethtool_stats = skge_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* @@ -3096,6 +3097,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* device is off until link detection */ netif_carrier_off(dev); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index f88f5e32b714..cfaf47c63c58 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -214,7 +214,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) { struct bmac_init_block *bb = bp->bmac_block; struct net_device *dev = bp->dev; - int i, gfp_flags = GFP_KERNEL; + int i; + gfp_t gfp_flags = GFP_KERNEL; if (from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index 5674003fc38a..b0dbc5187143 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -339,7 +339,7 @@ struct bigmac { #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d500a5771dbc..5de0554fd7c6 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -518,6 +518,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif + int phy, phy_idx = 0; /* when built into the kernel, we only print version if device is found */ @@ -549,6 +550,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; @@ -605,33 +607,31 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - if (1) { - int phy, phy_idx = 0; - np->phys[0] = 1; /* Default setting */ - np->mii_preamble_required++; - for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); - if ((mii_status & 0x0040) == 0) - np->mii_preamble_required++; - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->mii_if.advertising); - } - } - np->mii_preamble_required--; - - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", - dev->name, ioread32(ioaddr + ASICCtrl)); - goto err_out_unregister; + np->phys[0] = 1; /* Default setting */ + np->mii_preamble_required++; + for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(dev, phy, MII_BMSR); + int phyx = phy & 0x1f; + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phyx; + np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); + if ((mii_status & 0x0040) == 0) + np->mii_preamble_required++; + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phyx, mii_status, np->mii_if.advertising); } + } + np->mii_preamble_required--; - np->mii_if.phy_id = np->phys[0]; + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", + dev->name, ioread32(ioaddr + ASICCtrl)); + goto err_out_unregister; } + np->mii_if.phy_id = np->phys[0]; + /* Parse override configuration */ np->an_enable = 1; if (card_idx < MAX_UNITS) { @@ -692,7 +692,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, /* Reset the chip to erase previous misconfiguration. */ if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - iowrite16(0x007f, ioaddr + ASICCtrl + 2); + iowrite16(0x00ff, ioaddr + ASICCtrl + 2); if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); @@ -1619,6 +1619,7 @@ static struct ethtool_ops ethtool_ops = { .get_link = get_link, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 32057e65808b..9f491563944e 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -318,7 +318,7 @@ static void ibmtr_cleanup_card(struct net_device *dev) if (dev->base_addr) { outb(0,dev->base_addr+ADAPTRESET); - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0,dev->base_addr+ADAPTRESETREL); } @@ -854,8 +854,7 @@ static int tok_init_card(struct net_device *dev) writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); outb(0, PIOaddr + ADAPTRESET); - current->state=TASK_UNINTERRUPTIBLE; - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0, PIOaddr + ADAPTRESETREL); #ifdef ENABLE_PAGING @@ -903,8 +902,8 @@ static int tok_open(struct net_device *dev) DPRINTK("Adapter is up and running\n"); return 0; } - current->state=TASK_INTERRUPTIBLE; - i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */ + i=schedule_timeout_interruptible(TR_RETRY_INTERVAL); + /* wait 30 seconds */ if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */ } outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 9e7923192a49..05477d24fd49 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1101,7 +1101,7 @@ static int olympic_close(struct net_device *dev) while(olympic_priv->srb_queued) { - t = schedule_timeout(60*HZ); + t = schedule_timeout_interruptible(60*HZ); if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 2e39bf1f7462..c1925590a0e1 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1243,8 +1243,7 @@ void tms380tr_wait(unsigned long time) tmp = jiffies + time/(1000000/HZ); do { - current->state = TASK_INTERRUPTIBLE; - tmp = schedule_timeout(tmp); + tmp = schedule_timeout_interruptible(tmp); } while(time_after(tmp, jiffies)); #else udelay(time); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index a22d00198e4d..6b8eee8f7bfd 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1787,10 +1787,15 @@ static void __init de21041_get_srom_info (struct de_private *de) /* DEC now has a specification but early board makers just put the address in the first EEPROM locations. */ /* This does memcmp(eedata, eedata+16, 8) */ + +#ifndef CONFIG_MIPS_COBALT + for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) sa_offset = 20; +#endif + /* store MAC address */ for (i = 0; i < 6; i ++) de->dev->dev_addr[i] = ee_data[i + sa_offset]; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index ecfa6f8805ce..4c76cb794bfb 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -419,10 +419,9 @@ typhoon_reset(void __iomem *ioaddr, int wait_type) TYPHOON_STATUS_WAITING_FOR_HOST) goto out; - if(wait_type == WaitSleep) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } else + if(wait_type == WaitSleep) + schedule_timeout_uninterruptible(1); + else udelay(TYPHOON_UDELAY); } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fc7738ffbfff..241871589283 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -490,6 +490,8 @@ struct rhine_private { u8 tx_thresh, rx_thresh; struct mii_if_info mii_if; + struct work_struct tx_timeout_task; + struct work_struct check_media_task; void __iomem *base; }; @@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); +static void rhine_tx_timeout_task(struct net_device *dev); +static void rhine_check_media_task(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void rhine_tx(struct net_device *dev); @@ -814,8 +818,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { rc = -EIO; printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; @@ -850,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; + INIT_WORK(&rp->tx_timeout_task, + (void (*)(void *))rhine_tx_timeout_task, dev); + + INIT_WORK(&rp->check_media_task, + (void (*)(void *))rhine_check_media_task, dev); + /* dev->name not defined before register_netdev()! */ rc = register_netdev(dev); if (rc) @@ -1076,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) ioaddr + ChipCmd1); } +static void rhine_check_media_task(struct net_device *dev) +{ + rhine_check_media(dev, 0); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1129,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) if (quirks & rqRhineI) { iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR - /* Can be called from ISR. Evil. */ - mdelay(1); + /* Do not call from ISR! */ + msleep(1); /* 0x80 must be set immediately before turning it off */ iowrite8(0x80, ioaddr + MIICmd); @@ -1220,6 +1236,16 @@ static int rhine_open(struct net_device *dev) static void rhine_tx_timeout(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + + /* + * Move bulk of work outside of interrupt context + */ + schedule_work(&rp->tx_timeout_task); +} + +static void rhine_tx_timeout_task(struct net_device *dev) +{ + struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " @@ -1625,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status) spin_lock(&rp->lock); if (intr_status & IntrLinkChange) - rhine_check_media(dev, 0); + schedule_work(&rp->check_media_task); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); @@ -1829,6 +1855,7 @@ static struct ethtool_ops netdev_ethtool_ops = { .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -1872,6 +1899,9 @@ static int rhine_close(struct net_device *dev) spin_unlock_irq(&rp->lock); free_irq(rp->pdev->irq, dev); + + flush_scheduled_work(); + free_rbufs(dev); free_tbufs(dev); free_ring(dev); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index ace68e5bc6c9..e392ee8b37a1 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -1617,8 +1617,7 @@ static int get_wait_data(struct cosa_data *cosa) return r; } /* sleep if not ready to read */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", cosa_getstatus(cosa)); @@ -1644,8 +1643,7 @@ static int put_wait_data(struct cosa_data *cosa, int data) } #if 0 /* sleep if not ready to read */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); #endif } printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index 9e56fc346ba4..e6d005726aad 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -109,7 +109,7 @@ static long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; * < 0 error. * Context: process */ -int __init cycx_drv_init(void) +static int __init cycx_drv_init(void) { printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); @@ -119,7 +119,7 @@ int __init cycx_drv_init(void) /* Module 'remove' entry point. * o release all remaining system resources */ -void cycx_drv_cleanup(void) +static void cycx_drv_cleanup(void) { } @@ -184,8 +184,7 @@ int cycx_down(struct cycx_hw *hw) } /* Enable interrupt generation. */ -EXPORT_SYMBOL(cycx_inten); -void cycx_inten(struct cycx_hw *hw) +static void cycx_inten(struct cycx_hw *hw) { writeb(0, hw->dpmbase); } diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 7b48064364dc..430b1f630fb4 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -103,7 +103,7 @@ static struct cycx_device *cycx_card_array; /* adapter data space */ * < 0 error. * Context: process */ -int __init cycx_init(void) +static int __init cycx_init(void) { int cnt, err = -ENOMEM; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 02d57c0b4243..a631d1c2fa14 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -78,6 +78,7 @@ #define CYCLOMX_X25_DEBUG 1 +#include <linux/ctype.h> /* isdigit() */ #include <linux/errno.h> /* return codes */ #include <linux/if_arp.h> /* ARPHRD_HWX25 */ #include <linux/kernel.h> /* printk(), and other useful stuff */ @@ -418,7 +419,7 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, /* Set channel timeouts (default if not specified) */ chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; - } else if (is_digit(conf->addr[0])) { /* PVC */ + } else if (isdigit(conf->addr[0])) { /* PVC */ s16 lcn = dec_to_uint(conf->addr, 0); if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) @@ -1531,7 +1532,7 @@ static unsigned dec_to_uint(u8 *str, int len) if (!len) len = strlen(str); - for (; len && is_digit(*str); ++str, --len) + for (; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned) '0'); return val; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 520a77a798e2..2f61a47b4716 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -446,8 +446,8 @@ static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv, return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda; } -int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, - const char *msg) +static int state_check(u32 state, struct dscc4_dev_priv *dpriv, + struct net_device *dev, const char *msg) { int ret = 0; @@ -466,8 +466,9 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, return ret; } -void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv, - char *msg) +static void dscc4_tx_print(struct net_device *dev, + struct dscc4_dev_priv *dpriv, + char *msg) { printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n", dev->name, dpriv->tx_current, dpriv->tx_dirty, msg); @@ -507,7 +508,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) } } -inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev) +static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, + struct net_device *dev) { unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE; struct RxFD *rx_fd = dpriv->rx_fd + dirty; @@ -542,8 +544,7 @@ static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv, msg, i); goto done; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); rmb(); } while (++i > 0); printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); @@ -588,8 +589,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) (dpriv->iqtx[cur] & Xpr)) break; smp_rmb(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } while (++i > 0); return (i >= 0 ) ? i : -EAGAIN; @@ -1035,8 +1035,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr) /* Flush posted writes */ readl(ioaddr + GSTAR); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); for (i = 0; i < 16; i++) pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]); @@ -1894,7 +1893,7 @@ try: * It failed and locked solid. Thus the introduction of a dummy skb. * Problem is acknowledged in errata sheet DS5. Joy :o/ */ -struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) +static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) { struct sk_buff *skb; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 2c83cca34b86..7981a2c7906e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -74,11 +74,11 @@ MODULE_LICENSE("GPL"); /* * Modules parameters and associated varaibles */ -int fst_txq_low = FST_LOW_WATER_MARK; -int fst_txq_high = FST_HIGH_WATER_MARK; -int fst_max_reads = 7; -int fst_excluded_cards = 0; -int fst_excluded_list[FST_MAX_CARDS]; +static int fst_txq_low = FST_LOW_WATER_MARK; +static int fst_txq_high = FST_HIGH_WATER_MARK; +static int fst_max_reads = 7; +static int fst_excluded_cards = 0; +static int fst_excluded_list[FST_MAX_CARDS]; module_param(fst_txq_low, int, 0); module_param(fst_txq_high, int, 0); @@ -572,13 +572,13 @@ static void do_bottom_half_rx(struct fst_card_info *card); static void fst_process_tx_work_q(unsigned long work_q); static void fst_process_int_work_q(unsigned long work_q); -DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); -DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); +static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); +static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); -struct fst_card_info *fst_card_array[FST_MAX_CARDS]; -spinlock_t fst_work_q_lock; -u64 fst_work_txq; -u64 fst_work_intq; +static struct fst_card_info *fst_card_array[FST_MAX_CARDS]; +static spinlock_t fst_work_q_lock; +static u64 fst_work_txq; +static u64 fst_work_intq; static void fst_q_work_item(u64 * queue, int card_index) @@ -980,8 +980,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd) /* Wait for any previous command to complete */ while (mbval > NAK) { spin_unlock_irqrestore(&card->card_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&card->card_lock, flags); if (++safety > 2000) { @@ -1498,7 +1497,7 @@ do_bottom_half_rx(struct fst_card_info *card) * The interrupt service routine * Dev_id is our fst_card_info pointer */ -irqreturn_t +static irqreturn_t fst_intr(int irq, void *dev_id, struct pt_regs *regs) { struct fst_card_info *card; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index a5d6891c9d4c..e1601d35dced 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -330,7 +330,7 @@ static int pvc_close(struct net_device *dev) -int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { pvc_device *pvc = dev_to_pvc(dev); fr_proto_pvc_info info; diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c index 9dccd9546a17..3b94352b0d03 100644 --- a/drivers/net/wan/lmc/lmc_debug.c +++ b/drivers/net/wan/lmc/lmc_debug.c @@ -8,10 +8,10 @@ /* * Prints out len, max to 80 octets using printk, 20 per line */ -void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) -{ #ifdef DEBUG #ifdef LMC_PACKET_LOG +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) +{ int iNewLine = 1; char str[80], *pstr; @@ -43,26 +43,24 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) } sprintf(pstr, "\n"); printk(str); +} #endif #endif -} #ifdef DEBUG u_int32_t lmcEventLogIndex = 0; u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; -#endif void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) { -#ifdef DEBUG lmcEventLogBuf[lmcEventLogIndex++] = EventNum; lmcEventLogBuf[lmcEventLogIndex++] = arg2; lmcEventLogBuf[lmcEventLogIndex++] = arg3; lmcEventLogBuf[lmcEventLogIndex++] = jiffies; lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1; -#endif } +#endif /* DEBUG */ void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index f55ce76b00ed..af8b55fdd9d9 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -48,14 +48,6 @@ */ /* - * For lack of a better place, put the SSI cable stuff here. - */ -char *lmc_t1_cables[] = { - "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35", - "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL -}; - -/* * protocol independent method. */ static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *); diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index 73401b0f0151..2024b26b99e6 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -472,24 +472,8 @@ enum pc300_loopback_cmds { #ifdef __KERNEL__ /* Function Prototypes */ -int dma_buf_write(pc300_t *, int, ucchar *, int); -int dma_buf_read(pc300_t *, int, struct sk_buff *); void tx_dma_start(pc300_t *, int); -void rx_dma_start(pc300_t *, int); -void tx_dma_stop(pc300_t *, int); -void rx_dma_stop(pc300_t *, int); -int cpc_queue_xmit(struct sk_buff *, struct net_device *); -void cpc_net_rx(struct net_device *); -void cpc_sca_status(pc300_t *, int); -int cpc_change_mtu(struct net_device *, int); -int cpc_ioctl(struct net_device *, struct ifreq *, int); -int ch_config(pc300dev_t *); -int rx_config(pc300dev_t *); -int tx_config(pc300dev_t *); -void cpc_opench(pc300dev_t *); -void cpc_closech(pc300dev_t *); int cpc_open(struct net_device *dev); -int cpc_close(struct net_device *dev); int cpc_set_media(hdlc_device *, int); #endif /* __KERNEL__ */ diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 3e7753b10717..a3e65d1bc19b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -291,6 +291,7 @@ static uclong detect_ram(pc300_t *); static void plx_init(pc300_t *); static void cpc_trace(struct net_device *, struct sk_buff *, char); static int cpc_attach(struct net_device *, unsigned short, unsigned short); +static int cpc_close(struct net_device *dev); #ifdef CONFIG_PC300_MLPPP void cpc_tty_init(pc300dev_t * dev); @@ -437,7 +438,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch) printk("\n"); } -int dma_get_rx_frame_size(pc300_t * card, int ch) +static int dma_get_rx_frame_size(pc300_t * card, int ch) { volatile pcsca_bd_t __iomem *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; @@ -462,7 +463,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) * dma_buf_write: writes a frame to the Tx DMA buffers * NOTE: this function writes one frame at a time. */ -int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) +static int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) { int i, nchar; volatile pcsca_bd_t __iomem *ptdescr; @@ -503,7 +504,7 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) * dma_buf_read: reads a frame from the Rx DMA buffers * NOTE: this function reads one frame at a time. */ -int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) +static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) { int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -560,7 +561,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) return (rcvd); } -void tx_dma_stop(pc300_t * card, int ch) +static void tx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); @@ -571,7 +572,7 @@ void tx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_stop(pc300_t * card, int ch) +static void rx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); @@ -582,7 +583,7 @@ void rx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_start(pc300_t * card, int ch) +static void rx_dma_start(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -607,7 +608,7 @@ void rx_dma_start(pc300_t * card, int ch) /*************************/ /*** FALC Routines ***/ /*************************/ -void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) +static void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) { void __iomem *falcbase = card->hw.falcbase; unsigned long i = 0; @@ -622,7 +623,7 @@ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) cpc_writeb(falcbase + F_REG(CMDR, ch), cmd); } -void falc_intr_enable(pc300_t * card, int ch) +static void falc_intr_enable(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -672,7 +673,7 @@ void falc_intr_enable(pc300_t * card, int ch) } } -void falc_open_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_open_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -688,7 +689,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot) (0x80 >> (timeslot & 0x07))); } -void falc_close_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_close_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -704,7 +705,7 @@ void falc_close_timeslot(pc300_t * card, int ch, int timeslot) ~(0x80 >> (timeslot & 0x07))); } -void falc_close_all_timeslots(pc300_t * card, int ch) +static void falc_close_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -726,7 +727,7 @@ void falc_close_all_timeslots(pc300_t * card, int ch) } } -void falc_open_all_timeslots(pc300_t * card, int ch) +static void falc_open_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -758,7 +759,7 @@ void falc_open_all_timeslots(pc300_t * card, int ch) } } -void falc_init_timeslot(pc300_t * card, int ch) +static void falc_init_timeslot(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -776,7 +777,7 @@ void falc_init_timeslot(pc300_t * card, int ch) } } -void falc_enable_comm(pc300_t * card, int ch) +static void falc_enable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -792,7 +793,7 @@ void falc_enable_comm(pc300_t * card, int ch) ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_disable_comm(pc300_t * card, int ch) +static void falc_disable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -806,7 +807,7 @@ void falc_disable_comm(pc300_t * card, int ch) ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_init_t1(pc300_t * card, int ch) +static void falc_init_t1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -975,7 +976,7 @@ void falc_init_t1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_e1(pc300_t * card, int ch) +static void falc_init_e1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1155,7 +1156,7 @@ void falc_init_e1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_hdlc(pc300_t * card, int ch) +static void falc_init_hdlc(pc300_t * card, int ch) { void __iomem *falcbase = card->hw.falcbase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -1181,7 +1182,7 @@ void falc_init_hdlc(pc300_t * card, int ch) falc_intr_enable(card, ch); } -void te_config(pc300_t * card, int ch) +static void te_config(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1241,7 +1242,7 @@ void te_config(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -void falc_check_status(pc300_t * card, int ch, unsigned char frs0) +static void falc_check_status(pc300_t * card, int ch, unsigned char frs0) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1397,7 +1398,7 @@ void falc_check_status(pc300_t * card, int ch, unsigned char frs0) } } -void falc_update_stats(pc300_t * card, int ch) +static void falc_update_stats(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1450,7 +1451,7 @@ void falc_update_stats(pc300_t * card, int ch) * the synchronizer and then sent to the system interface. *---------------------------------------------------------------------------- */ -void falc_remote_loop(pc300_t * card, int ch, int loop_on) +static void falc_remote_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1495,7 +1496,7 @@ void falc_remote_loop(pc300_t * card, int ch, int loop_on) * coding must be identical. *---------------------------------------------------------------------------- */ -void falc_local_loop(pc300_t * card, int ch, int loop_on) +static void falc_local_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1522,7 +1523,7 @@ void falc_local_loop(pc300_t * card, int ch, int loop_on) * looped. They are originated by the FALC-LH transmitter. *---------------------------------------------------------------------------- */ -void falc_payload_loop(pc300_t * card, int ch, int loop_on) +static void falc_payload_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1576,7 +1577,7 @@ void falc_payload_loop(pc300_t * card, int ch, int loop_on) * Description: Turns XLU bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xlu(pc300_t * card, int ch) +static void turn_off_xlu(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1597,7 +1598,7 @@ void turn_off_xlu(pc300_t * card, int ch) * Description: Turns XLD bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xld(pc300_t * card, int ch) +static void turn_off_xld(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1619,7 +1620,7 @@ void turn_off_xld(pc300_t * card, int ch) * to generate a LOOP activation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_up_code(pc300_t * card, int ch) +static void falc_generate_loop_up_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1652,7 +1653,7 @@ void falc_generate_loop_up_code(pc300_t * card, int ch) * to generate a LOOP deactivation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_down_code(pc300_t * card, int ch) +static void falc_generate_loop_down_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1682,7 +1683,7 @@ void falc_generate_loop_down_code(pc300_t * card, int ch) * it on the reception side. *---------------------------------------------------------------------------- */ -void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) +static void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1729,7 +1730,7 @@ void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) * Description: This routine returns the bit error counter value *---------------------------------------------------------------------------- */ -ucshort falc_pattern_test_error(pc300_t * card, int ch) +static ucshort falc_pattern_test_error(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1769,7 +1770,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) netif_rx(skb); } -void cpc_tx_timeout(struct net_device *dev) +static void cpc_tx_timeout(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1797,7 +1798,7 @@ void cpc_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) +static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1880,7 +1881,7 @@ int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -void cpc_net_rx(struct net_device *dev) +static void cpc_net_rx(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -2403,7 +2404,7 @@ static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void cpc_sca_status(pc300_t * card, int ch) +static void cpc_sca_status(pc300_t * card, int ch) { ucchar ilar; void __iomem *scabase = card->hw.scabase; @@ -2495,7 +2496,7 @@ void cpc_sca_status(pc300_t * card, int ch) } } -void cpc_falc_status(pc300_t * card, int ch) +static void cpc_falc_status(pc300_t * card, int ch) { pc300ch_t *chan = &card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -2523,7 +2524,7 @@ void cpc_falc_status(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -int cpc_change_mtu(struct net_device *dev, int new_mtu) +static int cpc_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU)) return -EINVAL; @@ -2531,7 +2532,7 @@ int cpc_change_mtu(struct net_device *dev, int new_mtu) return 0; } -int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; @@ -2856,7 +2857,7 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io) } } -int ch_config(pc300dev_t * d) +static int ch_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -3004,7 +3005,7 @@ int ch_config(pc300dev_t * d) return 0; } -int rx_config(pc300dev_t * d) +static int rx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3035,7 +3036,7 @@ int rx_config(pc300dev_t * d) return 0; } -int tx_config(pc300dev_t * d) +static int tx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3098,7 +3099,7 @@ static int cpc_attach(struct net_device *dev, unsigned short encoding, return 0; } -void cpc_opench(pc300dev_t * d) +static void cpc_opench(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3116,7 +3117,7 @@ void cpc_opench(pc300dev_t * d) cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR)); } -void cpc_closech(pc300dev_t * d) +static void cpc_closech(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3173,7 +3174,7 @@ int cpc_open(struct net_device *dev) return 0; } -int cpc_close(struct net_device *dev) +static int cpc_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 8454bf6caaa7..52f26b9c69d2 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -112,10 +112,10 @@ typedef struct _st_cpc_tty_area { static struct tty_driver serial_drv; /* local variables */ -st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; +static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; -int cpc_tty_cnt=0; /* number of intrfaces configured with MLPPP */ -int cpc_tty_unreg_flag = 0; +static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */ +static int cpc_tty_unreg_flag = 0; /* TTY functions prototype */ static int cpc_tty_open(struct tty_struct *tty, struct file *flip); @@ -132,9 +132,9 @@ static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); -int pc300_tiocmset(struct tty_struct *, struct file *, - unsigned int, unsigned int); -int pc300_tiocmget(struct tty_struct *, struct file *); +static int pc300_tiocmset(struct tty_struct *, struct file *, + unsigned int, unsigned int); +static int pc300_tiocmget(struct tty_struct *, struct file *); /* functions called by PC300 driver */ void cpc_tty_init(pc300dev_t *dev); @@ -538,8 +538,8 @@ static int cpc_tty_chars_in_buffer(struct tty_struct *tty) return(0); } -int pc300_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static int pc300_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { st_cpc_tty_area *cpc_tty; @@ -565,7 +565,7 @@ int pc300_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -int pc300_tiocmget(struct tty_struct *tty, struct file *file) +static int pc300_tiocmget(struct tty_struct *tty, struct file *file) { unsigned int result; unsigned char status; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 3ac9a45b20fa..036adc4f8ba7 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -182,7 +182,7 @@ static char sdla_byte(struct net_device *dev, int addr) return(byte); } -void sdla_stop(struct net_device *dev) +static void sdla_stop(struct net_device *dev) { struct frad_local *flp; @@ -209,7 +209,7 @@ void sdla_stop(struct net_device *dev) } } -void sdla_start(struct net_device *dev) +static void sdla_start(struct net_device *dev) { struct frad_local *flp; @@ -247,7 +247,7 @@ void sdla_start(struct net_device *dev) * ***************************************************/ -int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) +static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) { unsigned long start, done, now; char resp, *temp; @@ -505,7 +505,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, static int sdla_reconfig(struct net_device *dev); -int sdla_activate(struct net_device *slave, struct net_device *master) +static int sdla_activate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -527,7 +527,7 @@ int sdla_activate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deactivate(struct net_device *slave, struct net_device *master) +static int sdla_deactivate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -549,7 +549,7 @@ int sdla_deactivate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_assoc(struct net_device *slave, struct net_device *master) +static int sdla_assoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -585,7 +585,7 @@ int sdla_assoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deassoc(struct net_device *slave, struct net_device *master) +static int sdla_deassoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -613,7 +613,7 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) +static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) { struct frad_local *flp; struct dlci_local *dlp; @@ -1324,7 +1324,7 @@ NOTE: This is rather a useless action right now, as the return(0); } -int sdla_change_mtu(struct net_device *dev, int new_mtu) +static int sdla_change_mtu(struct net_device *dev, int new_mtu) { struct frad_local *flp; @@ -1337,7 +1337,7 @@ int sdla_change_mtu(struct net_device *dev, int new_mtu) return(-EOPNOTSUPP); } -int sdla_set_config(struct net_device *dev, struct ifmap *map) +static int sdla_set_config(struct net_device *dev, struct ifmap *map) { struct frad_local *flp; int i; diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 0497dbdb8631..7f1ce9d4333e 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -822,7 +822,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->card = card; /* verify media address */ - if (is_digit(conf->addr[0])) { + if (isdigit(conf->addr[0])) { dlci = dec_to_uint(conf->addr, 0); @@ -3456,7 +3456,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c index 8a95d61a2f8f..63f846d6f3a6 100644 --- a/drivers/net/wan/sdla_x25.c +++ b/drivers/net/wan/sdla_x25.c @@ -957,7 +957,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - }else if (is_digit(conf->addr[0])){ /* PVC */ + }else if (isdigit(conf->addr[0])){ /* PVC */ int lcn = dec_to_uint(conf->addr, 0); if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ @@ -3875,7 +3875,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; @@ -3896,9 +3896,9 @@ static unsigned int hex_to_uint (unsigned char* str, int len) for (val = 0; len; ++str, --len) { ch = *str; - if (is_digit(ch)) + if (isdigit(ch)) val = (val << 4) + (ch - (unsigned)'0'); - else if (is_hex_digit(ch)) + else if (isxdigit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); else break; } diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index c8bc6da57a41..7c2cf2e76300 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -642,9 +642,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) * Enable interrupt generation. */ -EXPORT_SYMBOL(sdla_inten); - -int sdla_inten (sdlahw_t* hw) +static int sdla_inten (sdlahw_t* hw) { unsigned port = hw->port; int tmp, i; @@ -698,8 +696,7 @@ int sdla_inten (sdlahw_t* hw) * Disable interrupt generation. */ -EXPORT_SYMBOL(sdla_intde); - +#if 0 int sdla_intde (sdlahw_t* hw) { unsigned port = hw->port; @@ -748,14 +745,13 @@ int sdla_intde (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Acknowledge SDLA hardware interrupt. */ -EXPORT_SYMBOL(sdla_intack); - -int sdla_intack (sdlahw_t* hw) +static int sdla_intack (sdlahw_t* hw) { unsigned port = hw->port; int tmp; @@ -827,8 +823,7 @@ void read_S514_int_stat (sdlahw_t* hw, u32* int_status) * Generate an interrupt to adapter's CPU. */ -EXPORT_SYMBOL(sdla_intr); - +#if 0 int sdla_intr (sdlahw_t* hw) { unsigned port = hw->port; @@ -863,6 +858,7 @@ int sdla_intr (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Execute Adapter Command. diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index a6d3b55013a5..2d1bba06a085 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -221,7 +221,7 @@ static void sppp_clear_timeout(struct sppp *p) * here. */ -void sppp_input (struct net_device *dev, struct sk_buff *skb) +static void sppp_input (struct net_device *dev, struct sk_buff *skb) { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); @@ -355,8 +355,6 @@ done: return; } -EXPORT_SYMBOL(sppp_input); - /* * Handle transmit packets. */ @@ -990,7 +988,7 @@ EXPORT_SYMBOL(sppp_reopen); * the mtu is out of range. */ -int sppp_change_mtu(struct net_device *dev, int new_mtu) +static int sppp_change_mtu(struct net_device *dev, int new_mtu) { if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) return -EINVAL; @@ -998,8 +996,6 @@ int sppp_change_mtu(struct net_device *dev, int new_mtu) return 0; } -EXPORT_SYMBOL(sppp_change_mtu); - /** * sppp_do_ioctl - Ioctl handler for ppp/hdlc * @dev: Device subject to ioctl @@ -1456,7 +1452,7 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t return 0; } -struct packet_type sppp_packet_type = { +static struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, }; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 06998c2240d9..cb429e783749 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1046,7 +1046,6 @@ static WifiCtlHdr wifictlhdr8023 = { } }; -#ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; @@ -1067,7 +1066,6 @@ typedef struct wep_key_t { /* List of Wireless Handlers (new API) */ static const struct iw_handler_def airo_handler_def; -#endif /* WIRELESS_EXT */ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; @@ -1110,10 +1108,8 @@ static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs static int airo_thread(void *data); static void timer_func( struct net_device *dev ); static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#ifdef WIRELESS_EXT static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); static void airo_read_wireless_stats (struct airo_info *local); -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT static int readrids(struct net_device *dev, aironet_ioctl *comp); static int writerids(struct net_device *dev, aironet_ioctl *comp); @@ -1187,12 +1183,10 @@ struct airo_info { int fid; } xmit, xmit11; struct net_device *wifidev; -#ifdef WIRELESS_EXT struct iw_statistics wstats; // wireless stats unsigned long scan_timestamp; /* Time started to scan */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT */ #ifdef MICSUPPORT /* MIC stuff */ struct crypto_tfm *tfm; @@ -2527,7 +2521,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, unsigned long mem_start, mem_len, aux_start, aux_len; int rc = -1; int i; - unsigned char *busaddroff,*vpackoff; + dma_addr_t busaddroff; + unsigned char *vpackoff; unsigned char __iomem *pciaddroff; mem_start = pci_resource_start(pci, 1); @@ -2570,7 +2565,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* * Setup descriptor RX, TX, CONFIG */ - busaddroff = (unsigned char *)ai->shared_dma; + busaddroff = ai->shared_dma; pciaddroff = ai->pciaux + AUX_OFFSET; vpackoff = ai->shared; @@ -2579,7 +2574,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->rxfids[i].pending = 0; ai->rxfids[i].card_ram_off = pciaddroff; ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff; + ai->rxfids[i].rx_desc.host_addr = busaddroff; ai->rxfids[i].rx_desc.valid = 1; ai->rxfids[i].rx_desc.len = PKTSIZE; ai->rxfids[i].rx_desc.rdy = 0; @@ -2594,7 +2589,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->txfids[i].card_ram_off = pciaddroff; ai->txfids[i].virtual_host_addr = vpackoff; ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff; + ai->txfids[i].tx_desc.host_addr = busaddroff; memcpy(ai->txfids[i].virtual_host_addr, &wifictlhdr8023, sizeof(wifictlhdr8023)); @@ -2607,8 +2602,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Rid descriptor setup */ ai->config_desc.card_ram_off = pciaddroff; ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff; - ai->ridbus = (dma_addr_t)busaddroff; + ai->config_desc.rid_desc.host_addr = busaddroff; + ai->ridbus = busaddroff; ai->config_desc.rid_desc.rid = 0; ai->config_desc.rid_desc.len = RIDSIZE; ai->config_desc.rid_desc.valid = 1; @@ -2647,9 +2642,7 @@ static void wifi_setup(struct net_device *dev) dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -2675,9 +2668,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, dev->priv = ethdev->priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; -#ifdef WIRELESS_EXT dev->wireless_data = ethdev->wireless_data; -#endif /* WIRELESS_EXT */ memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); err = register_netdev(dev); if (err<0) { @@ -2755,11 +2746,9 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->set_multicast_list = &airo_set_multicast_list; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; ai->wireless_data.spy_data = &ai->spy_data; dev->wireless_data = &ai->wireless_data; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -5515,12 +5504,13 @@ static int airo_pci_resume(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; Resp rsp; + pci_power_t prev_state = pdev->current_state; - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0); + pci_enable_wake(pdev, PCI_D0, 0); - if (ai->power.event > 1) { + if (prev_state != PCI_D1) { reset_card(dev, 0); mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); @@ -5598,7 +5588,6 @@ static void __exit airo_cleanup_module( void ) remove_proc_entry("aironet", proc_root_driver); } -#ifdef WIRELESS_EXT /* * Initial Wireless Extension code for Aironet driver by : * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00 @@ -7107,8 +7096,6 @@ static const struct iw_handler_def airo_handler_def = .get_wireless_stats = airo_get_wireless_stats, }; -#endif /* WIRELESS_EXT */ - /* * This defines the configuration part of the Wireless Extensions * Note : irq and spinlock protection will occur in the subroutines @@ -7187,7 +7174,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -#ifdef WIRELESS_EXT /* * Get the Wireless stats out of the driver * Note : irq and spinlock protection will occur in the subroutines @@ -7260,7 +7246,6 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) return &local->wstats; } -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT /* diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 9d496703c465..7b321f7cf358 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -15,28 +15,11 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - -#include <asm/io.h> -#include <asm/system.h> -#include <asm/current.h> -#include <asm/prom.h> -#include <asm/machdep.h> +#include <linux/delay.h> #include <asm/pmac_feature.h> -#include <asm/irq.h> -#include <asm/uaccess.h> #include "orinoco.h" diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 587869d86eee..d57011028b72 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv); static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l static int start_tx (struct sk_buff *skb, struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; @@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, + struct ieee80211_hdr_4addr *header, u8 *body, int body_len) { u16 buff; @@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); } -static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -990,7 +990,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) return (crc ^ 0xffffffff) == netcrc; } -static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { u8 mac4[6]; @@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *heade static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -2650,7 +2650,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) { - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct auth_body auth; header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); @@ -2688,7 +2688,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct ass_req_format { u16 capability; u16 listen_interval; @@ -2738,7 +2738,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); } -static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header) +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header) { if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; @@ -2788,7 +2788,7 @@ static int retrieve_bss(struct atmel_private *priv) } -static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header, +static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3072,7 +3072,7 @@ static void atmel_smooth_qual(struct atmel_private *priv) } /* deals with incoming managment frames. */ -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi) { u16 subtype; diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 21c3d0d227e6..eba0d9d2b7c5 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -39,17 +39,10 @@ */ #include <linux/config.h> - #include <linux/module.h> -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/init.h> #include <linux/kernel.h> -#include <linux/net.h> -#include <asm/errno.h> +#include <linux/init.h> +#include <linux/delay.h> #include "hermes.h" diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 8c9e874c9118..ad28e3294360 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -30,9 +30,8 @@ * access to the hermes_t structure, and to the hardware */ -#include <linux/delay.h> #include <linux/if_ether.h> -#include <asm/byteorder.h> +#include <asm/io.h> /* * Limits and constants @@ -192,13 +191,13 @@ #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ struct hermes_tx_descriptor { - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; } __attribute__ ((packed)); #define HERMES_TXSTAT_RETRYERR (0x0001) @@ -222,60 +221,60 @@ struct hermes_tx_descriptor { #define HERMES_INQ_SEC_STAT_AGERE (0xF202) struct hermes_tallies_frame { - u16 TxUnicastFrames; - u16 TxMulticastFrames; - u16 TxFragments; - u16 TxUnicastOctets; - u16 TxMulticastOctets; - u16 TxDeferredTransmissions; - u16 TxSingleRetryFrames; - u16 TxMultipleRetryFrames; - u16 TxRetryLimitExceeded; - u16 TxDiscards; - u16 RxUnicastFrames; - u16 RxMulticastFrames; - u16 RxFragments; - u16 RxUnicastOctets; - u16 RxMulticastOctets; - u16 RxFCSErrors; - u16 RxDiscards_NoBuffer; - u16 TxDiscardsWrongSA; - u16 RxWEPUndecryptable; - u16 RxMsgInMsgFragments; - u16 RxMsgInBadMsgFragments; + __le16 TxUnicastFrames; + __le16 TxMulticastFrames; + __le16 TxFragments; + __le16 TxUnicastOctets; + __le16 TxMulticastOctets; + __le16 TxDeferredTransmissions; + __le16 TxSingleRetryFrames; + __le16 TxMultipleRetryFrames; + __le16 TxRetryLimitExceeded; + __le16 TxDiscards; + __le16 RxUnicastFrames; + __le16 RxMulticastFrames; + __le16 RxFragments; + __le16 RxUnicastOctets; + __le16 RxMulticastOctets; + __le16 RxFCSErrors; + __le16 RxDiscards_NoBuffer; + __le16 TxDiscardsWrongSA; + __le16 RxWEPUndecryptable; + __le16 RxMsgInMsgFragments; + __le16 RxMsgInBadMsgFragments; /* Those last are probably not available in very old firmwares */ - u16 RxDiscards_WEPICVError; - u16 RxDiscards_WEPExcluded; + __le16 RxDiscards_WEPICVError; + __le16 RxDiscards_WEPExcluded; } __attribute__ ((packed)); /* Grabbed from wlan-ng - Thanks Mark... - Jean II * This is the result of a scan inquiry command */ /* Structure describing info about an Access Point */ struct prism2_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ - u16 essid_len; /* ESSID length */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ u8 rates[10]; /* Bit rate supported */ - u16 proberesp_rate; /* Data rate of the response frame */ - u16 atim; /* ATIM window time, Kus (hostscan only) */ + __le16 proberesp_rate; /* Data rate of the response frame */ + __le16 atim; /* ATIM window time, Kus (hostscan only) */ } __attribute__ ((packed)); /* Same stuff for the Lucent/Agere card. * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */ struct agere_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ } __attribute__ ((packed)); @@ -283,16 +282,16 @@ struct agere_scan_apinfo { struct symbol_scan_apinfo { u8 channel; /* Channel where the AP sits */ u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ - u16 rates[5]; /* Bit rate supported */ - u16 basic_rates; /* Basic rates bitmask */ + __le16 rates[5]; /* Bit rate supported */ + __le16 basic_rates; /* Basic rates bitmask */ u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ } __attribute__ ((packed)); @@ -312,7 +311,7 @@ union hermes_scan_info { #define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) struct hermes_linkstatus { - u16 linkstatus; /* Link status */ + __le16 linkstatus; /* Link status */ } __attribute__ ((packed)); struct hermes_response { @@ -321,8 +320,8 @@ struct hermes_response { /* "ID" structure - used for ESSID and station nickname */ struct hermes_idstring { - u16 len; - u16 val[16]; + __le16 len; + __le16 val[16]; } __attribute__ ((packed)); struct hermes_multicast { @@ -447,7 +446,7 @@ static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) { - u16 rec; + __le16 rec; int err; err = HERMES_READ_RECORD(hw, bap, rid, &rec); @@ -457,7 +456,7 @@ static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) { - u16 rec = cpu_to_le16(word); + __le16 rec = cpu_to_le16(word); return HERMES_WRITE_RECORD(hw, bap, rid, &rec); } diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c index e7f5821b4942..6a96cd9f2685 100644 --- a/drivers/net/wireless/hostap/hostap.c +++ b/drivers/net/wireless/hostap/hostap.c @@ -716,9 +716,6 @@ static int prism2_close(struct net_device *dev) hostap_deauth_all_stas(dev, local->ap, 1); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - if (local->func->dev_close && local->func->dev_close(local)) - return 0; - if (dev == local->dev) { local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); } @@ -766,9 +763,6 @@ static int prism2_open(struct net_device *dev) local->hw_downloading) return -ENODEV; - if (local->func->dev_open && local->func->dev_open(local)) - return 1; - if (!try_module_get(local->hw_module)) return -ENODEV; local->num_dev_open++; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index b0501243b175..ffac50899454 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -6,10 +6,10 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " "jiffies=%ld\n", @@ -51,7 +51,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, int hdrlen, phdrlen, head_need, tail_need; u16 fc; int prism_header, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -70,7 +70,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, phdrlen = 0; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { @@ -215,7 +215,7 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq, /* Called only as a tasklet (software IRQ) */ static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) +prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; @@ -229,7 +229,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + + sizeof(struct ieee80211_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */); @@ -267,7 +267,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) /* Called only as a tasklet (software IRQ) */ static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { u16 sc; unsigned int seq; @@ -441,7 +441,7 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, u16 stype) { if (local->iw_mode == IW_MODE_MASTER) { - hostap_update_sta_ps(local, (struct ieee80211_hdr *) + hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *) skb->data); } @@ -520,7 +520,7 @@ static inline struct net_device *prism2_rx_get_wds(local_info_t *local, static inline int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, +hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { /* FIX: is this really supposed to accept WDS frames only in Master @@ -579,13 +579,13 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) { struct net_device *dev = local->dev; u16 fc, ethertype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -619,13 +619,13 @@ static inline int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); if (local->tkip_countermeasures && @@ -658,13 +658,13 @@ static inline int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, int keyidx, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); @@ -689,7 +689,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; struct net_device *wds = NULL; @@ -716,7 +716,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, dev = local->ddev; iface = netdev_priv(dev); - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; stats = hostap_get_stats(dev); if (skb->len < 10) @@ -737,7 +737,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, struct iw_quality wstats; wstats.level = rx_stats->signal; wstats.noise = rx_stats->noise; - wstats.updated = 6; /* No qual value */ + wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, hdr->addr2, &wstats); } @@ -889,7 +890,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ @@ -941,7 +942,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; prism2_frag_cache_invalidate(local, hdr); } @@ -952,7 +953,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { if (local->ieee_802_1x && hostap_is_eapol_frame(local, skb)) { diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6358015f6526..9d24f8a38ac5 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,9 +1,9 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", name, skb->len, jiffies); @@ -41,7 +41,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; + struct ieee80211_hdr_4addr hdr; u16 fc, ethertype = 0; enum { WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME @@ -244,7 +244,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; iface = netdev_priv(dev); @@ -266,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) meta->iface = iface; if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { @@ -289,7 +289,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; int hdr_len, res; @@ -303,7 +303,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (local->tkip_countermeasures && crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " "TX packet to " MACSTR "\n", @@ -317,15 +317,15 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (skb == NULL) return NULL; - if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || - skb_tailroom(skb) < crypt->ops->extra_postfix_len) && - pskb_expand_head(skb, crypt->ops->extra_prefix_len, - crypt->ops->extra_postfix_len, GFP_ATOMIC)) { + if ((skb_headroom(skb) < crypt->ops->extra_mpdu_prefix_len || + skb_tailroom(skb) < crypt->ops->extra_mpdu_postfix_len) && + pskb_expand_head(skb, crypt->ops->extra_mpdu_prefix_len, + crypt->ops->extra_mpdu_postfix_len, GFP_ATOMIC)) { kfree_skb(skb); return NULL; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); hdr_len = hostap_80211_get_hdrlen(fc); @@ -360,7 +360,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) ap_tx_ret tx_ret; struct hostap_skb_tx_data *meta; int no_encrypt = 0; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -403,7 +403,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_ret = hostap_handle_sta_tx(local, &tx); skb = tx.skb; meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); switch (tx_ret) { case AP_TX_CONTINUE: diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 930cef8367f2..9da94ab7f05f 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -591,14 +591,14 @@ static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (!ap->local->hostapd || !ap->local->apdev) { dev_kfree_skb(skb); return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* Pass the TX callback frame to the hostapd; use 802.11 header version @@ -623,7 +623,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -633,7 +633,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || @@ -692,7 +692,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -702,7 +702,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && @@ -757,12 +757,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; if (skb->len < 24) goto fail; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (ok) { spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); @@ -918,7 +918,7 @@ static void prism2_send_mgmt(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; struct sk_buff *skb; struct hostap_skb_tx_data *meta; @@ -944,7 +944,7 @@ static void prism2_send_mgmt(struct net_device *dev, fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(fc); - hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen); if (body) memcpy(skb_put(skb, body_len), body, body_len); @@ -1256,14 +1256,14 @@ static char * ap_auth_make_challenge(struct ap_data *ap) } skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_prefix_len + - ap->crypt->extra_postfix_len); + ap->crypt->extra_mpdu_prefix_len + + ap->crypt->extra_mpdu_postfix_len); if (skb == NULL) { kfree(tmpbuf); return NULL; } - skb_reserve(skb, ap->crypt->extra_prefix_len); + skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { @@ -1272,7 +1272,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap) return NULL; } - memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, + memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len, WLAN_AUTH_CHALLENGE_LEN); dev_kfree_skb(skb); @@ -1285,7 +1285,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; size_t hdrlen; struct ap_data *ap = local->ap; char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; @@ -1498,7 +1498,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int reassoc) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char body[12], *p, *lpos; int len, left; u16 *pos; @@ -1705,7 +1705,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); int len; u16 reason_code, *pos; @@ -1746,7 +1746,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len; u16 reason_code, *pos; @@ -1784,7 +1784,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; @@ -1801,7 +1801,7 @@ static void ap_handle_data_nullfunc(local_info_t *local, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; struct sta_info *sta; @@ -1860,7 +1860,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, /* Called only as a scheduled task for pending AP frames. */ static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; @@ -1979,7 +1979,7 @@ static void handle_wds_oper_queue(void *data) static void handle_beacon(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len, left; u16 *pos, beacon_int, capability; @@ -2137,11 +2137,11 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, struct net_device *dev = local->dev; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); @@ -2258,7 +2258,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, struct hostap_interface *iface; local_info_t *local; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -2268,7 +2268,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, local->stats.rx_packets++; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && @@ -2289,7 +2289,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, static void schedule_packet_send(local_info_t *local, struct sta_info *sta) { struct sk_buff *skb; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; if (skb_queue_empty(&sta->tx_buf)) @@ -2302,7 +2302,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) return; } - hdr = (struct ieee80211_hdr *) skb_put(skb, 16); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_ctl = __constant_cpu_to_le16( @@ -2349,7 +2349,7 @@ static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); qual[count].updated = sta->last_rx_updated; - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; count++; if (count >= buf_size) @@ -2467,7 +2467,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) } #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; /* To be continued, we should make good use of IWEVCUSTOM */ } @@ -2685,7 +2685,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) struct sta_info *sta = NULL; struct sk_buff *skb = tx->skb; int set_tim, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; meta = (struct hostap_skb_tx_data *) skb->cb; @@ -2694,7 +2694,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) meta->iface->type == HOSTAP_INTERFACE_STA) goto out; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (hdr->addr1[0] & 0x01) { /* broadcast/multicast frame - no AP related processing */ @@ -2821,10 +2821,10 @@ void hostap_handle_sta_release(void *ptr) void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) { struct sta_info *sta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; spin_lock(&local->ap->sta_table_lock); @@ -2892,7 +2892,7 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, /* Called only as a tasklet (software IRQ). Called for each RX frame to update * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sta_info *sta; u16 fc; @@ -2925,12 +2925,12 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, int ret; struct sta_info *sta; u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (local->ap == NULL) return AP_RX_CONTINUE; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); @@ -3058,7 +3058,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr) { @@ -3160,7 +3160,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) /* Called only as a tasklet (software IRQ) */ int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct sta_info *sta; @@ -3174,7 +3174,7 @@ int hostap_update_rx_stats(struct ap_data *ap, sta->last_rx_silence = rx_stats->noise; sta->last_rx_signal = rx_stats->signal; sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = 7; + sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; if (rx_stats->rate == 10) sta->rx_count[0]++; else if (rx_stats->rate == 20) diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 816a52bcea8f..6d00df69c2e3 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -233,7 +233,7 @@ struct hostap_tx_data { ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); void hostap_handle_sta_release(void *ptr); void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr); typedef enum { AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED } ap_rx_ret; @@ -241,13 +241,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, +int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, +int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats); void hostap_update_rates(local_info_t *local); void hostap_add_wds_links(local_info_t *local); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index faa83badf0a1..2643976a6677 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -492,42 +492,10 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) } -static int prism2_pccard_dev_open(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - hw_priv->link->open++; - return 0; -} - - -static int prism2_pccard_dev_close(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv; - - if (local == NULL || local->hw_priv == NULL) - return 1; - hw_priv = local->hw_priv; - if (hw_priv->link == NULL) - return 1; - - if (!hw_priv->link->open) { - printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " - "link not open?!\n", local->dev->name); - return 1; - } - - hw_priv->link->open--; - - return 0; -} - - static struct prism2_helper_functions prism2_pccard_funcs = { .card_present = prism2_pccard_card_present, .cor_sreset = prism2_pccard_cor_sreset, - .dev_open = prism2_pccard_dev_open, - .dev_close = prism2_pccard_dev_close, .genesis_reset = prism2_pccard_genesis_reset, .hw_type = HOSTAP_HW_PCCARD, }; @@ -597,13 +565,14 @@ static void prism2_detach(dev_link_t *link) *linkp = link->next; /* release net devices */ if (link->priv) { + struct hostap_cs_priv *hw_priv; struct net_device *dev; struct hostap_interface *iface; dev = link->priv; iface = netdev_priv(dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; + hw_priv = iface->local->hw_priv; prism2_free_local_data(dev); + kfree(hw_priv); } kfree(link); } @@ -883,6 +852,13 @@ static int prism2_event(event_t event, int priority, { dev_link_t *link = args->client_data; struct net_device *dev = (struct net_device *) link->priv; + int dev_open = 0; + + if (link->state & DEV_CONFIG) { + struct hostap_interface *iface = netdev_priv(dev); + if (iface && iface->local) + dev_open = iface->local->num_dev_open > 0; + } switch (event) { case CS_EVENT_CARD_INSERTION: @@ -911,7 +887,7 @@ static int prism2_event(event_t event, int priority, case CS_EVENT_RESET_PHYSICAL: PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); if (link->state & DEV_CONFIG) { - if (link->open) { + if (dev_open) { netif_stop_queue(dev); netif_device_detach(dev); } @@ -931,8 +907,8 @@ static int prism2_event(event_t event, int priority, pcmcia_request_configuration(link->handle, &link->conf); prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, link->open ? 0 : 1); - if (link->open) { + prism2_hw_config(dev, dev_open ? 0 : 1); + if (dev_open) { netif_device_attach(dev); netif_start_queue(dev); } diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index e533a663deda..59fc15572395 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3322,6 +3322,18 @@ static void prism2_free_local_data(struct net_device *dev) iface = netdev_priv(dev); local = iface->local; + /* Unregister all netdevs before freeing local data. */ + list_for_each_safe(ptr, n, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type == HOSTAP_INTERFACE_MASTER) { + /* special handling for this interface below */ + continue; + } + hostap_remove_interface(iface->dev, 0, 1); + } + + unregister_netdev(local->dev); + flush_scheduled_work(); if (timer_pending(&local->crypt_deinit_timer)) @@ -3382,15 +3394,6 @@ static void prism2_free_local_data(struct net_device *dev) prism2_download_free_data(local->dl_sec); #endif /* PRISM2_DOWNLOAD_SUPPORT */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - prism2_clear_set_tim_queue(local); list_for_each_safe(ptr, n, &local->bss_list) { @@ -3403,7 +3406,6 @@ static void prism2_free_local_data(struct net_device *dev) kfree(local->last_scan_results); kfree(local->generic_elem); - unregister_netdev(local->dev); free_netdev(local->dev); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index e720369a3515..53f5246c40aa 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -50,7 +50,8 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) #endif /* in_atomic */ if (update && prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | + IW_QUAL_DBM; wstats->qual.qual = local->comms_qual; wstats->qual.level = local->avg_signal; @@ -59,7 +60,7 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) wstats->qual.qual = 0; wstats->qual.level = 0; wstats->qual.noise = 0; - wstats->qual.updated = 0; + wstats->qual.updated = IW_QUAL_ALL_INVALID; } return wstats; @@ -1827,13 +1828,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - /* FIX: - * I do not know how this is possible, but iwe_stream_add_event - * seems to re-order memcpy execution so that len is set only - * after copying.. Pre-setting len here "fixes" this, but real - * problems should be solved (after which these iwe.len - * settings could be removed from this function). */ - iwe.len = IW_EV_ADDR_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); @@ -1843,7 +1837,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ssid_len; iwe.u.data.flags = 1; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); memset(&iwe, 0, sizeof(iwe)); @@ -1859,7 +1852,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - iwe.len = IW_EV_UINT_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } @@ -1877,7 +1869,6 @@ static char * __prism2_translate_scan(local_info_t *local, if (chan > 0) { iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; iwe.u.freq.e = 1; - iwe.len = IW_EV_FREQ_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } @@ -1894,7 +1885,10 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); } - iwe.len = IW_EV_QUAL_LEN; + iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED + | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID + | IW_QUAL_DBM; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); } @@ -1906,7 +1900,6 @@ static char * __prism2_translate_scan(local_info_t *local, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ @@ -1930,7 +1923,7 @@ static char * __prism2_translate_scan(local_info_t *local, } /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); + buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); if (buf && scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 025f8cdb5566..da0c80fb941c 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -59,11 +59,13 @@ static struct pci_device_id prism2_pci_id_table[] __devinitdata = { static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); @@ -74,12 +76,14 @@ static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u8 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readb(hw_priv->mem_start + a); @@ -91,11 +95,13 @@ static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); @@ -106,12 +112,14 @@ static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u16 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readw(hw_priv->mem_start + a); @@ -277,8 +285,6 @@ static struct prism2_helper_functions prism2_pci_funcs = { .card_present = NULL, .cor_sreset = prism2_pci_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_pci_genesis_reset, .hw_type = HOSTAP_HW_PCI, }; @@ -352,8 +358,6 @@ static int prism2_pci_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (irq_registered && dev) free_irq(dev->irq, dev); @@ -364,10 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev, err_out_disable: pci_disable_device(pdev); - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); return -ENODEV; } @@ -392,9 +394,8 @@ static void prism2_pci_remove(struct pci_dev *pdev) free_irq(dev->irq, dev); mem_start = hw_priv->mem_start; - kfree(hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); iounmap(mem_start); @@ -441,7 +442,7 @@ static int prism2_pci_resume(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); static struct pci_driver prism2_pci_drv_id = { - .name = "prism2_pci", + .name = "hostap_pci", .id_table = prism2_pci_id_table, .probe = prism2_pci_probe, .remove = prism2_pci_remove, diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 474ef83d813e..78d67b408b2f 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -328,8 +328,6 @@ static struct prism2_helper_functions prism2_plx_funcs = { .card_present = NULL, .cor_sreset = prism2_plx_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_plx_genesis_reset, .hw_type = HOSTAP_HW_PLX, }; @@ -570,10 +568,8 @@ static int prism2_plx_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); if (irq_registered && dev) free_irq(dev->irq, dev); @@ -606,9 +602,8 @@ static void prism2_plx_remove(struct pci_dev *pdev) if (dev->irq) free_irq(dev->irq, dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); pci_disable_device(pdev); } @@ -616,7 +611,7 @@ static void prism2_plx_remove(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); static struct pci_driver prism2_plx_drv_id = { - .name = "prism2_plx", + .name = "hostap_plx", .id_table = prism2_plx_id_table, .probe = prism2_plx_probe, .remove = prism2_plx_remove, diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index cc061e1560d3..cfd801559492 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -552,8 +552,6 @@ struct prism2_helper_functions { * (hostap_{cs,plx,pci}.c */ int (*card_present)(local_info_t *local); void (*cor_sreset)(local_info_t *local); - int (*dev_open)(local_info_t *local); - int (*dev_close)(local_info_t *local); void (*genesis_reset)(local_info_t *local, int hcr); /* the following functions are from hostap_hw.c, but they may have some diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 2414e6493aa5..ad7f8cd76db9 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -800,8 +800,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, * doesn't seem to have as many firmware restart cycles... * * As a test, we're sticking in a 1/100s delay here */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100); + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); return 0; @@ -1256,8 +1255,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv) IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); i = 5000; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(40 * HZ / 1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(40)); /* Todo... wait for sync command ... */ read_register(priv->net_dev, IPW_REG_INTA, &inta); @@ -1411,8 +1409,7 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) (val2 & IPW2100_COMMAND_PHY_OFF)) return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_PHY_OFF_LOOP_DELAY); + schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); } return -EIO; @@ -1466,7 +1463,7 @@ fail_up: static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) { -#define HW_POWER_DOWN_DELAY (HZ / 10) +#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) struct host_command cmd = { .host_command = HOST_PRE_POWER_DOWN, @@ -1520,10 +1517,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) printk(KERN_WARNING DRV_NAME ": " "%s: Power down command failed: Error %d\n", priv->net_dev->name, err); - else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_POWER_DOWN_DELAY); - } + else + schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); } priv->status &= ~STATUS_ENABLED; @@ -2953,7 +2948,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) int next = txq->next; int i = 0; struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; while (!list_empty(&priv->tx_pend_list)) { /* if there isn't enough space in TBD queue, then @@ -2989,7 +2984,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) packet->index = txq->next; ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb-> + hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { @@ -3274,7 +3269,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data, return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev) +static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, + int pri) { struct ipw2100_priv *priv = ieee80211_priv(dev); struct list_head *element; diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 2a3cdbd50168..c9e99ce15d66 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -808,7 +808,7 @@ struct ipw2100_priv { struct ipw2100_rx { union { unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; u32 status; struct ipw2100_notification notification; struct ipw2100_cmd_header command; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b7f275c00de3..de4e6c23e4b8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4904,7 +4904,7 @@ static void ipw_rx(struct ipw_priv *priv) { struct ipw_rx_mem_buffer *rxb; struct ipw_rx_packet *pkt; - struct ieee80211_hdr *header; + struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; @@ -4967,8 +4967,9 @@ static void ipw_rx(struct ipw_priv *priv) #endif header = - (struct ieee80211_hdr *)(rxb->skb->data + - IPW_RX_FRAME_SIZE); + (struct ieee80211_hdr_4addr *)(rxb->skb-> + data + + IPW_RX_FRAME_SIZE); /* TODO: Check Ad-Hoc dest/source and make sure * that we are actually parsing these packets * correctly -- we should probably use the @@ -5317,8 +5318,6 @@ static int ipw_wx_set_freq(struct net_device *dev, IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); return ipw_set_channel(priv, (u8) fwrq->m); - - return 0; } static int ipw_wx_get_freq(struct net_device *dev, @@ -6010,12 +6009,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } if (priv->adapter == IPW_2915ABG) { - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; if (mode & IEEE_A) { band |= IEEE80211_52GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } else { if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " @@ -6023,20 +6022,20 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, return -EINVAL; } - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } if (mode & IEEE_B) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_CCK_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; if (mode & IEEE_G) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; priv->ieee->mode = mode; priv->ieee->freq_band = band; @@ -6325,7 +6324,7 @@ we need to heavily modify the ieee80211_skb_to_txb. static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) + struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; @@ -6448,7 +6447,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) } static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, - struct net_device *dev) + struct net_device *dev, int pri) { struct ipw_priv *priv = ieee80211_priv(dev); unsigned long flags; @@ -7108,7 +7107,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; @@ -7124,7 +7123,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; band = IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 5b00882133f9..e9cf32bf3e31 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1654,12 +1654,12 @@ static const long ipw_frequencies[] = { #define IPW_MAX_CONFIG_RETRIES 10 -static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr) +static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr) { u32 retval; u16 fc; - retval = sizeof(struct ieee80211_hdr); + retval = sizeof(struct ieee80211_hdr_3addr); fc = le16_to_cpu(hdr->frame_ctl); /* diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index ca6c03c89926..92793b958e32 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -57,9 +57,7 @@ #include <linux/bitops.h> #ifdef CONFIG_NET_RADIO #include <linux/wireless.h> -#if WIRELESS_EXT > 12 #include <net/iw_handler.h> -#endif /* WIRELESS_EXT > 12 */ #endif #include <pcmcia/cs_types.h> @@ -225,10 +223,7 @@ static void update_stats(struct net_device *dev); static struct net_device_stats *netwave_get_stats(struct net_device *dev); /* Wireless extensions */ -#ifdef WIRELESS_EXT static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); -#endif -static int netwave_ioctl(struct net_device *, struct ifreq *, int); static void set_multicast_list(struct net_device *dev); @@ -260,26 +255,7 @@ static dev_link_t *dev_list; because they generally can't be allocated dynamically. */ -#if WIRELESS_EXT <= 12 -/* Wireless extensions backward compatibility */ - -/* Part of iw_handler prototype we need */ -struct iw_request_info -{ - __u16 cmd; /* Wireless Extension command */ - __u16 flags; /* More to come ;-) */ -}; - -/* Wireless Extension Backward compatibility - Jean II - * If the new wireless device private ioctl range is not defined, - * default to standard device private ioctl range */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - -#else /* WIRELESS_EXT <= 12 */ static const struct iw_handler_def netwave_handler_def; -#endif /* WIRELESS_EXT <= 12 */ #define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ @@ -319,9 +295,7 @@ typedef struct netwave_private { struct timer_list watchdog; /* To avoid blocking state */ struct site_survey nss; struct net_device_stats stats; -#ifdef WIRELESS_EXT struct iw_statistics iw_stats; /* Wireless stats */ -#endif } netwave_private; #ifdef NETWAVE_STATS @@ -353,7 +327,6 @@ static inline void wait_WOC(unsigned int iobase) while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; } -#ifdef WIRELESS_EXT static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, kio_addr_t iobase) { u_short resultBuffer; @@ -376,9 +349,7 @@ static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, sizeof(struct site_survey)); } } -#endif -#ifdef WIRELESS_EXT /* * Function netwave_get_wireless_stats (dev) * @@ -411,7 +382,6 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) return &priv->iw_stats; } -#endif /* * Function netwave_attach (void) @@ -471,13 +441,7 @@ static dev_link_t *netwave_attach(void) dev->get_stats = &netwave_get_stats; dev->set_multicast_list = &set_multicast_list; /* wireless extensions */ -#if WIRELESS_EXT <= 16 - dev->get_wireless_stats = &netwave_get_wireless_stats; -#endif /* WIRELESS_EXT <= 16 */ -#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; -#endif /* WIRELESS_EXT > 12 */ - dev->do_ioctl = &netwave_ioctl; dev->tx_timeout = &netwave_watchdog; dev->watchdog_timeo = TX_TIMEOUT; @@ -576,13 +540,8 @@ static int netwave_set_nwid(struct net_device *dev, /* Disable interrupts & save flags */ spin_lock_irqsave(&priv->spinlock, flags); -#if WIRELESS_EXT > 8 if(!wrqu->nwid.disabled) { domain = wrqu->nwid.value; -#else /* WIRELESS_EXT > 8 */ - if(wrqu->nwid.on) { - domain = wrqu->nwid.nwid; -#endif /* WIRELESS_EXT > 8 */ printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); wait_WOC(iobase); @@ -606,15 +565,9 @@ static int netwave_get_nwid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { -#if WIRELESS_EXT > 8 wrqu->nwid.value = domain; wrqu->nwid.disabled = 0; wrqu->nwid.fixed = 1; -#else /* WIRELESS_EXT > 8 */ - wrqu->nwid.nwid = domain; - wrqu->nwid.on = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } @@ -657,17 +610,11 @@ static int netwave_get_scramble(struct net_device *dev, { key[1] = scramble_key & 0xff; key[0] = (scramble_key>>8) & 0xff; -#if WIRELESS_EXT > 8 wrqu->encoding.flags = IW_ENCODE_ENABLED; wrqu->encoding.length = 2; -#else /* WIRELESS_EXT > 8 */ - wrqu->encoding.method = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } -#if WIRELESS_EXT > 8 /* * Wireless Handler : get mode */ @@ -683,7 +630,6 @@ static int netwave_get_mode(struct net_device *dev, return 0; } -#endif /* WIRELESS_EXT > 8 */ /* * Wireless Handler : get range info @@ -702,11 +648,9 @@ static int netwave_get_range(struct net_device *dev, /* Set all the info we don't care or don't know about to zero */ memset(range, 0, sizeof(struct iw_range)); -#if WIRELESS_EXT > 10 /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 9; /* Nothing for us in v10 and v11 */ -#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range->throughput = 450 * 1000; /* don't argue on this ! */ @@ -720,16 +664,12 @@ static int netwave_get_range(struct net_device *dev, range->max_qual.level = 255; range->max_qual.noise = 0; -#if WIRELESS_EXT > 7 range->num_bitrates = 1; range->bitrate[0] = 1000000; /* 1 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ -#if WIRELESS_EXT > 8 range->encoding_size[0] = 2; /* 16 bits scrambling */ range->num_encoding_sizes = 1; range->max_encoding_tokens = 1; /* Only one key possible */ -#endif /* WIRELESS_EXT > 8 */ return ret; } @@ -775,8 +715,6 @@ static const struct iw_priv_args netwave_private_args[] = { "getsitesurvey" }, }; -#if WIRELESS_EXT > 12 - static const iw_handler netwave_handler[] = { NULL, /* SIOCSIWNAME */ @@ -839,131 +777,8 @@ static const struct iw_handler_def netwave_handler_def = .standard = (iw_handler *) netwave_handler, .private = (iw_handler *) netwave_private_handler, .private_args = (struct iw_priv_args *) netwave_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = netwave_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ }; -#endif /* WIRELESS_EXT > 12 */ - -/* - * Function netwave_ioctl (dev, rq, cmd) - * - * Perform ioctl : config & info stuff - * This is the stuff that are treated the wireless extensions (iwconfig) - * - */ -static int netwave_ioctl(struct net_device *dev, /* ioctl device */ - struct ifreq *rq, /* Data passed */ - int cmd) /* Ioctl number */ -{ - int ret = 0; -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - struct iwreq *wrq = (struct iwreq *) rq; -#endif -#endif - - DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); - - /* Look what is the request */ - switch(cmd) { - /* --------------- WIRELESS EXTENSIONS --------------- */ -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - case SIOCGIWNAME: - netwave_get_name(dev, NULL, &(wrq->u), NULL); - break; - case SIOCSIWNWID: - ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); - break; - case SIOCGIWNWID: - ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); - break; -#if WIRELESS_EXT > 8 /* Note : The API did change... */ - case SIOCGIWENCODE: - /* Get scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); - if(copy_to_user(wrq->u.encoding.pointer, key, 2)) - ret = -EFAULT; - } - break; - case SIOCSIWENCODE: - /* Set scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - if(copy_from_user(key, wrq->u.encoding.pointer, 2)) - { - ret = -EFAULT; - break; - } - ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); - } - break; - case SIOCGIWMODE: - /* Mode of operation */ - ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); - break; -#else /* WIRELESS_EXT > 8 */ - case SIOCGIWENCODE: - /* Get scramble key */ - ret = netwave_get_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; - case SIOCSIWENCODE: - /* Set scramble key */ - ret = netwave_set_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; -#endif /* WIRELESS_EXT > 8 */ - case SIOCGIWRANGE: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); - if (copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; - } - break; - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - /* Set the number of ioctl available */ - wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - (u_char *) netwave_private_args, - sizeof(netwave_private_args))) - ret = -EFAULT; - } - break; - case SIOCGIPSNAP: - if(wrq->u.data.pointer != (caddr_t) 0) { - char buffer[sizeof( struct site_survey)]; - ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - buffer, - sizeof( struct site_survey))) - { - printk(KERN_DEBUG "Bad buffer!\n"); - break; - } - } - break; -#endif /* WIRELESS_EXT <= 12 */ -#endif /* WIRELESS_EXT */ - default: - ret = -EOPNOTSUPP; - } - - return ret; -} /* * Function netwave_pcmcia_config (link) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 15ceaf615756..d3d4ec9e242e 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -77,30 +77,16 @@ #define DRIVER_NAME "orinoco" #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> #include <linux/netdevice.h> -#include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/wireless.h> #include <net/iw_handler.h> #include <net/ieee80211.h> -#include <net/ieee80211.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - -#include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" @@ -137,7 +123,7 @@ MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); /* We do this this way to avoid ifdefs in the actual code */ #ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_number) +#define SPY_NUMBER(priv) (priv->spy_data.spy_number) #else #define SPY_NUMBER(priv) 0 #endif /* WIRELESS_SPY */ @@ -216,31 +202,32 @@ static struct { /********************************************************************/ /* Used in Event handling. - * We avoid nested structres as they break on ARM -- Moustafa */ + * We avoid nested structures as they break on ARM -- Moustafa */ struct hermes_tx_descriptor_802_11 { /* hermes_tx_descriptor */ - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; - /* ieee802_11_hdr */ - u16 frame_ctl; - u16 duration_id; + /* ieee80211_hdr */ + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; - u16 data_len; + + __le16 data_len; /* ethhdr */ - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ + u8 h_dest[ETH_ALEN]; /* destination eth addr */ + u8 h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ /* p8022_hdr */ u8 dsap; @@ -248,31 +235,31 @@ struct hermes_tx_descriptor_802_11 { u8 ctrl; u8 oui[3]; - u16 ethertype; + __be16 ethertype; } __attribute__ ((packed)); /* Rx frame header except compatibility 802.3 header */ struct hermes_rx_descriptor { /* Control */ - u16 status; - u32 time; + __le16 status; + __le32 time; u8 silence; u8 signal; u8 rate; u8 rxflow; - u32 reserved; + __le32 reserved; /* 802.11 header */ - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; /* Data length */ - u16 data_len; + __le16 data_len; } __attribute__ ((packed)); /********************************************************************/ @@ -396,14 +383,14 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) /* If a spy address is defined, we report stats of the * first spy address - Jean II */ if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; + wstats->qual.qual = priv->spy_data.spy_stat[0].qual; + wstats->qual.level = priv->spy_data.spy_stat[0].level; + wstats->qual.noise = priv->spy_data.spy_stat[0].noise; + wstats->qual.updated = priv->spy_data.spy_stat[0].updated; } } else { struct { - u16 qual, signal, noise; + __le16 qual, signal, noise; } __attribute__ ((packed)) cq; err = HERMES_READ_RECORD(hw, USER_BAP, @@ -505,11 +492,9 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) /* Check packet length, pad short packets, round up odd length */ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); - if (skb->len < len) { - skb = skb_padto(skb, len); - if (skb == NULL) - goto fail; - } + skb = skb_padto(skb, len); + if (skb == NULL) + goto fail; len -= ETH_HLEN; eh = (struct ethhdr *)skb->data; @@ -634,16 +619,17 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); + u16 status; struct hermes_tx_descriptor_802_11 hdr; int err = 0; if (fid == DUMMY_FID) return; /* Nothing's really happened */ - /* Read the frame header */ + /* Read part of the frame header - we need status and addr1 */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_tx_descriptor) + - sizeof(struct ieee80211_hdr), + offsetof(struct hermes_tx_descriptor_802_11, + addr2), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); @@ -663,8 +649,8 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ - hdr.status = le16_to_cpu(hdr.status); - if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { + status = le16_to_cpu(hdr.status); + if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { union iwreq_data wrqu; /* Copy 802.11 dest address. @@ -723,18 +709,13 @@ static inline int is_ethersnap(void *_hdr) static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - struct orinoco_private *priv = netdev_priv(dev); - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].level = level - 0x95; - priv->spy_stat[i].noise = noise - 0x95; - priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; - priv->spy_stat[i].updated = 7; - } + struct iw_quality wstats; + wstats.level = level - 0x95; + wstats.noise = noise - 0x95; + wstats.qual = (level > noise) ? (level - noise) : 0; + wstats.updated = 7; + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); } static void orinoco_stat_gather(struct net_device *dev, @@ -1055,7 +1036,7 @@ static void orinoco_join_ap(struct net_device *dev) unsigned long flags; struct join_req { u8 bssid[ETH_ALEN]; - u16 channel; + __le16 channel; } __attribute__ ((packed)) req; const int atom_len = offsetof(struct prism2_scan_apinfo, atim); struct prism2_scan_apinfo *atom = NULL; @@ -1070,7 +1051,7 @@ static void orinoco_join_ap(struct net_device *dev) return; if (orinoco_lock(priv, &flags) != 0) - goto out; + goto fail_lock; /* Sanity checks in case user changed something in the meantime */ if (! priv->bssid_fixed) @@ -1115,8 +1096,10 @@ static void orinoco_join_ap(struct net_device *dev) printk(KERN_ERR "%s: Error issuing join request\n", dev->name); out: - kfree(buf); orinoco_unlock(priv, &flags); + + fail_lock: + kfree(buf); } /* Send new BSSID to userspace */ @@ -1134,12 +1117,14 @@ static void orinoco_send_wevents(struct net_device *dev) err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) - return; + goto out; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + + out: orinoco_unlock(priv, &flags); } @@ -1148,8 +1133,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); u16 infofid; struct { - u16 len; - u16 type; + __le16 len; + __le16 type; } __attribute__ ((packed)) info; int len, type; int err; @@ -2464,6 +2449,10 @@ struct net_device *alloc_orinocodev(int sizeof_card, dev->get_stats = orinoco_get_stats; dev->ethtool_ops = &orinoco_ethtool_ops; dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; +#ifdef WIRELESS_SPY + priv->wireless_data.spy_data = &priv->spy_data; + dev->wireless_data = &priv->wireless_data; +#endif dev->change_mtu = orinoco_change_mtu; dev->set_multicast_list = orinoco_set_multicast_list; /* we use the default eth_mac_addr for setting the MAC addr */ @@ -2835,7 +2824,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, } } - if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ /* Quality stats meaningless in ad-hoc mode */ } else { range->max_qual.qual = 0x8b - 0x2f; @@ -2882,6 +2871,14 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, range->min_r_time = 0; range->max_r_time = 65535 * 1000; /* ??? */ + /* Event capability (kernel) */ + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + /* Event capability (driver) */ + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + TRACE_EXIT(dev->name); return 0; @@ -3841,92 +3838,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Spy is used for link quality/strength measurements in Ad-Hoc mode - * Jean II */ -static int orinoco_ioctl_setspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) - -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number = srq->length; - int i; - unsigned long flags; - - /* Make sure nobody mess with the structure while we do */ - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* orinoco_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Now, let the others play */ - orinoco_unlock(priv, &flags); - - /* Do NOT call commit handler */ - return 0; -} - -static int orinoco_ioctl_getspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - number = priv->spy_number; - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - if (number > 0) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path might update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(extra + (sizeof(struct sockaddr) * number), - priv->spy_stat, sizeof(struct iw_quality) * number); - } - /* Reset updated flags. */ - for (i = 0; i < number; i++) - priv->spy_stat[i].updated = 0; - - orinoco_unlock(priv, &flags); - - srq->length = number; - - return 0; -} - /* Trigger a scan (look for other cells in the vicinity */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, @@ -3999,7 +3910,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, HERMES_HOSTSCAN_SYMBOL_BCAST); break; case FIRMWARE_TYPE_INTERSIL: { - u16 req[3]; + __le16 req[3]; req[0] = cpu_to_le16(0x3fff); /* All channels */ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ @@ -4073,7 +3984,7 @@ static inline int orinoco_translate_scan(struct net_device *dev, case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) { - atom_len = le16_to_cpup((u16 *)scan); + atom_len = le16_to_cpup((__le16 *)scan); /* Sanity check for atom_len */ if (atom_len < sizeof(struct prism2_scan_apinfo)) { printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", @@ -4357,8 +4268,10 @@ static const iw_handler orinoco_handler[] = { [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy, - [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 2f213a7103fe..7a17bb31fc89 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -7,12 +7,11 @@ #ifndef _ORINOCO_H #define _ORINOCO_H -#define DRIVER_VERSION "0.15rc2" +#define DRIVER_VERSION "0.15rc3" -#include <linux/types.h> -#include <linux/spinlock.h> #include <linux/netdevice.h> #include <linux/wireless.h> +#include <net/iw_handler.h> #include <linux/version.h> #include "hermes.h" @@ -28,7 +27,7 @@ #define ORINOCO_MAX_KEYS 4 struct orinoco_key { - u16 len; /* always stored as little-endian */ + __le16 len; /* always stored as little-endian */ char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); @@ -36,14 +35,14 @@ struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; - u16 len; + __be16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; - u16 ethertype; + unsigned short ethertype; } __attribute__ ((packed)); typedef enum { @@ -112,9 +111,8 @@ struct orinoco_private { u16 pm_on, pm_mcast, pm_period, pm_timeout; u16 preamble; #ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; + struct iw_spy_data spy_data; /* iwspy support */ + struct iw_public_data wireless_data; #endif /* Configuration dependent variables */ diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index bedd7f9f23e4..dc1128a00971 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -14,33 +14,16 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif /* __IN_PCMCIA_PACKAGE__ */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - +#include <linux/delay.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - #include "orinoco.h" /********************************************************************/ @@ -97,17 +80,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int orinoco_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void orinoco_cs_config(dev_link_t * link); -static void orinoco_cs_release(dev_link_t * link); -static int orinoco_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *orinoco_cs_attach(void); -static void orinoco_cs_detach(dev_link_t *); +static void orinoco_cs_release(dev_link_t *link); +static void orinoco_cs_detach(dev_link_t *link); /********************************************************************/ /* Device methods */ @@ -603,49 +577,85 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION "Pavel Roskin <proski@gnu.org>, et al)"; static struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ + PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ + PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ + PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ + PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ + PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ + PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ + PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ + PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), + PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), + PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), + PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), + PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), + PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), + PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), + PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), + PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), + PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); @@ -656,8 +666,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, - .event = orinoco_cs_event, .detach = orinoco_cs_detach, + .event = orinoco_cs_event, .id_table = orinoco_cs_ids, }; diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 86fa58e5cfac..d8afd51ff8a5 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -40,29 +40,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ @@ -108,7 +92,7 @@ static int nortel_pci_cor_reset(struct orinoco_private *priv) return 0; } -int nortel_pci_hw_init(struct nortel_pci_card *card) +static int nortel_pci_hw_init(struct nortel_pci_card *card) { int i; u32 reg; diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 42e03438291b..5362c214fc8e 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -93,28 +93,12 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include "hermes.h" #include "orinoco.h" /* All the magic there is from wlan-ng */ diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 7ab05b89fb3f..210e73776545 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -117,29 +117,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 85893f42445b..5e68b7026186 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -53,29 +53,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 9a8790e3580c..5c1a1adf1ff8 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -462,14 +462,12 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info, /* txpower is supported in dBm's */ range->txpower_capa = IW_TXPOW_DBM; -#if WIRELESS_EXT > 16 /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); -#endif /* WIRELESS_EXT > 16 */ if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; @@ -693,14 +691,13 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, extra + dwrq->length, &(bsslist->bsslist[i]), noise); -#if WIRELESS_EXT > 16 + /* Check if there is space for one more entry */ if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { /* Ask user space to try again with a bigger buffer */ rvalue = -E2BIG; break; } -#endif /* WIRELESS_EXT > 16 */ } kfree(bsslist); @@ -2727,12 +2724,7 @@ const struct iw_handler_def prism54_handler_def = { .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = prism54_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ -#if WIRELESS_EXT == 16 - .spy_offset = offsetof(islpci_private, spy_data), -#endif /* WIRELESS_EXT == 16 */ }; /* For wpa_supplicant */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 6f13d4a8e2d3..6c9584a9f284 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -439,8 +439,7 @@ prism54_bring_down(islpci_private *priv) wmb(); /* wait a while for the device to reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50*HZ/1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(50)); return 0; } @@ -491,8 +490,7 @@ islpci_reset_if(islpci_private *priv) /* The software reset acknowledge needs about 220 msec here. * Be conservative and wait for up to one second. */ - set_current_state(TASK_UNINTERRUPTIBLE); - remaining = schedule_timeout(HZ); + remaining = schedule_timeout_uninterruptible(HZ); if(remaining > 0) { result = 0; @@ -839,13 +837,9 @@ islpci_setup(struct pci_dev *pdev) priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? priv->monitor_type : ARPHRD_ETHER; -#if WIRELESS_EXT > 16 /* Add pointers to enable iwspy support. */ priv->wireless_data.spy_data = &priv->spy_data; ndev->wireless_data = &priv->wireless_data; -#else /* WIRELESS_EXT > 16 */ - ndev->get_wireless_stats = &prism54_get_wireless_stats; -#endif /* WIRELESS_EXT > 16 */ /* save the start and end address of the PCI memory area */ ndev->mem_start = (unsigned long) priv->device_base; diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 32a1019f1b36..efbed4397951 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -100,9 +100,7 @@ typedef struct { struct iw_spy_data spy_data; /* iwspy support */ -#if WIRELESS_EXT > 16 struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT > 16 */ int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index b6f2e5a223be..4937a5ad4b2c 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -455,7 +455,7 @@ islpci_mgt_transaction(struct net_device *ndev, struct islpci_mgmtframe **recvframe) { islpci_private *priv = netdev_priv(ndev); - const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10); long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; int err; DEFINE_WAIT(wait); @@ -475,8 +475,7 @@ islpci_mgt_transaction(struct net_device *ndev, int timeleft; struct islpci_mgmtframe *frame; - set_current_state(TASK_UNINTERRUPTIBLE); - timeleft = schedule_timeout(wait_cycle_jiffies); + timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies); frame = xchg(&priv->mgmt_received, NULL); if (frame) { if (frame->header->oid == oid) { diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e9c5ea0f5535..70fd6fd8feb9 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1649,28 +1649,28 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev) */ static const iw_handler ray_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit, - [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) ray_get_name, - [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) ray_set_freq, - [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) ray_get_freq, - [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) ray_set_mode, - [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) ray_get_mode, - [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range, + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) ray_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) ray_get_name, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) ray_set_freq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) ray_get_freq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) ray_set_mode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) ray_get_mode, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) ray_get_range, #ifdef WIRELESS_SPY - [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_set_spy, - [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_get_spy, - [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy, - [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, #endif /* WIRELESS_SPY */ - [SIOCGIWAP -SIOCIWFIRST] (iw_handler) ray_get_wap, - [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid, - [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid, - [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) ray_set_rate, - [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) ray_get_rate, - [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) ray_set_rts, - [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) ray_get_rts, - [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) ray_set_frag, - [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) ray_get_frag, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) ray_get_wap, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) ray_set_essid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) ray_get_essid, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) ray_set_rate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) ray_get_rate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) ray_set_rts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) ray_get_rts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) ray_set_frag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) ray_get_frag, }; #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ @@ -1678,9 +1678,9 @@ static const iw_handler ray_handler[] = { #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ static const iw_handler ray_private_handler[] = { - [0] (iw_handler) ray_set_framing, - [1] (iw_handler) ray_get_framing, - [3] (iw_handler) ray_get_country, + [0] = (iw_handler) ray_set_framing, + [1] = (iw_handler) ray_get_framing, + [3] = (iw_handler) ray_get_country, }; static const struct iw_priv_args ray_private_args[] = { diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 39c6cdf7f3f7..b1bbc8e8e91f 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -22,58 +22,23 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif /* __IN_PCMCIA_PACKAGE__ */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - +#include <linux/delay.h> +#include <linux/firmware.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - #include "orinoco.h" -/* - * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into - * the driver. Use get_symbol_fw script to generate spectrum_fw.h and - * copy it to the same directory as spectrum_cs.c. - * - * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the - * runtime using hotplug. Use the same get_symbol_fw script to generate - * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the - * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and - * make sure that you have hotplug installed and enabled in the kernel. - */ -/* #define SPECTRUM_FW_INCLUDED 1 */ - -#ifdef SPECTRUM_FW_INCLUDED -/* Header with the firmware */ -#include "spectrum_fw.h" -#else /* !SPECTRUM_FW_INCLUDED */ -#include <linux/firmware.h> static unsigned char *primsym; static unsigned char *secsym; static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; -#endif /* !SPECTRUM_FW_INCLUDED */ /********************************************************************/ /* Module stuff */ @@ -124,17 +89,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int spectrum_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void spectrum_cs_config(dev_link_t * link); -static void spectrum_cs_release(dev_link_t * link); -static int spectrum_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *spectrum_cs_attach(void); -static void spectrum_cs_detach(dev_link_t *); +static void spectrum_cs_release(dev_link_t *link); +static void spectrum_cs_detach(dev_link_t *link); /********************************************************************/ /* Firmware downloader */ @@ -182,8 +138,8 @@ static void spectrum_cs_detach(dev_link_t *); * Each block has the following structure. */ struct dblock { - u32 _addr; /* adapter address where to write the block */ - u16 _len; /* length of the data only, in bytes */ + __le32 _addr; /* adapter address where to write the block */ + __le16 _len; /* length of the data only, in bytes */ char data[0]; /* data to be written */ } __attribute__ ((packed)); @@ -193,9 +149,9 @@ struct dblock { * items with matching ID should be written. */ struct pdr { - u32 _id; /* record ID */ - u32 _addr; /* adapter address where to write the data */ - u32 _len; /* expected length of the data, in bytes */ + __le32 _id; /* record ID */ + __le32 _addr; /* adapter address where to write the data */ + __le32 _len; /* expected length of the data, in bytes */ char next[0]; /* next PDR starts here */ } __attribute__ ((packed)); @@ -206,8 +162,8 @@ struct pdr { * be plugged into the secondary firmware. */ struct pdi { - u16 _len; /* length of ID and data, in words */ - u16 _id; /* record ID */ + __le16 _len; /* length of ID and data, in words */ + __le16 _id; /* record ID */ char data[0]; /* plug data */ } __attribute__ ((packed));; @@ -414,7 +370,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) /* Read PDA from the adapter */ static int -spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) +spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) { int ret; int pda_size; @@ -445,7 +401,7 @@ spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) /* Parse PDA and write the records into the adapter */ static int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - u16 *pda) + __le16 *pda) { int ret; struct pdi *pdi; @@ -511,7 +467,7 @@ spectrum_dl_image(hermes_t *hw, dev_link_t *link, const struct dblock *first_block; /* Plug Data Area (PDA) */ - u16 pda[PDA_WORDS]; + __le16 pda[PDA_WORDS]; /* Binary block begins after the 0x1A marker */ ptr = image; @@ -571,8 +527,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) { int ret; client_handle_t handle = link->handle; - -#ifndef SPECTRUM_FW_INCLUDED const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, @@ -592,7 +546,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) secondary_fw_name); return -ENOENT; } -#endif /* Load primary firmware */ ret = spectrum_dl_image(hw, link, primsym); @@ -1085,7 +1038,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static struct pcmcia_device_id spectrum_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */ + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); @@ -1096,8 +1049,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = spectrum_cs_attach, - .event = spectrum_cs_event, .detach = spectrum_cs_detach, + .event = spectrum_cs_event, .id_table = spectrum_cs_ids, }; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 7a5e20a17890..b0d8b5b03152 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -430,7 +430,6 @@ static void fee_read(unsigned long ioaddr, /* I/O port of the card */ } } -#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ /*------------------------------------------------------------------*/ /* @@ -514,7 +513,6 @@ static void fee_write(unsigned long ioaddr, /* I/O port of the card */ fee_wait(ioaddr, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /************************ I82586 SUBROUTINES *************************/ /* @@ -973,11 +971,9 @@ static void wv_mmc_show(struct net_device * dev) mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1499,7 +1495,6 @@ static int wavelan_set_mac_address(struct net_device * dev, void *addr) } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2473,7 +2468,6 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4194,11 +4188,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 509ff22a6caa..166e28b9a4f7 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -409,11 +409,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ /* Warning: this stuff will slow down the driver. */ #define WIRELESS_SPY /* Enable spying addresses. */ #undef HISTOGRAM /* Enable histogram of signal level. */ -#endif /****************************** DEBUG ******************************/ @@ -506,12 +504,10 @@ struct net_local u_short tx_first_free; u_short tx_first_in_use; -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless-specific statistics */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* number of intervals */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 183c4732ef65..4b3c98f5c564 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -415,7 +415,6 @@ fee_read(u_long base, /* i/o port of the card */ } } -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -500,7 +499,6 @@ fee_write(u_long base, /* i/o port of the card */ fee_wait(base, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /******************* WaveLAN Roaming routines... ********************/ @@ -1161,10 +1159,8 @@ wv_mmc_show(struct net_device * dev) mmc_read(base, 0, (u_char *)&m, sizeof(m)); mmc_out(base, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -1550,7 +1546,6 @@ wavelan_set_mac_address(struct net_device * dev, } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2793,7 +2788,6 @@ wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4679,11 +4673,9 @@ wavelan_attach(void) dev->watchdog_timeo = WATCHDOG_JIFFIES; SET_ETHTOOL_OPS(dev, &ops); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif /* Other specific data */ dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 01d882be8790..724a715089c9 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -472,11 +472,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Warning : these stuff will slow down the driver... */ #define WIRELESS_SPY /* Enable spying addresses */ #undef HISTOGRAM /* Enable histogram of sig level... */ -#endif /****************************** DEBUG ******************************/ @@ -624,12 +622,10 @@ struct net_local int rfp; /* Last DMA machine receive pointer */ int overrunning; /* Receiver overrun flag */ -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless specific stats */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* Number of intervals */ diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 7fcbe589c3f2..4303c50c2ab6 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; + struct ieee80211_hdr_4addr mac_hdr; } __attribute__ ((packed)); /* diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 0e98a9d9834c..a3bd91a61827 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -836,7 +836,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * This function implements the pci_alloc_consistent function. */ static void * -ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) +ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *ret; #if 0 diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 82ea68b55df4..bd8b3e5a5cd7 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -986,7 +986,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * See Documentation/DMA-mapping.txt */ static void *sba_alloc_consistent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, int gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index bb90a1448a53..81ded52c8959 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -122,7 +122,7 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) static int pcmcia_probe(struct sa1111_dev *dev) { - char *base; + void __iomem *base; if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index fa09440d82e5..38f50b7129a2 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -16,7 +16,7 @@ MODULE_LICENSE("GPL"); fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, - int nr_events, const fsm_node *tmpl, int tmpl_len, int order) + int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order) { int i; fsm_instance *this; diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h index f9a011001eb6..1b8a7e7c34f3 100644 --- a/drivers/s390/net/fsm.h +++ b/drivers/s390/net/fsm.h @@ -110,7 +110,7 @@ extern fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, int nr_events, const fsm_node *tmpl, - int tmpl_len, int order); + int tmpl_len, gfp_t order); /** * Releases an FSM diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 9963479ba89f..38a2441564d7 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -275,6 +275,10 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \ QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \ QETH_MAX_QUEUES,0x103}, \ + {0x1731,0x06,0x1732,0x06,QETH_CARD_TYPE_OSN,0, \ + QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \ + QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \ + QETH_MAX_QUEUES,0}, \ {0,0,0,0,0,0,0,0,0}} #define QETH_REAL_CARD 1 @@ -363,10 +367,22 @@ struct qeth_hdr_layer2 { __u8 reserved2[16]; } __attribute__ ((packed)); +struct qeth_hdr_osn { + __u8 id; + __u8 reserved; + __u16 seq_no; + __u16 reserved2; + __u16 control_flags; + __u16 pdu_length; + __u8 reserved3[18]; + __u32 ccid; +} __attribute__ ((packed)); + struct qeth_hdr { union { struct qeth_hdr_layer2 l2; struct qeth_hdr_layer3 l3; + struct qeth_hdr_osn osn; } hdr; } __attribute__ ((packed)); @@ -413,6 +429,7 @@ enum qeth_header_ids { QETH_HEADER_TYPE_LAYER3 = 0x01, QETH_HEADER_TYPE_LAYER2 = 0x02, QETH_HEADER_TYPE_TSO = 0x03, + QETH_HEADER_TYPE_OSN = 0x04, }; /* flags for qeth_hdr.ext_flags */ #define QETH_HDR_EXT_VLAN_FRAME 0x01 @@ -582,7 +599,6 @@ enum qeth_card_states { * Protocol versions */ enum qeth_prot_versions { - QETH_PROT_SNA = 0x0001, QETH_PROT_IPV4 = 0x0004, QETH_PROT_IPV6 = 0x0006, }; @@ -761,6 +777,11 @@ enum qeth_threads { QETH_RECOVER_THREAD = 2, }; +struct qeth_osn_info { + int (*assist_cb)(struct net_device *dev, void *data); + int (*data_cb)(struct sk_buff *skb); +}; + struct qeth_card { struct list_head list; enum qeth_card_states state; @@ -803,6 +824,7 @@ struct qeth_card { int use_hard_stop; int (*orig_hard_header)(struct sk_buff *,struct net_device *, unsigned short,void *,void *,unsigned); + struct qeth_osn_info osn_info; }; struct qeth_card_list_struct { @@ -916,10 +938,12 @@ qeth_get_hlen(__u8 link_type) static inline unsigned short qeth_get_netdev_flags(struct qeth_card *card) { - if (card->options.layer2) + if (card->options.layer2 && + (card->info.type == QETH_CARD_TYPE_OSAE)) return 0; switch (card->info.type) { case QETH_CARD_TYPE_IQD: + case QETH_CARD_TYPE_OSN: return IFF_NOARP; #ifdef CONFIG_QETH_IPV6 default: @@ -956,9 +980,10 @@ static inline int qeth_get_max_mtu_for_card(int cardtype) { switch (cardtype) { + case QETH_CARD_TYPE_UNKNOWN: - return 61440; case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: return 61440; case QETH_CARD_TYPE_IQD: return 57344; @@ -1004,6 +1029,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu) case QETH_CARD_TYPE_IQD: return ((mtu >= 576) && (mtu <= card->info.max_mtu + 4096 - 32)); + case QETH_CARD_TYPE_OSN: case QETH_CARD_TYPE_UNKNOWN: default: return 1; @@ -1015,6 +1041,7 @@ qeth_get_arphdr_type(int cardtype, int linktype) { switch (cardtype) { case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: switch (linktype) { case QETH_LINK_TYPE_LANE_TR: case QETH_LINK_TYPE_HSTR: @@ -1182,4 +1209,16 @@ qeth_fill_header(struct qeth_card *, struct qeth_hdr *, extern void qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int); +extern int +qeth_osn_assist(struct net_device *, void *, int); + +extern int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)); + +extern void +qeth_osn_deregister(struct net_device *); + #endif /* __QETH_H__ */ diff --git a/drivers/s390/net/qeth_fs.h b/drivers/s390/net/qeth_fs.h index 5c9a51ce91b6..c0b4c8d82c45 100644 --- a/drivers/s390/net/qeth_fs.h +++ b/drivers/s390/net/qeth_fs.h @@ -12,7 +12,7 @@ #ifndef __QETH_FS_H__ #define __QETH_FS_H__ -#define VERSION_QETH_FS_H "$Revision: 1.9 $" +#define VERSION_QETH_FS_H "$Revision: 1.10 $" extern const char *VERSION_QETH_PROC_C; extern const char *VERSION_QETH_SYS_C; @@ -43,6 +43,12 @@ extern void qeth_remove_device_attributes(struct device *dev); extern int +qeth_create_device_attributes_osn(struct device *dev); + +extern void +qeth_remove_device_attributes_osn(struct device *dev); + +extern int qeth_create_driver_attributes(void); extern void @@ -108,6 +114,8 @@ qeth_get_cardname(struct qeth_card *card) return " OSD Express"; case QETH_CARD_TYPE_IQD: return " HiperSockets"; + case QETH_CARD_TYPE_OSN: + return " OSN QDIO"; default: return " unknown"; } @@ -153,6 +161,8 @@ qeth_get_cardname_short(struct qeth_card *card) } case QETH_CARD_TYPE_IQD: return "HiperSockets"; + case QETH_CARD_TYPE_OSN: + return "OSN"; default: return "unknown"; } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index bd28e2438d7f..692003c9f896 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -196,7 +196,6 @@ qeth_notifier_register(struct task_struct *p, int signum) { struct qeth_notify_list_struct *n_entry; - /*check first if entry already exists*/ spin_lock(&qeth_notify_lock); list_for_each_entry(n_entry, &qeth_notify_list, list) { @@ -1024,7 +1023,10 @@ qeth_set_intial_options(struct qeth_card *card) card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.fake_ll = 0; - card->options.layer2 = 0; + if (card->info.type == QETH_CARD_TYPE_OSN) + card->options.layer2 = 1; + else + card->options.layer2 = 0; } /** @@ -1113,19 +1115,20 @@ qeth_determine_card_type(struct qeth_card *card) QETH_DBF_TEXT(setup, 2, "detcdtyp"); + card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; while (known_devices[i][4]) { if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) && (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) { card->info.type = known_devices[i][4]; + card->qdio.no_out_queues = known_devices[i][8]; + card->info.is_multicast_different = known_devices[i][9]; if (is_1920_device(card)) { PRINT_INFO("Priority Queueing not able " "due to hardware limitations!\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; - } else { - card->qdio.no_out_queues = known_devices[i][8]; - } - card->info.is_multicast_different = known_devices[i][9]; + } return 0; } i++; @@ -1149,6 +1152,8 @@ qeth_probe_device(struct ccwgroup_device *gdev) if (!get_device(dev)) return -ENODEV; + QETH_DBF_TEXT_(setup, 2, "%s", gdev->dev.bus_id); + card = qeth_alloc_card(); if (!card) { put_device(dev); @@ -1158,28 +1163,27 @@ qeth_probe_device(struct ccwgroup_device *gdev) card->read.ccwdev = gdev->cdev[0]; card->write.ccwdev = gdev->cdev[1]; card->data.ccwdev = gdev->cdev[2]; - - if ((rc = qeth_setup_card(card))){ - QETH_DBF_TEXT_(setup, 2, "2err%d", rc); - put_device(dev); - qeth_free_card(card); - return rc; - } gdev->dev.driver_data = card; card->gdev = gdev; gdev->cdev[0]->handler = qeth_irq; gdev->cdev[1]->handler = qeth_irq; gdev->cdev[2]->handler = qeth_irq; - rc = qeth_create_device_attributes(dev); - if (rc) { + if ((rc = qeth_determine_card_type(card))){ + PRINT_WARN("%s: not a valid card type\n", __func__); + QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + put_device(dev); + qeth_free_card(card); + return rc; + } + if ((rc = qeth_setup_card(card))){ + QETH_DBF_TEXT_(setup, 2, "2err%d", rc); put_device(dev); qeth_free_card(card); return rc; } - if ((rc = qeth_determine_card_type(card))){ - PRINT_WARN("%s: not a valid card type\n", __func__); - QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + rc = qeth_create_device_attributes(dev); + if (rc) { put_device(dev); qeth_free_card(card); return rc; @@ -1660,6 +1664,8 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) netif_carrier_on(card->dev); qeth_schedule_recovery(card); return NULL; + case IPA_CMD_MODCCID: + return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: QETH_DBF_TEXT(trace,3, "irla"); break; @@ -1721,6 +1727,14 @@ qeth_send_control_data_cb(struct qeth_channel *channel, cmd = qeth_check_ipa_data(card, iob); if ((cmd == NULL) && (card->state != CARD_STATE_DOWN)) goto out; + /*in case of OSN : check if cmd is set */ + if (card->info.type == QETH_CARD_TYPE_OSN && + cmd && + cmd->hdr.command != IPA_CMD_STARTLAN && + card->osn_info.assist_cb != NULL) { + card->osn_info.assist_cb(card->dev, cmd); + goto out; + } spin_lock_irqsave(&card->lock, flags); list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { @@ -1737,8 +1751,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel, keep_reply = reply->callback(card, reply, (unsigned long)cmd); - } - else + } else keep_reply = reply->callback(card, reply, (unsigned long)iob); @@ -1768,6 +1781,24 @@ out: qeth_release_buffer(channel,iob); } +static inline void +qeth_prepare_control_data(struct qeth_card *card, int len, +struct qeth_cmd_buffer *iob) +{ + qeth_setup_ccw(&card->write,iob->data,len); + iob->callback = qeth_release_buffer; + + memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), + &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.trans_hdr++; + memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), + &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.pdu_hdr++; + memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), + &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); + QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); +} + static int qeth_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob, @@ -1778,24 +1809,11 @@ qeth_send_control_data(struct qeth_card *card, int len, { int rc; unsigned long flags; - struct qeth_reply *reply; + struct qeth_reply *reply = NULL; struct timer_list timer; QETH_DBF_TEXT(trace, 2, "sendctl"); - qeth_setup_ccw(&card->write,iob->data,len); - - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.trans_hdr++; - - memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), - &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.pdu_hdr++; - memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), - &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); - iob->callback = qeth_release_buffer; - reply = qeth_alloc_reply(card); if (!reply) { PRINT_WARN("Could no alloc qeth_reply!\n"); @@ -1810,10 +1828,6 @@ qeth_send_control_data(struct qeth_card *card, int len, init_timer(&timer); timer.function = qeth_cmd_timeout; timer.data = (unsigned long) reply; - if (IS_IPA(iob->data)) - timer.expires = jiffies + QETH_IPA_TIMEOUT; - else - timer.expires = jiffies + QETH_TIMEOUT; init_waitqueue_head(&reply->wait_q); spin_lock_irqsave(&card->lock, flags); list_add_tail(&reply->list, &card->cmd_waiter_list); @@ -1821,6 +1835,11 @@ qeth_send_control_data(struct qeth_card *card, int len, QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); wait_event(card->wait_q, atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + if (IS_IPA(iob->data)) + timer.expires = jiffies + QETH_IPA_TIMEOUT; + else + timer.expires = jiffies + QETH_TIMEOUT; QETH_DBF_TEXT(trace, 6, "noirqpnd"); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, @@ -1848,6 +1867,62 @@ qeth_send_control_data(struct qeth_card *card, int len, } static int +qeth_osn_send_control_data(struct qeth_card *card, int len, + struct qeth_cmd_buffer *iob) +{ + unsigned long flags; + int rc = 0; + + QETH_DBF_TEXT(trace, 5, "osndctrd"); + + wait_event(card->wait_q, + atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + QETH_DBF_TEXT(trace, 6, "osnoirqp"); + spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); + rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, + (addr_t) iob, 0, 0); + spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); + if (rc){ + PRINT_WARN("qeth_osn_send_control_data: " + "ccw_device_start rc = %i\n", rc); + QETH_DBF_TEXT_(trace, 2, " err%d", rc); + qeth_release_buffer(iob->channel, iob); + atomic_set(&card->write.irq_pending, 0); + wake_up(&card->wait_q); + } + return rc; +} + +static inline void +qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + char prot_type) +{ + memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); + memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), + &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); +} + +static int +qeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + int data_len) +{ + u16 s1, s2; + +QETH_DBF_TEXT(trace,4,"osndipa"); + + qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2); + s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len); + s2 = (u16)data_len; + memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); + memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); + return qeth_osn_send_control_data(card, s1, iob); +} + +static int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int (*reply_cb) (struct qeth_card *,struct qeth_reply*, unsigned long), @@ -1858,17 +1933,14 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, QETH_DBF_TEXT(trace,4,"sendipa"); - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; - - memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); - + qeth_prepare_ipa_cmd(card,iob,prot_type); rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob, reply_cb, reply_param); return rc; @@ -2010,7 +2082,10 @@ qeth_ulp_enable(struct qeth_card *card) *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (__u8) card->info.portno; if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; @@ -2100,15 +2175,21 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf, } static inline struct sk_buff * -qeth_get_skb(unsigned int length) +qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; + int add_len; + + add_len = 0; + if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) + add_len = sizeof(struct qeth_hdr); #ifdef CONFIG_QETH_VLAN - if ((skb = dev_alloc_skb(length + VLAN_HLEN))) - skb_reserve(skb, VLAN_HLEN); -#else - skb = dev_alloc_skb(length); + else + add_len = VLAN_HLEN; #endif + skb = dev_alloc_skb(length + add_len); + if (skb && add_len) + skb_reserve(skb, add_len); return skb; } @@ -2138,7 +2219,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, offset += sizeof(struct qeth_hdr); if (card->options.layer2) - skb_len = (*hdr)->hdr.l2.pkt_length; + if (card->info.type == QETH_CARD_TYPE_OSN) + skb_len = (*hdr)->hdr.osn.pdu_length; + else + skb_len = (*hdr)->hdr.l2.pkt_length; else skb_len = (*hdr)->hdr.l3.length; @@ -2146,15 +2230,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, return NULL; if (card->options.fake_ll){ if(card->dev->type == ARPHRD_IEEE802_TR){ - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_TR); } else { - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_ETH); } - } else if (!(skb = qeth_get_skb(skb_len))) + } else if (!(skb = qeth_get_skb(skb_len, *hdr))) goto no_mem; data_ptr = element->addr + offset; while (skb_len) { @@ -2453,8 +2537,12 @@ qeth_process_inbound_buffer(struct qeth_card *card, skb->dev = card->dev; if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); - else + else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) qeth_rebuild_skb(card, skb, hdr); + else { /*in case of OSN*/ + skb_push(skb, sizeof(struct qeth_hdr)); + memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); + } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ dev_kfree_skb_any(skb); @@ -2465,7 +2553,10 @@ qeth_process_inbound_buffer(struct qeth_card *card, vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); else #endif - rxrc = netif_rx(skb); + if (card->info.type == QETH_CARD_TYPE_OSN) + rxrc = card->osn_info.data_cb(skb); + else + rxrc = netif_rx(skb); card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += skb->len; @@ -3150,8 +3241,6 @@ qeth_init_qdio_info(struct qeth_card *card) INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); /* outbound */ - card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; - card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } static int @@ -3466,7 +3555,7 @@ qeth_mpc_initialize(struct qeth_card *card) return 0; out_qdio: - qeth_qdio_clear_card(card, card->info.type==QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type!=QETH_CARD_TYPE_IQD); return rc; } @@ -3491,6 +3580,9 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) case QETH_CARD_TYPE_IQD: dev = alloc_netdev(0, "hsi%d", ether_setup); break; + case QETH_CARD_TYPE_OSN: + dev = alloc_netdev(0, "osn%d", ether_setup); + break; default: dev = alloc_etherdev(0); } @@ -3655,7 +3747,8 @@ qeth_open(struct net_device *dev) if (card->state != CARD_STATE_SOFTSETUP) return -ENODEV; - if ( (card->options.layer2) && + if ( (card->info.type != QETH_CARD_TYPE_OSN) && + (card->options.layer2) && (!card->info.layer2_mac_registered)) { QETH_DBF_TEXT(trace,4,"nomacadr"); return -EPERM; @@ -3693,6 +3786,9 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; + if (card->info.type == QETH_CARD_TYPE_OSN) + return cast_type; + if (skb->dst && skb->dst->neighbour){ cast_type = skb->dst->neighbour->type; if ((cast_type == RTN_BROADCAST) || @@ -3782,13 +3878,16 @@ static inline int qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, struct qeth_hdr **hdr, int ipv) { - int rc; + int rc = 0; #ifdef CONFIG_QETH_VLAN u16 *tag; #endif QETH_DBF_TEXT(trace, 6, "prepskb"); - + if (card->info.type == QETH_CARD_TYPE_OSN) { + *hdr = (struct qeth_hdr *)(*skb)->data; + return rc; + } rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); if (rc) return rc; @@ -4291,8 +4390,14 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) } } } + if ((card->info.type == QETH_CARD_TYPE_OSN) && + (skb->protocol == htons(ETH_P_IPV6))) { + dev_kfree_skb_any(skb); + return 0; + } cast_type = qeth_get_cast_type(card, skb); - if ((cast_type == RTN_BROADCAST) && (card->info.broadcast_capable == 0)){ + if ((cast_type == RTN_BROADCAST) && + (card->info.broadcast_capable == 0)){ card->stats.tx_dropped++; card->stats.tx_errors++; dev_kfree_skb_any(skb); @@ -4320,7 +4425,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); return rc; } - qeth_fill_header(card, hdr, skb, ipv, cast_type); + if (card->info.type != QETH_CARD_TYPE_OSN) + qeth_fill_header(card, hdr, skb, ipv, cast_type); } if (large_send == QETH_LARGE_SEND_EDDP) { @@ -4381,6 +4487,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) case MII_BMCR: /* Basic mode control register */ rc = BMCR_FULLDPLX; if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)&& + (card->info.link_type != QETH_LINK_TYPE_OSN) && (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH)) rc |= BMCR_SPEED100; break; @@ -5004,6 +5111,9 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) (card->state != CARD_STATE_SOFTSETUP)) return -ENODEV; + if (card->info.type == QETH_CARD_TYPE_OSN) + return -EPERM; + switch (cmd){ case SIOC_QETH_ARP_SET_NO_ENTRIES: if ( !capable(CAP_NET_ADMIN) || @@ -5329,6 +5439,9 @@ qeth_set_multicast_list(struct net_device *dev) { struct qeth_card *card = (struct qeth_card *) dev->priv; + if (card->info.type == QETH_CARD_TYPE_OSN) + return ; + QETH_DBF_TEXT(trace,3,"setmulti"); qeth_delete_mc_addresses(card); qeth_add_multicast_ipv4(card); @@ -5370,6 +5483,94 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot) return addr; } +int +qeth_osn_assist(struct net_device *dev, + void *data, + int data_len) +{ + struct qeth_cmd_buffer *iob; + struct qeth_card *card; + int rc; + + QETH_DBF_TEXT(trace, 2, "osnsdmc"); + if (!dev) + return -ENODEV; + card = (struct qeth_card *)dev->priv; + if (!card) + return -ENODEV; + if ((card->state != CARD_STATE_UP) && + (card->state != CARD_STATE_SOFTSETUP)) + return -ENODEV; + iob = qeth_wait_for_buffer(&card->write); + memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len); + rc = qeth_osn_send_ipa_cmd(card, iob, data_len); + return rc; +} + +static struct net_device * +qeth_netdev_by_devno(unsigned char *read_dev_no) +{ + struct qeth_card *card; + struct net_device *ndev; + unsigned char *readno; + __u16 temp_dev_no, card_dev_no; + char *endp; + unsigned long flags; + + ndev = NULL; + memcpy(&temp_dev_no, read_dev_no, 2); + read_lock_irqsave(&qeth_card_list.rwlock, flags); + list_for_each_entry(card, &qeth_card_list.list, list) { + readno = CARD_RDEV_ID(card); + readno += (strlen(readno) - 4); + card_dev_no = simple_strtoul(readno, &endp, 16); + if (card_dev_no == temp_dev_no) { + ndev = card->dev; + break; + } + } + read_unlock_irqrestore(&qeth_card_list.rwlock, flags); + return ndev; +} + +int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **dev, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)) +{ + struct qeth_card * card; + + QETH_DBF_TEXT(trace, 2, "osnreg"); + *dev = qeth_netdev_by_devno(read_dev_no); + if (*dev == NULL) + return -ENODEV; + card = (struct qeth_card *)(*dev)->priv; + if (!card) + return -ENODEV; + if ((assist_cb == NULL) || (data_cb == NULL)) + return -EINVAL; + card->osn_info.assist_cb = assist_cb; + card->osn_info.data_cb = data_cb; + return 0; +} + +void +qeth_osn_deregister(struct net_device * dev) +{ + struct qeth_card *card; + + QETH_DBF_TEXT(trace, 2, "osndereg"); + if (!dev) + return; + card = (struct qeth_card *)dev->priv; + if (!card) + return; + card->osn_info.assist_cb = NULL; + card->osn_info.data_cb = NULL; + return; +} + static void qeth_delete_mc_addresses(struct qeth_card *card) { @@ -5700,6 +5901,12 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p) QETH_DBF_TEXT(trace, 3, "setmcLY3"); return -EOPNOTSUPP; } + if (card->info.type == QETH_CARD_TYPE_OSN) { + PRINT_WARN("Setting MAC address on %s is not supported.\n", + dev->name); + QETH_DBF_TEXT(trace, 3, "setmcOSN"); + return -EOPNOTSUPP; + } QETH_DBF_TEXT_(trace, 3, "%s", CARD_BUS_ID(card)); QETH_DBF_HEX(trace, 3, addr->sa_data, OSA_ADDR_LEN); rc = qeth_layer2_send_delmac(card, &card->dev->dev_addr[0]); @@ -6076,9 +6283,8 @@ qeth_netdev_init(struct net_device *dev) qeth_get_hlen(card->info.link_type) + card->options.add_hhlen; dev->addr_len = OSA_ADDR_LEN; dev->mtu = card->info.initial_mtu; - - SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); - + if (card->info.type != QETH_CARD_TYPE_OSN) + SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); SET_MODULE_OWNER(dev); return 0; } @@ -6095,6 +6301,7 @@ qeth_init_func_level(struct qeth_card *card) QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT; } else { if (card->info.type == QETH_CARD_TYPE_IQD) + /*FIXME:why do we have same values for dis and ena for osae??? */ card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT; else @@ -6124,7 +6331,7 @@ retry: ccw_device_set_online(CARD_WDEV(card)); ccw_device_set_online(CARD_DDEV(card)); } - rc = qeth_qdio_clear_card(card,card->info.type==QETH_CARD_TYPE_OSAE); + rc = qeth_qdio_clear_card(card,card->info.type!=QETH_CARD_TYPE_IQD); if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(setup, 2, "break1"); return rc; @@ -6176,8 +6383,8 @@ retry: card->dev = qeth_get_netdevice(card->info.type, card->info.link_type); if (!card->dev){ - qeth_qdio_clear_card(card, card->info.type == - QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type != + QETH_CARD_TYPE_IQD); rc = -ENODEV; QETH_DBF_TEXT_(setup, 2, "6err%d", rc); goto out; @@ -7084,6 +7291,8 @@ qeth_softsetup_card(struct qeth_card *card) return rc; } else card->lan_online = 1; + if (card->info.type==QETH_CARD_TYPE_OSN) + goto out; if (card->options.layer2) { card->dev->features |= NETIF_F_HW_VLAN_FILTER | @@ -7255,7 +7464,8 @@ qeth_stop_card(struct qeth_card *card, int recovery_mode) if (card->read.state == CH_STATE_UP && card->write.state == CH_STATE_UP && (card->state == CARD_STATE_UP)) { - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_stop(card->dev); } else { rtnl_lock(); @@ -7437,7 +7647,8 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) { QETH_DBF_TEXT(setup ,2, "startag"); - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_open(card->dev); } else { rtnl_lock(); @@ -7469,33 +7680,36 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) static void qeth_make_parameters_consistent(struct qeth_card *card) { - if (card->options.layer2) { - if (card->info.type == QETH_CARD_TYPE_IQD) { - PRINT_ERR("Device %s does not support " \ - "layer 2 functionality. " \ - "Ignoring layer2 option.\n",CARD_BUS_ID(card)); - } - IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + if (card->options.layer2 == 0) + return; + if (card->info.type == QETH_CARD_TYPE_OSN) + return; + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_ERR("Device %s does not support layer 2 functionality." \ + " Ignoring layer2 option.\n",CARD_BUS_ID(card)); + card->options.layer2 = 0; + return; + } + IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #ifdef CONFIG_QETH_IPV6 - IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #endif - IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, - QETH_CHECKSUM_DEFAULT, - "Checksumming options are"); - IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, - QETH_TR_BROADCAST_ALLRINGS, - "Broadcast mode options are"); - IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, - QETH_TR_MACADDR_NONCANONICAL, - "Canonical MAC addr options are"); - IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, - "Broadcast faking options are"); - IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, - DEFAULT_ADD_HHLEN,"Option add_hhlen is"); - IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); - } + IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, + QETH_CHECKSUM_DEFAULT, + "Checksumming options are"); + IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, + QETH_TR_BROADCAST_ALLRINGS, + "Broadcast mode options are"); + IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, + QETH_TR_MACADDR_NONCANONICAL, + "Canonical MAC addr options are"); + IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, + "Broadcast faking options are"); + IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, + DEFAULT_ADD_HHLEN,"Option add_hhlen is"); + IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); } @@ -7525,8 +7739,7 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode) return -EIO; } - if (card->options.layer2) - qeth_make_parameters_consistent(card); + qeth_make_parameters_consistent(card); if ((rc = qeth_hardsetup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); @@ -7585,6 +7798,7 @@ qeth_set_online(struct ccwgroup_device *gdev) static struct ccw_device_id qeth_ids[] = { {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, + {CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN}, {}, }; MODULE_DEVICE_TABLE(ccw, qeth_ids); @@ -8329,6 +8543,9 @@ again: printk("qeth: removed\n"); } +EXPORT_SYMBOL(qeth_osn_register); +EXPORT_SYMBOL(qeth_osn_deregister); +EXPORT_SYMBOL(qeth_osn_assist); module_init(qeth_init); module_exit(qeth_exit); MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c index f685ecc7da99..30e053d3cac2 100644 --- a/drivers/s390/net/qeth_mpc.c +++ b/drivers/s390/net/qeth_mpc.c @@ -11,7 +11,7 @@ #include <asm/cio.h> #include "qeth_mpc.h" -const char *VERSION_QETH_MPC_C = "$Revision: 1.11 $"; +const char *VERSION_QETH_MPC_C = "$Revision: 1.12 $"; unsigned char IDX_ACTIVATE_READ[]={ 0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00, @@ -138,7 +138,9 @@ unsigned char IPA_PDU_HEADER[]={ sizeof(struct qeth_ipa_cmd)%256, 0x00, sizeof(struct qeth_ipa_cmd)/256, - sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77, + sizeof(struct qeth_ipa_cmd)%256, + 0x05, + 0x77,0x77,0x77,0x77, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x01,0x00, sizeof(struct qeth_ipa_cmd)/256, diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h index 3d916b5c5d09..7edc5f1fc0d2 100644 --- a/drivers/s390/net/qeth_mpc.h +++ b/drivers/s390/net/qeth_mpc.h @@ -46,13 +46,16 @@ extern unsigned char IPA_PDU_HEADER[]; /* IP Assist related definitions */ /*****************************************************************************/ #define IPA_CMD_INITIATOR_HOST 0x00 -#define IPA_CMD_INITIATOR_HYDRA 0x01 +#define IPA_CMD_INITIATOR_OSA 0x01 +#define IPA_CMD_INITIATOR_HOST_REPLY 0x80 +#define IPA_CMD_INITIATOR_OSA_REPLY 0x81 #define IPA_CMD_PRIM_VERSION_NO 0x01 enum qeth_card_types { QETH_CARD_TYPE_UNKNOWN = 0, QETH_CARD_TYPE_OSAE = 10, QETH_CARD_TYPE_IQD = 1234, + QETH_CARD_TYPE_OSN = 11, }; #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 @@ -61,6 +64,7 @@ enum qeth_link_types { QETH_LINK_TYPE_FAST_ETH = 0x01, QETH_LINK_TYPE_HSTR = 0x02, QETH_LINK_TYPE_GBIT_ETH = 0x03, + QETH_LINK_TYPE_OSN = 0x04, QETH_LINK_TYPE_10GBIT_ETH = 0x10, QETH_LINK_TYPE_LANE_ETH100 = 0x81, QETH_LINK_TYPE_LANE_TR = 0x82, @@ -111,6 +115,9 @@ enum qeth_ipa_cmds { IPA_CMD_DELGMAC = 0x24, IPA_CMD_SETVLAN = 0x25, IPA_CMD_DELVLAN = 0x26, + IPA_CMD_SETCCID = 0x41, + IPA_CMD_DELCCID = 0x42, + IPA_CMD_MODCCID = 0x43, IPA_CMD_SETIP = 0xb1, IPA_CMD_DELIP = 0xb7, IPA_CMD_QIPASSIST = 0xb2, @@ -437,8 +444,9 @@ enum qeth_ipa_arp_return_codes { #define QETH_ARP_DATA_SIZE 3968 #define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8) /* Helper functions */ -#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) - +#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \ + (cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY)) + /*****************************************************************************/ /* END OF IP Assist related definitions */ /*****************************************************************************/ @@ -483,6 +491,7 @@ extern unsigned char ULP_ENABLE[]; /* Layer 2 defintions */ #define QETH_PROT_LAYER2 0x08 #define QETH_PROT_TCPIP 0x03 +#define QETH_PROT_OSN2 0x0a #define QETH_ULP_ENABLE_PROT_TYPE(buffer) (buffer+0x50) #define QETH_IPA_CMD_PROT_TYPE(buffer) (buffer+0x19) diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index dda105b73063..f91a02db5743 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.54 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.55 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.54 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.55 $"; /*****************************************************************************/ /* */ @@ -937,6 +937,19 @@ static struct attribute_group qeth_device_attr_group = { .attrs = (struct attribute **)qeth_device_attrs, }; +static struct device_attribute * qeth_osn_device_attrs[] = { + &dev_attr_state, + &dev_attr_chpid, + &dev_attr_if_name, + &dev_attr_card_type, + &dev_attr_buffer_count, + &dev_attr_recover, + NULL, +}; + +static struct attribute_group qeth_osn_device_attr_group = { + .attrs = (struct attribute **)qeth_osn_device_attrs, +}; #define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_id = { \ @@ -1667,7 +1680,12 @@ int qeth_create_device_attributes(struct device *dev) { int ret; + struct qeth_card *card = dev->driver_data; + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_create_group(&dev->kobj, + &qeth_osn_device_attr_group); + if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group))) return ret; if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){ @@ -1693,6 +1711,12 @@ qeth_create_device_attributes(struct device *dev) void qeth_remove_device_attributes(struct device *dev) { + struct qeth_card *card = dev->driver_data; + + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_remove_group(&dev->kobj, + &qeth_osn_device_attr_group); + sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 3ee9b8b33be0..9c9f162bd6ed 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -489,11 +489,11 @@ config SCSI_SATA_NV If unsure, say N. -config SCSI_SATA_PROMISE - tristate "Promise SATA TX2/TX4 support" +config SCSI_PDC_ADMA + tristate "Pacific Digital ADMA support" depends on SCSI_SATA && PCI help - This option enables support for Promise Serial ATA TX2/TX4. + This option enables support for Pacific Digital ADMA controllers If unsure, say N. @@ -505,6 +505,14 @@ config SCSI_SATA_QSTOR If unsure, say N. +config SCSI_SATA_PROMISE + tristate "Promise SATA TX2/TX4 support" + depends on SCSI_SATA && PCI + help + This option enables support for Promise Serial ATA TX2/TX4. + + If unsure, say N. + config SCSI_SATA_SX4 tristate "Promise SATA SX4 support" depends on SCSI_SATA && PCI && EXPERIMENTAL @@ -521,6 +529,14 @@ config SCSI_SATA_SIL If unsure, say N. +config SCSI_SATA_SIL24 + tristate "Silicon Image 3124/3132 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Silicon Image 3124/3132 Serial ATA. + + If unsure, say N. + config SCSI_SATA_SIS tristate "SiS 964/180 SATA support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 48529d180ca8..2d4439826c08 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o +obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o @@ -137,6 +138,7 @@ obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o +obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2c8fa828e24..fe8187d6f58b 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -216,7 +216,7 @@ static Scsi_Host_Template ahci_sht = { .ordered_flush = 1, }; -static struct ata_port_operations ahci_ops = { +static const struct ata_port_operations ahci_ops = { .port_disable = ata_port_disable, .check_status = ahci_check_status, @@ -407,7 +407,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) return 0xffffffffU; } - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -425,7 +425,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, return; } - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_phy_reset(struct ata_port *ap) @@ -453,14 +453,14 @@ static void ahci_phy_reset(struct ata_port *ap) static u8 ahci_check_status(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } static u8 ahci_check_err(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; } @@ -672,17 +672,36 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * for (i = 0; i < host_set->n_ports; i++) { struct ata_port *ap; - u32 tmp; - VPRINTK("port %u\n", i); + if (!(irq_stat & (1 << i))) + continue; + ap = host_set->ports[i]; - tmp = irq_stat & (1 << i); - if (tmp && ap) { + if (ap) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (ahci_host_intr(ap, qc)) - irq_ack |= (1 << i); + if (!ahci_host_intr(ap, qc)) + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + printk(KERN_WARNING + "ahci(%s): unhandled interrupt on port %u\n", + pci_name(pdev), i); + } + + VPRINTK("port %u\n", i); + } else { + VPRINTK("port %u (no irq)\n", i); + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + printk(KERN_WARNING + "ahci(%s): interrupt on disabled port %u\n", + pci_name(pdev), i); + } } + + irq_ack |= (1 << i); } if (irq_ack) { diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index d71cef767cec..be021478f416 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -147,7 +147,7 @@ static Scsi_Host_Template piix_sht = { .ordered_flush = 1, }; -static struct ata_port_operations piix_pata_ops = { +static const struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, @@ -177,7 +177,7 @@ static struct ata_port_operations piix_pata_ops = { .host_stop = ata_host_stop, }; -static struct ata_port_operations piix_sata_ops = { +static const struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c10e45b94b62..3d13fdee4fc2 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1357,7 +1357,7 @@ static int port_detect(unsigned long port_base, unsigned int j, for (i = 0; i < shost->can_queue; i++) { size_t sz = shost->sg_tablesize *sizeof(struct sg_list); - unsigned int gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; + gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; ha->cp[i].sglist = kmalloc(sz, gfp_mask); if (!ha->cp[i].sglist) { printk diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 02fe371b0ab8..f24d84538fd5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -287,7 +287,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; - int gfp_mask = GFP_KERNEL, rval; + gfp_t gfp_mask = GFP_KERNEL; + int rval; if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e5b01997117a..f53d7b8ac33f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -48,6 +48,7 @@ #include <linux/completion.h> #include <linux/suspend.h> #include <linux/workqueue.h> +#include <linux/jiffies.h> #include <scsi/scsi.h> #include "scsi.h" #include "scsi_priv.h" @@ -62,14 +63,15 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift); static int fgb(u32 bitmap); -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static void __ata_qc_complete(struct ata_queued_cmd *qc); static unsigned int ata_unique_id = 1; @@ -85,7 +87,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /** - * ata_tf_load - send taskfile registers to host controller + * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -95,7 +97,7 @@ MODULE_VERSION(DRV_VERSION); * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -153,7 +155,7 @@ static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) * Inherited from caller. */ -static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -222,7 +224,7 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * Inherited from caller. */ -void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_tf_load_mmio(ap, tf); @@ -242,7 +244,7 @@ void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -263,7 +265,7 @@ static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -283,7 +285,7 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_exec_command_mmio(ap, tf); @@ -303,7 +305,7 @@ void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) +static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf) { unsigned long flags; @@ -326,7 +328,7 @@ static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); @@ -346,7 +348,7 @@ static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); ap->ops->exec_command(ap, tf); @@ -556,7 +558,7 @@ u8 ata_chk_err(struct ata_port *ap) * Inherited from caller. */ -void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp) { fis[0] = 0x27; /* Register - Host to Device FIS */ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, @@ -597,7 +599,7 @@ void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) * Inherited from caller. */ -void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) +void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) { tf->command = fis[2]; /* status */ tf->feature = fis[3]; /* error */ @@ -615,79 +617,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) tf->hob_nsect = fis[13]; } -/** - * ata_prot_to_cmd - determine which read/write opcodes to use - * @protocol: ATA_PROT_xxx taskfile protocol - * @lba48: true is lba48 is present - * - * Given necessary input, determine which read/write commands - * to use to transfer data. - * - * LOCKING: - * None. - */ -static int ata_prot_to_cmd(int protocol, int lba48) -{ - int rcmd = 0, wcmd = 0; - - switch (protocol) { - case ATA_PROT_PIO: - if (lba48) { - rcmd = ATA_CMD_PIO_READ_EXT; - wcmd = ATA_CMD_PIO_WRITE_EXT; - } else { - rcmd = ATA_CMD_PIO_READ; - wcmd = ATA_CMD_PIO_WRITE; - } - break; - - case ATA_PROT_DMA: - if (lba48) { - rcmd = ATA_CMD_READ_EXT; - wcmd = ATA_CMD_WRITE_EXT; - } else { - rcmd = ATA_CMD_READ; - wcmd = ATA_CMD_WRITE; - } - break; - - default: - return -1; - } - - return rcmd | (wcmd << 8); -} +static const u8 ata_rw_cmds[] = { + /* pio multi */ + ATA_CMD_READ_MULTI, + ATA_CMD_WRITE_MULTI, + ATA_CMD_READ_MULTI_EXT, + ATA_CMD_WRITE_MULTI_EXT, + /* pio */ + ATA_CMD_PIO_READ, + ATA_CMD_PIO_WRITE, + ATA_CMD_PIO_READ_EXT, + ATA_CMD_PIO_WRITE_EXT, + /* dma */ + ATA_CMD_READ, + ATA_CMD_WRITE, + ATA_CMD_READ_EXT, + ATA_CMD_WRITE_EXT +}; /** - * ata_dev_set_protocol - set taskfile protocol and r/w commands - * @dev: device to examine and configure + * ata_rwcmd_protocol - set taskfile r/w commands and protocol + * @qc: command to examine and configure * - * Examine the device configuration, after we have - * read the identify-device page and configured the - * data transfer mode. Set internal state related to - * the ATA taskfile protocol (pio, pio mult, dma, etc.) - * and calculate the proper read/write commands to use. + * Examine the device configuration and tf->flags to calculate + * the proper read/write commands and protocol to use. * * LOCKING: * caller. */ -static void ata_dev_set_protocol(struct ata_device *dev) +void ata_rwcmd_protocol(struct ata_queued_cmd *qc) { - int pio = (dev->flags & ATA_DFLAG_PIO); - int lba48 = (dev->flags & ATA_DFLAG_LBA48); - int proto, cmd; + struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; - if (pio) - proto = dev->xfer_protocol = ATA_PROT_PIO; - else - proto = dev->xfer_protocol = ATA_PROT_DMA; + int index, lba48, write; + + lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0; + write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0; - cmd = ata_prot_to_cmd(proto, lba48); - if (cmd < 0) - BUG(); + if (dev->flags & ATA_DFLAG_PIO) { + tf->protocol = ATA_PROT_PIO; + index = dev->multi_count ? 0 : 4; + } else { + tf->protocol = ATA_PROT_DMA; + index = 8; + } - dev->read_cmd = cmd & 0xff; - dev->write_cmd = (cmd >> 8) & 0xff; + tf->command = ata_rw_cmds[index + lba48 + write]; } static const char * xfer_mode_str[] = { @@ -869,7 +845,7 @@ static unsigned int ata_devchk(struct ata_port *ap, * the event of failure. */ -unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -961,7 +937,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) * caller. */ -void ata_dev_id_string(u16 *id, unsigned char *s, +void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len) { unsigned int c; @@ -1078,7 +1054,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, * caller. */ -static inline void ata_dump_id(struct ata_device *dev) +static inline void ata_dump_id(const struct ata_device *dev) { DPRINTK("49==0x%04x " "53==0x%04x " @@ -1106,6 +1082,31 @@ static inline void ata_dump_id(struct ata_device *dev) dev->id[93]); } +/* + * Compute the PIO modes available for this device. This is not as + * trivial as it seems if we must consider early devices correctly. + * + * FIXME: pre IDE drive timing (do we care ?). + */ + +static unsigned int ata_pio_modes(const struct ata_device *adev) +{ + u16 modes; + + /* Usual case. Word 53 indicates word 88 is valid */ + if (adev->id[ATA_ID_FIELD_VALID] & (1 << 2)) { + modes = adev->id[ATA_ID_PIO_MODES] & 0x03; + modes <<= 3; + modes |= 0x7; + return modes; + } + + /* If word 88 isn't valid then Word 51 holds the PIO timing number + for the maximum. Turn it into a mask and return it */ + modes = (2 << (adev->id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + return modes; +} + /** * ata_dev_identify - obtain IDENTIFY x DEVICE page * @ap: port on which device we wish to probe resides @@ -1131,7 +1132,7 @@ static inline void ata_dump_id(struct ata_device *dev) static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; - unsigned int i; + unsigned int major_version; u16 tmp; unsigned long xfer_modes; u8 status; @@ -1229,9 +1230,9 @@ retry: * common ATA, ATAPI feature tests */ - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) { - printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id); + /* we require DMA support (bits 8 of word 49) */ + if (!ata_id_has_dma(dev->id)) { + printk(KERN_DEBUG "ata%u: no dma\n", ap->id); goto err_out_nosup; } @@ -1239,10 +1240,8 @@ retry: xfer_modes = dev->id[ATA_ID_UDMA_MODES]; if (!xfer_modes) xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; - if (!xfer_modes) { - xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); - xfer_modes |= (0x7 << ATA_SHIFT_PIO); - } + if (!xfer_modes) + xfer_modes = ata_pio_modes(dev); ata_dump_id(dev); @@ -1251,32 +1250,75 @@ retry: if (!ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; + /* get major version */ tmp = dev->id[ATA_ID_MAJOR_VER]; - for (i = 14; i >= 1; i--) - if (tmp & (1 << i)) + for (major_version = 14; major_version >= 1; major_version--) + if (tmp & (1 << major_version)) break; - /* we require at least ATA-3 */ - if (i < 3) { - printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id); - goto err_out_nosup; + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY + * INITIALIZE DEVICE PARAMETERS + * anything else.. + * Some drives were very specific about that exact sequence. + */ + if (major_version < 4 || (!ata_id_has_lba(dev->id))) { + ata_dev_init_params(ap, dev); + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + ata_dev_reread_id(ap, dev); } - if (ata_id_has_lba48(dev->id)) { - dev->flags |= ATA_DFLAG_LBA48; - dev->n_sectors = ata_id_u64(dev->id, 100); - } else { - dev->n_sectors = ata_id_u32(dev->id, 60); + if (ata_id_has_lba(dev->id)) { + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(dev->id)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev->id, 100); + } else { + dev->n_sectors = ata_id_u32(dev->id, 60); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA"); + } else { + /* CHS */ + + /* Default translation */ + dev->cylinders = dev->id[1]; + dev->heads = dev->id[3]; + dev->sectors = dev->id[6]; + dev->n_sectors = dev->cylinders * dev->heads * dev->sectors; + + if (ata_id_current_chs_valid(dev->id)) { + /* Current CHS translation is valid. */ + dev->cylinders = dev->id[54]; + dev->heads = dev->id[55]; + dev->sectors = dev->id[56]; + + dev->n_sectors = ata_id_u32(dev->id, 57); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + (int)dev->cylinders, (int)dev->heads, (int)dev->sectors); + } ap->host->max_cmd_len = 16; - - /* print device info to dmesg */ - printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", - ap->id, device, - ata_mode_string(xfer_modes), - (unsigned long long)dev->n_sectors, - dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } /* ATAPI-specific feature tests */ @@ -1310,7 +1352,7 @@ err_out: } -static inline u8 ata_dev_knobble(struct ata_port *ap) +static inline u8 ata_dev_knobble(const struct ata_port *ap) { return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id))); } @@ -1496,7 +1538,153 @@ void ata_port_disable(struct ata_port *ap) ap->flags |= ATA_FLAG_PORT_DISABLED; } -static struct { +/* + * This mode timing computation functionality is ported over from + * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik + */ +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. + */ + +static const struct ata_timing ata_timing[] = { + + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + +/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + +/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */ + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + + { 0xFF } +}; + +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT) +{ + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); +} + +void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, + struct ata_timing *m, unsigned int what) +{ + if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup); + if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); + if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); + if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active); + if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover); + if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); + if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); +} + +static const struct ata_timing* ata_timing_find_mode(unsigned short speed) +{ + const struct ata_timing *t; + + for (t = ata_timing; t->mode != speed; t++) + if (t->mode == 0xFF) + return NULL; + return t; +} + +int ata_timing_compute(struct ata_device *adev, unsigned short speed, + struct ata_timing *t, int T, int UT) +{ + const struct ata_timing *s; + struct ata_timing p; + + /* + * Find the mode. + */ + + if (!(s = ata_timing_find_mode(speed))) + return -EINVAL; + + /* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MW_DMA cycle timing. + */ + + if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + memset(&p, 0, sizeof(p)); + if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) { + if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO]; + else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY]; + } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { + p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN]; + } + ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); + } + + /* + * Convert the timing to bus clock counts. + */ + + ata_timing_quantize(s, t, T, UT); + + /* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T + * and some other commands. We have to ensure that the DMA cycle timing is + * slower/equal than the fastest PIO timing. + */ + + if (speed > XFER_PIO_4) { + ata_timing_compute(adev, adev->pio_mode, &p, T, UT); + ata_timing_merge(&p, t, t, ATA_TIMING_ALL); + } + + /* + * Lenghten active & recovery time so that cycle time is correct. + */ + + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} + +static const struct { unsigned int shift; u8 base; } xfer_mode_classes[] = { @@ -1603,7 +1791,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, */ static void ata_set_mode(struct ata_port *ap) { - unsigned int i, xfer_shift; + unsigned int xfer_shift; u8 xfer_mode; int rc; @@ -1632,11 +1820,6 @@ static void ata_set_mode(struct ata_port *ap) if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); - for (i = 0; i < 2; i++) { - struct ata_device *dev = &ap->device[i]; - ata_dev_set_protocol(dev); - } - return; err_out: @@ -1910,7 +2093,8 @@ err_out: DPRINTK("EXIT\n"); } -static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev) +static void ata_pr_blacklisted(const struct ata_port *ap, + const struct ata_device *dev) { printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n", ap->id, dev->devno); @@ -1948,7 +2132,7 @@ static const char * ata_dma_blacklist [] = { "_NEC DV5800A", }; -static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) +static int ata_dma_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; char *s; @@ -1973,9 +2157,9 @@ static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) return 0; } -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift) { - struct ata_device *master, *slave; + const struct ata_device *master, *slave; unsigned int mask; master = &ap->device[0]; @@ -1987,14 +2171,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->udma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2004,14 +2188,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->mwdma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2075,7 +2259,7 @@ static int fgb(u32 bitmap) * Zero on success, negative on error. */ -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out) { @@ -2144,6 +2328,110 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) } /** + * ata_dev_reread_id - Reread the device identify device info + * @ap: port where the device is + * @dev: device to reread the identify device info + * + * LOCKING: + */ + +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->dma_dir = DMA_FROM_DEVICE; + + if (dev->class == ATA_DEV_ATA) { + qc->tf.command = ATA_CMD_ID_ATA; + DPRINTK("do ATA identify\n"); + } else { + qc->tf.command = ATA_CMD_ID_ATAPI; + DPRINTK("do ATAPI identify\n"); + } + + qc->tf.flags |= ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + goto err_out; + + wait_for_completion(&wait); + + swap_buf_le16(dev->id, ATA_ID_WORDS); + + ata_dump_id(dev); + + DPRINTK("EXIT\n"); + + return; +err_out: + ata_port_disable(ap); +} + +/** + * ata_dev_init_params - Issue INIT DEV PARAMS command + * @ap: Port associated with device @dev + * @dev: Device to which command will be sent + * + * LOCKING: + */ + +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; + u16 sectors = dev->id[6]; + u16 heads = dev->id[3]; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return; + + /* set up init dev params taskfile */ + DPRINTK("init dev params \n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + qc->tf.command = ATA_CMD_INIT_DEV_PARAMS; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = sectors; + qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + +/** * ata_sg_clean - Unmap DMA memory associated with command * @qc: Command containing DMA memory to be released * @@ -2413,32 +2701,32 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) /** * ata_pio_poll - - * @ap: + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) * * RETURNS: - * + * timeout value to use */ static unsigned long ata_pio_poll(struct ata_port *ap) { u8 status; - unsigned int poll_state = PIO_ST_UNKNOWN; - unsigned int reg_state = PIO_ST_UNKNOWN; - const unsigned int tmout_state = PIO_ST_TMOUT; - - switch (ap->pio_task_state) { - case PIO_ST: - case PIO_ST_POLL: - poll_state = PIO_ST_POLL; - reg_state = PIO_ST; + unsigned int poll_state = HSM_ST_UNKNOWN; + unsigned int reg_state = HSM_ST_UNKNOWN; + const unsigned int tmout_state = HSM_ST_TMOUT; + + switch (ap->hsm_task_state) { + case HSM_ST: + case HSM_ST_POLL: + poll_state = HSM_ST_POLL; + reg_state = HSM_ST; break; - case PIO_ST_LAST: - case PIO_ST_LAST_POLL: - poll_state = PIO_ST_LAST_POLL; - reg_state = PIO_ST_LAST; + case HSM_ST_LAST: + case HSM_ST_LAST_POLL: + poll_state = HSM_ST_LAST_POLL; + reg_state = HSM_ST_LAST; break; default: BUG(); @@ -2448,20 +2736,20 @@ static unsigned long ata_pio_poll(struct ata_port *ap) status = ata_chk_status(ap); if (status & ATA_BUSY) { if (time_after(jiffies, ap->pio_task_timeout)) { - ap->pio_task_state = tmout_state; + ap->hsm_task_state = tmout_state; return 0; } - ap->pio_task_state = poll_state; + ap->hsm_task_state = poll_state; return ATA_SHORT_PAUSE; } - ap->pio_task_state = reg_state; + ap->hsm_task_state = reg_state; return 0; } /** - * ata_pio_complete - - * @ap: + * ata_pio_complete - check if drive is busy or idle + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2480,14 +2768,14 @@ static int ata_pio_complete (struct ata_port *ap) * we enter, BSY will be cleared in a chk-status or two. If not, * the drive is probably seeking or something. Snooze for a couple * msecs, then chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { msleep(2); drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { - ap->pio_task_state = PIO_ST_LAST_POLL; + ap->hsm_task_state = HSM_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return 0; } @@ -2495,14 +2783,14 @@ static int ata_pio_complete (struct ata_port *ap) drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; ata_poll_qc_complete(qc, drv_stat); @@ -2513,7 +2801,7 @@ static int ata_pio_complete (struct ata_port *ap) /** - * swap_buf_le16 - + * swap_buf_le16 - swap halves of 16-words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. * @@ -2522,6 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap) * vice-versa. * * LOCKING: + * Inherited from caller. */ void swap_buf_le16(u16 *buf, unsigned int buf_words) { @@ -2544,7 +2833,6 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * * LOCKING: * Inherited from caller. - * */ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2590,7 +2878,6 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2630,7 +2917,6 @@ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2662,7 +2948,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned char *buf; if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; @@ -2712,7 +2998,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) unsigned int offset, count; if (qc->curbytes + bytes >= qc->nbytes) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; next_sg: if (unlikely(qc->cursg >= qc->n_elem)) { @@ -2734,7 +3020,7 @@ next_sg: for (i = 0; i < words; i++) ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2783,7 +3069,6 @@ next_sg: * * LOCKING: * Inherited from caller. - * */ static void atapi_pio_bytes(struct ata_queued_cmd *qc) @@ -2815,12 +3100,12 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) err_out: printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", ap->id, dev->devno); - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; } /** - * ata_pio_sector - - * @ap: + * ata_pio_block - start PIO on a block + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2832,19 +3117,19 @@ static void ata_pio_block(struct ata_port *ap) u8 status; /* - * This is purely hueristic. This is a fast path. + * This is purely heuristic. This is a fast path. * Sometimes when we enter, BSY will be cleared in * a chk-status or two. If not, the drive is probably seeking * or something. Snooze for a couple msecs, then * chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ status = ata_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ap->pio_task_state = PIO_ST_POLL; + ap->hsm_task_state = HSM_ST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return; } @@ -2856,7 +3141,7 @@ static void ata_pio_block(struct ata_port *ap) if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2864,7 +3149,7 @@ static void ata_pio_block(struct ata_port *ap) } else { /* handle BSY=0, DRQ=0 as error */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return; } @@ -2884,7 +3169,7 @@ static void ata_pio_error(struct ata_port *ap) printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", ap->id, drv_stat); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; ata_poll_qc_complete(qc, drv_stat | ATA_ERR); } @@ -2899,25 +3184,25 @@ fsm_start: timeout = 0; qc_completed = 0; - switch (ap->pio_task_state) { - case PIO_ST_IDLE: + switch (ap->hsm_task_state) { + case HSM_ST_IDLE: return; - case PIO_ST: + case HSM_ST: ata_pio_block(ap); break; - case PIO_ST_LAST: + case HSM_ST_LAST: qc_completed = ata_pio_complete(ap); break; - case PIO_ST_POLL: - case PIO_ST_LAST_POLL: + case HSM_ST_POLL: + case HSM_ST_LAST_POLL: timeout = ata_pio_poll(ap); break; - case PIO_ST_TMOUT: - case PIO_ST_ERR: + case HSM_ST_TMOUT: + case HSM_ST_ERR: ata_pio_error(ap); return; } @@ -2928,52 +3213,6 @@ fsm_start: goto fsm_start; } -static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd) -{ - DECLARE_COMPLETION(wait); - struct ata_queued_cmd *qc; - unsigned long flags; - int rc; - - DPRINTK("ATAPI request sense\n"); - - qc = ata_qc_new_init(ap, dev); - BUG_ON(qc == NULL); - - /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - - ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); - qc->dma_dir = DMA_FROM_DEVICE; - - memset(&qc->cdb, 0, ap->cdb_len); - qc->cdb[0] = REQUEST_SENSE; - qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - qc->tf.command = ATA_CMD_PACKET; - - qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - - qc->waiting = &wait; - qc->complete_fn = ata_qc_complete_noop; - - spin_lock_irqsave(&ap->host_set->lock, flags); - rc = ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - if (rc) - ata_port_disable(ap); - else - wait_for_completion(&wait); - - DPRINTK("EXIT\n"); -} - /** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out @@ -3091,14 +3330,14 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("ENTER\n"); qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { + if (qc) + ata_qc_timeout(qc); + else { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); goto out; } - ata_qc_timeout(qc); - out: DPRINTK("EXIT\n"); } @@ -3155,15 +3394,12 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, qc->nbytes = qc->curbytes = 0; ata_tf_init(ap, &qc->tf, dev->devno); - - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; } return qc; } -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) { return 0; } @@ -3201,7 +3437,6 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_free(struct ata_queued_cmd *qc) { @@ -3221,7 +3456,6 @@ void ata_qc_free(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) @@ -3360,7 +3594,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ ata_qc_set_polling(qc); ata_tf_to_host_nolock(ap, &qc->tf); - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); break; @@ -3586,7 +3820,7 @@ u8 ata_bmdma_status(struct ata_port *ap) void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); return host_stat; } @@ -3715,7 +3949,6 @@ idle_irq: * * RETURNS: * IRQ_NONE or IRQ_HANDLED. - * */ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) @@ -3806,7 +4039,7 @@ static void atapi_packet_task(void *_data) ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* PIO commands are handled by polling */ - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); } @@ -3827,6 +4060,7 @@ err_out: * May be used as the port_start() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ int ata_port_start (struct ata_port *ap) @@ -3852,6 +4086,7 @@ int ata_port_start (struct ata_port *ap) * May be used as the port_stop() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ void ata_port_stop (struct ata_port *ap) @@ -3874,6 +4109,7 @@ void ata_host_stop (struct ata_host_set *host_set) * @do_unregister: 1 if we fully unregister, 0 to just stop the port * * LOCKING: + * Inherited from caller. */ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) @@ -3901,12 +4137,11 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) * * LOCKING: * Inherited from caller. - * */ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, struct ata_host_set *host_set, - struct ata_probe_ent *ent, unsigned int port_no) + const struct ata_probe_ent *ent, unsigned int port_no) { unsigned int i; @@ -3962,10 +4197,9 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, * * RETURNS: * New ata_port on success, for NULL on error. - * */ -static struct ata_port * ata_host_add(struct ata_probe_ent *ent, +static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, struct ata_host_set *host_set, unsigned int port_no) { @@ -4010,10 +4244,9 @@ err_out: * * RETURNS: * Number of ports registered. Zero on error (no ports registered). - * */ -int ata_device_add(struct ata_probe_ent *ent) +int ata_device_add(const struct ata_probe_ent *ent) { unsigned int count = 0, i; struct device *dev = ent->dev; @@ -4113,7 +4346,7 @@ int ata_device_add(struct ata_probe_ent *ent) for (i = 0; i < count; i++) { struct ata_port *ap = host_set->ports[i]; - scsi_scan_host(ap->host); + ata_scsi_scan_host(ap); } dev_set_drvdata(dev, host_set); @@ -4142,7 +4375,6 @@ err_out: * Inherited from calling layer (may sleep). */ - void ata_host_set_remove(struct ata_host_set *host_set) { struct ata_port *ap; @@ -4232,7 +4464,7 @@ void ata_std_ports(struct ata_ioports *ioaddr) } static struct ata_probe_ent * -ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port) +ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; @@ -4273,85 +4505,86 @@ void ata_pci_host_stop (struct ata_host_set *host_set) * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized * @port: array[2] of pointers to port info structures. + * @ports: bitmap of ports present * * Utility function which allocates and initializes an * ata_probe_ent structure for a standard dual-port * PIO-based IDE controller. The returned ata_probe_ent * structure can be passed to ata_device_add(). The returned * ata_probe_ent structure should then be freed with kfree(). + * + * The caller need only pass the address of the primary port, the + * secondary will be deduced automatically. If the device has non + * standard secondary port mappings this function can be called twice, + * once for each interface. */ struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + int p = 0; + if (!probe_ent) return NULL; - probe_ent->n_ports = 2; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + if (ports & ATA_PORT_PRIMARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); + ata_std_ports(&probe_ent->port[p]); + p++; + } - ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent->port[1]); + if (ports & ATA_PORT_SECONDARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; + ata_std_ports(&probe_ent->port[p]); + p++; + } + probe_ent->n_ports = p; return probe_ent; } -static struct ata_probe_ent * -ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, - struct ata_probe_ent **ppe2) +static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info **port, int port_num) { - struct ata_probe_ent *probe_ent, *probe_ent2; + struct ata_probe_ent *probe_ent; probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; - probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]); - if (!probe_ent2) { - kfree(probe_ent); - return NULL; - } - - probe_ent->n_ports = 1; - probe_ent->irq = 14; - probe_ent->hard_port_no = 0; probe_ent->legacy_mode = 1; - - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - - probe_ent2->hard_port_no = 1; - probe_ent2->legacy_mode = 1; - - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - + probe_ent->n_ports = 1; + probe_ent->hard_port_no = port_num; + + switch(port_num) + { + case 0: + probe_ent->irq = 14; + probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x3f6; + break; + case 1: + probe_ent->irq = 15; + probe_ent->port[0].cmd_addr = 0x170; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x376; + break; + } + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num; ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent2->port[0]); - - *ppe2 = probe_ent2; return probe_ent; } @@ -4374,13 +4607,12 @@ ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, * * RETURNS: * Zero on success, negative on errno-based value on error. - * */ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { - struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; + struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL; struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; @@ -4397,7 +4629,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0 && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - /* TODO: support transitioning to native mode? */ + /* TODO: What if one channel is in native mode ... */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) @@ -4405,11 +4637,20 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } /* FIXME... */ - if ((!legacy_mode) && (n_ports > 1)) { - printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n"); - return -EINVAL; + if ((!legacy_mode) && (n_ports > 2)) { + printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n"); + n_ports = 2; + /* For now */ } + /* FIXME: Really for ATA it isn't safe because the device may be + multi-purpose and we want to leave it alone if it was already + enabled. Secondly for shared use as Arjan says we want refcounting + + Checking dev->is_enabled is insufficient as this is not set at + boot for the primary video which is BIOS enabled + */ + rc = pci_enable_device(pdev); if (rc) return rc; @@ -4420,6 +4661,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out; } + /* FIXME: Should use platform specific mappers for legacy port ranges */ if (legacy_mode) { if (!request_region(0x1f0, 8, "libata")) { struct resource *conflict, res; @@ -4464,10 +4706,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out_regions; if (legacy_mode) { - probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2); - } else - probe_ent = ata_pci_init_native_mode(pdev, port); - if (!probe_ent) { + if (legacy_mode & (1 << 0)) + probe_ent = ata_pci_init_legacy_port(pdev, port, 0); + if (legacy_mode & (1 << 1)) + probe_ent2 = ata_pci_init_legacy_port(pdev, port, 1); + } else { + if (n_ports == 2) + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + else + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY); + } + if (!probe_ent && !probe_ent2) { rc = -ENOMEM; goto err_out_regions; } @@ -4505,7 +4754,7 @@ err_out: * @pdev: PCI device that was removed * * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occured. + * hot-unplug or module unload event has occurred. * Handle this by unregistering all objects associated * with this PCI device. Free those objects. Then finally * release PCI resources and disable device. @@ -4526,7 +4775,7 @@ void ata_pci_remove_one (struct pci_dev *pdev) } /* move to PCI subsystem */ -int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits) +int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) { unsigned long tmp = 0; @@ -4579,6 +4828,27 @@ static void __exit ata_exit(void) module_init(ata_init); module_exit(ata_exit); +static unsigned long ratelimit_time; +static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED; + +int ata_ratelimit(void) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&ata_ratelimit_lock, flags); + + if (time_after(jiffies, ratelimit_time)) { + rc = 1; + ratelimit_time = jiffies + (HZ/5); + } else + rc = 0; + + spin_unlock_irqrestore(&ata_ratelimit_lock, flags); + + return rc; +} + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -4620,6 +4890,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); +EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); @@ -4631,6 +4902,9 @@ EXPORT_SYMBOL_GPL(ata_dev_id_string); EXPORT_SYMBOL_GPL(ata_dev_config); EXPORT_SYMBOL_GPL(ata_scsi_simulate); +EXPORT_SYMBOL_GPL(ata_timing_compute); +EXPORT_SYMBOL_GPL(ata_timing_merge); + #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_host_stop); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 104fd9a63e73..58858886d751 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -44,11 +44,19 @@ #include "libata.h" -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); +typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + done(cmd); +} + /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined @@ -182,7 +190,6 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; u8 err = 0; - unsigned char *sb = cmd->sense_buffer; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -225,8 +232,6 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) }; int i = 0; - cmd->result = SAM_STAT_CHECK_CONDITION; - /* * Is this an error we can process/parse */ @@ -281,11 +286,9 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) /* Look for best matches first */ if((sense_table[i][0] & err) == sense_table[i][0]) { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); return; } i++; @@ -300,11 +303,9 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { if(stat_table[i][0] & drv_stat) { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; + ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */, + sense_table[i][2] /* asc */, + sense_table[i][3] /* ascq */ ); return; } i++; @@ -313,15 +314,12 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ - sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0x11, 0x4); + /* "unrecovered read error" */ } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0xc, 0x2); + /* "write error - auto-reallocation failed" */ } } @@ -420,7 +418,7 @@ int ata_scsi_error(struct Scsi_Host *host) */ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, - u8 *scsicmd) + const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; @@ -430,15 +428,26 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, ; /* ignore IMMED bit, violates sat-r05 */ } if (scsicmd[4] & 0x2) - return 1; /* LOEJ bit set not supported */ + goto invalid_fld; /* LOEJ bit set not supported */ if (((scsicmd[4] >> 4) & 0xf) != 0) - return 1; /* power conditions not supported */ + goto invalid_fld; /* power conditions not supported */ if (scsicmd[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ - tf->lbah = 0x0; - tf->lbam = 0x0; - tf->lbal = 0x0; - tf->device |= ATA_LBA; + + if (qc->dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + } else { + /* CHS */ + tf->lbal = 0x1; /* sect */ + tf->lbam = 0x0; /* cyl low */ + tf->lbah = 0x0; /* cyl high */ + } + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ } else { tf->nsect = 0; /* time period value (0 implies now) */ @@ -453,6 +462,11 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, */ return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; } @@ -471,14 +485,14 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((tf->flags & ATA_TFLAG_LBA48) && + if ((qc->dev->flags & ATA_DFLAG_LBA48) && (ata_id_has_flush_ext(qc->dev->id))) tf->command = ATA_CMD_FLUSH_EXT; else @@ -488,6 +502,99 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } /** + * scsi_6_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 6-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("six-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 8; + lba |= ((u64)scsicmd[3]); + + len |= ((u32)scsicmd[4]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_10_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 10-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("ten-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 24; + lba |= ((u64)scsicmd[3]) << 16; + lba |= ((u64)scsicmd[4]) << 8; + lba |= ((u64)scsicmd[5]); + + len |= ((u32)scsicmd[7]) << 8; + len |= ((u32)scsicmd[8]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_16_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 16-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("sixteen-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 56; + lba |= ((u64)scsicmd[3]) << 48; + lba |= ((u64)scsicmd[4]) << 40; + lba |= ((u64)scsicmd[5]) << 32; + lba |= ((u64)scsicmd[6]) << 24; + lba |= ((u64)scsicmd[7]) << 16; + lba |= ((u64)scsicmd[8]) << 8; + lba |= ((u64)scsicmd[9]); + + len |= ((u32)scsicmd[10]) << 24; + len |= ((u32)scsicmd[11]) << 16; + len |= ((u32)scsicmd[12]) << 8; + len |= ((u32)scsicmd[13]); + + *plba = lba; + *plen = len; +} + +/** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate @@ -501,82 +608,110 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; u64 dev_sectors = qc->dev->n_sectors; - u64 sect = 0; - u32 n_sect = 0; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - tf->device |= ATA_LBA; - if (scsicmd[0] == VERIFY) { - sect |= ((u64)scsicmd[2]) << 24; - sect |= ((u64)scsicmd[3]) << 16; - sect |= ((u64)scsicmd[4]) << 8; - sect |= ((u64)scsicmd[5]); + if (scsicmd[0] == VERIFY) + scsi_10_lba_len(scsicmd, &block, &n_block); + else if (scsicmd[0] == VERIFY_16) + scsi_16_lba_len(scsicmd, &block, &n_block); + else + goto invalid_fld; - n_sect |= ((u32)scsicmd[7]) << 8; - n_sect |= ((u32)scsicmd[8]); - } + if (!n_block) + goto nothing_to_do; + if (block >= dev_sectors) + goto out_of_range; + if ((block + n_block) > dev_sectors) + goto out_of_range; - else if (scsicmd[0] == VERIFY_16) { - sect |= ((u64)scsicmd[2]) << 56; - sect |= ((u64)scsicmd[3]) << 48; - sect |= ((u64)scsicmd[4]) << 40; - sect |= ((u64)scsicmd[5]) << 32; - sect |= ((u64)scsicmd[6]) << 24; - sect |= ((u64)scsicmd[7]) << 16; - sect |= ((u64)scsicmd[8]) << 8; - sect |= ((u64)scsicmd[9]); - - n_sect |= ((u32)scsicmd[10]) << 24; - n_sect |= ((u32)scsicmd[11]) << 16; - n_sect |= ((u32)scsicmd[12]) << 8; - n_sect |= ((u32)scsicmd[13]); - } + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; - else - return 1; + if (dev->flags & ATA_DFLAG_LBA48) { + if (n_block > (64 * 1024)) + goto invalid_fld; - if (!n_sect) - return 1; - if (sect >= dev_sectors) - return 1; - if ((sect + n_sect) > dev_sectors) - return 1; - if (lba48) { - if (n_sect > (64 * 1024)) - return 1; - } else { - if (n_sect > 256) - return 1; - } + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + tf->command = ATA_CMD_VERIFY_EXT; - if (lba48) { - tf->command = ATA_CMD_VERIFY_EXT; + tf->hob_nsect = (n_block >> 8) & 0xff; - tf->hob_nsect = (n_sect >> 8) & 0xff; + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + if (n_block > 256) + goto invalid_fld; - tf->hob_lbah = (sect >> 40) & 0xff; - tf->hob_lbam = (sect >> 32) & 0xff; - tf->hob_lbal = (sect >> 24) & 0xff; + /* use LBA28 */ + tf->command = ATA_CMD_VERIFY; + + tf->device |= (block >> 24) & 0xf; + } + + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; } else { + /* CHS */ + u32 sect, head, cyl, track; + + if (n_block > 256) + goto invalid_fld; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + tf->command = ATA_CMD_VERIFY; - - tf->device |= (sect >> 24) & 0xf; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - tf->nsect = n_sect & 0xff; + return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; - tf->lbah = (sect >> 16) & 0xff; - tf->lbam = (sect >> 8) & 0xff; - tf->lbal = sect & 0xff; +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; - return 0; +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; + return 1; } /** @@ -599,106 +734,137 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->protocol = qc->dev->xfer_protocol; - tf->device |= ATA_LBA; - if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || - scsicmd[0] == READ_16) { - tf->command = qc->dev->read_cmd; - } else { - tf->command = qc->dev->write_cmd; + if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || + scsicmd[0] == WRITE_16) tf->flags |= ATA_TFLAG_WRITE; - } - if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - if (lba48) { - tf->hob_nsect = scsicmd[7]; - tf->hob_lbal = scsicmd[2]; + /* Calculate the SCSI LBA and transfer length. */ + switch (scsicmd[0]) { + case READ_10: + case WRITE_10: + scsi_10_lba_len(scsicmd, &block, &n_block); + break; + case READ_6: + case WRITE_6: + scsi_6_lba_len(scsicmd, &block, &n_block); - qc->nsect = ((unsigned int)scsicmd[7] << 8) | - scsicmd[8]; - } else { - /* if we don't support LBA48 addressing, the request - * -may- be too large. */ - if ((scsicmd[2] & 0xf0) || scsicmd[7]) - return 1; + /* for 6-byte r/w commands, transfer length 0 + * means 256 blocks of data, not 0 block. + */ + if (!n_block) + n_block = 256; + break; + case READ_16: + case WRITE_16: + scsi_16_lba_len(scsicmd, &block, &n_block); + break; + default: + DPRINTK("no-byte command\n"); + goto invalid_fld; + } - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; + /* Check and compose ATA command */ + if (!n_block) + /* For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + */ + goto nothing_to_do; - qc->nsect = scsicmd[8]; - } + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; - tf->nsect = scsicmd[8]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[4]; - tf->lbah = scsicmd[3]; + if (dev->flags & ATA_DFLAG_LBA48) { + /* The request -may- be too large for LBA48. */ + if ((block >> 48) || (n_block > 65536)) + goto out_of_range; - VPRINTK("ten-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ - return 1; - return 0; - } + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; - if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - qc->nsect = tf->nsect = scsicmd[4]; - if (!qc->nsect) { - qc->nsect = 256; - if (lba48) - tf->hob_nsect = 1; - } + tf->hob_nsect = (n_block >> 8) & 0xff; - tf->lbal = scsicmd[3]; - tf->lbam = scsicmd[2]; - tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + /* use LBA28 */ - VPRINTK("six-byte command\n"); - return 0; - } + /* The request -may- be too large for LBA28. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; - if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - /* rule out impossible LBAs and sector counts */ - if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) - return 1; + tf->device |= (block >> 24) & 0xf; + } - if (lba48) { - tf->hob_nsect = scsicmd[12]; - tf->hob_lbal = scsicmd[6]; - tf->hob_lbam = scsicmd[5]; - tf->hob_lbah = scsicmd[4]; + ata_rwcmd_protocol(qc); - qc->nsect = ((unsigned int)scsicmd[12] << 8) | - scsicmd[13]; - } else { - /* once again, filter out impossible non-zero values */ - if (scsicmd[4] || scsicmd[5] || scsicmd[12] || - (scsicmd[6] & 0xf0)) - return 1; + qc->nsect = n_block; + tf->nsect = n_block & 0xff; - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[6]; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; - qc->nsect = scsicmd[13]; - } + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; + + ata_rwcmd_protocol(qc); + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } - tf->nsect = scsicmd[13]; - tf->lbal = scsicmd[9]; - tf->lbam = scsicmd[8]; - tf->lbah = scsicmd[7]; + return 0; - VPRINTK("sixteen-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ - return 1; - return 0; - } +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; - DPRINTK("no-byte command\n"); +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; return 1; } @@ -731,6 +897,12 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * This function sets up an ata_queued_cmd structure for the * SCSI command, and sends that ata_queued_cmd to the hardware. * + * The xlat_func argument (actor) returns 0 if ready to execute + * ATA command, else 1 to finish translation. If 1 is returned + * then cmd->result (and possibly cmd->sense_buffer) are assumed + * to be set reflecting an error condition or clean (early) + * termination. + * * LOCKING: * spin_lock_irqsave(host_set lock) */ @@ -747,7 +919,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc = ata_scsi_qc_new(ap, dev, cmd, done); if (!qc) - return; + goto err_mem; /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || @@ -755,7 +927,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", ap->id, dev->devno); - goto err_out; + goto err_did; } if (cmd->use_sg) @@ -770,19 +942,28 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc, scsicmd)) - goto err_out; + goto early_finish; /* select device, send command to hardware */ if (ata_qc_issue(qc)) - goto err_out; + goto err_did; VPRINTK("EXIT\n"); return; -err_out: +early_finish: + ata_qc_free(qc); + done(cmd); + DPRINTK("EXIT - early finish (good or error)\n"); + return; + +err_did: ata_qc_free(qc); - ata_bad_cdb(cmd, done); - DPRINTK("EXIT - badcmd\n"); +err_mem: + cmd->result = (DID_ERROR << 16); + done(cmd); + DPRINTK("EXIT - internal\n"); + return; } /** @@ -849,7 +1030,8 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * Mapping the response buffer, calling the command's handler, * and handling the handler's return value. This return value * indicates whether the handler wishes the SCSI command to be - * completed successfully, or not. + * completed successfully (0), or not (in which case cmd->result + * and sense buffer are assumed to be set). * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -868,12 +1050,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, rc = actor(args, rbuf, buflen); ata_scsi_rbuf_put(cmd, rbuf); - if (rc) - ata_bad_cdb(cmd, args->done); - else { + if (rc == 0) cmd->result = SAM_STAT_GOOD; - args->done(cmd); - } + args->done(cmd); } /** @@ -1179,8 +1358,16 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, * in the same manner) */ page_control = scsicmd[2] >> 6; - if ((page_control != 0) && (page_control != 3)) - return 1; + switch (page_control) { + case 0: /* current */ + break; /* supported */ + case 3: /* saved */ + goto saving_not_supp; + case 1: /* changeable */ + case 2: /* defaults */ + default: + goto invalid_fld; + } if (six_byte) output_len = 4; @@ -1211,7 +1398,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, break; default: /* invalid page code */ - return 1; + goto invalid_fld; } if (six_byte) { @@ -1224,6 +1411,16 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, } return 0; + +invalid_fld: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +saving_not_supp: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + /* "Saving parameters not supported" */ + return 1; } /** @@ -1246,10 +1443,20 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, VPRINTK("ENTER\n"); - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); + if (ata_id_has_lba(args->id)) { + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + } else { + /* CHS default translation */ + n_sectors = args->id[1] * args->id[3] * args->id[6]; + + if (ata_id_current_chs_valid(args->id)) + /* CHS current translation */ + n_sectors = ata_id_u32(args->id, 57); + } + n_sectors--; /* ATA TotalUserSectors - 1 */ if (args->cmd->cmnd[0] == READ_CAPACITY) { @@ -1313,6 +1520,34 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, } /** + * ata_scsi_set_sense - Set SCSI sense data and status + * @cmd: SCSI request to be handled + * @sk: SCSI-defined sense key + * @asc: SCSI-defined additional sense code + * @ascq: SCSI-defined additional sense code qualifier + * + * Helper function that builds a valid fixed format, current + * response code and the given sense key (sk), additional sense + * code (asc) and additional sense code qualifier (ascq) with + * a SCSI command status of %SAM_STAT_CHECK_CONDITION and + * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . + * + * LOCKING: + * Not required + */ + +void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; /* fixed format, current */ + cmd->sense_buffer[2] = sk; + cmd->sense_buffer[7] = 18 - 8; /* additional sense length */ + cmd->sense_buffer[12] = asc; + cmd->sense_buffer[13] = ascq; +} + +/** * ata_scsi_badcmd - End a SCSI request with an error * @cmd: SCSI request to be handled * @done: SCSI command completion function @@ -1330,30 +1565,84 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ILLEGAL_REQUEST; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); done(cmd); } +void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + DPRINTK("ATAPI request sense\n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + /* FIXME: is this needed? */ + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + + ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); + qc->dma_dir = DMA_FROM_DEVICE; + + memset(&qc->cdb, 0, ap->cdb_len); + qc->cdb[0] = REQUEST_SENSE; + qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; + + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.command = ATA_CMD_PACKET; + + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + qc->nbytes = SCSI_SENSE_BUFFERSIZE; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { + VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat); + + if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + + else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); + /* FIXME: command completion with check condition + * but no sense causes the error handler to run, + * which then issues REQUEST SENSE, fills in the sense + * buffer, and completes the command (for the second + * time). We need to issue REQUEST SENSE some other + * way, to avoid completing the command twice. + */ cmd->result = SAM_STAT_CHECK_CONDITION; qc->scsidone(cmd); return 1; - } else { + } + + else { u8 *scsicmd = cmd->cmnd; if (scsicmd[0] == INQUIRY) { @@ -1361,15 +1650,30 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) unsigned int buflen; buflen = ata_scsi_rbuf_get(cmd, &buf); - buf[2] = 0x5; - buf[3] = (buf[3] & 0xf0) | 2; + + /* ATAPI devices typically report zero for their SCSI version, + * and sometimes deviate from the spec WRT response data + * format. If SCSI version is reported as zero like normal, + * then we make the following fixups: 1) Fake MMC-5 version, + * to indicate to the Linux scsi midlayer this is a modern + * device. 2) Ensure response data format / ATAPI information + * are always correct. + */ + /* FIXME: do we ever override EVPD pages and the like, with + * this code? + */ + if (buf[2] == 0) { + buf[2] = 0x5; + buf[3] = 0x32; + } + ata_scsi_rbuf_put(cmd, buf); } + cmd->result = SAM_STAT_GOOD; } qc->scsidone(cmd); - return 0; } /** @@ -1384,7 +1688,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * Zero on success, non-zero on failure. */ -static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; @@ -1453,7 +1757,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) */ static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev; @@ -1610,7 +1914,7 @@ void ata_scsi_simulate(u16 *id, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; - u8 *scsicmd = cmd->cmnd; + const u8 *scsicmd = cmd->cmnd; args.id = id; args.cmd = cmd; @@ -1630,7 +1934,7 @@ void ata_scsi_simulate(u16 *id, case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else if (scsicmd[2] == 0x00) @@ -1640,7 +1944,7 @@ void ata_scsi_simulate(u16 *id, else if (scsicmd[2] == 0x83) ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case MODE_SENSE: @@ -1650,7 +1954,7 @@ void ata_scsi_simulate(u16 *id, case MODE_SELECT: /* unconditionally return */ case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case READ_CAPACITY: @@ -1661,7 +1965,7 @@ void ata_scsi_simulate(u16 *id, if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case REPORT_LUNS: @@ -1673,8 +1977,26 @@ void ata_scsi_simulate(u16 *id, /* all other commands */ default: - ata_bad_scsiop(cmd, done); + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); + /* "Invalid command operation code" */ + done(cmd); break; } } +void ata_scsi_scan_host(struct ata_port *ap) +{ + struct ata_device *dev; + unsigned int i; + + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ata_dev_present(dev)) + scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); + } +} + diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index d608b3a0f6fe..3d60190584ba 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -39,18 +39,23 @@ struct ata_scsi_args { /* libata-core.c */ extern int atapi_enabled; +extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); +extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); -extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); /* libata-scsi.c */ +extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd); +extern void ata_scsi_scan_host(struct ata_port *ap); extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, @@ -76,18 +81,10 @@ extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq); +extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, + u8 sk, u8 asc, u8 ascq); extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); -static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x20, 0x00); -} - -static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x24, 0x00); -} - #endif /* __LIBATA_H__ */ diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 0aba13ceaacf..352df47bcaca 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -39,7 +39,7 @@ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ static void * -lpfc_pool_kmalloc(unsigned int gfp_flags, void *data) +lpfc_pool_kmalloc(gfp_t gfp_flags, void *data) { return kmalloc((unsigned long)data, gfp_flags); } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 0bb60de0bded..172839fce0eb 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5146,7 +5146,8 @@ static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) { - int i, priority; + int i; + gfp_t priority; struct osst_buffer *tb; if (from_initialization) @@ -5178,7 +5179,8 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (STbuffer->buffer_size >= OS_FRAME_SIZE) return 1; diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c new file mode 100644 index 000000000000..9820f272f889 --- /dev/null +++ b/drivers/scsi/pdc_adma.c @@ -0,0 +1,739 @@ +/* + * pdc_adma.c - Pacific Digital Corporation ADMA + * + * Maintained by: Mark Lord <mlord@pobox.com> + * + * Copyright 2005 Mark Lord + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * + * Supports ATA disks in single-packet ADMA mode. + * Uses PIO for everything else. + * + * TODO: Use ADMA transfers for ATAPI devices, when possible. + * This requires careful attention to a number of quirks of the chip. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include "scsi.h" +#include <scsi/scsi_host.h> +#include <asm/io.h> +#include <linux/libata.h> + +#define DRV_NAME "pdc_adma" +#define DRV_VERSION "0.01" + +/* macro to calculate base address for ATA regs */ +#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) + +/* macro to calculate base address for ADMA regs */ +#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) + +enum { + ADMA_PORTS = 2, + ADMA_CPB_BYTES = 40, + ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16, + ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES, + + ADMA_DMA_BOUNDARY = 0xffffffff, + + /* global register offsets */ + ADMA_MODE_LOCK = 0x00c7, + + /* per-channel register offsets */ + ADMA_CONTROL = 0x0000, /* ADMA control */ + ADMA_STATUS = 0x0002, /* ADMA status */ + ADMA_CPB_COUNT = 0x0004, /* CPB count */ + ADMA_CPB_CURRENT = 0x000c, /* current CPB address */ + ADMA_CPB_NEXT = 0x000c, /* next CPB address */ + ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */ + ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */ + ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */ + + /* ADMA_CONTROL register bits */ + aNIEN = (1 << 8), /* irq mask: 1==masked */ + aGO = (1 << 7), /* packet trigger ("Go!") */ + aRSTADM = (1 << 5), /* ADMA logic reset */ + aRSTA = (1 << 2), /* ATA hard reset */ + aPIOMD4 = 0x0003, /* PIO mode 4 */ + + /* ADMA_STATUS register bits */ + aPSD = (1 << 6), + aUIRQ = (1 << 4), + aPERR = (1 << 0), + + /* CPB bits */ + cDONE = (1 << 0), + cVLD = (1 << 0), + cDAT = (1 << 2), + cIEN = (1 << 3), + + /* PRD bits */ + pORD = (1 << 4), + pDIRO = (1 << 5), + pEND = (1 << 7), + + /* ATA register flags */ + rIGN = (1 << 5), + rEND = (1 << 7), + + /* ATA register addresses */ + ADMA_REGS_CONTROL = 0x0e, + ADMA_REGS_SECTOR_COUNT = 0x12, + ADMA_REGS_LBA_LOW = 0x13, + ADMA_REGS_LBA_MID = 0x14, + ADMA_REGS_LBA_HIGH = 0x15, + ADMA_REGS_DEVICE = 0x16, + ADMA_REGS_COMMAND = 0x17, + + /* PCI device IDs */ + board_1841_idx = 0, /* ADMA 2-port controller */ +}; + +typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t; + +struct adma_port_priv { + u8 *pkt; + dma_addr_t pkt_dma; + adma_state_t state; +}; + +static int adma_ata_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); +static irqreturn_t adma_intr (int irq, void *dev_instance, + struct pt_regs *regs); +static int adma_port_start(struct ata_port *ap); +static void adma_host_stop(struct ata_host_set *host_set); +static void adma_port_stop(struct ata_port *ap); +static void adma_phy_reset(struct ata_port *ap); +static void adma_qc_prep(struct ata_queued_cmd *qc); +static int adma_qc_issue(struct ata_queued_cmd *qc); +static int adma_check_atapi_dma(struct ata_queued_cmd *qc); +static void adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 adma_bmdma_status(struct ata_port *ap); +static void adma_irq_clear(struct ata_port *ap); +static void adma_eng_timeout(struct ata_port *ap); + +static Scsi_Host_Template adma_ata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ENABLE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ADMA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations adma_ata_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = adma_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + .phy_reset = adma_phy_reset, + .qc_prep = adma_qc_prep, + .qc_issue = adma_qc_issue, + .eng_timeout = adma_eng_timeout, + .irq_handler = adma_intr, + .irq_clear = adma_irq_clear, + .port_start = adma_port_start, + .port_stop = adma_port_stop, + .host_stop = adma_host_stop, + .bmdma_stop = adma_bmdma_stop, + .bmdma_status = adma_bmdma_status, +}; + +static struct ata_port_info adma_port_info[] = { + /* board_1841_idx */ + { + .sht = &adma_ata_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + .pio_mask = 0x10, /* pio4 */ + .udma_mask = 0x1f, /* udma0-4 */ + .port_ops = &adma_ata_ops, + }, +}; + +static struct pci_device_id adma_ata_pci_tbl[] = { + { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_1841_idx }, + + { } /* terminate list */ +}; + +static struct pci_driver adma_ata_pci_driver = { + .name = DRV_NAME, + .id_table = adma_ata_pci_tbl, + .probe = adma_ata_init_one, + .remove = ata_pci_remove_one, +}; + +static int adma_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return 1; /* ATAPI DMA not yet supported */ +} + +static void adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + /* nothing */ +} + +static u8 adma_bmdma_status(struct ata_port *ap) +{ + return 0; +} + +static void adma_irq_clear(struct ata_port *ap) +{ + /* nothing */ +} + +static void adma_reset_engine(void __iomem *chan) +{ + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4, chan + ADMA_CONTROL); + udelay(2); +} + +static void adma_reinit_engine(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + void __iomem *mmio_base = ap->host_set->mmio_base; + void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr); + ata_check_status(ap); + + /* reset the ADMA engine */ + adma_reset_engine(chan); + + /* set in-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_IN); + + /* set CPB pointer */ + writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT); + + /* set out-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_OUT); + + /* set CPB count */ + writew(1, chan + ADMA_CPB_COUNT); + + /* read/discard ADMA status */ + readb(chan + ADMA_STATUS); +} + +static inline void adma_enter_reg_mode(struct ata_port *ap) +{ + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + writew(aPIOMD4, chan + ADMA_CONTROL); + readb(chan + ADMA_STATUS); /* flush */ +} + +static void adma_phy_reset(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + pp->state = adma_state_idle; + adma_reinit_engine(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} + +static void adma_eng_timeout(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + if (pp->state != adma_state_idle) /* healthy paranoia */ + pp->state = adma_state_mmio; + adma_reinit_engine(ap); + ata_eng_timeout(ap); +} + +static int adma_fill_sg(struct ata_queued_cmd *qc) +{ + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct adma_port_priv *pp = ap->private_data; + u8 *buf = pp->pkt; + int nelem, i = (2 + buf[3]) * 8; + u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); + + for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) { + u32 addr; + u32 len; + + addr = (u32)sg_dma_address(sg); + *(__le32 *)(buf + i) = cpu_to_le32(addr); + i += 4; + + len = sg_dma_len(sg) >> 3; + *(__le32 *)(buf + i) = cpu_to_le32(len); + i += 4; + + if ((nelem + 1) == qc->n_elem) + pFLAGS |= pEND; + buf[i++] = pFLAGS; + buf[i++] = qc->dev->dma_mode & 0xf; + buf[i++] = 0; /* pPKLW */ + buf[i++] = 0; /* reserved */ + + *(__le32 *)(buf + i) + = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4); + i += 4; + + VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", nelem, + (unsigned long)addr, len); + } + return i; +} + +static void adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + u8 *buf = pp->pkt; + u32 pkt_dma = (u32)pp->pkt_dma; + int i = 0; + + VPRINTK("ENTER\n"); + + adma_enter_reg_mode(qc->ap); + if (qc->tf.protocol != ATA_PROT_DMA) { + ata_qc_prep(qc); + return; + } + + buf[i++] = 0; /* Response flags */ + buf[i++] = 0; /* reserved */ + buf[i++] = cVLD | cDAT | cIEN; + i++; /* cLEN, gets filled in below */ + + *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */ + i += 4; /* cNCPB */ + i += 4; /* cPRD, gets filled in below */ + + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + + /* ATA registers; must be a multiple of 4 */ + buf[i++] = qc->tf.device; + buf[i++] = ADMA_REGS_DEVICE; + if ((qc->tf.flags & ATA_TFLAG_LBA48)) { + buf[i++] = qc->tf.hob_nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.hob_lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.hob_lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.hob_lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + } + buf[i++] = qc->tf.nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + buf[i++] = 0; + buf[i++] = ADMA_REGS_CONTROL; + buf[i++] = rIGN; + buf[i++] = 0; + buf[i++] = qc->tf.command; + buf[i++] = ADMA_REGS_COMMAND | rEND; + + buf[3] = (i >> 3) - 2; /* cLEN */ + *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */ + + i = adma_fill_sg(qc); + wmb(); /* flush PRDs and pkt to memory */ +#if 0 + /* dump out CPB + PRDs for debug */ + { + int j, len = 0; + static char obuf[2048]; + for (j = 0; j < i; ++j) { + len += sprintf(obuf+len, "%02x ", buf[j]); + if ((j & 7) == 7) { + printk("%s\n", obuf); + len = 0; + } + } + if (len) + printk("%s\n", obuf); + } +#endif +} + +static inline void adma_packet_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + VPRINTK("ENTER, ap %p\n", ap); + + /* fire up the ADMA engine */ + writew(aPIOMD4 | aGO, chan + ADMA_CONTROL); +} + +static int adma_qc_issue(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pp->state = adma_state_pkt; + adma_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + pp->state = adma_state_mmio; + return ata_qc_issue_prot(qc); +} + +static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + u8 __iomem *mmio_base = host_set->mmio_base; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap = host_set->ports[port_no]; + struct adma_port_priv *pp; + struct ata_queued_cmd *qc; + void __iomem *chan = ADMA_REGS(mmio_base, port_no); + u8 drv_stat, status = readb(chan + ADMA_STATUS); + + if (status == 0) + continue; + handled = 1; + adma_enter_reg_mode(ap); + if ((ap->flags & ATA_FLAG_PORT_DISABLED)) + continue; + pp = ap->private_data; + if (!pp || pp->state != adma_state_pkt) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + drv_stat = 0; + if ((status & (aPERR | aPSD | aUIRQ))) + drv_stat = ATA_ERR; + else if (pp->pkt[0] != cDONE) + drv_stat = ATA_ERR; + ata_qc_complete(qc, drv_stat); + } + return handled; +} + +static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap; + ap = host_set->ports[port_no]; + if (ap && (!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))) { + struct ata_queued_cmd *qc; + struct adma_port_priv *pp = ap->private_data; + if (!pp || pp->state != adma_state_mmio) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + + /* check main status, clearing INTRQ */ + u8 status = ata_chk_status(ap); + if ((status & ATA_BUSY)) + continue; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* complete taskfile transaction */ + pp->state = adma_state_idle; + ata_qc_complete(qc, status); + handled = 1; + } + } + } + return handled; +} + +static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int handled = 0; + + VPRINTK("ENTER\n"); + + spin_lock(&host_set->lock); + handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set); + spin_unlock(&host_set->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(handled); +} + +static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = + port->data_addr = base + 0x000; + port->error_addr = + port->feature_addr = base + 0x004; + port->nsect_addr = base + 0x008; + port->lbal_addr = base + 0x00c; + port->lbam_addr = base + 0x010; + port->lbah_addr = base + 0x014; + port->device_addr = base + 0x018; + port->status_addr = + port->command_addr = base + 0x01c; + port->altstatus_addr = + port->ctl_addr = base + 0x038; +} + +static int adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + adma_enter_reg_mode(ap); + rc = -ENOMEM; + pp = kcalloc(1, sizeof(*pp), GFP_KERNEL); + if (!pp) + goto err_out; + pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); + if (!pp->pkt) + goto err_out_kfree; + /* paranoia? */ + if ((pp->pkt_dma & 7) != 0) { + printk("bad alignment for pp->pkt_dma: %08x\n", + (u32)pp->pkt_dma); + goto err_out_kfree2; + } + memset(pp->pkt, 0, ADMA_PKT_BYTES); + ap->private_data = pp; + adma_reinit_engine(ap); + return 0; + +err_out_kfree2: + kfree(pp); +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp = ap->private_data; + + adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no)); + if (pp != NULL) { + ap->private_data = NULL; + if (pp->pkt != NULL) + dma_free_coherent(dev, ADMA_PKT_BYTES, + pp->pkt, pp->pkt_dma); + kfree(pp); + } + ata_port_stop(ap); +} + +static void adma_host_stop(struct ata_host_set *host_set) +{ + unsigned int port_no; + + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no)); + + ata_pci_host_stop(host_set); +} + +static void adma_host_init(unsigned int chip_id, + struct ata_probe_ent *probe_ent) +{ + unsigned int port_no; + void __iomem *mmio_base = probe_ent->mmio_base; + + /* enable/lock aGO operation */ + writeb(7, mmio_base + ADMA_MODE_LOCK); + + /* reset the ADMA logic */ + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(mmio_base, port_no)); +} + +static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) +{ + int rc; + + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME + "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + return rc; + } + return 0; +} + +static int adma_ata_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + void __iomem *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc, port_no; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { + rc = -ENODEV; + goto err_out_regions; + } + + mmio_base = pci_iomap(pdev, 4, 0); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + rc = adma_set_dma_masks(pdev, mmio_base); + if (rc) + goto err_out_iounmap; + + probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_iounmap; + } + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = adma_port_info[board_idx].sht; + probe_ent->host_flags = adma_port_info[board_idx].host_flags; + probe_ent->pio_mask = adma_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = adma_port_info[board_idx].udma_mask; + probe_ent->port_ops = adma_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + probe_ent->n_ports = ADMA_PORTS; + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { + adma_ata_setup_port(&probe_ent->port[port_no], + ADMA_ATA_REGS((unsigned long)mmio_base, port_no)); + } + + pci_set_master(pdev); + + /* initialize adapter */ + adma_host_init(board_idx, probe_ent); + + rc = ata_device_add(probe_ent); + kfree(probe_ent); + if (rc != ADMA_PORTS) + goto err_out_iounmap; + return 0; + +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init adma_ata_init(void) +{ + return pci_module_init(&adma_ata_pci_driver); +} + +static void __exit adma_ata_exit(void) +{ + pci_unregister_driver(&adma_ata_pci_driver); +} + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(adma_ata_init); +module_exit(adma_ata_exit); diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1ed32e7b5472..e451941ad81d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -52,7 +52,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); extern int qla24xx_load_risc_hotplug(scsi_qla_host_t *, uint32_t *); -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); @@ -277,7 +277,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* * Global Function Prototypes in qla_rscn.c source file. */ -extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *, int); extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 23d095d3817b..fbb6feee40cf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1685,7 +1685,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Returns a pointer to the allocated fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c index 1eba98828636..7534efcc8918 100644 --- a/drivers/scsi/qla2xxx/qla_rscn.c +++ b/drivers/scsi/qla2xxx/qla_rscn.c @@ -1066,7 +1066,7 @@ qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, * Returns a pointer to the allocated RSCN fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ea76fe44585e..422e0b6f603a 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -35,7 +35,7 @@ #include <asm/io.h> #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.12" +#define DRV_VERSION "0.25" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -55,31 +55,61 @@ enum { MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ, - MV_Q_CT = 32, - MV_CRQB_SZ = 32, - MV_CRPB_SZ = 8, + MV_USE_Q_DEPTH = ATA_DEF_QUEUE, - MV_DMA_BOUNDARY = 0xffffffffU, - SATAHC_MASK = (~(MV_SATAHC_REG_SZ - 1)), + MV_MAX_Q_DEPTH = 32, + MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1, + + /* CRQB needs alignment on a 1KB boundary. Size == 1KB + * CRPB needs alignment on a 256B boundary. Size == 256B + * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB + * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B + */ + MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH), + MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH), + MV_MAX_SG_CT = 176, + MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), + MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), + + /* Our DMA boundary is determined by an ePRD being unable to handle + * anything larger than 64KB + */ + MV_DMA_BOUNDARY = 0xffffU, MV_PORTS_PER_HC = 4, /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ MV_PORT_HC_SHIFT = 2, - /* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */ + /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */ MV_PORT_MASK = 3, /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ - MV_FLAG_BDMA = (1 << 28), /* Basic DMA */ + MV_FLAG_GLBL_SFT_RST = (1 << 28), /* Global Soft Reset support */ + MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), + MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | + MV_FLAG_GLBL_SFT_RST), chip_504x = 0, chip_508x = 1, chip_604x = 2, chip_608x = 3, + CRQB_FLAG_READ = (1 << 0), + CRQB_TAG_SHIFT = 1, + CRQB_CMD_ADDR_SHIFT = 8, + CRQB_CMD_CS = (0x2 << 11), + CRQB_CMD_LAST = (1 << 15), + + CRPB_FLAG_STATUS_SHIFT = 8, + + EPRD_FLAG_END_OF_TBL = (1 << 31), + /* PCI interface registers */ + PCI_COMMAND_OFS = 0xc00, + PCI_MAIN_CMD_STS_OFS = 0xd30, STOP_PCI_MASTER = (1 << 2), PCI_MASTER_EMPTY = (1 << 3), @@ -111,20 +141,13 @@ enum { HC_CFG_OFS = 0, HC_IRQ_CAUSE_OFS = 0x14, - CRBP_DMA_DONE = (1 << 0), /* shift by port # */ + CRPB_DMA_DONE = (1 << 0), /* shift by port # */ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */ DEV_IRQ = (1 << 8), /* shift by port # */ /* Shadow block registers */ - SHD_PIO_DATA_OFS = 0x100, - SHD_FEA_ERR_OFS = 0x104, - SHD_SECT_CNT_OFS = 0x108, - SHD_LBA_L_OFS = 0x10C, - SHD_LBA_M_OFS = 0x110, - SHD_LBA_H_OFS = 0x114, - SHD_DEV_HD_OFS = 0x118, - SHD_CMD_STA_OFS = 0x11C, - SHD_CTL_AST_OFS = 0x120, + SHD_BLK_OFS = 0x100, + SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ @@ -132,6 +155,11 @@ enum { /* Port registers */ EDMA_CFG_OFS = 0, + EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */ + EDMA_CFG_NCQ = (1 << 5), + EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ + EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ + EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ EDMA_ERR_IRQ_CAUSE_OFS = 0x8, EDMA_ERR_IRQ_MASK_OFS = 0xc, @@ -161,33 +189,85 @@ enum { EDMA_ERR_LNK_DATA_TX | EDMA_ERR_TRANS_PROTO), + EDMA_REQ_Q_BASE_HI_OFS = 0x10, + EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */ + EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, + + EDMA_REQ_Q_OUT_PTR_OFS = 0x18, + EDMA_REQ_Q_PTR_SHIFT = 5, + + EDMA_RSP_Q_BASE_HI_OFS = 0x1c, + EDMA_RSP_Q_IN_PTR_OFS = 0x20, + EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ + EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, + EDMA_RSP_Q_PTR_SHIFT = 3, + EDMA_CMD_OFS = 0x28, EDMA_EN = (1 << 0), EDMA_DS = (1 << 1), ATA_RST = (1 << 2), - /* BDMA is 6xxx part only */ - BDMA_CMD_OFS = 0x224, - BDMA_START = (1 << 0), + /* Host private flags (hp_flags) */ + MV_HP_FLAG_MSI = (1 << 0), - MV_UNDEF = 0, + /* Port private flags (pp_flags) */ + MV_PP_FLAG_EDMA_EN = (1 << 0), + MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; -struct mv_port_priv { +/* Command ReQuest Block: 32B */ +struct mv_crqb { + u32 sg_addr; + u32 sg_addr_hi; + u16 ctrl_flags; + u16 ata_cmd[11]; +}; +/* Command ResPonse Block: 8B */ +struct mv_crpb { + u16 id; + u16 flags; + u32 tmstmp; }; -struct mv_host_priv { +/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */ +struct mv_sg { + u32 addr; + u32 flags_size; + u32 addr_hi; + u32 reserved; +}; +struct mv_port_priv { + struct mv_crqb *crqb; + dma_addr_t crqb_dma; + struct mv_crpb *crpb; + dma_addr_t crpb_dma; + struct mv_sg *sg_tbl; + dma_addr_t sg_tbl_dma; + + unsigned req_producer; /* cp of req_in_ptr */ + unsigned rsp_consumer; /* cp of rsp_out_ptr */ + u32 pp_flags; +}; + +struct mv_host_priv { + u32 hp_flags; }; static void mv_irq_clear(struct ata_port *ap); static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static u8 mv_check_err(struct ata_port *ap); static void mv_phy_reset(struct ata_port *ap); -static int mv_master_reset(void __iomem *mmio_base); +static void mv_host_stop(struct ata_host_set *host_set); +static int mv_port_start(struct ata_port *ap); +static void mv_port_stop(struct ata_port *ap); +static void mv_qc_prep(struct ata_queued_cmd *qc); +static int mv_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static Scsi_Host_Template mv_sht = { @@ -196,13 +276,13 @@ static Scsi_Host_Template mv_sht = { .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, - .can_queue = ATA_DEF_QUEUE, + .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_UNDEF, + .sg_tablesize = MV_MAX_SG_CT, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, - .use_clustering = MV_UNDEF, + .use_clustering = ATA_SHT_USE_CLUSTERING, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, @@ -210,21 +290,22 @@ static Scsi_Host_Template mv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations mv_ops = { +static const struct ata_port_operations mv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, + .check_err = mv_check_err, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, .phy_reset = mv_phy_reset, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_prep = mv_qc_prep, + .qc_issue = mv_qc_issue, - .eng_timeout = ata_eng_timeout, + .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, @@ -232,46 +313,39 @@ static struct ata_port_operations mv_ops = { .scr_read = mv_scr_read, .scr_write = mv_scr_write, - .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .port_start = mv_port_start, + .port_stop = mv_port_stop, + .host_stop = mv_host_stop, }; static struct ata_port_info mv_port_info[] = { { /* chip_504x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = MV_COMMON_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_508x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_DUAL_HC), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_604x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, { /* chip_608x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC | - MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | + MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, }; @@ -306,12 +380,6 @@ static inline void writelfl(unsigned long data, void __iomem *addr) (void) readl(addr); /* flush to avoid PCI posted write */ } -static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio) -{ - return ((void __iomem *)((unsigned long)port_mmio & - (unsigned long)SATAHC_MASK)); -} - static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) { return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ)); @@ -329,24 +397,150 @@ static inline void __iomem *mv_ap_base(struct ata_port *ap) return mv_port_base(ap->host_set->mmio_base, ap->port_no); } -static inline int mv_get_hc_count(unsigned long flags) +static inline int mv_get_hc_count(unsigned long hp_flags) { - return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1); + return ((hp_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } -static inline int mv_is_edma_active(struct ata_port *ap) +static void mv_irq_clear(struct ata_port *ap) +{ +} + +/** + * mv_start_dma - Enable eDMA engine + * @base: port base address + * @pp: port private data + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) +{ + if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { + writelfl(EDMA_EN, base + EDMA_CMD_OFS); + pp->pp_flags |= MV_PP_FLAG_EDMA_EN; + } + assert(EDMA_EN & readl(base + EDMA_CMD_OFS)); +} + +/** + * mv_stop_dma - Disable eDMA engine + * @ap: ATA channel to manipulate + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_stop_dma(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); - return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); + struct mv_port_priv *pp = ap->private_data; + u32 reg; + int i; + + if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) { + /* Disable EDMA if active. The disable bit auto clears. + */ + writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } else { + assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS))); + } + + /* now properly wait for the eDMA to stop */ + for (i = 1000; i > 0; i--) { + reg = readl(port_mmio + EDMA_CMD_OFS); + if (!(EDMA_EN & reg)) { + break; + } + udelay(100); + } + + if (EDMA_EN & reg) { + printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); + /* FIXME: Consider doing a reset here to recover */ + } } -static inline int mv_port_bdma_capable(struct ata_port *ap) +#ifdef ATA_DEBUG +static void mv_dump_mem(void __iomem *start, unsigned bytes) { - return (ap->flags & MV_FLAG_BDMA); + int b, w; + for (b = 0; b < bytes; ) { + DPRINTK("%p: ", start + b); + for (w = 0; b < bytes && w < 4; w++) { + printk("%08x ",readl(start + b)); + b += sizeof(u32); + } + printk("\n"); + } } +#endif -static void mv_irq_clear(struct ata_port *ap) +static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) +{ +#ifdef ATA_DEBUG + int b, w; + u32 dw; + for (b = 0; b < bytes; ) { + DPRINTK("%02x: ", b); + for (w = 0; b < bytes && w < 4; w++) { + (void) pci_read_config_dword(pdev,b,&dw); + printk("%08x ",dw); + b += sizeof(u32); + } + printk("\n"); + } +#endif +} +static void mv_dump_all_regs(void __iomem *mmio_base, int port, + struct pci_dev *pdev) { +#ifdef ATA_DEBUG + void __iomem *hc_base = mv_hc_base(mmio_base, + port >> MV_PORT_HC_SHIFT); + void __iomem *port_base; + int start_port, num_ports, p, start_hc, num_hcs, hc; + + if (0 > port) { + start_hc = start_port = 0; + num_ports = 8; /* shld be benign for 4 port devs */ + num_hcs = 2; + } else { + start_hc = port >> MV_PORT_HC_SHIFT; + start_port = port; + num_ports = num_hcs = 1; + } + DPRINTK("All registers for port(s) %u-%u:\n", start_port, + num_ports > 1 ? num_ports - 1 : start_port); + + if (NULL != pdev) { + DPRINTK("PCI config space regs:\n"); + mv_dump_pci_cfg(pdev, 0x68); + } + DPRINTK("PCI regs:\n"); + mv_dump_mem(mmio_base+0xc00, 0x3c); + mv_dump_mem(mmio_base+0xd00, 0x34); + mv_dump_mem(mmio_base+0xf00, 0x4); + mv_dump_mem(mmio_base+0x1d00, 0x6c); + for (hc = start_hc; hc < start_hc + num_hcs; hc++) { + hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT); + DPRINTK("HC regs (HC %i):\n", hc); + mv_dump_mem(hc_base, 0x1c); + } + for (p = start_port; p < start_port + num_ports; p++) { + port_base = mv_port_base(mmio_base, p); + DPRINTK("EDMA regs (port %i):\n",p); + mv_dump_mem(port_base, 0x54); + DPRINTK("SATA regs (port %i):\n",p); + mv_dump_mem(port_base+0x300, 0x60); + } +#endif } static unsigned int mv_scr_offset(unsigned int sc_reg_in) @@ -389,30 +583,37 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } -static int mv_master_reset(void __iomem *mmio_base) +/** + * mv_global_soft_reset - Perform the 6xxx global soft reset + * @mmio_base: base address of the HBA + * + * This routine only applies to 6xxx parts. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_global_soft_reset(void __iomem *mmio_base) { void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS; int i, rc = 0; u32 t; - VPRINTK("ENTER\n"); - /* Following procedure defined in PCI "main command and status * register" table. */ t = readl(reg); writel(t | STOP_PCI_MASTER, reg); - for (i = 0; i < 100; i++) { - msleep(10); + for (i = 0; i < 1000; i++) { + udelay(1); t = readl(reg); if (PCI_MASTER_EMPTY & t) { break; } } if (!(PCI_MASTER_EMPTY & t)) { - printk(KERN_ERR DRV_NAME "PCI master won't flush\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); + rc = 1; goto done; } @@ -425,39 +626,399 @@ static int mv_master_reset(void __iomem *mmio_base) } while (!(GLOB_SFT_RST & t) && (i-- > 0)); if (!(GLOB_SFT_RST & t)) { - printk(KERN_ERR DRV_NAME "can't set global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't set global reset\n"); + rc = 1; goto done; } - /* clear reset */ + /* clear reset and *reenable the PCI master* (not mentioned in spec) */ i = 5; do { - writel(t & ~GLOB_SFT_RST, reg); + writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); t = readl(reg); udelay(1); } while ((GLOB_SFT_RST & t) && (i-- > 0)); if (GLOB_SFT_RST & t) { - printk(KERN_ERR DRV_NAME "can't clear global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); + rc = 1; } - - done: - VPRINTK("EXIT, rc = %i\n", rc); +done: return rc; } -static void mv_err_intr(struct ata_port *ap) +/** + * mv_host_stop - Host specific cleanup/stop routine. + * @host_set: host data structure + * + * Disable ints, cleanup host memory, call general purpose + * host_stop. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_host_stop(struct ata_host_set *host_set) { - void __iomem *port_mmio; - u32 edma_err_cause, serr = 0; + struct mv_host_priv *hpriv = host_set->private_data; + struct pci_dev *pdev = to_pci_dev(host_set->dev); + + if (hpriv->hp_flags & MV_HP_FLAG_MSI) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } + kfree(hpriv); + ata_host_stop(host_set); +} + +/** + * mv_port_start - Port specific init/start routine. + * @ap: ATA channel to manipulate + * + * Allocate and point to DMA memory, init port private memory, + * zero indices. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp; + void __iomem *port_mmio = mv_ap_base(ap); + void *mem; + dma_addr_t mem_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + return -ENOMEM; + } + memset(pp, 0, sizeof(*pp)); + + mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); + if (!mem) { + kfree(pp); + return -ENOMEM; + } + memset(mem, 0, MV_PORT_PRIV_DMA_SZ); + + /* First item in chunk of DMA memory: + * 32-slot command request table (CRQB), 32 bytes each in size + */ + pp->crqb = mem; + pp->crqb_dma = mem_dma; + mem += MV_CRQB_Q_SZ; + mem_dma += MV_CRQB_Q_SZ; + + /* Second item: + * 32-slot command response table (CRPB), 8 bytes each in size + */ + pp->crpb = mem; + pp->crpb_dma = mem_dma; + mem += MV_CRPB_Q_SZ; + mem_dma += MV_CRPB_Q_SZ; + + /* Third item: + * Table of scatter-gather descriptors (ePRD), 16 bytes each + */ + pp->sg_tbl = mem; + pp->sg_tbl_dma = mem_dma; + + writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | + EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS); + + writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); + writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, + port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); + writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); + + writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); + writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, + port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + pp->req_producer = pp->rsp_consumer = 0; + + /* Don't turn on EDMA here...do it before DMA commands only. Else + * we'll be unable to send non-data, PIO, etc due to restricted access + * to shadow regs. + */ + ap->private_data = pp; + return 0; +} + +/** + * mv_port_stop - Port specific cleanup/stop routine. + * @ap: ATA channel to manipulate + * + * Stop DMA, cleanup port memory. + * + * LOCKING: + * This routine uses the host_set lock to protect the DMA stop. + */ +static void mv_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp = ap->private_data; + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + mv_stop_dma(ap); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + ap->private_data = NULL; + dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); + kfree(pp); +} + +/** + * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries + * @qc: queued command whose SG list to source from + * + * Populate the SG list and mark the last entry. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_fill_sg(struct ata_queued_cmd *qc) +{ + struct mv_port_priv *pp = qc->ap->private_data; + unsigned int i; + + for (i = 0; i < qc->n_elem; i++) { + u32 sg_len; + dma_addr_t addr; + + addr = sg_dma_address(&qc->sg[i]); + sg_len = sg_dma_len(&qc->sg[i]); + + pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); + pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); + assert(0 == (sg_len & ~MV_DMA_BOUNDARY)); + pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); + } + if (0 < qc->n_elem) { + pp->sg_tbl[qc->n_elem - 1].flags_size |= + cpu_to_le32(EPRD_FLAG_END_OF_TBL); + } +} + +static inline unsigned mv_inc_q_index(unsigned *index) +{ + *index = (*index + 1) & MV_MAX_Q_DEPTH_MASK; + return *index; +} + +static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last) +{ + *cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS | + (last ? CRQB_CMD_LAST : 0); +} - /* bug here b/c we got an err int on a port we don't know about, - * so there's no way to clear it +/** + * mv_qc_prep - Host specific command preparation. + * @qc: queued command to prepare + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it handles prep of the CRQB + * (command request block), does some sanity checking, and calls + * the SG load routine. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mv_port_priv *pp = ap->private_data; + u16 *cw; + struct ata_taskfile *tf; + u16 flags = 0; + + if (ATA_PROT_DMA != qc->tf.protocol) { + return; + } + + /* the req producer index should be the same as we remember it */ + assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + + /* Fill in command request block */ - BUG_ON(NULL == ap); - port_mmio = mv_ap_base(ap); + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + flags |= CRQB_FLAG_READ; + } + assert(MV_MAX_Q_DEPTH > qc->tag); + flags |= qc->tag << CRQB_TAG_SHIFT; + + pp->crqb[pp->req_producer].sg_addr = + cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); + pp->crqb[pp->req_producer].sg_addr_hi = + cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); + pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags); + + cw = &pp->crqb[pp->req_producer].ata_cmd[0]; + tf = &qc->tf; + + /* Sadly, the CRQB cannot accomodate all registers--there are + * only 11 bytes...so we must pick and choose required + * registers based on the command. So, we drop feature and + * hob_feature for [RW] DMA commands, but they are needed for + * NCQ. NCQ will drop hob_nsect. + */ + switch (tf->command) { + case ATA_CMD_READ: + case ATA_CMD_READ_EXT: + case ATA_CMD_WRITE: + case ATA_CMD_WRITE_EXT: + mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0); + break; +#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ + case ATA_CMD_FPDMA_READ: + case ATA_CMD_FPDMA_WRITE: + mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); + mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); + break; +#endif /* FIXME: remove this line when NCQ added */ + default: + /* The only other commands EDMA supports in non-queued and + * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none + * of which are defined/used by Linux. If we get here, this + * driver needs work. + * + * FIXME: modify libata to give qc_prep a return value and + * return error here. + */ + BUG_ON(tf->command); + break; + } + mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0); + mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */ + + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) { + return; + } + mv_fill_sg(qc); +} + +/** + * mv_qc_issue - Initiate a command to the host + * @qc: queued command to start + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it sanity checks our local + * caches of the request producer/consumer indices then enables + * DMA and bumps the request producer index. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *port_mmio = mv_ap_base(qc->ap); + struct mv_port_priv *pp = qc->ap->private_data; + u32 in_ptr; + + if (ATA_PROT_DMA != qc->tf.protocol) { + /* We're about to send a non-EDMA capable command to the + * port. Turn off EDMA so there won't be problems accessing + * shadow block, etc registers. + */ + mv_stop_dma(qc->ap); + return ata_qc_issue_prot(qc); + } + + in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + /* the req producer index should be the same as we remember it */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + /* until we do queuing, the queue should be empty at this point */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); + + mv_inc_q_index(&pp->req_producer); /* now incr producer index */ + + mv_start_dma(port_mmio, pp); + + /* and write the request in pointer to kick the EDMA to life */ + in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; + in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT; + writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + return 0; +} + +/** + * mv_get_crpb_status - get status from most recently completed cmd + * @ap: ATA channel to manipulate + * + * This routine is for use when the port is in DMA mode, when it + * will be using the CRPB (command response block) method of + * returning command completion information. We assert indices + * are good, grab status, and bump the response consumer index to + * prove that we're up to date. + * + * LOCKING: + * Inherited from caller. + */ +static u8 mv_get_crpb_status(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + u32 out_ptr; + + out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* the response consumer index should be the same as we remember it */ + assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* increment our consumer index... */ + pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer); + + /* and, until we do NCQ, there should only be 1 CRPB waiting */ + assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> + EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* write out our inc'd consumer index so EDMA knows we're caught up */ + out_ptr &= EDMA_RSP_Q_BASE_LO_MASK; + out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT; + writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* Return ATA status register for completed CRPB */ + return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT); +} + +/** + * mv_err_intr - Handle error interrupts on the port + * @ap: ATA channel to manipulate + * + * In most cases, just clear the interrupt and move on. However, + * some cases require an eDMA reset, which is done right before + * the COMRESET in mv_phy_reset(). The SERR case requires a + * clear of pending errors in the SATA SERROR register. Finally, + * if the port disabled DMA, update our cached copy to match. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_err_intr(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + u32 edma_err_cause, serr = 0; edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -465,8 +1026,12 @@ static void mv_err_intr(struct ata_port *ap) serr = scr_read(ap, SCR_ERROR); scr_write_flush(ap, SCR_ERROR, serr); } - DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", - ap->port_no, edma_err_cause, serr); + if (EDMA_ERR_SELF_DIS & edma_err_cause) { + struct mv_port_priv *pp = ap->private_data; + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } + DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x " + "SERR: 0x%08x\n", ap->id, edma_err_cause, serr); /* Clear EDMA now that SERR cleanup done */ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -477,7 +1042,21 @@ static void mv_err_intr(struct ata_port *ap) } } -/* Handle any outstanding interrupts in a single SATAHC +/** + * mv_host_intr - Handle all interrupts on the given host controller + * @host_set: host specific structure + * @relevant: port error bits relevant to this host controller + * @hc: which host controller we're to look at + * + * Read then write clear the HC interrupt status then walk each + * port connected to the HC and see if it needs servicing. Port + * success ints are reported in the HC interrupt status reg, the + * port error ints are reported in the higher level main + * interrupt status register and thus are passed in via the + * 'relevant' argument. + * + * LOCKING: + * Inherited from caller. */ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, unsigned int hc) @@ -487,8 +1066,8 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, struct ata_port *ap; struct ata_queued_cmd *qc; u32 hc_irq_cause; - int shift, port, port0, hard_port; - u8 ata_status; + int shift, port, port0, hard_port, handled; + u8 ata_status = 0; if (hc == 0) { port0 = 0; @@ -499,7 +1078,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, /* we'll need the HC success int register in most cases */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); if (hc_irq_cause) { - writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); + writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); } VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", @@ -508,35 +1087,38 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { ap = host_set->ports[port]; hard_port = port & MV_PORT_MASK; /* range 0-3 */ - ata_status = 0xffU; + handled = 0; /* ensure ata_status is set if handled++ */ - if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) { - BUG_ON(NULL == ap); - /* rcv'd new resp, basic DMA complete, or ATA IRQ */ - /* This is needed to clear the ATA INTRQ. - * FIXME: don't read the status reg in EDMA mode! + if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { + /* new CRPB on the queue; just one at a time until NCQ + */ + ata_status = mv_get_crpb_status(ap); + handled++; + } else if ((DEV_IRQ << hard_port) & hc_irq_cause) { + /* received ATA IRQ; read the status reg to clear INTRQ */ ata_status = readb((void __iomem *) ap->ioaddr.status_addr); + handled++; } - shift = port * 2; + shift = port << 1; /* (port * 2) */ if (port >= MV_PORTS_PER_HC) { shift++; /* skip bit 8 in the HC Main IRQ reg */ } if ((PORT0_ERR << shift) & relevant) { mv_err_intr(ap); - /* FIXME: smart to OR in ATA_ERR? */ + /* OR in ATA_ERR to ensure libata knows we took one */ ata_status = readb((void __iomem *) ap->ioaddr.status_addr) | ATA_ERR; + handled++; } - if (ap) { + if (handled && ap) { qc = ata_qc_from_tag(ap, ap->active_tag); if (NULL != qc) { VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); - BUG_ON(0xffU == ata_status); /* mark qc status appropriately */ ata_qc_complete(qc, ata_status); } @@ -545,17 +1127,30 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, VPRINTK("EXIT\n"); } +/** + * mv_interrupt - + * @irq: unused + * @dev_instance: private data; in this case the host structure + * @regs: unused + * + * Read the read only register to determine if any host + * controllers have pending interrupts. If so, call lower level + * routine to handle. Also check for PCI errors which are only + * reported here. + * + * LOCKING: + * This routine holds the host_set lock while processing pending + * interrupts. + */ static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio; + void __iomem *mmio = host_set->mmio_base; u32 irq_stat; - mmio = host_set->mmio_base; irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); - n_hcs = mv_get_hc_count(host_set->ports[0]->flags); /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault @@ -564,64 +1159,105 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_NONE; } + n_hcs = mv_get_hc_count(host_set->ports[0]->flags); spin_lock(&host_set->lock); for (hc = 0; hc < n_hcs; hc++) { u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT)); if (relevant) { mv_host_intr(host_set, relevant, hc); - handled = 1; + handled++; } } if (PCI_ERR & irq_stat) { - /* FIXME: these are all masked by default, but still need - * to recover from them properly. - */ - } + printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", + readl(mmio + PCI_IRQ_CAUSE_OFS)); + DPRINTK("All regs @ PCI error\n"); + mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev)); + + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + handled++; + } spin_unlock(&host_set->lock); return IRQ_RETVAL(handled); } +/** + * mv_check_err - Return the error shadow register to caller. + * @ap: ATA channel to manipulate + * + * Marvell requires DMA to be stopped before accessing shadow + * registers. So we do that, then return the needed register. + * + * LOCKING: + * Inherited from caller. FIXME: protect mv_stop_dma with lock? + */ +static u8 mv_check_err(struct ata_port *ap) +{ + mv_stop_dma(ap); /* can't read shadow regs if DMA on */ + return readb((void __iomem *) ap->ioaddr.error_addr); +} + +/** + * mv_phy_reset - Perform eDMA reset followed by COMRESET + * @ap: ATA channel to manipulate + * + * Part of this is taken from __sata_phy_reset and modified to + * not sleep since this routine gets called from interrupt level. + * + * LOCKING: + * Inherited from caller. This is coded to safe to call at + * interrupt level, i.e. it does not sleep. + */ static void mv_phy_reset(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; - u32 edma = 0, bdma; + unsigned long timeout; VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - edma = readl(port_mmio + EDMA_CMD_OFS); - if (EDMA_EN & edma) { - /* disable EDMA if active */ - edma &= ~EDMA_EN; - writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS); - udelay(1); - } else if (mv_port_bdma_capable(ap) && - (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) { - /* disable BDMA if active */ - writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS); - } + mv_stop_dma(ap); - writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); udelay(25); /* allow reset propagation */ /* Spec never mentions clearing the bit. Marvell's driver does * clear the bit, however. */ - writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(0, port_mmio + EDMA_CMD_OFS); - VPRINTK("Done. Now calling __sata_phy_reset()\n"); + VPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); /* proceed to init communications via the scr_control reg */ - __sata_phy_reset(ap); + scr_write_flush(ap, SCR_CONTROL, 0x301); + mdelay(1); + scr_write_flush(ap, SCR_CONTROL, 0x300); + timeout = jiffies + (HZ * 1); + do { + mdelay(10); + if ((scr_read(ap, SCR_STATUS) & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); - if (ap->flags & ATA_FLAG_PORT_DISABLED) { - VPRINTK("Port disabled pre-sig. Exiting.\n"); + VPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); + + if (sata_dev_present(ap)) { + ata_port_probe(ap); + } else { + printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n", + ap->id, scr_read(ap, SCR_STATUS)); + ata_port_disable(ap); return; } + ap->cbl = ATA_CBL_SATA; tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); @@ -636,37 +1272,118 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("EXIT\n"); } -static void mv_port_init(struct ata_ioports *port, unsigned long base) +/** + * mv_eng_timeout - Routine called by libata when SCSI times out I/O + * @ap: ATA channel to manipulate + * + * Intent is to clear all pending error conditions, reset the + * chip/bus, fail the command, and move on. + * + * LOCKING: + * This routine holds the host_set lock while failing the command. + */ +static void mv_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + unsigned long flags; + + printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id); + DPRINTK("All regs @ start of eng_timeout\n"); + mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, + to_pci_dev(ap->host_set->dev)); + + qc = ata_qc_from_tag(ap, ap->active_tag); + printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", + ap->host_set->mmio_base, ap, qc, qc->scsicmd, + &qc->scsicmd->cmnd); + + mv_err_intr(ap); + mv_phy_reset(ap); + + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + } else { + /* hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, ATA_ERR); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } +} + +/** + * mv_port_init - Perform some early initialization on a single port. + * @port: libata data structure storing shadow register addresses + * @port_mmio: base address of the port + * + * Initialize shadow register mmio addresses, clear outstanding + * interrupts on the port, and unmask interrupts for the future + * start of the port. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) { - /* PIO related setup */ - port->data_addr = base + SHD_PIO_DATA_OFS; - port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS; - port->nsect_addr = base + SHD_SECT_CNT_OFS; - port->lbal_addr = base + SHD_LBA_L_OFS; - port->lbam_addr = base + SHD_LBA_M_OFS; - port->lbah_addr = base + SHD_LBA_H_OFS; - port->device_addr = base + SHD_DEV_HD_OFS; - port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS; - port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS; - /* unused */ + unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; + unsigned serr_ofs; + + /* PIO related setup + */ + port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); + port->error_addr = + port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR); + port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT); + port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL); + port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM); + port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH); + port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE); + port->status_addr = + port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS); + /* special case: control/altstatus doesn't have ATA_REG_ address */ + port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; + + /* unused: */ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0; + /* Clear any currently outstanding port interrupt conditions */ + serr_ofs = mv_scr_offset(SCR_ERROR); + writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); + writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + /* unmask all EDMA error interrupts */ - writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS); + writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", - readl((void __iomem *)base + EDMA_CFG_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS)); + readl(port_mmio + EDMA_CFG_OFS), + readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS), + readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } +/** + * mv_host_init - Perform some early initialization of the host. + * @probe_ent: early data struct representing the host + * + * If possible, do an early global reset of the host. Then do + * our port init and clear/unmask all/relevant host interrupts. + * + * LOCKING: + * Inherited from caller. + */ static int mv_host_init(struct ata_probe_ent *probe_ent) { int rc = 0, n_hc, port, hc; void __iomem *mmio = probe_ent->mmio_base; void __iomem *port_mmio; - if (mv_master_reset(probe_ent->mmio_base)) { + if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && + mv_global_soft_reset(probe_ent->mmio_base)) { rc = 1; goto done; } @@ -676,17 +1393,27 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) for (port = 0; port < probe_ent->n_ports; port++) { port_mmio = mv_port_base(mmio, port); - mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio); + mv_port_init(&probe_ent->port[port], port_mmio); } for (hc = 0; hc < n_hc; hc++) { - VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc, - readl(mv_hc_base(mmio, hc) + HC_CFG_OFS), - readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS)); + void __iomem *hc_mmio = mv_hc_base(mmio, hc); + + VPRINTK("HC%i: HC config=0x%08x HC IRQ cause " + "(before clear)=0x%08x\n", hc, + readl(hc_mmio + HC_CFG_OFS), + readl(hc_mmio + HC_IRQ_CAUSE_OFS)); + + /* Clear any currently outstanding hc interrupt conditions */ + writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); - writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + /* Clear any currently outstanding host interrupt conditions */ + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + + /* and unmask interrupt generation for host regs */ + writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", @@ -694,11 +1421,53 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + PCI_IRQ_CAUSE_OFS), readl(mmio + PCI_IRQ_MASK_OFS)); - - done: +done: return rc; } +/** + * mv_print_info - Dump key info to kernel log for perusal. + * @probe_ent: early data struct representing the host + * + * FIXME: complete this. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_print_info(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + struct mv_host_priv *hpriv = probe_ent->private_data; + u8 rev_id, scc; + const char *scc_s; + + /* Use this to determine the HW stepping of the chip so we know + * what errata to workaround + */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + + pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc); + if (scc == 0) + scc_s = "SCSI"; + else if (scc == 0x01) + scc_s = "RAID"; + else + scc_s = "unknown"; + + printk(KERN_INFO DRV_NAME + "(%s) %u slots %u ports %s mode IRQ via %s\n", + pci_name(pdev), (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, + scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); +} + +/** + * mv_init_one - handle a positive probe of a Marvell host + * @pdev: PCI device found + * @ent: PCI device ID entry for the matched host + * + * LOCKING: + * Inherited from caller. + */ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -706,16 +1475,12 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mv_host_priv *hpriv; unsigned int board_idx = (unsigned int)ent->driver_data; void __iomem *mmio_base; - int pci_dev_busy = 0; - int rc; + int pci_dev_busy = 0, rc; if (!printed_version++) { - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME " version " DRV_VERSION "\n"); } - VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - rc = pci_enable_device(pdev); if (rc) { return rc; @@ -727,8 +1492,6 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out; } - pci_intx(pdev, 1); - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { rc = -ENOMEM; @@ -739,8 +1502,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR), - pci_resource_len(pdev, MV_PRIMARY_BAR)); + mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -769,37 +1531,40 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_out_hpriv; } -/* mv_print_info(probe_ent); */ - { - int b, w; - u32 dw[4]; /* hold a line of 16b */ - VPRINTK("PCI config space:\n"); - for (b = 0; b < 0x40; ) { - for (w = 0; w < 4; w++) { - (void) pci_read_config_dword(pdev,b,&dw[w]); - b += sizeof(*dw); - } - VPRINTK("%08x %08x %08x %08x\n", - dw[0],dw[1],dw[2],dw[3]); - } + /* Enable interrupts */ + if (pci_enable_msi(pdev) == 0) { + hpriv->hp_flags |= MV_HP_FLAG_MSI; + } else { + pci_intx(pdev, 1); } - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + mv_dump_pci_cfg(pdev, 0x68); + mv_print_info(probe_ent); + + if (ata_device_add(probe_ent) == 0) { + rc = -ENODEV; /* No devices discovered */ + goto err_out_dev_add; + } + kfree(probe_ent); return 0; - err_out_hpriv: +err_out_dev_add: + if (MV_HP_FLAG_MSI & hpriv->hp_flags) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } +err_out_hpriv: kfree(hpriv); - err_out_iounmap: - iounmap(mmio_base); - err_out_free_ent: +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_free_ent: kfree(probe_ent); - err_out_regions: +err_out_regions: pci_release_regions(pdev); - err_out: +err_out: if (!pci_dev_busy) { pci_disable_device(pdev); } diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index cb832b03ec5e..1a56d6c79ddd 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -238,7 +238,7 @@ static Scsi_Host_Template nv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations nv_ops = { +static const struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -331,7 +331,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) return 0xffffffffU; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -345,7 +345,7 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) return; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -405,7 +405,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = -ENOMEM; ppi = &nv_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 538ad727bd2e..eee93b0016df 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -87,8 +87,8 @@ static void pdc_port_stop(struct ata_port *ap); static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_sata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); @@ -113,7 +113,7 @@ static Scsi_Host_Template pdc_ata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_sata_ops = { +static const struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -136,7 +136,7 @@ static struct ata_port_operations pdc_sata_ops = { .host_stop = ata_pci_host_stop, }; -static struct ata_port_operations pdc_pata_ops = { +static const struct ata_port_operations pdc_pata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -324,7 +324,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -333,7 +333,7 @@ static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -438,11 +438,11 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, break; default: - ap->stats.idle_irq++; - break; + ap->stats.idle_irq++; + break; } - return handled; + return handled; } static void pdc_irq_clear(struct ata_port *ap) @@ -523,8 +523,8 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) @@ -546,7 +546,7 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -554,7 +554,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index ffcdeb68641c..250dafa6bc36 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -51,8 +51,6 @@ enum { QS_PRD_BYTES = QS_MAX_PRD * 16, QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, - QS_DMA_BOUNDARY = ~0UL, - /* global register offsets */ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ QS_HID_HPHY = 0x0004, /* host physical interface info */ @@ -101,6 +99,10 @@ enum { board_2068_idx = 0, /* QStor 4-port SATA/RAID */ }; +enum { + QS_DMA_BOUNDARY = ~0UL +}; + typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; struct qs_port_priv { @@ -145,7 +147,7 @@ static Scsi_Host_Template qs_ata_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations qs_ata_ops = { +static const struct ata_port_operations qs_ata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index ba98a175ee3a..3a056173fb95 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -150,7 +150,7 @@ static Scsi_Host_Template sil_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sil_ops = { +static const struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, @@ -289,7 +289,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -297,7 +297,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c new file mode 100644 index 000000000000..32d730bd5bb6 --- /dev/null +++ b/drivers/scsi/sata_sil24.c @@ -0,0 +1,875 @@ +/* + * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers + * + * Copyright 2005 Tejun Heo + * + * Based on preview driver from Silicon Image. + * + * NOTE: No NCQ/ATAPI support yet. The preview driver didn't support + * NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make + * those work. Enabling those shouldn't be difficult. Basic + * structure is all there (in libata-dev tree). If you have any + * information about this hardware, please contact me or linux-ide. + * Info is needed on... + * + * - How to issue tagged commands and turn on sactive on issue accordingly. + * - Where to put an ATAPI command and how to tell the device to send it. + * - How to enable/use 64bit. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <scsi/scsi_host.h> +#include "scsi.h" +#include <linux/libata.h> +#include <asm/io.h> + +#define DRV_NAME "sata_sil24" +#define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */ + +/* + * Port request block (PRB) 32 bytes + */ +struct sil24_prb { + u16 ctrl; + u16 prot; + u32 rx_cnt; + u8 fis[6 * 4]; +}; + +/* + * Scatter gather entry (SGE) 16 bytes + */ +struct sil24_sge { + u64 addr; + u32 cnt; + u32 flags; +}; + +/* + * Port multiplier + */ +struct sil24_port_multiplier { + u32 diag; + u32 sactive; +}; + +enum { + /* + * Global controller registers (128 bytes @ BAR0) + */ + /* 32 bit regs */ + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */ + + PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ + PORT_ACTIVATE_UPPER_ADDR= 0x101c, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* Unknown FIS received */ + PORT_IRQ_SDB_FIS = (1 << 11), /* SDB FIS received */ + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */ + PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */ + PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */ + PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */ + PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */ + PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */ + PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */ + PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */ + PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */ + PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */ + PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */ + PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */ + PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ + PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */ + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* board id */ + BID_SIL3124 = 0, + BID_SIL3132 = 1, + BID_SIL3131 = 2, + + IRQ_STAT_4PORTS = 0xf, +}; + +struct sil24_cmd_block { + struct sil24_prb prb; + struct sil24_sge sge[LIBATA_MAX_PRD]; +}; + +/* + * ap->private_data + * + * The preview driver always returned 0 for status. We emulate it + * here from the previous interrupt. + */ +struct sil24_port_priv { + struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ + dma_addr_t cmd_block_dma; /* DMA base addr for them */ + struct ata_taskfile tf; /* Cached taskfile registers */ +}; + +/* ap->host_set->private_data */ +struct sil24_host_priv { + void *host_base; /* global controller control (128 bytes @BAR0) */ + void *port_base; /* port registers (4 * 8192 bytes @BAR2) */ +}; + +static u8 sil24_check_status(struct ata_port *ap); +static u8 sil24_check_err(struct ata_port *ap); +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void sil24_phy_reset(struct ata_port *ap); +static void sil24_qc_prep(struct ata_queued_cmd *qc); +static int sil24_qc_issue(struct ata_queued_cmd *qc); +static void sil24_irq_clear(struct ata_port *ap); +static void sil24_eng_timeout(struct ata_port *ap); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sil24_port_start(struct ata_port *ap); +static void sil24_port_stop(struct ata_port *ap); +static void sil24_host_stop(struct ata_host_set *host_set); +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +static struct pci_device_id sil24_pci_tbl[] = { + { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, + { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, + { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { } /* terminate list */ +}; + +static struct pci_driver sil24_pci_driver = { + .name = DRV_NAME, + .id_table = sil24_pci_tbl, + .probe = sil24_init_one, + .remove = ata_pci_remove_one, /* safe? */ +}; + +static Scsi_Host_Template sil24_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, + .ordered_flush = 1, /* NCQ not supported yet */ +}; + +static const struct ata_port_operations sil24_ops = { + .port_disable = ata_port_disable, + + .check_status = sil24_check_status, + .check_altstatus = sil24_check_status, + .check_err = sil24_check_err, + .dev_select = ata_noop_dev_select, + + .tf_read = sil24_tf_read, + + .phy_reset = sil24_phy_reset, + + .qc_prep = sil24_qc_prep, + .qc_issue = sil24_qc_issue, + + .eng_timeout = sil24_eng_timeout, + + .irq_handler = sil24_interrupt, + .irq_clear = sil24_irq_clear, + + .scr_read = sil24_scr_read, + .scr_write = sil24_scr_write, + + .port_start = sil24_port_start, + .port_stop = sil24_port_stop, + .host_stop = sil24_host_stop, +}; + +/* + * Use bits 30-31 of host_flags to encode available port numbers. + * Current maxium is 4. + */ +#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) +#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) + +static struct ata_port_info sil24_port_info[] = { + /* sil_3124 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3132 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3131/sil_3531 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, +}; + +static inline void sil24_update_tf(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + void *port = (void *)ap->ioaddr.cmd_addr; + struct sil24_prb *prb = port; + + ata_tf_from_fis(prb->fis, &pp->tf); +} + +static u8 sil24_check_status(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.command; +} + +static u8 sil24_check_err(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.feature; +} + +static int sil24_scr_map[] = { + [SCR_CONTROL] = 0, + [SCR_STATUS] = 1, + [SCR_ERROR] = 2, + [SCR_ACTIVE] = 3, +}; + +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + return readl(scr_addr + sil24_scr_map[sc_reg] * 4); + } + return 0xffffffffU; +} + +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); + } +} + +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct sil24_port_priv *pp = ap->private_data; + *tf = pp->tf; +} + +static void sil24_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + /* + * No ATAPI yet. Just unconditionally indicate ATA device. + * If ATAPI device is attached, it will fail ATA_CMD_ID_ATA + * and libata core will ignore the device. + */ + if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) + ap->device[0].class = ATA_DEV_ATA; +} + +static inline void sil24_fill_sg(struct ata_queued_cmd *qc, + struct sil24_cmd_block *cb) +{ + struct scatterlist *sg = qc->sg; + struct sil24_sge *sge = cb->sge; + unsigned i; + + for (i = 0; i < qc->n_elem; i++, sg++, sge++) { + sge->addr = cpu_to_le64(sg_dma_address(sg)); + sge->cnt = cpu_to_le32(sg_dma_len(sg)); + sge->flags = 0; + sge->flags = i < qc->n_elem - 1 ? 0 : cpu_to_le32(SGE_TRM); + } +} + +static void sil24_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct sil24_port_priv *pp = ap->private_data; + struct sil24_cmd_block *cb = pp->cmd_block + qc->tag; + struct sil24_prb *prb = &cb->prb; + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + break; + default: + /* ATAPI isn't supported yet */ + BUG(); + } + + ata_tf_to_fis(&qc->tf, prb->fis, 0); + + if (qc->flags & ATA_QCFLAG_DMAMAP) + sil24_fill_sg(qc, cb); +} + +static int sil24_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void *port = (void *)ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); + + writel((u32)paddr, port + PORT_CMD_ACTIVATE); + return 0; +} + +static void sil24_irq_clear(struct ata_port *ap) +{ + /* unused */ +} + +static int __sil24_reset_controller(void *port) +{ + int cnt; + u32 tmp; + + /* Reset controller state. Is this correct? */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); /* sync */ + + /* Max ~100ms */ + for (cnt = 0; cnt < 1000; cnt++) { + udelay(100); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_DEV_RST)) + break; + } + + if (tmp & PORT_CS_DEV_RST) + return -1; + return 0; +} + +static void sil24_reset_controller(struct ata_port *ap) +{ + printk(KERN_NOTICE DRV_NAME + " ata%u: resetting controller...\n", ap->id); + if (__sil24_reset_controller((void *)ap->ioaddr.cmd_addr)) + printk(KERN_ERR DRV_NAME + " ata%u: failed to reset controller\n", ap->id); +} + +static void sil24_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: tiemout without command\n", + ap->id); + return; + } + + /* + * hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); +} + +static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct sil24_port_priv *pp = ap->private_data; + void *port = (void *)ap->ioaddr.cmd_addr; + u32 irq_stat, cmd_err, sstatus, serror; + + irq_stat = readl(port + PORT_IRQ_STAT); + writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ + + if (!(irq_stat & PORT_IRQ_ERROR)) { + /* ignore non-completion, non-error irqs for now */ + printk(KERN_WARNING DRV_NAME + "ata%u: non-error exception irq (irq_stat %x)\n", + ap->id, irq_stat); + return; + } + + cmd_err = readl(port + PORT_CMD_ERR); + sstatus = readl(port + PORT_SSTATUS); + serror = readl(port + PORT_SERROR); + if (serror) + writel(serror, port + PORT_SERROR); + + printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" + " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", + ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + + if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { + /* + * Device is reporting error, tf registers are valid. + */ + sil24_update_tf(ap); + } else { + /* + * Other errors. libata currently doesn't have any + * mechanism to report these errors. Just turn on + * ATA_ERR. + */ + pp->tf.command = ATA_ERR; + } + + if (qc) + ata_qc_complete(qc, pp->tf.command); + + sil24_reset_controller(ap); +} + +static inline void sil24_host_intr(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + void *port = (void *)ap->ioaddr.cmd_addr; + u32 slot_stat; + + slot_stat = readl(port + PORT_SLOT_STAT); + if (!(slot_stat & HOST_SSTAT_ATTN)) { + struct sil24_port_priv *pp = ap->private_data; + /* + * !HOST_SSAT_ATTN guarantees successful completion, + * so reading back tf registers is unnecessary for + * most commands. TODO: read tf registers for + * commands which require these values on successful + * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, + * DEVICE RESET and READ PORT MULTIPLIER (any more?). + */ + sil24_update_tf(ap); + + if (qc) + ata_qc_complete(qc, pp->tf.command); + } else + sil24_error_intr(ap, slot_stat); +} + +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct sil24_host_priv *hpriv = host_set->private_data; + unsigned handled = 0; + u32 status; + int i; + + status = readl(hpriv->host_base + HOST_IRQ_STAT); + + if (status == 0xffffffff) { + printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); + goto out; + } + + if (!(status & IRQ_STAT_4PORTS)) + goto out; + + spin_lock(&host_set->lock); + + for (i = 0; i < host_set->n_ports; i++) + if (status & (1 << i)) { + struct ata_port *ap = host_set->ports[i]; + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { + sil24_host_intr(host_set->ports[i]); + handled++; + } else + printk(KERN_ERR DRV_NAME + ": interrupt from disabled port %d\n", i); + } + + spin_unlock(&host_set->lock); + out: + return IRQ_RETVAL(handled); +} + +static int sil24_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp; + struct sil24_cmd_block *cb; + size_t cb_size = sizeof(*cb); + dma_addr_t cb_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + memset(pp, 0, sizeof(*pp)); + + pp->tf.command = ATA_DRDY; + + cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); + if (!cb) { + kfree(pp); + return -ENOMEM; + } + memset(cb, 0, cb_size); + + pp->cmd_block = cb; + pp->cmd_block_dma = cb_dma; + + ap->private_data = pp; + + return 0; +} + +static void sil24_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp = ap->private_data; + size_t cb_size = sizeof(*pp->cmd_block); + + dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); + kfree(pp); +} + +static void sil24_host_stop(struct ata_host_set *host_set) +{ + struct sil24_host_priv *hpriv = host_set->private_data; + + iounmap(hpriv->host_base); + iounmap(hpriv->port_base); + kfree(hpriv); +} + +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_port_info *pinfo = &sil24_port_info[board_id]; + struct ata_probe_ent *probe_ent = NULL; + struct sil24_host_priv *hpriv = NULL; + void *host_base = NULL, *port_base = NULL; + int i, rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto out_disable; + + rc = -ENOMEM; + /* ioremap mmio registers */ + host_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host_base) + goto out_free; + port_base = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!port_base) + goto out_free; + + /* allocate & init probe_ent and hpriv */ + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + goto out_free; + + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + goto out_free; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pinfo->sht; + probe_ent->host_flags = pinfo->host_flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags); + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = port_base; + probe_ent->private_data = hpriv; + + memset(hpriv, 0, sizeof(*hpriv)); + hpriv->host_base = host_base; + hpriv->port_base = port_base; + + /* + * Configure the device + */ + /* + * FIXME: This device is certainly 64-bit capable. We just + * don't know how to use it. After fixing 32bit activation in + * this function, enable 64bit masks here. + */ + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + + /* GPIO off */ + writel(0, host_base + HOST_FLASH_CMD); + + /* Mask interrupts during initialization */ + writel(0, host_base + HOST_CTRL); + + for (i = 0; i < probe_ent->n_ports; i++) { + void *port = port_base + i * PORT_REGS_SIZE; + unsigned long portu = (unsigned long)port; + u32 tmp; + int cnt; + + probe_ent->port[i].cmd_addr = portu + PORT_PRB; + probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + + ata_std_ports(&probe_ent->port[i]); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* Clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + readl(port + PORT_CTRL_STAT); /* sync */ + for (cnt = 0; cnt < 10; cnt++) { + msleep(10); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_PORT_RST)) + break; + } + if (tmp & PORT_CS_PORT_RST) + printk(KERN_ERR DRV_NAME + "(%s): failed to clear port RST\n", + pci_name(pdev)); + } + + /* Zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* FIXME: 32bit activation? */ + writel(0, port + PORT_ACTIVATE_UPPER_ADDR); + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_STAT); + + /* Configure interrupts */ + writel(0xffff, port + PORT_IRQ_ENABLE_CLR); + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_SDB_FIS, + port + PORT_IRQ_ENABLE_SET); + + /* Clear interrupts */ + writel(0x0fff0fff, port + PORT_IRQ_STAT); + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* Clear port multiplier enable and resume bits */ + writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + + /* Reset itself */ + if (__sil24_reset_controller(port)) + printk(KERN_ERR DRV_NAME + "(%s): failed to reset controller\n", + pci_name(pdev)); + } + + /* Turn on interrupts */ + writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + + kfree(probe_ent); + return 0; + + out_free: + if (host_base) + iounmap(host_base); + if (port_base) + iounmap(port_base); + kfree(probe_ent); + kfree(hpriv); + pci_release_regions(pdev); + out_disable: + pci_disable_device(pdev); + return rc; +} + +static int __init sil24_init(void) +{ + return pci_module_init(&sil24_pci_driver); +} + +static void __exit sil24_exit(void) +{ + pci_unregister_driver(&sil24_pci_driver); +} + +MODULE_AUTHOR("Tejun Heo"); +MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sil24_pci_tbl); + +module_init(sil24_init); +module_exit(sil24_exit); diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index b227e51d12f4..057f7b98b6c4 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -102,7 +102,7 @@ static Scsi_Host_Template sis_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sis_ops = { +static const struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -263,7 +263,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &sis_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index d89d968bedac..e0f9570bc6dd 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -102,7 +102,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, } -static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -297,7 +297,7 @@ static Scsi_Host_Template k2_sata_sht = { }; -static struct ata_port_operations k2_sata_ops = { +static const struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 540a85191172..af08f4f650c1 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -137,7 +137,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void *dimm_mmio; + void __iomem *dimm_mmio; unsigned int doing_hdma; unsigned int hdma_prod; @@ -157,8 +157,8 @@ static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); @@ -196,7 +196,7 @@ static Scsi_Host_Template pdc_sata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_20621_ops = { +static const struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -247,7 +247,7 @@ static void pdc20621_host_stop(struct ata_host_set *host_set) { struct pci_dev *pdev = to_pci_dev(host_set->dev); struct pdc_host_priv *hpriv = host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; pci_iounmap(pdev, dimm_mmio); kfree(hpriv); @@ -669,8 +669,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -747,8 +747,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -899,7 +899,7 @@ out: DPRINTK("EXIT\n"); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -907,7 +907,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -1014,7 +1014,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist); + memcpy_toio(dimm_mmio + offset / 4, psource, dist); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -1023,8 +1023,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, - window_size / 4); + memcpy_toio(dimm_mmio, psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += window_size; @@ -1035,7 +1034,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4); + memcpy_toio(dimm_mmio, psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); } diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 4c9fb8b71be1..d68dc7d3422c 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -90,7 +90,7 @@ static Scsi_Host_Template uli_sht = { .ordered_flush = 1, }; -static struct ata_port_operations uli_ops = { +static const struct ata_port_operations uli_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -202,7 +202,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &uli_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 128b996b07b7..80e291a909a9 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -109,7 +109,7 @@ static Scsi_Host_Template svia_sht = { .ordered_flush = 1, }; -static struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -212,7 +212,7 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) struct ata_probe_ent *probe_ent; struct ata_port_info *ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index cf94e0158a8d..5af05fdf8544 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -86,7 +86,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -95,16 +95,16 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { - unsigned long mask_addr; + void __iomem *mask_addr; u8 mask; - mask_addr = (unsigned long) ap->host_set->mmio_base + + mask_addr = ap->host_set->mmio_base + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -115,7 +115,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) } -static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -231,7 +231,7 @@ static Scsi_Host_Template vsc_sata_sht = { }; -static struct ata_port_operations vsc_sata_ops = { +static const struct ata_port_operations vsc_sata_ops = { .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, @@ -283,7 +283,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d struct ata_probe_ent *probe_ent = NULL; unsigned long base; int pci_dev_busy = 0; - void *mmio_base; + void __iomem *mmio_base; int rc; if (!printed_version++) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1f0ebabf6d47..a5711d545d71 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(scsi_device_types); * Returns: Pointer to request block. */ struct scsi_request *scsi_allocate_request(struct scsi_device *sdev, - int gfp_mask) + gfp_t gfp_mask) { const int offset = ALIGN(sizeof(struct scsi_request), 4); const int size = offset + sizeof(struct request); @@ -196,7 +196,7 @@ struct scsi_host_cmd_pool { unsigned int users; char *name; unsigned int slab_flags; - unsigned int gfp_mask; + gfp_t gfp_mask; }; static struct scsi_host_cmd_pool scsi_cmd_pool = { @@ -213,7 +213,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { static DECLARE_MUTEX(host_cmd_pool_mutex); static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, - int gfp_mask) + gfp_t gfp_mask) { struct scsi_cmnd *cmd; @@ -245,7 +245,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, * * Returns: The allocated scsi command structure. */ -struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) +struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) { struct scsi_cmnd *cmd; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index de7f98cc38fe..6a3f6aae8a97 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -205,7 +205,8 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; - int data_direction, gfp_mask = GFP_KERNEL; + int data_direction; + gfp_t gfp_mask = GFP_KERNEL; if (!sic) return -EINVAL; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0074f28c37b2..3ff538809786 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -677,7 +677,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, int gfp_mask) +static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct scsi_host_sg_pool *sgp; struct scatterlist *sgl; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 40886e1c9616..861e51375d70 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2644,7 +2644,7 @@ static char * sg_page_malloc(int rqSz, int lowDma, int *retSzp) { char *resp = NULL; - int page_mask; + gfp_t page_mask; int order, a_size; int resSz = rqSz; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index d45ba4832162..5eb54d8019b4 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3577,7 +3577,8 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a static struct st_buffer * new_tape_buffer(int from_initialization, int need_dma, int max_sg) { - int i, priority, got = 0, segs = 0; + int i, got = 0, segs = 0; + gfp_t priority; struct st_buffer *tb; if (from_initialization) @@ -3610,7 +3611,8 @@ static struct st_buffer * /* Try to allocate enough space in the tape buffer */ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (new_size <= STbuffer->buffer_size) return 1; diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 679e678c7e6a..ddd0307fece2 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -50,6 +50,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/hardware.h> #include <asm/hardware/amba.h> #include <asm/hardware/amba_serial.h> diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 1ff629c74750..938d185841c9 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -50,6 +50,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> #include <asm/hardware/amba_serial.h> diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 87ef368384fb..6a67e8f585b3 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -408,7 +408,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON1, .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 0, @@ -417,7 +421,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON2, .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 1, @@ -551,6 +559,7 @@ console_initcall(clps711xuart_console_init); static struct uart_driver clps711x_reg = { .driver_name = "ttyCL", .dev_name = "ttyCL", + .devfs_name = "ttyCL", .major = SERIAL_CLPS711X_MAJOR, .minor = SERIAL_CLPS711X_MINOR, .nr = UART_NR, diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 7999686d7b47..8cc4cedadd99 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -358,6 +358,9 @@ static int serial_pxa_startup(struct uart_port *port) unsigned long flags; int retval; + if (port->line == 3) /* HWUART */ + up->mcr |= UART_MCR_AFE; + else up->mcr = 0; /* @@ -481,8 +484,10 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios, if ((up->port.uartclk / quot) < (2400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; - else + else if ((up->port.uartclk / quot) < (230400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; /* * Ok, we're now changing the port state. Do it with @@ -772,6 +777,20 @@ static struct uart_pxa_port serial_pxa_ports[] = { .ops = &serial_pxa_pops, .line = 2, }, + }, { /* HWUART */ + .name = "HWUART", + .cken = CKEN4_HWUART, + .port = { + .type = PORT_PXA, + .iotype = UPIO_MEM, + .membase = (void *)&HWUART, + .mapbase = __PREG(HWUART), + .irq = IRQ_HWUART, + .uartclk = 921600 * 16, + .fifosize = 64, + .ops = &serial_pxa_pops, + .line = 3, + }, } }; diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index fc15b4acc8af..57e800ac3cee 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index c3eb66f5a1a4..14c47a10da86 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1113,7 +1113,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) +static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index ac451fa7e4d2..1f1ed6211af8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, unsigned mem_flags); + int (*submit_urb) (struct urb *urb, gfp_t mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -200,7 +200,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags); + gfp_t mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -247,7 +247,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - unsigned mem_flags, dma_addr_t *dma); + gfp_t mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f1fb67fe22a8..f9a81e84dbdf 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -321,7 +321,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - unsigned mem_flags + gfp_t mem_flags ) { int i; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c846fefb7386..b32898e0a27d 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) +struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, unsigned mem_flags) +int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int pipe, temp, max; struct usb_device *dev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7d131509e419..4c57f3f649ed 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1147,7 +1147,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f2bdf4e1eb80..503201764f6b 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) +dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned mem_flags + gfp_t mem_flags ) { char *retval; struct dummy_ep *ep; @@ -541,7 +541,7 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) static int dummy_queue (struct usb_ep *_ep, struct usb_request *_req, - unsigned mem_flags) + gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -992,7 +992,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 49459e33e952..f1024e804d5c 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags); static int -set_ether_config (struct eth_dev *dev, unsigned gfp_flags) +set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1081,7 +1081,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1598,7 +1598,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1724,7 +1724,7 @@ clean: } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, unsigned gfp_flags) + unsigned n, gfp_t gfp_flags) { unsigned i; struct usb_request *req; @@ -1763,7 +1763,7 @@ extra: return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags) { int status; @@ -1779,7 +1779,7 @@ fail: return status; } -static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) +static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; @@ -1962,7 +1962,7 @@ drop: * normally just one notification will be queued. */ -static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, gfp_t); static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void @@ -2024,7 +2024,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags) +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); @@ -2092,7 +2092,7 @@ static int eth_stop (struct net_device *net) /*-------------------------------------------------------------------------*/ static struct usb_request * -eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) +eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags) { struct usb_request *req; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index eaab26f4ed37..b0f3cd63e3b9 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) +goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ finished: /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct goku_request *req; struct goku_ep *ep; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 4842577789c9..012d1e5f1524 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -71,13 +71,13 @@ static char *state_names[] = { static int lh7a40x_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *); static int lh7a40x_ep_disable(struct usb_ep *ep); -static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int); +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t); static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, - int); + gfp_t); static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, unsigned); -static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int); +static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); static int lh7a40x_set_halt(struct usb_ep *ep, int); static int lh7a40x_fifo_status(struct usb_ep *ep); @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, unsigned gfp_flags) + dma_addr_t * dma, gfp_t gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 477fab2e74d1..c32e1f7476da 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 58b3ec97fb9a..b7885dc0f42f 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) +omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -937,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 00dfe42d7a86..647028590b23 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { char *retval; @@ -422,7 +422,7 @@ static inline void ep0_idle (struct pxa2xx_udc *dev) } static int -write_packet(volatile unsigned long *uddr, struct pxa2xx_request *req, unsigned max) +write_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max) { u8 *buf; unsigned length, count; @@ -874,7 +874,7 @@ done: /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index a58f3e6e71f1..19a883f7d1b8 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -69,11 +69,11 @@ struct pxa2xx_ep { * UDDR = UDC Endpoint Data Register (the fifo) * DRCM = DMA Request Channel Map */ - volatile unsigned long *reg_udccs; - volatile unsigned long *reg_ubcr; - volatile unsigned long *reg_uddr; + volatile u32 *reg_udccs; + volatile u32 *reg_ubcr; + volatile u32 *reg_uddr; #ifdef USE_DMA - volatile unsigned long *reg_drcmr; + volatile u32 *reg_drcmr; #define drcmr(n) .reg_drcmr = & DRCMR ## n , #else #define drcmr(n) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index c925d9222f53..b35ac6d334f8 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -2091,7 +2091,7 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * usb_request or NULL if there is an error. */ static struct usb_request * -gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) +gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags) { struct usb_request *req; @@ -2132,7 +2132,7 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * endpoint, buffer len, and kmalloc flags. */ static struct gs_req_entry * -gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) { struct gs_req_entry *req; @@ -2173,7 +2173,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags) { int i; struct gs_port *port; @@ -2255,7 +2255,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6890e773b2a2..ec9c424f1d97 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) +source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) +set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) +set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b948ffd94f45..f5eb9e7b5b18 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -983,7 +983,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 5c38ad869485..91c2ab43cbcc 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -45,7 +45,7 @@ static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma) INIT_LIST_HEAD (&qtd->qtd_list); } -static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qtd *qtd; dma_addr_t dma; @@ -79,7 +79,7 @@ static void qh_destroy (struct kref *kref) dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); } -static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qh *qh; dma_addr_t dma; @@ -161,7 +161,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) } /* remember to add cleanup code (above) if you add anything here */ -static int ehci_mem_init (struct ehci_hcd *ehci, int flags) +static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) { int i; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 940d38ca7d91..5bb872c3496d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -477,7 +477,7 @@ qh_urb_transaction ( struct ehci_hcd *ehci, struct urb *urb, struct list_head *head, - int flags + gfp_t flags ) { struct ehci_qtd *qtd, *qtd_prev; dma_addr_t buf; @@ -629,7 +629,7 @@ static struct ehci_qh * qh_make ( struct ehci_hcd *ehci, struct urb *urb, - int flags + gfp_t flags ) { struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); u32 info1 = 0, info2 = 0; @@ -906,7 +906,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ccc7300baa6d..f0c8aa1ccd5d 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -589,7 +589,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { unsigned epnum; unsigned long flags; @@ -634,7 +634,7 @@ done: /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (unsigned mem_flags) +iso_stream_alloc (gfp_t mem_flags) { struct ehci_iso_stream *stream; @@ -851,7 +851,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, unsigned mem_flags) +iso_sched_alloc (unsigned packets, gfp_t mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -924,7 +924,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_itd *itd; @@ -1418,7 +1418,7 @@ itd_complete ( /*-------------------------------------------------------------------------*/ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1529,7 +1529,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_sitd *sitd; @@ -1779,7 +1779,7 @@ sitd_complete ( static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 0f6183a829c4..642f35068ce2 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -694,7 +694,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 67c1aa5eb1c1..f8da8c7af7c6 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index fd3c4d3714bd..9fb83dfb1eb4 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -84,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, unsigned mem_flags) +td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) +ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 03cf6accfe64..b5e7a478bc01 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -818,7 +818,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index ea0d168a8c67..4e0fbe2c1a9a 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1164,7 +1164,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, unsigned mem_flags) + struct urb *urb, gfp_t mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 03fb70ef2eb3..0592cb5e6c4d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -137,7 +137,7 @@ static void async_complete(struct urb *urb, struct pt_regs *ptregs) static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, __u8 request, __u8 requesttype, __u16 value, __u16 index, - unsigned int mem_flags) + gfp_t mem_flags) { struct usb_device *usbdev; struct uss720_async_request *rq; @@ -204,7 +204,7 @@ static unsigned int kill_all_async_requests_priv(struct parport_uss720_private * /* --------------------------------------------------------------------- */ -static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags) +static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; @@ -238,7 +238,7 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha return -EIO; } -static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags) +static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 861f00a43750..252a34fbb42c 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -753,7 +753,7 @@ static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - unsigned flags) + gfp_t flags) { int padlen; int headroom = skb_headroom(skb); diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index c8763ae33c73..c0f263b202a6 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -301,7 +301,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; int length = skb->len; diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index e04b0ce3611a..c82655d3d448 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -477,13 +477,13 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); /**************************************************************** int_callback *****************************************************************/ -static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, int mf) +static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) { int status; @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - unsigned mem_flags) + gfp_t mem_flags) { int result; diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index a4309c4a491b..cee55f8cf64f 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -500,7 +500,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 2ed2e5fb7778..b5a925dc1beb 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -517,7 +517,7 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { struct rndis_data_hdr *hdr; struct sk_buff *skb2; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6c460918d54f..fce81d738933 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); static void rx_complete (struct urb *urb, struct pt_regs *regs); -static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) +static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 7aa0abd1a9bd..89fc4958eecf 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -107,7 +107,7 @@ struct driver_info { /* fixup tx packet (add framing) */ struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, unsigned flags); + struct sk_buff *skb, gfp_t flags); /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index ee3b892aeabc..5d4b7d55b097 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -62,7 +62,7 @@ */ static struct sk_buff * -zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index c4e479ee926a..2f52261c7cc1 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -521,7 +521,7 @@ static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int int reqlen; char seq=0; struct urb *urb; - unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; + gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; len += 4; /* first 4 are for header */ diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 321dbe91dc14..cde6fd8eb390 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -22,6 +22,7 @@ #include <linux/ioport.h> #include <linux/list.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> |