From e5b13cb10de209f924fdf9478214bcf7e4008d6d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:51:43 -0800 Subject: [NETNS]: Process devinet ioctl in the correct namespace. Add namespace parameter to devinet_ioctl and locate device inside it for state changes. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index fc4e3db649e8..da05ab47ff2f 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -129,7 +129,7 @@ extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern struct net_device *ip_dev_find(struct net *net, __be32 addr); extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); -extern int devinet_ioctl(unsigned int cmd, void __user *); +extern int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_by_index(struct net *, int); extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); -- cgit v1.2.3 From 4c563f7669c10a12354b72b518c2287ffc6ebfb3 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 28 Feb 2008 21:31:08 -0800 Subject: [XFRM]: Speed up xfrm_policy and xfrm_state walking Change xfrm_policy and xfrm_state walking algorithm from O(n^2) to O(n). This is achieved adding the entries to one more list which is used solely for walking the entries. This also fixes some races where the dump can have duplicate or missing entries when the SPD/SADB is modified during an ongoing dump. Dumping SADB with 20000 entries using "time ip xfrm state" the sys time dropped from 1.012s to 0.080s. Signed-off-by: Timo Teras Signed-off-by: David S. Miller --- include/linux/xfrm.h | 3 +- include/net/xfrm.h | 52 +++++++++++++++++++++++++++++++-- net/key/af_key.c | 24 ++++++++++++--- net/xfrm/xfrm_policy.c | 79 +++++++++++++++++++++++++++++--------------------- net/xfrm/xfrm_state.c | 53 ++++++++++++++++++++++----------- net/xfrm/xfrm_user.c | 71 +++++++++++++++++++++++++++------------------ 6 files changed, 197 insertions(+), 85 deletions(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index e31b8c84f2c9..0c82c80b277f 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -113,7 +113,8 @@ enum { XFRM_POLICY_TYPE_MAIN = 0, XFRM_POLICY_TYPE_SUB = 1, - XFRM_POLICY_TYPE_MAX = 2 + XFRM_POLICY_TYPE_MAX = 2, + XFRM_POLICY_TYPE_ANY = 255 }; enum diff --git a/include/net/xfrm.h b/include/net/xfrm.h index eea7785cc757..9b6205665190 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -121,6 +121,7 @@ extern struct mutex xfrm_cfg_mutex; struct xfrm_state { /* Note: bydst is re-used during gc */ + struct list_head all; struct hlist_node bydst; struct hlist_node bysrc; struct hlist_node byspi; @@ -424,6 +425,7 @@ struct xfrm_tmpl struct xfrm_policy { struct xfrm_policy *next; + struct list_head bytype; struct hlist_node bydst; struct hlist_node byidx; @@ -1160,6 +1162,18 @@ struct xfrm6_tunnel { int priority; }; +struct xfrm_state_walk { + struct xfrm_state *state; + int count; + u8 proto; +}; + +struct xfrm_policy_walk { + struct xfrm_policy *policy; + int count; + u8 type, cur_type; +}; + extern void xfrm_init(void); extern void xfrm4_init(void); extern void xfrm_state_init(void); @@ -1184,7 +1198,23 @@ static inline void xfrm6_fini(void) extern int xfrm_proc_init(void); #endif -extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *); +static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) +{ + walk->proto = proto; + walk->state = NULL; + walk->count = 0; +} + +static inline void xfrm_state_walk_done(struct xfrm_state_walk *walk) +{ + if (walk->state != NULL) { + xfrm_state_put(walk->state); + walk->state = NULL; + } +} + +extern int xfrm_state_walk(struct xfrm_state_walk *walk, + int (*func)(struct xfrm_state *, int, void*), void *); extern struct xfrm_state *xfrm_state_alloc(void); extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, @@ -1306,7 +1336,25 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) #endif struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); -extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); + +static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) +{ + walk->cur_type = XFRM_POLICY_TYPE_MAIN; + walk->type = type; + walk->policy = NULL; + walk->count = 0; +} + +static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) +{ + if (walk->policy != NULL) { + xfrm_pol_put(walk->policy); + walk->policy = NULL; + } +} + +extern int xfrm_policy_walk(struct xfrm_policy_walk *walk, + int (*func)(struct xfrm_policy *, int, int, void*), void *); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, struct xfrm_selector *sel, diff --git a/net/key/af_key.c b/net/key/af_key.c index 8b5f486ac80f..7cb6f1213360 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1742,12 +1742,18 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr { u8 proto; struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; + struct xfrm_state_walk walk; + int rc; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return -EINVAL; - return xfrm_state_walk(proto, dump_sa, &data); + xfrm_state_walk_init(&walk, proto); + rc = xfrm_state_walk(&walk, dump_sa, &data); + xfrm_state_walk_done(&walk); + + return rc; } static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) @@ -1780,7 +1786,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) static u32 gen_reqid(void) { + struct xfrm_policy_walk walk; u32 start; + int rc; static u32 reqid = IPSEC_MANUAL_REQID_MAX; start = reqid; @@ -1788,8 +1796,10 @@ static u32 gen_reqid(void) ++reqid; if (reqid == 0) reqid = IPSEC_MANUAL_REQID_MAX+1; - if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, - (void*)&reqid) != -EEXIST) + xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); + rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid); + xfrm_policy_walk_done(&walk); + if (rc != -EEXIST) return reqid; } while (reqid != start); return 0; @@ -2665,8 +2675,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; + struct xfrm_policy_walk walk; + int rc; + + xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); + rc = xfrm_policy_walk(&walk, dump_sp, &data); + xfrm_policy_walk_done(&walk); - return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); + return rc; } static int key_notify_policy_flush(struct km_event *c) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9fc4c315f6cd..bae94a8031a2 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex); static DEFINE_RWLOCK(xfrm_policy_lock); +static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; EXPORT_SYMBOL(xfrm_policy_count); @@ -208,6 +209,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) policy = kzalloc(sizeof(struct xfrm_policy), gfp); if (policy) { + INIT_LIST_HEAD(&policy->bytype); INIT_HLIST_NODE(&policy->bydst); INIT_HLIST_NODE(&policy->byidx); rwlock_init(&policy->lock); @@ -230,6 +232,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) if (del_timer(&policy->timer)) BUG(); + write_lock_bh(&xfrm_policy_lock); + list_del(&policy->bytype); + write_unlock_bh(&xfrm_policy_lock); + security_xfrm_policy_free(policy); kfree(policy); } @@ -584,6 +590,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); + list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); write_unlock_bh(&xfrm_policy_lock); if (delpol) @@ -822,57 +829,60 @@ out: } EXPORT_SYMBOL(xfrm_policy_flush); -int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), +int xfrm_policy_walk(struct xfrm_policy_walk *walk, + int (*func)(struct xfrm_policy *, int, int, void*), void *data) { - struct xfrm_policy *pol, *last = NULL; - struct hlist_node *entry; - int dir, last_dir = 0, count, error; + struct xfrm_policy *old, *pol, *last = NULL; + int error = 0; + + if (walk->type >= XFRM_POLICY_TYPE_MAX && + walk->type != XFRM_POLICY_TYPE_ANY) + return -EINVAL; + if (walk->policy == NULL && walk->count != 0) + return 0; + + old = pol = walk->policy; + walk->policy = NULL; read_lock_bh(&xfrm_policy_lock); - count = 0; - for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { - struct hlist_head *table = xfrm_policy_bydst[dir].table; - int i; + for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { + if (walk->type != walk->cur_type && + walk->type != XFRM_POLICY_TYPE_ANY) + continue; - hlist_for_each_entry(pol, entry, - &xfrm_policy_inexact[dir], bydst) { - if (pol->type != type) + if (pol == NULL) { + pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], + struct xfrm_policy, bytype); + } + list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { + if (pol->dead) continue; if (last) { - error = func(last, last_dir % XFRM_POLICY_MAX, - count, data); - if (error) + error = func(last, xfrm_policy_id2dir(last->index), + walk->count, data); + if (error) { + xfrm_pol_hold(last); + walk->policy = last; goto out; - } - last = pol; - last_dir = dir; - count++; - } - for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { - hlist_for_each_entry(pol, entry, table + i, bydst) { - if (pol->type != type) - continue; - if (last) { - error = func(last, last_dir % XFRM_POLICY_MAX, - count, data); - if (error) - goto out; } - last = pol; - last_dir = dir; - count++; } + last = pol; + walk->count++; } + pol = NULL; } - if (count == 0) { + if (walk->count == 0) { error = -ENOENT; goto out; } - error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); + if (last) + error = func(last, xfrm_policy_id2dir(last->index), 0, data); out: read_unlock_bh(&xfrm_policy_lock); + if (old != NULL) + xfrm_pol_put(old); return error; } EXPORT_SYMBOL(xfrm_policy_walk); @@ -2365,6 +2375,9 @@ static void __init xfrm_policy_init(void) panic("XFRM: failed to allocate bydst hash\n"); } + for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) + INIT_LIST_HEAD(&xfrm_policy_bytype[dir]); + INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); register_netdevice_notifier(&xfrm_dev_notifier); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7ba65e82941c..9880b792e6a5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock); * Main use is finding SA after policy selected tunnel or transport mode. * Also, it can be used by ah/esp icmp error handler to find offending SA. */ +static LIST_HEAD(xfrm_state_all); static struct hlist_head *xfrm_state_bydst __read_mostly; static struct hlist_head *xfrm_state_bysrc __read_mostly; static struct hlist_head *xfrm_state_byspi __read_mostly; @@ -510,6 +511,7 @@ struct xfrm_state *xfrm_state_alloc(void) if (x) { atomic_set(&x->refcnt, 1); atomic_set(&x->tunnel_users, 0); + INIT_LIST_HEAD(&x->all); INIT_HLIST_NODE(&x->bydst); INIT_HLIST_NODE(&x->bysrc); INIT_HLIST_NODE(&x->byspi); @@ -533,6 +535,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) { BUG_TRAP(x->km.state == XFRM_STATE_DEAD); + spin_lock_bh(&xfrm_state_lock); + list_del(&x->all); + spin_unlock_bh(&xfrm_state_lock); + spin_lock_bh(&xfrm_state_gc_lock); hlist_add_head(&x->bydst, &xfrm_state_gc_list); spin_unlock_bh(&xfrm_state_gc_lock); @@ -909,6 +915,8 @@ static void __xfrm_state_insert(struct xfrm_state *x) x->genid = ++xfrm_state_genid; + list_add_tail(&x->all, &xfrm_state_all); + h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, x->props.reqid, x->props.family); hlist_add_head(&x->bydst, xfrm_state_bydst+h); @@ -1518,36 +1526,47 @@ unlock: } EXPORT_SYMBOL(xfrm_alloc_spi); -int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), +int xfrm_state_walk(struct xfrm_state_walk *walk, + int (*func)(struct xfrm_state *, int, void*), void *data) { - int i; - struct xfrm_state *x, *last = NULL; - struct hlist_node *entry; - int count = 0; + struct xfrm_state *old, *x, *last = NULL; int err = 0; + if (walk->state == NULL && walk->count != 0) + return 0; + + old = x = walk->state; + walk->state = NULL; spin_lock_bh(&xfrm_state_lock); - for (i = 0; i <= xfrm_state_hmask; i++) { - hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { - if (!xfrm_id_proto_match(x->id.proto, proto)) - continue; - if (last) { - err = func(last, count, data); - if (err) - goto out; + if (x == NULL) + x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); + list_for_each_entry_from(x, &xfrm_state_all, all) { + if (x->km.state == XFRM_STATE_DEAD) + continue; + if (!xfrm_id_proto_match(x->id.proto, walk->proto)) + continue; + if (last) { + err = func(last, walk->count, data); + if (err) { + xfrm_state_hold(last); + walk->state = last; + goto out; } - last = x; - count++; } + last = x; + walk->count++; } - if (count == 0) { + if (walk->count == 0) { err = -ENOENT; goto out; } - err = func(last, 0, data); + if (last) + err = func(last, 0, data); out: spin_unlock_bh(&xfrm_state_lock); + if (old != NULL) + xfrm_state_put(old); return err; } EXPORT_SYMBOL(xfrm_state_walk); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f971ca5645f8..f5fd5b3147cc 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -532,8 +532,6 @@ struct xfrm_dump_info { struct sk_buff *out_skb; u32 nlmsg_seq; u16 nlmsg_flags; - int start_idx; - int this_idx; }; static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) @@ -600,9 +598,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) struct nlmsghdr *nlh; int err; - if (sp->this_idx < sp->start_idx) - goto out; - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); if (nlh == NULL) @@ -615,8 +610,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) goto nla_put_failure; nlmsg_end(skb, nlh); -out: - sp->this_idx++; return 0; nla_put_failure: @@ -624,18 +617,32 @@ nla_put_failure: return err; } +static int xfrm_dump_sa_done(struct netlink_callback *cb) +{ + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; + xfrm_state_walk_done(walk); + return 0; +} + static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) { + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; struct xfrm_dump_info info; + BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + info.in_skb = cb->skb; info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; - info.this_idx = 0; - info.start_idx = cb->args[0]; - (void) xfrm_state_walk(0, dump_one_state, &info); - cb->args[0] = info.this_idx; + + if (!cb->args[0]) { + cb->args[0] = 1; + xfrm_state_walk_init(walk, 0); + } + + (void) xfrm_state_walk(walk, dump_one_state, &info); return skb->len; } @@ -654,7 +661,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, info.out_skb = skb; info.nlmsg_seq = seq; info.nlmsg_flags = 0; - info.this_idx = info.start_idx = 0; if (dump_one_state(x, 0, &info)) { kfree_skb(skb); @@ -1232,9 +1238,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr struct sk_buff *skb = sp->out_skb; struct nlmsghdr *nlh; - if (sp->this_idx < sp->start_idx) - goto out; - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); if (nlh == NULL) @@ -1250,8 +1253,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr goto nlmsg_failure; nlmsg_end(skb, nlh); -out: - sp->this_idx++; return 0; nlmsg_failure: @@ -1259,21 +1260,33 @@ nlmsg_failure: return -EMSGSIZE; } +static int xfrm_dump_policy_done(struct netlink_callback *cb) +{ + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + + xfrm_policy_walk_done(walk); + return 0; +} + static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) { + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; struct xfrm_dump_info info; + BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + info.in_skb = cb->skb; info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; - info.this_idx = 0; - info.start_idx = cb->args[0]; - (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); -#ifdef CONFIG_XFRM_SUB_POLICY - (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); -#endif - cb->args[0] = info.this_idx; + + if (!cb->args[0]) { + cb->args[0] = 1; + xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); + } + + (void) xfrm_policy_walk(walk, dump_one_policy, &info); return skb->len; } @@ -1293,7 +1306,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, info.out_skb = skb; info.nlmsg_seq = seq; info.nlmsg_flags = 0; - info.this_idx = info.start_idx = 0; if (dump_one_policy(xp, dir, 0, &info) < 0) { kfree_skb(skb); @@ -1891,15 +1903,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { static struct xfrm_link { int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); int (*dump)(struct sk_buff *, struct netlink_callback *); + int (*done)(struct netlink_callback *); } xfrm_dispatch[XFRM_NR_MSGTYPES] = { [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, - .dump = xfrm_dump_sa }, + .dump = xfrm_dump_sa, + .done = xfrm_dump_sa_done }, [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, - .dump = xfrm_dump_policy }, + .dump = xfrm_dump_policy, + .done = xfrm_dump_policy_done }, [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, @@ -1938,7 +1953,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; - return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); + return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done); } err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, -- cgit v1.2.3 From 9b0f976f27f00a81cf47643d90854659626795b4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:13:15 -0800 Subject: [INET]: Remove struct net_proto_family* from _init calls. struct net_proto_family* is not used in icmp[v6]_init, ndisc_init, igmp_init and tcp_v4_init. Remove it. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 2 +- include/net/icmp.h | 2 +- include/net/ndisc.h | 4 ++-- include/net/tcp.h | 2 +- net/ipv4/af_inet.c | 4 ++-- net/ipv4/icmp.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/af_inet6.c | 6 +++--- net/ipv6/icmp.c | 2 +- net/ipv6/mcast.c | 2 +- net/ipv6/ndisc.c | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 7c5e9817e998..8f86d6b621c8 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -176,7 +176,7 @@ extern void icmpv6_send(struct sk_buff *skb, __u32 info, struct net_device *dev); -extern int icmpv6_init(struct net_proto_family *ops); +extern int icmpv6_init(void); extern int icmpv6_err_convert(int type, int code, int *err); extern void icmpv6_cleanup(void); diff --git a/include/net/icmp.h b/include/net/icmp.h index 9f7ef3c8baef..7bf714d9d7c7 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -48,7 +48,7 @@ struct sk_buff; extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); -extern void icmp_init(struct net_proto_family *ops); +extern void icmp_init(void); extern void icmp_out_count(unsigned char type); /* Move into dst.h ? */ diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 59b70624b056..5aedf324de66 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -77,7 +77,7 @@ struct nd_opt_hdr { } __attribute__((__packed__)); -extern int ndisc_init(struct net_proto_family *ops); +extern int ndisc_init(void); extern void ndisc_cleanup(void); @@ -107,7 +107,7 @@ extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *d /* * IGMP */ -extern int igmp6_init(struct net_proto_family *ops); +extern int igmp6_init(void); extern void igmp6_cleanup(void); diff --git a/include/net/tcp.h b/include/net/tcp.h index 7de4ea3a04d9..ae9774b478f5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1373,7 +1373,7 @@ struct tcp_request_sock_ops { #endif }; -extern void tcp_v4_init(struct net_proto_family *ops); +extern void tcp_v4_init(void); extern void tcp_init(void); #endif /* _TCP_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c270080f370e..a7a99ac856dc 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1415,7 +1415,7 @@ static int __init inet_init(void) ip_init(); - tcp_v4_init(&inet_family_ops); + tcp_v4_init(); /* Setup TCP slab cache for open requests. */ tcp_init(); @@ -1430,7 +1430,7 @@ static int __init inet_init(void) * Set the ICMP layer up */ - icmp_init(&inet_family_ops); + icmp_init(); /* * Initialise the multicast router diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index a13c074dac09..98372db66c66 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1139,7 +1139,7 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { }, }; -void __init icmp_init(struct net_proto_family *ops) +void __init icmp_init(void) { struct inet_sock *inet; int i; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 00156bf421ca..256032a41069 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2443,7 +2443,7 @@ struct proto tcp_prot = { REF_PROTO_INUSE(tcp) }; -void __init tcp_v4_init(struct net_proto_family *ops) +void __init tcp_v4_init(void) { if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f0aa97738746..9869f87243cf 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -808,13 +808,13 @@ static int __init inet6_init(void) if (err) goto sysctl_fail; #endif - err = icmpv6_init(&inet6_family_ops); + err = icmpv6_init(); if (err) goto icmp_fail; - err = ndisc_init(&inet6_family_ops); + err = ndisc_init(); if (err) goto ndisc_fail; - err = igmp6_init(&inet6_family_ops); + err = igmp6_init(); if (err) goto igmp_fail; err = ipv6_netfilter_init(); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 121d517bf91c..b9b13a77ba30 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -780,7 +780,7 @@ drop_no_count: */ static struct lock_class_key icmpv6_socket_sk_dst_lock_key; -int __init icmpv6_init(struct net_proto_family *ops) +int __init icmpv6_init(void) { struct sock *sk; int err, i, j; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ab228d1ea114..8ce894d90063 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2597,7 +2597,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { }; #endif -int __init igmp6_init(struct net_proto_family *ops) +int __init igmp6_init(void) { struct ipv6_pinfo *np; struct sock *sk; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0d33a7d32125..1fc33c8c7232 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1733,7 +1733,7 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, #endif -int __init ndisc_init(struct net_proto_family *ops) +int __init ndisc_init(void) { struct ipv6_pinfo *np; struct sock *sk; -- cgit v1.2.3 From ee688b000d35f413f33561ec9c7d3355be561e2f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Jan 2008 19:38:39 +0100 Subject: nl80211: export hardware bitrate/channel capabilities This makes nl80211 export the hardware bitrate/channel capabilities as registered in a wiphy. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 64 ++++++++++++++++++++++++++++++++++++++++++ net/wireless/nl80211.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9fecf902419c..63695060db9f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -161,6 +161,9 @@ enum nl80211_commands { * given for %NL80211_CMD_GET_STATION, nested attribute containing * info as possible, see &enum nl80211_sta_stats. * + * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, + * consisting of a nested array. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -195,6 +198,8 @@ enum nl80211_attrs { NL80211_ATTR_STA_VLAN, NL80211_ATTR_STA_STATS, + NL80211_ATTR_WIPHY_BANDS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -280,4 +285,63 @@ enum nl80211_sta_stats { NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 }; +/** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, + * an array of nested frequency attributes + * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, + * an array of nested bitrate attributes + */ +enum nl80211_band_attr { + __NL80211_BAND_ATTR_INVALID, + NL80211_BAND_ATTR_FREQS, + NL80211_BAND_ATTR_RATES, + + /* keep last */ + __NL80211_BAND_ATTR_AFTER_LAST, + NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_frequency_attr - frequency attributes + * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz + * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current + * regulatory domain. + * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is + * permitted on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory + * on this channel in current regulatory domain. + */ +enum nl80211_frequency_attr { + __NL80211_FREQUENCY_ATTR_INVALID, + NL80211_FREQUENCY_ATTR_FREQ, + NL80211_FREQUENCY_ATTR_DISABLED, + NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, + NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_RADAR, + + /* keep last */ + __NL80211_FREQUENCY_ATTR_AFTER_LAST, + NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_bitrate_attr - bitrate attributes + * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps + * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported + * in 2.4 GHz band. + */ +enum nl80211_bitrate_attr { + __NL80211_BITRATE_ATTR_INVALID, + NL80211_BITRATE_ATTR_RATE, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, + + /* keep last */ + __NL80211_BITRATE_ATTR_AFTER_LAST, + NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3a214f63f91..b123f58d3909 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -98,6 +98,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { void *hdr; + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; + enum ieee80211_band band; + struct ieee80211_channel *chan; + struct ieee80211_rate *rate; + int i; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); if (!hdr) @@ -105,6 +112,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); + if (!nl_bands) + goto nla_put_failure; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!dev->wiphy.bands[band]) + continue; + + nl_band = nla_nest_start(msg, band); + if (!nl_band) + goto nla_put_failure; + + /* add frequencies */ + nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); + if (!nl_freqs) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { + nl_freq = nla_nest_start(msg, i); + if (!nl_freq) + goto nla_put_failure; + + chan = &dev->wiphy.bands[band]->channels[i]; + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + nla_nest_end(msg, nl_freq); + } + + nla_nest_end(msg, nl_freqs); + + /* add bitrates */ + nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); + if (!nl_rates) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { + nl_rate = nla_nest_start(msg, i); + if (!nl_rate) + goto nla_put_failure; + + rate = &dev->wiphy.bands[band]->bitrates[i]; + NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, + rate->bitrate); + if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); + + nla_nest_end(msg, nl_rate); + } + + nla_nest_end(msg, nl_rates); + + nla_nest_end(msg, nl_band); + } + nla_nest_end(msg, nl_bands); + return genlmsg_end(msg, hdr); nla_put_failure: -- cgit v1.2.3 From 66f7ac50ed7cc5c19a62bc97e8f6e7891004a03a Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 31 Jan 2008 19:48:22 +0100 Subject: nl80211: Add monitor interface configuration flags This allows precise control over what a monitor interface shows. Signed-off-by: Michael Wu Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 35 +++++++++++++++++++++++++++++++++++ include/net/cfg80211.h | 24 ++++++++++++++++++++++-- net/mac80211/cfg.c | 4 ++-- net/wireless/nl80211.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 101 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 63695060db9f..a9f0b93324a2 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -164,6 +164,9 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, * consisting of a nested array. * + * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_mntr_flags. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -200,6 +203,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_BANDS, + NL80211_ATTR_MNTR_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -344,4 +349,34 @@ enum nl80211_bitrate_attr { NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 }; +/** + * enum nl80211_mntr_flags - monitor configuration flags + * + * Monitor configuration flags. + * + * @__NL80211_MNTR_FLAG_INVALID: reserved + * + * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS + * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @NL80211_MNTR_FLAG_CONTROL: pass control frames + * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering + * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. + * overrides all other flags. + * + * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use + * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag + */ +enum nl80211_mntr_flags { + __NL80211_MNTR_FLAG_INVALID, + NL80211_MNTR_FLAG_FCSFAIL, + NL80211_MNTR_FLAG_PLCPFAIL, + NL80211_MNTR_FLAG_CONTROL, + NL80211_MNTR_FLAG_OTHER_BSS, + NL80211_MNTR_FLAG_COOK_FRAMES, + + /* keep last */ + __NL80211_MNTR_FLAG_AFTER_LAST, + NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bcc480b8892a..ab4caf63954f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -163,6 +163,26 @@ struct station_stats { u32 tx_bytes; }; +/** + * enum monitor_flags - monitor flags + * + * Monitor interface configuration flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS + * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @MONITOR_FLAG_CONTROL: pass control frames + * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering + * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + */ +enum monitor_flags { + MONITOR_FLAG_FCSFAIL = 1<attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); @@ -362,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); + err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, + type, err ? NULL : &flags); rtnl_unlock(); unlock: @@ -375,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 flags; if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -395,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, - nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags); rtnl_unlock(); unlock: -- cgit v1.2.3 From ffc7689ddae5cbe12bde437ae0f2b386d568b5cd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 20 Feb 2008 19:08:10 +0100 Subject: ssb: Add support for 8bit register access This adds support for 8bit wide register reads/writes. This is needed in order to support the gigabit ethernet core. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 18 ++++++++++++++++++ drivers/ssb/pci.c | 28 ++++++++++++++++++++++++++++ drivers/ssb/pcmcia.c | 32 ++++++++++++++++++++++++++++++++ include/linux/ssb/ssb.h | 10 ++++++++++ 4 files changed, 88 insertions(+) (limited to 'include/linux') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index bedb2b4ee9d2..8db40c4b86e9 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -505,6 +505,14 @@ error: return err; } +static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readb(bus->mmio + offset); +} + static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; @@ -521,6 +529,14 @@ static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) return readl(bus->mmio + offset); } +static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writeb(value, bus->mmio + offset); +} + static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) { struct ssb_bus *bus = dev->bus; @@ -539,8 +555,10 @@ static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ static const struct ssb_bus_ops ssb_ssb_ops = { + .read8 = ssb_ssb_read8, .read16 = ssb_ssb_read16, .read32 = ssb_ssb_read32, + .write8 = ssb_ssb_write8, .write16 = ssb_ssb_write16, .write32 = ssb_ssb_write32, }; diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index b434df75047f..1facc7620fc8 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -572,6 +572,19 @@ static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) } #endif /* DEBUG */ +static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return 0xFF; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return 0xFF; + } + return ioread8(bus->mmio + offset); +} + static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; @@ -598,6 +611,19 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) return ioread32(bus->mmio + offset); } +static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + iowrite8(value, bus->mmio + offset); +} + static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) { struct ssb_bus *bus = dev->bus; @@ -626,8 +652,10 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) /* Not "static", as it's used in main.c */ const struct ssb_bus_ops ssb_pci_ops = { + .read8 = ssb_pci_read8, .read16 = ssb_pci_read16, .read32 = ssb_pci_read32, + .write8 = ssb_pci_write8, .write16 = ssb_pci_write16, .write32 = ssb_pci_write32, }; diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 46816cda8b98..84b3a845a8a8 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -172,6 +172,22 @@ static int select_core_and_segment(struct ssb_device *dev, return 0; } +static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + unsigned long flags; + int err; + u8 value = 0xFF; + + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) + value = readb(bus->mmio + offset); + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return value; +} + static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; @@ -206,6 +222,20 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) return (lo | (hi << 16)); } +static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + struct ssb_bus *bus = dev->bus; + unsigned long flags; + int err; + + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) + writeb(value, bus->mmio + offset); + mmiowb(); + spin_unlock_irqrestore(&bus->bar_lock, flags); +} + static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) { struct ssb_bus *bus = dev->bus; @@ -238,8 +268,10 @@ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) /* Not "static", as it's used in main.c */ const struct ssb_bus_ops ssb_pcmcia_ops = { + .read8 = ssb_pcmcia_read8, .read16 = ssb_pcmcia_read16, .read32 = ssb_pcmcia_read32, + .write8 = ssb_pcmcia_write8, .write16 = ssb_pcmcia_write16, .write32 = ssb_pcmcia_write32, }; diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 20add65215af..860d28c6d149 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -72,8 +72,10 @@ struct ssb_device; /* Lowlevel read/write operations on the device MMIO. * Internal, don't use that outside of ssb. */ struct ssb_bus_ops { + u8 (*read8)(struct ssb_device *dev, u16 offset); u16 (*read16)(struct ssb_device *dev, u16 offset); u32 (*read32)(struct ssb_device *dev, u16 offset); + void (*write8)(struct ssb_device *dev, u16 offset, u8 value); void (*write16)(struct ssb_device *dev, u16 offset, u16 value); void (*write32)(struct ssb_device *dev, u16 offset, u32 value); }; @@ -344,6 +346,10 @@ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); /* Device MMIO register read/write functions. */ +static inline u8 ssb_read8(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read8(dev, offset); +} static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) { return dev->ops->read16(dev, offset); @@ -352,6 +358,10 @@ static inline u32 ssb_read32(struct ssb_device *dev, u16 offset) { return dev->ops->read32(dev, offset); } +static inline void ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + dev->ops->write8(dev, offset, value); +} static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) { dev->ops->write16(dev, offset, value); -- cgit v1.2.3 From 28de57d1a9eb7e67badb731297197fcbef0cc19e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 22 Feb 2008 16:14:58 +0100 Subject: ssb: Add CHIPCO IRQ access functions This patch adds functions to setup and read the CHIPCO IRQ. Signed-off-by: Aurelien Jarno Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon.c | 10 ++++++++++ include/linux/ssb/ssb_driver_chipcommon.h | 4 ++++ 2 files changed, 14 insertions(+) (limited to 'include/linux') diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index e586321a473a..45b672a69003 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -353,6 +353,16 @@ void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); } +void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + chipco_write32_masked(cc, SSB_CHIPCO_IRQMASK, mask, value); +} + +u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask) +{ + return chipco_read32(cc, SSB_CHIPCO_IRQSTAT) & mask; +} + u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) { return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 536851b946f6..b548a54ff1f5 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -390,6 +390,10 @@ extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks); +void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value); + +u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask); + /* Chipcommon GPIO pin access. */ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); -- cgit v1.2.3 From 988b705077d8f922408913f4f521ae073256d4a1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Mar 2008 12:20:57 -0800 Subject: [ARP]: Introduce the arp_hdr_len helper. There are some place, that calculate the ARP header length. These calculations are correct, but a) some operate with "magic" constants, b) enlarge the code length (sometimes at the cost of coding style), c) are not informative from the first glance. The proposal is to introduce a helper, that includes all the good sides of these calculations. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 5 +---- include/linux/if_arp.h | 6 ++++++ net/core/netpoll.c | 6 ++---- net/ipv4/arp.c | 9 +++------ net/ipv4/ipconfig.c | 5 +---- net/ipv4/netfilter/arp_tables.c | 5 +---- 6 files changed, 14 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 966643473da7..5fc9d8d58ece 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2646,10 +2646,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack if (!slave || !slave_do_arp_validate(bond, slave)) goto out_unlock; - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto out_unlock; arp = arp_hdr(skb); diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 296e8e86e91d..4d3401812e6c 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -156,6 +156,12 @@ static inline struct arphdr *arp_hdr(const struct sk_buff *skb) { return (struct arphdr *)skb_network_header(skb); } + +static inline int arp_hdr_len(struct net_device *dev) +{ + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2; +} #endif #endif /* _LINUX_IF_ARP_H */ diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 6faa128a4c8e..7ae98659d79d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -384,9 +384,7 @@ static void arp_reply(struct sk_buff *skb) if (skb->dev->flags & IFF_NOARP) return; - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * skb->dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return; skb_reset_network_header(skb); @@ -414,7 +412,7 @@ static void arp_reply(struct sk_buff *skb) ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; - size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + size = arp_hdr_len(skb->dev); send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), LL_RESERVED_SPACE(np->dev)); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8e17f65f4002..69e80bd9774a 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -570,14 +570,13 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, * Allocate a buffer */ - skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) - + LL_RESERVED_SPACE(dev), GFP_ATOMIC); + skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb_reset_network_header(skb); - arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); + arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev)); skb->dev = dev; skb->protocol = htons(ETH_P_ARP); if (src_hw == NULL) @@ -916,9 +915,7 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, goto freeskb; /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto freeskb; arp = arp_hdr(skb); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index c90e75a66e81..f84041d1f623 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -459,10 +459,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (rarp->ar_pro != htons(ETH_P_IP)) goto drop; - if (!pskb_may_pull(skb, - sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * 4))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto drop; /* OK, it is all there and looks valid, process... */ diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index a7591ce344d2..9b5904486184 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -233,10 +233,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, void *table_base; struct xt_table_info *private; - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * skb->dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; indev = in ? in->name : nulldevname; -- cgit v1.2.3 From e898d4db2749c6052072e9bc4448e396cbdeb06a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 1 Mar 2008 01:06:47 +0900 Subject: [UDP]: Allow users to configure UDP-Lite. Let's give users an option for disabling UDP-Lite (~4K). old: | text data bss dec hex filename | 286498 12432 6072 305002 4a76a net/ipv4/built-in.o | 193830 8192 3204 205226 321aa net/ipv6/ipv6.o new (without UDP-Lite): | text data bss dec hex filename | 284086 12136 5432 301654 49a56 net/ipv4/built-in.o | 191835 7832 3076 202743 317f7 net/ipv6/ipv6.o Signed-off-by: YOSHIFUJI Hideaki --- include/linux/udp.h | 11 +++++++++++ include/net/ipv6.h | 5 +++++ include/net/transp_v6.h | 5 +++++ include/net/udplite.h | 9 +++++++-- net/ipv4/Kconfig | 10 ++++++++++ net/ipv4/Makefile | 3 ++- net/ipv4/af_inet.c | 7 ++++++- net/ipv4/proc.c | 5 ++++- net/ipv4/udp.c | 24 ++++++++++++++---------- net/ipv6/Makefile | 3 ++- net/ipv6/af_inet6.c | 14 ++++++++++++++ net/ipv6/ipv6_sockglue.c | 6 +++++- net/ipv6/proc.c | 6 ++++++ net/ipv6/udp.c | 16 ++++++++-------- 14 files changed, 99 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/udp.h b/include/linux/udp.h index 8ec703f462da..4144664d69d9 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -70,8 +70,10 @@ struct udp_sock { #define UDPLITE_BIT 0x1 /* set by udplite proto init function */ #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ +#ifdef CONFIG_IP_UDPLITE __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ __u8 unused[3]; +#endif /* * For encapsulation sockets. */ @@ -82,7 +84,16 @@ static inline struct udp_sock *udp_sk(const struct sock *sk) { return (struct udp_sock *)sk; } + +#ifdef CONFIG_IP_UDPLITE #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) +#define IS_PROTO_UDPLITE(__proto) ((__proto) == IPPROTO_UDPLITE) +#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP || (level) == SOL_UDPLITE) +#else +#define IS_UDPLITE(__sk) 0 +#define IS_PROTO_UDPLITE(__proto) 0 +#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP) +#endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8b05c65415cb..96b1763bfcaa 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -603,8 +603,13 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); +#ifdef CONFIG_IP_UDPLITE extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); +#else +static inline int udplite6_proc_init(void) { return 0; } +static inline void udplite6_proc_exit(void) { } +#endif extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 27394e0447d8..902e6c6bc793 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -27,8 +27,13 @@ extern int rawv6_init(void); extern void rawv6_exit(void); extern int udpv6_init(void); extern void udpv6_exit(void); +#ifdef CONFIG_IP_UDPLITE extern int udplitev6_init(void); extern void udplitev6_exit(void); +#else +static inline int udplitev6_init(void) { return 0; } +static inline void udplitev6_exit(void) { } +#endif extern int tcpv6_init(void); extern void tcpv6_exit(void); diff --git a/include/net/udplite.h b/include/net/udplite.h index b76b2e377af4..01ddb2c20264 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -25,7 +25,9 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, /* Designate sk as UDP-Lite socket */ static inline int udplite_sk_init(struct sock *sk) { +#ifdef CONFIG_IP_UDPLITE udp_sk(sk)->pcflag = UDPLITE_BIT; +#endif return 0; } @@ -69,7 +71,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) { int cscov = up->len; - +#ifdef CONFIG_IP_UDPLITE /* * Sender has set `partial coverage' option on UDP-Lite socket */ @@ -93,13 +95,15 @@ static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) * illegal, we fall back to the defaults here. */ } +#endif return cscov; } static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) { - int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); __wsum csum = 0; +#ifdef CONFIG_IP_UDPLITE + int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ @@ -112,6 +116,7 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) if ((cscov -= len) <= 0) break; } +#endif return csum; } diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 19880b086e71..efe3832c4ad8 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -632,5 +632,15 @@ config TCP_MD5SIG If unsure, say N. +config IP_UDPLITE + bool "IP: UDP-Lite Protocol (RFC 3828)" + default n + ---help--- + UDP-Lite (RFC 3828) is a UDP-like protocol with variable-length + checksum. Read for + details. + + If unsure, say N. + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index ad40ef3f9ebc..e88cebdf3e30 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o udplite.o \ + datagram.o raw.o udp.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o \ inet_fragment.o @@ -49,6 +49,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o +obj-$(CONFIG_IP_UDPLITE) += udplite.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f539bd48718..67260c0eaaa8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1317,15 +1317,18 @@ static int __init init_ipv4_mibs(void) if (snmp_mib_init((void **)udp_statistics, sizeof(struct udp_mib)) < 0) goto err_udp_mib; +#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_statistics, sizeof(struct udp_mib)) < 0) goto err_udplite_mib; - +#endif tcp_mib_init(); return 0; +#ifdef CONFIG_IP_UDPLITE err_udplite_mib: +#endif snmp_mib_free((void **)udp_statistics); err_udp_mib: snmp_mib_free((void **)tcp_statistics); @@ -1423,8 +1426,10 @@ static int __init inet_init(void) /* Setup UDP memory threshold */ udp_init(); +#ifdef CONFIG_IP_UDPLITE /* Add UDP-Lite (RFC 3828) */ udplite4_register(); +#endif /* * Set the ICMP layer up diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d63474c6b400..d75ddb7fa4b8 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -59,7 +59,9 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot), atomic_read(&udp_memory_allocated)); +#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot)); +#endif seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); @@ -349,6 +351,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) snmp_fold_field((void **)udp_statistics, snmp4_udp_list[i].entry)); +#ifdef CONFIG_IP_UDPLITE /* the UDP and UDP-Lite MIBs are the same */ seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) @@ -359,7 +362,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %lu", snmp_fold_field((void **)udplite_statistics, snmp4_udp_list[i].entry)); - +#endif seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7ea1b67b6de1..acc353aa89eb 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1127,7 +1127,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, UDP_SKB_CB(skb)->partial_cov = 0; UDP_SKB_CB(skb)->cscov = skb->len; - if (proto == IPPROTO_UDPLITE) { + if (IS_PROTO_UDPLITE(proto)) { err = udplite_checksum_init(skb, uh); if (err) return err; @@ -1175,7 +1175,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (ulen > skb->len) goto short_packet; - if (proto == IPPROTO_UDP) { + if (IS_PROTO_UDPLITE(proto)) { /* UDP validates ulen. */ if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) goto short_packet; @@ -1217,7 +1217,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1229,7 +1229,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], short_packet: LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), ulen, @@ -1244,14 +1244,14 @@ csum_error: * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); kfree_skb(skb); return 0; } @@ -1279,7 +1279,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, struct udp_sock *up = udp_sk(sk); int val; int err = 0; +#ifdef CONFIG_IP_UDPLITE int is_udplite = IS_UDPLITE(sk); +#endif if (optlenpcrlen = val; up->pcflag |= UDPLITE_RECV_CC; break; +#endif default: err = -ENOPROTOOPT; @@ -1352,7 +1356,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_push_pending_frames); return ip_setsockopt(sk, level, optname, optval, optlen); @@ -1362,7 +1366,7 @@ int udp_setsockopt(struct sock *sk, int level, int optname, int compat_udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_push_pending_frames); return compat_ip_setsockopt(sk, level, optname, optval, optlen); @@ -1416,7 +1420,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return ip_getsockopt(sk, level, optname, optval, optlen); } @@ -1425,7 +1429,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname, int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return compat_ip_getsockopt(sk, level, optname, optval, optlen); } diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index ae14617e607f..81969479955f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o @@ -17,6 +17,7 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o +ipv6-$(CONFIG_IP_UDPLITE) += udplite.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 9869f87243cf..243c42a6b80d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -691,12 +691,16 @@ static int __init init_ipv6_mibs(void) goto err_icmpmsg_mib; if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udp_mib; +#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udplite_mib; +#endif return 0; +#ifdef CONFIG_IP_UDPLITE err_udplite_mib: +#endif snmp_mib_free((void **)udp_stats_in6); err_udp_mib: snmp_mib_free((void **)icmpv6msg_statistics); @@ -715,7 +719,9 @@ static void cleanup_ipv6_mibs(void) snmp_mib_free((void **)icmpv6_statistics); snmp_mib_free((void **)icmpv6msg_statistics); snmp_mib_free((void **)udp_stats_in6); +#ifdef CONFIG_IP_UDPLITE snmp_mib_free((void **)udplite_stats_in6); +#endif } static int inet6_net_init(struct net *net) @@ -760,9 +766,11 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; +#ifdef CONFIG_IP_UDPLITE err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; +#endif err = proto_register(&rawv6_prot, 1); if (err) @@ -933,8 +941,10 @@ out_sock_register_fail: out_unregister_raw_proto: proto_unregister(&rawv6_prot); out_unregister_udplite_proto: +#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); out_unregister_udp_proto: +#endif proto_unregister(&udpv6_prot); out_unregister_tcp_proto: proto_unregister(&tcpv6_prot); @@ -950,7 +960,9 @@ static void __exit inet6_exit(void) rtnl_unregister_all(PF_INET6); udpv6_exit(); +#ifdef CONFIG_IP_UDPLITE udplitev6_exit(); +#endif tcpv6_exit(); /* Cleanup code parts. */ @@ -982,7 +994,9 @@ static void __exit inet6_exit(void) unregister_pernet_subsys(&inet6_net_ops); cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); +#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); +#endif proto_unregister(&udpv6_prot); proto_unregister(&tcpv6_prot); } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bf2a686aa13d..0a18fecb93d1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -239,7 +239,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && +#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && +#endif sk->sk_protocol != IPPROTO_TCP) break; @@ -279,7 +281,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } else { struct proto *prot = &udp_prot; - if (sk->sk_protocol == IPPROTO_UDPLITE) + if (IS_PROTO_UDPLITE(sk->sk_protocol)) prot = &udplite_prot; local_bh_disable(); sock_prot_inuse_add(sk->sk_prot, -1); @@ -844,7 +846,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && +#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && +#endif sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 199ef379e501..5ba7ae849d04 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -39,8 +39,10 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", sock_prot_inuse_get(&udpv6_prot)); +#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE6: inuse %d\n", sock_prot_inuse_get(&udplitev6_prot)); +#endif seq_printf(seq, "RAW6: inuse %d\n", sock_prot_inuse_get(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -111,6 +113,7 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; +#ifdef CONFIG_IP_UDPLITE static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), @@ -118,6 +121,7 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; +#endif static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) { @@ -176,7 +180,9 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); +#ifdef CONFIG_IP_UDPLITE snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); +#endif } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 53739de829db..55feac7ba717 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -400,7 +400,7 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, UDP_SKB_CB(skb)->partial_cov = 0; UDP_SKB_CB(skb)->cscov = skb->len; - if (proto == IPPROTO_UDPLITE) { + if (IS_PROTO_UDPLITE(proto)) { err = udplite_checksum_init(skb, uh); if (err) return err; @@ -489,7 +489,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -510,11 +510,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], short_packet: LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", ulen, skb->len); discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); kfree_skb(skb); return 0; } @@ -890,7 +890,7 @@ int udpv6_destroy_sock(struct sock *sk) int udpv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_v6_push_pending_frames); return ipv6_setsockopt(sk, level, optname, optval, optlen); @@ -900,7 +900,7 @@ int udpv6_setsockopt(struct sock *sk, int level, int optname, int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_v6_push_pending_frames); return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); @@ -910,7 +910,7 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return ipv6_getsockopt(sk, level, optname, optval, optlen); } @@ -919,7 +919,7 @@ int udpv6_getsockopt(struct sock *sk, int level, int optname, int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); } -- cgit v1.2.3 From 95e41e93e18d8e1e272ce23d96bae4f17ce11d42 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 6 Dec 2007 15:43:30 -0800 Subject: [IPV6]: Make ndisc_flow_init() common for later use. For later use, this patch is renaming ndisc_flow_init() to icmpv6_flow_init() and putting it in common place. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/icmpv6.h | 8 ++++++++ net/ipv6/icmp.c | 16 ++++++++++++++++ net/ipv6/ndisc.c | 23 ++++------------------- 3 files changed, 28 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 8f86d6b621c8..e4d4300d768f 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -182,6 +182,14 @@ extern int icmpv6_err_convert(int type, int code, extern void icmpv6_cleanup(void); extern void icmpv6_param_prob(struct sk_buff *skb, int code, int pos); + +struct flowi; +extern void icmpv6_flow_init(struct sock *sk, + struct flowi *fl, + u8 type, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int oif); #endif #endif diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 12c0b85d6c46..cff74127ea32 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -777,6 +777,22 @@ drop_no_count: return 0; } +void icmpv6_flow_init(struct sock *sk, struct flowi *fl, + u8 type, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int oif) +{ + memset(fl, 0, sizeof(*fl)); + ipv6_addr_copy(&fl->fl6_src, saddr); + ipv6_addr_copy(&fl->fl6_dst, daddr); + fl->proto = IPPROTO_ICMPV6; + fl->fl_icmp_type = type; + fl->fl_icmp_code = 0; + fl->oif = oif; + security_sk_classify_flow(sk, fl); +} + /* * Special lock-class for __icmpv6_sk: */ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1fc33c8c7232..8db5f4a419aa 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -441,21 +441,6 @@ static void pndisc_destructor(struct pneigh_entry *n) /* * Send a Neighbour Advertisement */ - -static inline void ndisc_flow_init(struct flowi *fl, u8 type, - struct in6_addr *saddr, struct in6_addr *daddr, - int oif) -{ - memset(fl, 0, sizeof(*fl)); - ipv6_addr_copy(&fl->fl6_src, saddr); - ipv6_addr_copy(&fl->fl6_dst, daddr); - fl->proto = IPPROTO_ICMPV6; - fl->fl_icmp_type = type; - fl->fl_icmp_code = 0; - fl->oif = oif; - security_sk_classify_flow(ndisc_socket->sk, fl); -} - static void __ndisc_send(struct net_device *dev, struct neighbour *neigh, struct in6_addr *daddr, struct in6_addr *saddr, @@ -474,8 +459,8 @@ static void __ndisc_send(struct net_device *dev, type = icmp6h->icmp6_type; - ndisc_flow_init(&fl, type, saddr, daddr, - dev->ifindex); + icmpv6_flow_init(ndisc_socket->sk, &fl, type, + saddr, daddr, dev->ifindex); dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); if (!dst) @@ -1439,8 +1424,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, return; } - ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, - dev->ifindex); + icmpv6_flow_init(ndisc_socket->sk, &fl, NDISC_REDIRECT, + &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); dst = ip6_route_output(NULL, &fl); if (dst == NULL) -- cgit v1.2.3 From ee6b967301b4aa5d4a4b61e2f682f086266db9fb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2008 18:30:47 -0800 Subject: [IPV4]: Add 'rtable' field in struct sk_buff to alias 'dst' and avoid casts (Anonymous) unions can help us to avoid ugly casts. A common cast it the (struct rtable *)skb->dst one. Defining an union like : union { struct dst_entry *dst; struct rtable *rtable; }; permits to use skb->rtable in place. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 ++++- include/net/inet_sock.h | 2 +- net/bridge/br_netfilter.c | 14 +++++++------- net/dccp/ipv4.c | 7 +++---- net/ipv4/arp.c | 4 ++-- net/ipv4/icmp.c | 10 +++++----- net/ipv4/igmp.c | 2 +- net/ipv4/ip_forward.c | 2 +- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_options.c | 16 ++++++++-------- net/ipv4/ip_output.c | 10 +++++----- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv4/ipmr.c | 6 +++--- net/ipv4/netfilter/ipt_MASQUERADE.c | 2 +- net/ipv4/netfilter/nf_nat_helper.c | 4 ++-- net/ipv4/route.c | 22 +++++++++++----------- net/ipv4/tcp_ipv4.c | 5 ++--- net/ipv4/udp_ipv4.c | 2 +- net/netfilter/nf_conntrack_netbios_ns.c | 2 +- net/sched/em_meta.c | 4 ++-- net/sctp/protocol.c | 8 ++++---- 23 files changed, 69 insertions(+), 68 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bbd8d0027e2f..7beb239d2ee0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -256,7 +256,10 @@ struct sk_buff { ktime_t tstamp; struct net_device *dev; - struct dst_entry *dst; + union { + struct dst_entry *dst; + struct rtable *rtable; + }; struct sec_path *sp; /* diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 89cd011edb99..8660cb0fa0dd 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -195,7 +195,7 @@ static inline int inet_sk_ehashfn(const struct sock *sk) static inline int inet_iif(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return skb->rtable->rt_iif; } #endif /* _INET_SOCK_H */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 1c0efd8ad9f3..0278a069c6f1 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -223,8 +223,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) } nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; - skb->dst = (struct dst_entry *)&__fake_rtable; - dst_hold(skb->dst); + skb->rtable = &__fake_rtable; + dst_hold(&__fake_rtable.u.dst); skb->dev = nf_bridge->physindev; nf_bridge_push_encap_header(skb); @@ -388,8 +388,8 @@ bridged_dnat: skb->pkt_type = PACKET_HOST; } } else { - skb->dst = (struct dst_entry *)&__fake_rtable; - dst_hold(skb->dst); + skb->rtable = &__fake_rtable; + dst_hold(&__fake_rtable.u.dst); } skb->dev = nf_bridge->physindev; @@ -608,9 +608,9 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (skb->dst == (struct dst_entry *)&__fake_rtable) { - dst_release(skb->dst); - skb->dst = NULL; + if (skb->rtable == &__fake_rtable) { + dst_release(&__fake_rtable.u.dst); + skb->rtable = NULL; } return NF_ACCEPT; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 514a40b7fc7f..17ad69e90e48 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -450,7 +450,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif, + struct flowi fl = { .oif = skb->rtable->rt_iif, .nl_u = { .ip4_u = { .daddr = ip_hdr(skb)->saddr, .saddr = ip_hdr(skb)->daddr, @@ -511,7 +511,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; - if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) + if (rxskb->rtable->rt_type != RTN_LOCAL) return; dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); @@ -563,8 +563,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 69e80bd9774a..efe01df8fc0e 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -475,7 +475,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) return 1; } - paddr = ((struct rtable*)skb->dst)->rt_gateway; + paddr = skb->rtable->rt_gateway; if (arp_set_predefined(inet_addr_type(&init_net, paddr), haddr, paddr, dev)) return 0; @@ -814,7 +814,7 @@ static int arp_process(struct sk_buff *skb) if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input(skb, tip, sip, 0, dev) == 0) { - rt = (struct rtable*)skb->dst; + rt = skb->rtable; addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cee77d606fbe..ff9a8e643fcc 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -381,7 +381,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct net *net = rt->u.dst.dev->nd_net; struct sock *sk = icmp_sk(net); struct inet_sock *inet = inet_sk(sk); @@ -438,7 +438,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct iphdr *iph; int room; struct icmp_bxm icmp_param; - struct rtable *rt = (struct rtable *)skb_in->dst; + struct rtable *rt = skb_in->rtable; struct ipcm_cookie ipc; __be32 saddr; u8 tos; @@ -616,7 +616,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) RT_TOS(tos), rt2->u.dst.dev); dst_release(&rt2->u.dst); - rt2 = (struct rtable *)skb_in->dst; + rt2 = skb_in->rtable; skb_in->dst = odst; } @@ -943,7 +943,7 @@ static void icmp_address(struct sk_buff *skb) static void icmp_address_reply(struct sk_buff *skb) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct net_device *dev = skb->dev; struct in_device *in_dev; struct in_ifaddr *ifa; @@ -988,7 +988,7 @@ static void icmp_discard(struct sk_buff *skb) int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { int nh; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d3f34a772f3b..6a4ee8da6994 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (((struct rtable*)skb->dst)->fl.iif == 0) + if (skb->rtable->fl.iif == 0) break; /* don't rely on MC router hearing unicast reports */ if (skb->pkt_type == PACKET_MULTICAST || diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 0b3b328d82db..9d6d3befd854 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -80,7 +80,7 @@ int ip_forward(struct sk_buff *skb) if (!xfrm4_route_forward(skb)) goto drop; - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e7821ba7a9a0..f9ee84420cb3 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -619,7 +619,7 @@ static int ipgre_rcv(struct sk_buff *skb) #ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(iph->daddr)) { /* Looped back packet, drop it! */ - if (((struct rtable*)skb->dst)->fl.iif == 0) + if (skb->rtable->fl.iif == 0) goto drop; tunnel->stat.multicast++; skb->pkt_type = PACKET_BROADCAST; @@ -699,7 +699,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (skb->protocol == htons(ETH_P_IP)) { - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 65631391d479..d36e310b314d 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -351,7 +351,7 @@ static int ip_rcv_finish(struct sk_buff *skb) if (iph->ihl > 5 && ip_rcv_options(skb)) goto drop; - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if (rt->rt_type == RTN_MULTICAST) IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); else if (rt->rt_type == RTN_BROADCAST) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index baaedd9689a0..df93a9c2efda 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -107,7 +107,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sptr = skb_network_header(skb); dptr = dopt->__data; - daddr = ((struct rtable*)skb->dst)->rt_spec_dst; + daddr = skb->rtable->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; @@ -258,7 +258,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) unsigned char * optptr; int optlen; unsigned char * pp_ptr = NULL; - struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL; + struct rtable *rt = skb ? skb->rtable : NULL; if (!opt) { opt = &(IPCB(skb)->opt); @@ -558,7 +558,7 @@ void ip_forward_options(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); unsigned char * optptr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; unsigned char *raw = skb_network_header(skb); if (opt->rr_needaddr) { @@ -606,7 +606,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) __be32 nexthop; struct iphdr *iph = ip_hdr(skb); unsigned char *optptr = skb_network_header(skb) + opt->srr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct rtable *rt2; int err; @@ -631,13 +631,13 @@ int ip_options_rcv_srr(struct sk_buff *skb) } memcpy(&nexthop, &optptr[srrptr-1], 4); - rt = (struct rtable*)skb->dst; - skb->dst = NULL; + rt = skb->rtable; + skb->rtable = NULL; err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); - rt2 = (struct rtable*)skb->dst; + rt2 = skb->rtable; if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { ip_rt_put(rt2); - skb->dst = &rt->u.dst; + skb->rtable = rt; return -EINVAL; } ip_rt_put(rt); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 341779e685d9..dc494ea594a7 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -142,7 +142,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; /* Build the IP header. */ @@ -240,7 +240,7 @@ static int ip_finish_output(struct sk_buff *skb) int ip_mc_output(struct sk_buff *skb) { struct sock *sk = skb->sk; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct net_device *dev = rt->u.dst.dev; /* @@ -321,7 +321,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) /* Skip all of this if the packet is already routed, * f.e. by something like SCTP. */ - rt = (struct rtable *) skb->dst; + rt = skb->rtable; if (rt != NULL) goto packet_routed; @@ -441,7 +441,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) unsigned int mtu, hlen, left, len, ll_rs, pad; int offset; __be16 not_last_frag; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; int err = 0; dev = rt->u.dst.dev; @@ -1357,7 +1357,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar } replyopts; struct ipcm_cookie ipc; __be32 daddr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; if (ip_options_echo(&replyopts.opt, skb)) return; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index de0572c88859..e7c9e4e72327 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -57,7 +57,7 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) { struct in_pktinfo info; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; info.ipi_addr.s_addr = ip_hdr(skb)->daddr; if (rt) { diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index dbaed69de06a..894bce96284a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -528,7 +528,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { /* NBMA tunnel */ - if ((rt = (struct rtable*)skb->dst) == NULL) { + if ((rt = skb->rtable) == NULL) { tunnel->stat.tx_fifo_errors++; goto tx_error; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a94f52c207a7..7d63d74ef62a 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1283,7 +1283,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local if (vif_table[vif].dev != skb->dev) { int true_vifi; - if (((struct rtable*)skb->dst)->fl.iif == 0) { + if (skb->rtable->fl.iif == 0) { /* It is our own packet, looped back. Very complicated situation... @@ -1357,7 +1357,7 @@ dont_forward: int ip_mr_input(struct sk_buff *skb) { struct mfc_cache *cache; - int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL; + int local = skb->rtable->rt_flags&RTCF_LOCAL; /* Packet is looped back after forward, it should not be forwarded second time, but still can be delivered locally. @@ -1594,7 +1594,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) { int err; struct mfc_cache *cache; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; read_lock(&mrt_lock); cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 313b3fcf387e..c6817b18366a 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -77,7 +77,7 @@ masquerade_tg(struct sk_buff *skb, const struct net_device *in, return NF_ACCEPT; mr = targinfo; - rt = (struct rtable *)skb->dst; + rt = skb->rtable; newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE); if (!newsrc) { printk("MASQUERADE: %s ate my IP address\n", out->name); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index ca57f47bbd25..2fca727aa8ba 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -139,7 +139,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; struct tcphdr *tcph; int oldlen, datalen; @@ -217,7 +217,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8c3e165f0034..1051326c36b2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1289,7 +1289,7 @@ reject_redirect: static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) { - struct rtable *rt = (struct rtable*)dst; + struct rtable *rt = (struct rtable *)dst; struct dst_entry *ret = dst; if (rt) { @@ -1330,7 +1330,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) void ip_rt_send_redirect(struct sk_buff *skb) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct in_device *in_dev = in_dev_get(rt->u.dst.dev); if (!in_dev) @@ -1379,7 +1379,7 @@ out: static int ip_error(struct sk_buff *skb) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; unsigned long now; int code; @@ -1548,7 +1548,7 @@ static void ipv4_link_failure(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - rt = (struct rtable *) skb->dst; + rt = skb->rtable; if (rt) dst_set_expires(&rt->u.dst, 0); } @@ -1708,7 +1708,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex); - return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst); + return rt_intern_hash(hash, rth, &skb->rtable); e_nobufs: in_dev_put(in_dev); @@ -1869,7 +1869,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif); - return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + return rt_intern_hash(hash, rth, &skb->rtable); } /* @@ -2025,7 +2025,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif); - err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + err = rt_intern_hash(hash, rth, &skb->rtable); goto done; no_route: @@ -2091,7 +2091,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); - skb->dst = (struct dst_entry*)rth; + skb->rtable = rth; return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2598,7 +2598,7 @@ int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp) static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct rtmsg *r; struct nlmsghdr *nlh; long expires; @@ -2742,7 +2742,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); local_bh_enable(); - rt = (struct rtable*) skb->dst; + rt = skb->rtable; if (err == 0 && rt->u.dst.error) err = -rt->u.dst.error; } else { @@ -2762,7 +2762,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (err) goto errout_free; - skb->dst = &rt->u.dst; + skb->rtable = rt; if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3873c4dbeaeb..a79e324638eb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -552,7 +552,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL) + if (skb->rtable->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ @@ -1262,8 +1262,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) #endif /* Never answer to SYNs send to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto drop; /* TW buckets are converted to open requests without diff --git a/net/ipv4/udp_ipv4.c b/net/ipv4/udp_ipv4.c index 40978de7fb51..fd14c2c50ed4 100644 --- a/net/ipv4/udp_ipv4.c +++ b/net/ipv4/udp_ipv4.c @@ -893,7 +893,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], struct sock *sk; struct udphdr *uh = udp_hdr(skb); unsigned short ulen; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; __be32 saddr = ip_hdr(skb)->saddr; __be32 daddr = ip_hdr(skb)->daddr; diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 9810d81e2a06..60dedaded84e 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -47,7 +47,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, { struct nf_conntrack_expect *exp; struct iphdr *iph = ip_hdr(skb); - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct in_device *in_dev; __be32 mask = 0; diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 3da4129b89d1..72cf86e3c090 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -256,10 +256,10 @@ META_COLLECTOR(int_rtclassid) META_COLLECTOR(int_rtiif) { - if (unlikely(skb->dst == NULL)) + if (unlikely(skb->rtable == NULL)) *err = -1; else - dst->value = ((struct rtable*) skb->dst)->fl.iif; + dst->value = skb->rtable->fl.iif; } /************************************************************************** diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8d9d929f6cea..1afef08f6c1d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -363,7 +363,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, return 0; /* Is this a broadcast address? */ - if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST) + if (skb && skb->rtable->rt_flags & RTCF_BROADCAST) return 0; return 1; @@ -539,7 +539,7 @@ static void sctp_v4_get_saddr(struct sctp_association *asoc, /* What interface did this skb arrive on? */ static int sctp_v4_skb_iif(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return skb->rtable->rt_iif; } /* Was this packet marked by Explicit Congestion Notification? */ @@ -828,8 +828,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n", __FUNCTION__, skb, skb->len, - NIPQUAD(((struct rtable *)skb->dst)->rt_src), - NIPQUAD(((struct rtable *)skb->dst)->rt_dst)); + NIPQUAD(skb->rtable->rt_src), + NIPQUAD(skb->rtable->rt_dst)); SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); return ip_queue_xmit(skb, ipfragok); -- cgit v1.2.3 From f59d43899e279c77924a7ada4bec8c70e5aeca06 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 5 Mar 2008 20:58:10 -0800 Subject: [IPV6]: Fix powerpc allmodconfig build warnings. Introduced by changeset 95e41e93e18d8e1e272ce23d96bae4f17ce11d42 ("[IPV6]: Make ndisc_flow_init() common for later use.") Reported by Stephen Rothwell. In file included from net/ipv6/netfilter/ip6_tables.c:21: include/linux/icmpv6.h:192: warning: 'struct in6_addr' declared inside parameter list include/linux/icmpv6.h:192: warning: its scope is only this definition or declaration, which is probably not what you want Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index e4d4300d768f..03067443198a 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -184,6 +184,7 @@ extern void icmpv6_param_prob(struct sk_buff *skb, int code, int pos); struct flowi; +struct in6_addr; extern void icmpv6_flow_init(struct sock *sk, struct flowi *fl, u8 type, -- cgit v1.2.3 From 37c5798968d0ce4d479f114f1d5785551b57bfa5 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:04 +0100 Subject: wireless: various definitions for mesh networking Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f577c8f1c66d..f27d11ab418b 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -97,6 +97,7 @@ #define IEEE80211_MAX_FRAME_LEN 2352 #define IEEE80211_MAX_SSID_LEN 32 +#define IEEE80211_MAX_MESH_ID_LEN 32 struct ieee80211_hdr { __le16 frame_control; @@ -109,6 +110,16 @@ struct ieee80211_hdr { } __attribute__ ((packed)); +struct ieee80211s_hdr { + u8 flags; + u8 ttl; + u8 seqnum[3]; + u8 eaddr1[6]; + u8 eaddr2[6]; + u8 eaddr3[6]; +} __attribute__ ((packed)); + + struct ieee80211_mgmt { __le16 frame_control; __le16 duration; @@ -206,6 +217,23 @@ struct ieee80211_mgmt { __le16 params; __le16 reason_code; } __attribute__((packed)) delba; + struct{ + u8 action_code; + /* capab_info for open and confirm, + * reason for close + */ + __le16 aux; + /* Followed in plink_confirm by status + * code, AID and supported rates, + * and directly by supported rates in + * plink_open and plink_close + */ + u8 variable[0]; + } __attribute__((packed)) plink_action; + struct{ + u8 action_code; + u8 variable[0]; + } __attribute__((packed)) mesh_action; } u; } __attribute__ ((packed)) action; } u; @@ -437,6 +465,13 @@ enum ieee80211_eid { WLAN_EID_TS_DELAY = 43, WLAN_EID_TCLAS_PROCESSING = 44, WLAN_EID_QOS_CAPA = 46, + /* 802.11s */ + WLAN_EID_MESH_CONFIG = 36, /* Pending IEEE 802.11 ANA approval */ + WLAN_EID_MESH_ID = 37, /* Pending IEEE 802.11 ANA approval */ + WLAN_EID_PEER_LINK = 40, /* Pending IEEE 802.11 ANA approval */ + WLAN_EID_PREQ = 53, /* Pending IEEE 802.11 ANA approval */ + WLAN_EID_PREP = 54, /* Pending IEEE 802.11 ANA approval */ + WLAN_EID_PERR = 55, /* Pending IEEE 802.11 ANA approval */ /* 802.11h */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, -- cgit v1.2.3 From cc0672a1066829be7e1b0128a13e36a2d0a15479 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Feb 2008 15:17:05 +0100 Subject: WEXT: add mesh interface type This introduces a new WEXT type IW_MODE_MESH for mesh networks, used for scan results. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/wireless.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 3160dfed73ca..2864b1699ecc 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -455,6 +455,7 @@ #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ +#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ /* Statistics flags (bitmask in updated) */ #define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ -- cgit v1.2.3 From 2ec600d672e74488f8d1acf67a0a2baed222564c Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:06 +0100 Subject: nl80211/cfg80211: support for mesh, sta dumping Added support for mesh id and mesh path operation as well as station structure dumping. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 119 +++++++++++-- include/net/cfg80211.h | 139 +++++++++++++-- net/mac80211/cfg.c | 20 ++- net/wireless/nl80211.c | 438 +++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 650 insertions(+), 66 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a9f0b93324a2..ea6517e58b04 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -78,6 +78,18 @@ * or, if no MAC address given, all stations, on the interface identified * by %NL80211_ATTR_IFINDEX. * + * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all mesh paths, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -112,6 +124,11 @@ enum nl80211_commands { /* add commands here */ + NL80211_CMD_GET_MPATH, + NL80211_CMD_SET_MPATH, + NL80211_CMD_NEW_MPATH, + NL80211_CMD_DEL_MPATH, + /* used to define NL80211_CMD_MAX below */ __NL80211_CMD_AFTER_LAST, NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 @@ -157,13 +174,21 @@ enum nl80211_commands { * restriction (at most %NL80211_MAX_SUPP_RATES). * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station * to, or the AP interface the station was originally added to to. - * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info + * @NL80211_ATTR_STA_INFO: information about a station, part of station info * given for %NL80211_CMD_GET_STATION, nested attribute containing - * info as possible, see &enum nl80211_sta_stats. + * info as possible, see &enum nl80211_sta_info. * * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, * consisting of a nested array. * + * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). + * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. + * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path + * info given for %NL80211_CMD_GET_MPATH, nested attribute described at + * &enum nl80211_mpath_info. + * + * * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of * &enum nl80211_mntr_flags. * @@ -199,7 +224,7 @@ enum nl80211_attrs { NL80211_ATTR_STA_LISTEN_INTERVAL, NL80211_ATTR_STA_SUPPORTED_RATES, NL80211_ATTR_STA_VLAN, - NL80211_ATTR_STA_STATS, + NL80211_ATTR_STA_INFO, NL80211_ATTR_WIPHY_BANDS, @@ -207,6 +232,11 @@ enum nl80211_attrs { /* add attributes here, update the policy in nl80211.c */ + NL80211_ATTR_MESH_ID, + NL80211_ATTR_STA_PLINK_ACTION, + NL80211_ATTR_MPATH_NEXT_HOP, + NL80211_ATTR_MPATH_INFO, + __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; @@ -223,6 +253,7 @@ enum nl80211_attrs { * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames + * @NL80211_IFTYPE_MESH_POINT: mesh point * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @__NL80211_IFTYPE_AFTER_LAST: internal use * @@ -238,6 +269,7 @@ enum nl80211_iftype { NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_WDS, NL80211_IFTYPE_MONITOR, + NL80211_IFTYPE_MESH_POINT, /* keep last */ __NL80211_IFTYPE_AFTER_LAST, @@ -267,27 +299,78 @@ enum nl80211_sta_flags { }; /** - * enum nl80211_sta_stats - station statistics + * enum nl80211_sta_info - station information * - * These attribute types are used with %NL80211_ATTR_STA_STATS + * These attribute types are used with %NL80211_ATTR_STA_INFO * when getting information about a station. * - * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved - * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) - * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) - * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) - * @__NL80211_STA_STAT_AFTER_LAST: internal - * @NL80211_STA_STAT_MAX: highest possible station stats attribute + * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved + * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) + * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute + */ +enum nl80211_sta_info { + __NL80211_STA_INFO_INVALID, + NL80211_STA_INFO_INACTIVE_TIME, + NL80211_STA_INFO_RX_BYTES, + NL80211_STA_INFO_TX_BYTES, + NL80211_STA_INFO_LLID, + NL80211_STA_INFO_PLID, + NL80211_STA_INFO_PLINK_STATE, + + /* keep last */ + __NL80211_STA_INFO_AFTER_LAST, + NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mpath_flags - nl80211 mesh path flags + * + * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active + * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running + * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN + * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set + * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded + */ +enum nl80211_mpath_flags { + NL80211_MPATH_FLAG_ACTIVE = 1<<0, + NL80211_MPATH_FLAG_RESOLVING = 1<<1, + NL80211_MPATH_FLAG_DSN_VALID = 1<<2, + NL80211_MPATH_FLAG_FIXED = 1<<3, + NL80211_MPATH_FLAG_RESOLVED = 1<<4, +}; + +/** + * enum nl80211_mpath_info - mesh path information + * + * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting + * information about a mesh path. + * + * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved + * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination + * @NL80211_ATTR_MPATH_DSN: destination sequence number + * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path + * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now + * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in + * &enum nl80211_mpath_flags; + * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec + * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries */ -enum nl80211_sta_stats { - __NL80211_STA_STAT_INVALID, - NL80211_STA_STAT_INACTIVE_TIME, - NL80211_STA_STAT_RX_BYTES, - NL80211_STA_STAT_TX_BYTES, +enum nl80211_mpath_info { + __NL80211_MPATH_INFO_INVALID, + NL80211_MPATH_INFO_FRAME_QLEN, + NL80211_MPATH_INFO_DSN, + NL80211_MPATH_INFO_METRIC, + NL80211_MPATH_INFO_EXPTIME, + NL80211_MPATH_INFO_FLAGS, + NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + NL80211_MPATH_INFO_DISCOVERY_RETRIES, /* keep last */ - __NL80211_STA_STAT_AFTER_LAST, - NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 + __NL80211_MPATH_INFO_AFTER_LAST, + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ab4caf63954f..e00750836ba5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -12,6 +12,16 @@ * Copyright 2006, 2007 Johannes Berg */ +/** + * struct vif_params - describes virtual interface parameters + * @mesh_id: mesh ID to use + * @mesh_id_len: length of the mesh ID + */ +struct vif_params { + u8 *mesh_id; + int mesh_id_len; +}; + /* Radiotap header iteration * implemented in net/wireless/radiotap.c * docs in Documentation/networking/radiotap-headers.txt @@ -108,6 +118,19 @@ enum station_flags { STATION_FLAG_WME = 1<ieee80211_ptr); struct sta_info *sta; @@ -307,13 +309,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, /* XXX: verify sta->dev == dev */ - stats->filled = STATION_STAT_INACTIVE_TIME | - STATION_STAT_RX_BYTES | - STATION_STAT_TX_BYTES; + sinfo->filled = STATION_INFO_INACTIVE_TIME | + STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES; - stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); - stats->rx_bytes = sta->rx_bytes; - stats->tx_bytes = sta->tx_bytes; + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); + sinfo->rx_bytes = sta->rx_bytes; + sinfo->tx_bytes = sta->tx_bytes; sta_info_put(sta); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5b3474798b8d..64a7460af734 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -81,8 +81,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, + [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_MESH_ID_LEN }, + [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, }; /* message building helper */ @@ -369,11 +373,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; + struct vif_params params; int err, ifindex; enum nl80211_iftype type; struct net_device *dev; u32 flags; + memset(¶ms, 0, sizeof(params)); + if (info->attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); if (type > NL80211_IFTYPE_MAX) @@ -392,12 +399,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) goto unlock; } + if (type == NL80211_IFTYPE_MESH_POINT && + info->attrs[NL80211_ATTR_MESH_ID]) { + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + } + rtnl_lock(); err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, - type, err ? NULL : &flags); + type, err ? NULL : &flags, ¶ms); rtnl_unlock(); unlock: @@ -408,10 +421,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; + struct vif_params params; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; u32 flags; + memset(¶ms, 0, sizeof(params)); + if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -430,15 +446,22 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) goto unlock; } + if (type == NL80211_IFTYPE_MESH_POINT && + info->attrs[NL80211_ATTR_MESH_ID]) { + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + } + rtnl_lock(); err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, nla_data(info->attrs[NL80211_ATTR_IFNAME]), - type, err ? NULL : &flags); + type, err ? NULL : &flags, ¶ms); rtnl_unlock(); + unlock: cfg80211_put_dev(drv); return err; @@ -866,10 +889,10 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, - u8 *mac_addr, struct station_stats *stats) + u8 *mac_addr, struct station_info *sinfo) { void *hdr; - struct nlattr *statsattr; + struct nlattr *sinfoattr; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); if (!hdr) @@ -878,20 +901,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); - if (!statsattr) + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); + if (!sinfoattr) goto nla_put_failure; - if (stats->filled & STATION_STAT_INACTIVE_TIME) - NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, - stats->inactive_time); - if (stats->filled & STATION_STAT_RX_BYTES) - NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, - stats->rx_bytes); - if (stats->filled & STATION_STAT_TX_BYTES) - NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, - stats->tx_bytes); - - nla_nest_end(msg, statsattr); + if (sinfo->filled & STATION_INFO_INACTIVE_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, + sinfo->inactive_time); + if (sinfo->filled & STATION_INFO_RX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, + sinfo->rx_bytes); + if (sinfo->filled & STATION_INFO_TX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, + sinfo->tx_bytes); + if (sinfo->filled & STATION_INFO_LLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, + sinfo->llid); + if (sinfo->filled & STATION_INFO_PLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, + sinfo->plid); + if (sinfo->filled & STATION_INFO_PLINK_STATE) + NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, + sinfo->plink_state); + + nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); @@ -899,17 +931,80 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, return genlmsg_cancel(msg, hdr); } +static int nl80211_dump_station(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int sta_idx = cb->args[2]; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct station_info sinfo; + struct cfg80211_registered_device *dev; + struct wireless_dev *wdev; + u8 mac_addr[ETH_ALEN]; + int err; + int exit = 0; + + /* TODO: filter by device */ + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (exit) + break; + if (++wp_idx < wp_start) + continue; + if_idx = 0; + + mutex_lock(&dev->devlist_mtx); + list_for_each_entry(wdev, &dev->netdev_list, list) { + if (exit) + break; + if (++if_idx < if_start) + continue; + if (!dev->ops->dump_station) + continue; + + for (;; ++sta_idx) { + rtnl_lock(); + err = dev->ops->dump_station(&dev->wiphy, + wdev->netdev, sta_idx, mac_addr, + &sinfo); + rtnl_unlock(); + if (err) { + sta_idx = 0; + break; + } + if (nl80211_send_station(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + wdev->netdev, mac_addr, + &sinfo) < 0) { + exit = 1; + break; + } + } + } + mutex_unlock(&dev->devlist_mtx); + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + cb->args[2] = sta_idx; + + return skb->len; +} static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; int err; struct net_device *dev; - struct station_stats stats; + struct station_info sinfo; struct sk_buff *msg; u8 *mac_addr = NULL; - memset(&stats, 0, sizeof(stats)); + memset(&sinfo, 0, sizeof(sinfo)); if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -926,15 +1021,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); + err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); rtnl_unlock(); + if (err) + goto out; + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) goto out; if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, - dev, mac_addr, &stats) < 0) + dev, mac_addr, &sinfo) < 0) goto out_free; err = genlmsg_unicast(msg, info->snd_pid); @@ -1005,6 +1103,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ¶ms.station_flags)) return -EINVAL; + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) + params.plink_action = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); if (err) return err; @@ -1119,6 +1221,273 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + u8 *dst, u8 *next_hop, + struct mpath_info *pinfo) +{ + void *hdr; + struct nlattr *pinfoattr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); + if (!pinfoattr) + goto nla_put_failure; + if (pinfo->filled & MPATH_INFO_FRAME_QLEN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, + pinfo->frame_qlen); + if (pinfo->filled & MPATH_INFO_DSN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, + pinfo->dsn); + if (pinfo->filled & MPATH_INFO_METRIC) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, + pinfo->metric); + if (pinfo->filled & MPATH_INFO_EXPTIME) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, + pinfo->exptime); + if (pinfo->filled & MPATH_INFO_FLAGS) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, + pinfo->flags); + if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + pinfo->discovery_timeout); + if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, + pinfo->discovery_retries); + + nla_nest_end(msg, pinfoattr); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + return genlmsg_cancel(msg, hdr); +} + +static int nl80211_dump_mpath(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int sta_idx = cb->args[2]; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct mpath_info pinfo; + struct cfg80211_registered_device *dev; + struct wireless_dev *wdev; + u8 dst[ETH_ALEN]; + u8 next_hop[ETH_ALEN]; + int err; + int exit = 0; + + /* TODO: filter by device */ + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (exit) + break; + if (++wp_idx < wp_start) + continue; + if_idx = 0; + + mutex_lock(&dev->devlist_mtx); + list_for_each_entry(wdev, &dev->netdev_list, list) { + if (exit) + break; + if (++if_idx < if_start) + continue; + if (!dev->ops->dump_mpath) + continue; + + for (;; ++sta_idx) { + rtnl_lock(); + err = dev->ops->dump_mpath(&dev->wiphy, + wdev->netdev, sta_idx, dst, + next_hop, &pinfo); + rtnl_unlock(); + if (err) { + sta_idx = 0; + break; + } + if (nl80211_send_mpath(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + wdev->netdev, dst, next_hop, + &pinfo) < 0) { + exit = 1; + break; + } + } + } + mutex_unlock(&dev->devlist_mtx); + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + cb->args[2] = sta_idx; + + return skb->len; +} + +static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct mpath_info pinfo; + struct sk_buff *msg; + u8 *dst = NULL; + u8 next_hop[ETH_ALEN]; + + memset(&pinfo, 0, sizeof(pinfo)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->get_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); + rtnl_unlock(); + + if (err) + goto out; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out; + + if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, + dev, dst, next_hop, &pinfo) < 0) + goto out_free; + + err = genlmsg_unicast(msg, info->snd_pid); + goto out; + + out_free: + nlmsg_free(msg); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->change_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} +static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->add_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + + if (info->attrs[NL80211_ATTR_MAC]) + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->del_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->del_mpath(&drv->wiphy, dev, dst); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -1203,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_STATION, .doit = nl80211_get_station, - /* TODO: implement dumpit */ + .dumpit = nl80211_dump_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, @@ -1225,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_GET_MPATH, + .doit = nl80211_get_mpath, + .dumpit = nl80211_dump_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_MPATH, + .doit = nl80211_set_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_MPATH, + .doit = nl80211_new_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_MPATH, + .doit = nl80211_del_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ -- cgit v1.2.3 From aab547ce0d1493d400b6468c521a0137cd8c1edf Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 29 Feb 2008 11:36:12 +0100 Subject: ssb: Add Gigabit Ethernet driver This adds the Gigabit Ethernet driver for the SSB Gigabit Ethernet core. This driver actually is a frontend to the Tigon3 driver. So the real work is done by tg3. This device is used in the Linksys WRT350N. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 9 ++ drivers/ssb/Makefile | 1 + drivers/ssb/driver_gige.c | 294 ++++++++++++++++++++++++++++++++++++ drivers/ssb/driver_mipscore.c | 1 + drivers/ssb/driver_pcicore.c | 160 +++++++++++--------- drivers/ssb/embedded.c | 90 +++++++++++ drivers/ssb/main.c | 30 +++- drivers/ssb/ssb_private.h | 2 + include/linux/ssb/ssb.h | 7 + include/linux/ssb/ssb_driver_gige.h | 174 +++++++++++++++++++++ include/linux/ssb/ssb_driver_pci.h | 19 +++ 11 files changed, 715 insertions(+), 72 deletions(-) create mode 100644 drivers/ssb/driver_gige.c create mode 100644 include/linux/ssb/ssb_driver_gige.h (limited to 'include/linux') diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index adea792fb675..f69ef0ba2613 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -125,4 +125,13 @@ config SSB_DRIVER_EXTIF If unsure, say N +config SSB_DRIVER_GIGE + bool "SSB Broadcom Gigabit Ethernet driver" + depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS + help + Driver for the Sonics Silicon Backplane attached + Broadcom Gigabit Ethernet. + + If unsure, say N + endmenu diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index de94c2eb7a37..910f35e32fc9 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o +ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o # b43 pci-ssb-bridge driver # Not strictly a part of SSB, but kept here for convenience diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c new file mode 100644 index 000000000000..172f90407b93 --- /dev/null +++ b/drivers/ssb/driver_gige.c @@ -0,0 +1,294 @@ +/* + * Sonics Silicon Backplane + * Broadcom Gigabit Ethernet core driver + * + * Copyright 2008, Broadcom Corporation + * Copyright 2008, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include + + +/* +MODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); +*/ + +static const struct ssb_device_id ssb_gige_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */ + + +static inline u8 gige_read8(struct ssb_gige *dev, u16 offset) +{ + return ssb_read8(dev->dev, offset); +} + +static inline u16 gige_read16(struct ssb_gige *dev, u16 offset) +{ + return ssb_read16(dev->dev, offset); +} + +static inline u32 gige_read32(struct ssb_gige *dev, u16 offset) +{ + return ssb_read32(dev->dev, offset); +} + +static inline void gige_write8(struct ssb_gige *dev, + u16 offset, u8 value) +{ + ssb_write8(dev->dev, offset, value); +} + +static inline void gige_write16(struct ssb_gige *dev, + u16 offset, u16 value) +{ + ssb_write16(dev->dev, offset, value); +} + +static inline void gige_write32(struct ssb_gige *dev, + u16 offset, u32 value) +{ + ssb_write32(dev->dev, offset, value); +} + +static inline +u8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset) +{ + BUG_ON(offset >= 256); + return gige_read8(dev, SSB_GIGE_PCICFG + offset); +} + +static inline +u16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset) +{ + BUG_ON(offset >= 256); + return gige_read16(dev, SSB_GIGE_PCICFG + offset); +} + +static inline +u32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset) +{ + BUG_ON(offset >= 256); + return gige_read32(dev, SSB_GIGE_PCICFG + offset); +} + +static inline +void gige_pcicfg_write8(struct ssb_gige *dev, + unsigned int offset, u8 value) +{ + BUG_ON(offset >= 256); + gige_write8(dev, SSB_GIGE_PCICFG + offset, value); +} + +static inline +void gige_pcicfg_write16(struct ssb_gige *dev, + unsigned int offset, u16 value) +{ + BUG_ON(offset >= 256); + gige_write16(dev, SSB_GIGE_PCICFG + offset, value); +} + +static inline +void gige_pcicfg_write32(struct ssb_gige *dev, + unsigned int offset, u32 value) +{ + BUG_ON(offset >= 256); + gige_write32(dev, SSB_GIGE_PCICFG + offset, value); +} + +static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); + unsigned long flags; + + if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (reg >= 256) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&dev->lock, flags); + switch (size) { + case 1: + *val = gige_pcicfg_read8(dev, reg); + break; + case 2: + *val = gige_pcicfg_read16(dev, reg); + break; + case 4: + *val = gige_pcicfg_read32(dev, reg); + break; + default: + WARN_ON(1); + } + spin_unlock_irqrestore(&dev->lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); + unsigned long flags; + + if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (reg >= 256) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&dev->lock, flags); + switch (size) { + case 1: + gige_pcicfg_write8(dev, reg, val); + break; + case 2: + gige_pcicfg_write16(dev, reg, val); + break; + case 4: + gige_pcicfg_write32(dev, reg, val); + break; + default: + WARN_ON(1); + } + spin_unlock_irqrestore(&dev->lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id) +{ + struct ssb_gige *dev; + u32 base, tmslow, tmshigh; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->dev = sdev; + + spin_lock_init(&dev->lock); + dev->pci_controller.pci_ops = &dev->pci_ops; + dev->pci_controller.io_resource = &dev->io_resource; + dev->pci_controller.mem_resource = &dev->mem_resource; + dev->pci_controller.io_map_base = 0x800; + dev->pci_ops.read = ssb_gige_pci_read_config; + dev->pci_ops.write = ssb_gige_pci_write_config; + + dev->io_resource.name = SSB_GIGE_IO_RES_NAME; + dev->io_resource.start = 0x800; + dev->io_resource.end = 0x8FF; + dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED; + + if (!ssb_device_is_enabled(sdev)) + ssb_device_enable(sdev, 0); + + /* Setup BAR0. This is a 64k MMIO region. */ + base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1)); + gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base); + gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0); + + dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME; + dev->mem_resource.start = base; + dev->mem_resource.end = base + 0x10000 - 1; + dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; + + /* Enable the memory region. */ + gige_pcicfg_write16(dev, PCI_COMMAND, + gige_pcicfg_read16(dev, PCI_COMMAND) + | PCI_COMMAND_MEMORY); + + /* Write flushing is controlled by the Flush Status Control register. + * We want to flush every register write with a timeout and we want + * to disable the IRQ mask while flushing to avoid concurrency. + * Note that automatic write flushing does _not_ work from + * an IRQ handler. The driver must flush manually by reading a register. + */ + gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068); + + /* Check if we have an RGMII or GMII PHY-bus. + * On RGMII do not bypass the DLLs */ + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmshigh = ssb_read32(sdev, SSB_TMSHIGH); + if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) { + tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS; + tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS; + dev->has_rgmii = 1; + } else { + tmslow |= SSB_GIGE_TMSLOW_TXBYPASS; + tmslow |= SSB_GIGE_TMSLOW_RXBYPASS; + dev->has_rgmii = 0; + } + tmslow |= SSB_GIGE_TMSLOW_DLLEN; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + + ssb_set_drvdata(sdev, dev); + register_pci_controller(&dev->pci_controller); + + return 0; +} + +bool pdev_is_ssb_gige_core(struct pci_dev *pdev) +{ + if (!pdev->resource[0].name) + return 0; + return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0); +} +EXPORT_SYMBOL(pdev_is_ssb_gige_core); + +int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev) +{ + struct ssb_gige *dev = ssb_get_drvdata(sdev); + struct resource *res; + + if (pdev->bus->ops != &dev->pci_ops) { + /* The PCI device is not on this SSB GigE bridge device. */ + return -ENODEV; + } + + /* Fixup the PCI resources. */ + res = &(pdev->resource[0]); + res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; + res->name = dev->mem_resource.name; + res->start = dev->mem_resource.start; + res->end = dev->mem_resource.end; + + /* Fixup interrupt lines. */ + pdev->irq = ssb_mips_irq(sdev) + 2; + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq); + + return 0; +} + +int ssb_gige_map_irq(struct ssb_device *sdev, + const struct pci_dev *pdev) +{ + struct ssb_gige *dev = ssb_get_drvdata(sdev); + + if (pdev->bus->ops != &dev->pci_ops) { + /* The PCI device is not on this SSB GigE bridge device. */ + return -ENODEV; + } + + return ssb_mips_irq(sdev) + 2; +} + +static struct ssb_driver ssb_gige_driver = { + .name = "BCM-GigE", + .id_table = ssb_gige_tbl, + .probe = ssb_gige_probe, +}; + +int ssb_gige_init(void) +{ + return ssb_driver_register(&ssb_gige_driver); +} diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3d3dd32bf3ab..e3fad3123ecb 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -209,6 +209,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) /* fallthrough */ case SSB_DEV_PCI: case SSB_DEV_ETHERNET: + case SSB_DEV_ETHERNET_GBIT: case SSB_DEV_80211: case SSB_DEV_USB20_HOST: /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 74b9a8aea52b..33a7d5620474 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -60,77 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock); /* Core to access the external PCI config space. Can only have one. */ static struct ssb_pcicore *extpci_core; -static u32 ssb_pcicore_pcibus_iobase = 0x100; -static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; - -int pcibios_plat_dev_init(struct pci_dev *d) -{ - struct resource *res; - int pos, size; - u32 *base; - - ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", - pci_name(d)); - - /* Fix up resource bases */ - for (pos = 0; pos < 6; pos++) { - res = &d->resource[pos]; - if (res->flags & IORESOURCE_IO) - base = &ssb_pcicore_pcibus_iobase; - else - base = &ssb_pcicore_pcibus_membase; - res->flags |= IORESOURCE_PCI_FIXED; - if (res->end) { - size = res->end - res->start + 1; - if (*base & (size - 1)) - *base = (*base + size) & ~(size - 1); - res->start = *base; - res->end = res->start + size - 1; - *base += size; - pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); - } - /* Fix up PCI bridge BAR0 only */ - if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) - break; - } - /* Fix up interrupt lines */ - d->irq = ssb_mips_irq(extpci_core->dev) + 2; - pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); - - return 0; -} - -static void __init ssb_fixup_pcibridge(struct pci_dev *dev) -{ - u8 lat; - - if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) - return; - - ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); - - /* Enable PCI bridge bus mastering and memory space */ - pci_set_master(dev); - if (pcibios_enable_device(dev, ~0) < 0) { - ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); - return; - } - - /* Enable PCI bridge BAR1 prefetch and burst */ - pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); - - /* Make sure our latency is high enough to handle the devices behind us */ - lat = 168; - ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", - pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} -DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - return ssb_mips_irq(extpci_core->dev) + 2; -} static u32 get_cfgspace_addr(struct ssb_pcicore *pc, unsigned int bus, unsigned int dev, @@ -320,6 +249,95 @@ static struct pci_controller ssb_pcicore_controller = { .mem_offset = 0x24000000, }; +static u32 ssb_pcicore_pcibus_iobase = 0x100; +static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; + +/* This function is called when doing a pci_enable_device(). + * We must first check if the device is a device on the PCI-core bridge. */ +int ssb_pcicore_plat_dev_init(struct pci_dev *d) +{ + struct resource *res; + int pos, size; + u32 *base; + + if (d->bus->ops != &ssb_pcicore_pciops) { + /* This is not a device on the PCI-core bridge. */ + return -ENODEV; + } + + ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", + pci_name(d)); + + /* Fix up resource bases */ + for (pos = 0; pos < 6; pos++) { + res = &d->resource[pos]; + if (res->flags & IORESOURCE_IO) + base = &ssb_pcicore_pcibus_iobase; + else + base = &ssb_pcicore_pcibus_membase; + res->flags |= IORESOURCE_PCI_FIXED; + if (res->end) { + size = res->end - res->start + 1; + if (*base & (size - 1)) + *base = (*base + size) & ~(size - 1); + res->start = *base; + res->end = res->start + size - 1; + *base += size; + pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); + } + /* Fix up PCI bridge BAR0 only */ + if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) + break; + } + /* Fix up interrupt lines */ + d->irq = ssb_mips_irq(extpci_core->dev) + 2; + pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); + + return 0; +} + +/* Early PCI fixup for a device on the PCI-core bridge. */ +static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev) +{ + u8 lat; + + if (dev->bus->ops != &ssb_pcicore_pciops) { + /* This is not a device on the PCI-core bridge. */ + return; + } + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) + return; + + ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); + + /* Enable PCI bridge bus mastering and memory space */ + pci_set_master(dev); + if (pcibios_enable_device(dev, ~0) < 0) { + ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); + return; + } + + /* Enable PCI bridge BAR1 prefetch and burst */ + pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); + + /* Make sure our latency is high enough to handle the devices behind us */ + lat = 168; + ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", + pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} +DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); + +/* PCI device IRQ mapping. */ +int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->bus->ops != &ssb_pcicore_pciops) { + /* This is not a device on the PCI-core bridge. */ + return -ENODEV; + } + return ssb_mips_irq(extpci_core->dev) + 2; +} + static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) { u32 val; diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index d3ade821555c..7dc3a6b41397 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -10,6 +10,9 @@ #include #include +#include +#include +#include #include "ssb_private.h" @@ -130,3 +133,90 @@ u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) return res; } EXPORT_SYMBOL(ssb_gpio_polarity); + +#ifdef CONFIG_SSB_DRIVER_GIGE +static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data) +{ + struct pci_dev *pdev = (struct pci_dev *)data; + struct ssb_device *dev; + unsigned int i; + int res; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) + continue; + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + res = ssb_gige_pcibios_plat_dev_init(dev, pdev); + if (res >= 0) + return res; + } + + return -ENODEV; +} +#endif /* CONFIG_SSB_DRIVER_GIGE */ + +int ssb_pcibios_plat_dev_init(struct pci_dev *dev) +{ + int err; + + err = ssb_pcicore_plat_dev_init(dev); + if (!err) + return 0; +#ifdef CONFIG_SSB_DRIVER_GIGE + err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback); + if (err >= 0) + return err; +#endif + /* This is not a PCI device on any SSB device. */ + + return -ENODEV; +} + +#ifdef CONFIG_SSB_DRIVER_GIGE +static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data) +{ + const struct pci_dev *pdev = (const struct pci_dev *)data; + struct ssb_device *dev; + unsigned int i; + int res; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) + continue; + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + res = ssb_gige_map_irq(dev, pdev); + if (res >= 0) + return res; + } + + return -ENODEV; +} +#endif /* CONFIG_SSB_DRIVER_GIGE */ + +int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int res; + + /* Check if this PCI device is a device on a SSB bus or device + * and return the IRQ number for it. */ + + res = ssb_pcicore_pcibios_map_irq(dev, slot, pin); + if (res >= 0) + return res; +#ifdef CONFIG_SSB_DRIVER_GIGE + res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback); + if (res >= 0) + return res; +#endif + /* This is not a PCI device on any SSB device. */ + + return -ENODEV; +} diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8db40c4b86e9..49d7bbb9bea7 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,25 @@ found: } #endif /* CONFIG_SSB_PCIHOST */ +int ssb_for_each_bus_call(unsigned long data, + int (*func)(struct ssb_bus *bus, unsigned long data)) +{ + struct ssb_bus *bus; + int res; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + res = func(bus, data); + if (res >= 0) { + ssb_buses_unlock(); + return res; + } + } + ssb_buses_unlock(); + + return -ENODEV; +} + static struct ssb_device *ssb_device_get(struct ssb_device *dev) { if (dev) @@ -1171,7 +1191,14 @@ static int __init ssb_modinit(void) err = b43_pci_ssb_bridge_init(); if (err) { ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " - "initialization failed"); + "initialization failed\n"); + /* don't fail SSB init because of this */ + err = 0; + } + err = ssb_gige_init(); + if (err) { + ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " + "driver initialization failed\n"); /* don't fail SSB init because of this */ err = 0; } @@ -1185,6 +1212,7 @@ fs_initcall(ssb_modinit); static void __exit ssb_modexit(void) { + ssb_gige_exit(); b43_pci_ssb_bridge_exit(); bus_unregister(&ssb_bustype); } diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 21eca2b5118b..d03b20983b1e 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); extern int ssb_devices_freeze(struct ssb_bus *bus); extern int ssb_devices_thaw(struct ssb_bus *bus); extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); +int ssb_for_each_bus_call(unsigned long data, + int (*func)(struct ssb_bus *bus, unsigned long data)); /* b43_pci_bridge.c */ #ifdef CONFIG_SSB_B43_PCI_BRIDGE diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 860d28c6d149..b7c388972fcf 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -422,5 +422,12 @@ extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); extern u32 ssb_admatch_base(u32 adm); extern u32 ssb_admatch_size(u32 adm); +/* PCI device mapping and fixup routines. + * Called from the architecture pcibios init code. + * These are only available on SSB_EMBEDDED configurations. */ +#ifdef CONFIG_SSB_EMBEDDED +int ssb_pcibios_plat_dev_init(struct pci_dev *dev); +int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); +#endif /* CONFIG_SSB_EMBEDDED */ #endif /* LINUX_SSB_H_ */ diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h new file mode 100644 index 000000000000..01fbdf5fef22 --- /dev/null +++ b/include/linux/ssb/ssb_driver_gige.h @@ -0,0 +1,174 @@ +#ifndef LINUX_SSB_DRIVER_GIGE_H_ +#define LINUX_SSB_DRIVER_GIGE_H_ + +#include +#include +#include + + +#ifdef CONFIG_SSB_DRIVER_GIGE + + +#define SSB_GIGE_PCIIO 0x0000 /* PCI I/O Registers (1024 bytes) */ +#define SSB_GIGE_RESERVED 0x0400 /* Reserved (1024 bytes) */ +#define SSB_GIGE_PCICFG 0x0800 /* PCI config space (256 bytes) */ +#define SSB_GIGE_SHIM_FLUSHSTAT 0x0C00 /* PCI to OCP: Flush status control (32bit) */ +#define SSB_GIGE_SHIM_FLUSHRDA 0x0C04 /* PCI to OCP: Flush read address (32bit) */ +#define SSB_GIGE_SHIM_FLUSHTO 0x0C08 /* PCI to OCP: Flush timeout counter (32bit) */ +#define SSB_GIGE_SHIM_BARRIER 0x0C0C /* PCI to OCP: Barrier register (32bit) */ +#define SSB_GIGE_SHIM_MAOCPSI 0x0C10 /* PCI to OCP: MaocpSI Control (32bit) */ +#define SSB_GIGE_SHIM_SIOCPMA 0x0C14 /* PCI to OCP: SiocpMa Control (32bit) */ + +/* TM Status High flags */ +#define SSB_GIGE_TMSHIGH_RGMII 0x00010000 /* Have an RGMII PHY-bus */ +/* TM Status Low flags */ +#define SSB_GIGE_TMSLOW_TXBYPASS 0x00080000 /* TX bypass (no delay) */ +#define SSB_GIGE_TMSLOW_RXBYPASS 0x00100000 /* RX bypass (no delay) */ +#define SSB_GIGE_TMSLOW_DLLEN 0x01000000 /* Enable DLL controls */ + +/* Boardflags (low) */ +#define SSB_GIGE_BFL_ROBOSWITCH 0x0010 + + +#define SSB_GIGE_MEM_RES_NAME "SSB Broadcom 47xx GigE memory" +#define SSB_GIGE_IO_RES_NAME "SSB Broadcom 47xx GigE I/O" + +struct ssb_gige { + struct ssb_device *dev; + + spinlock_t lock; + + /* True, if the device has an RGMII bus. + * False, if the device has a GMII bus. */ + bool has_rgmii; + + /* The PCI controller device. */ + struct pci_controller pci_controller; + struct pci_ops pci_ops; + struct resource mem_resource; + struct resource io_resource; +}; + +/* Check whether a PCI device is a SSB Gigabit Ethernet core. */ +extern bool pdev_is_ssb_gige_core(struct pci_dev *pdev); + +/* Convert a pci_dev pointer to a ssb_gige pointer. */ +static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) +{ + if (!pdev_is_ssb_gige_core(pdev)) + return NULL; + return container_of(pdev->bus->ops, struct ssb_gige, pci_ops); +} + +/* Returns whether the PHY is connected by an RGMII bus. */ +static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + return (dev ? dev->has_rgmii : 0); +} + +/* Returns whether we have a Roboswitch. */ +static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return !!(dev->dev->bus->sprom.boardflags_lo & + SSB_GIGE_BFL_ROBOSWITCH); + return 0; +} + +/* Returns whether we can only do one DMA at once. */ +static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return ((dev->dev->bus->chip_id == 0x4785) && + (dev->dev->bus->chip_rev < 2)); + return 0; +} + +/* Returns whether we must flush posted writes. */ +static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return (dev->dev->bus->chip_id == 0x4785); + return 0; +} + +extern char * nvram_get(const char *name); +/* Get the device MAC address */ +static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) +{ +#ifdef CONFIG_BCM947XX + char *res = nvram_get("et0macaddr"); + if (res) + memcpy(macaddr, res, 6); +#endif +} + +extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); +extern int ssb_gige_map_irq(struct ssb_device *sdev, + const struct pci_dev *pdev); + +/* The GigE driver is not a standalone module, because we don't have support + * for unregistering the driver. So we could not unload the module anyway. */ +extern int ssb_gige_init(void); +static inline void ssb_gige_exit(void) +{ + /* Currently we can not unregister the GigE driver, + * because we can not unregister the PCI bridge. */ + BUG(); +} + + +#else /* CONFIG_SSB_DRIVER_GIGE */ +/* Gigabit Ethernet driver disabled */ + + +static inline int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev) +{ + return -ENOSYS; +} +static inline int ssb_gige_map_irq(struct ssb_device *sdev, + const struct pci_dev *pdev) +{ + return -ENOSYS; +} +static inline int ssb_gige_init(void) +{ + return 0; +} +static inline void ssb_gige_exit(void) +{ +} + +static inline bool pdev_is_ssb_gige_core(struct pci_dev *pdev) +{ + return 0; +} +static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) +{ + return NULL; +} +static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) +{ + return 0; +} + +#endif /* CONFIG_SSB_DRIVER_GIGE */ +#endif /* LINUX_SSB_DRIVER_GIGE_H_ */ diff --git a/include/linux/ssb/ssb_driver_pci.h b/include/linux/ssb/ssb_driver_pci.h index 5e25bac4ed31..41e330e51c2a 100644 --- a/include/linux/ssb/ssb_driver_pci.h +++ b/include/linux/ssb/ssb_driver_pci.h @@ -1,6 +1,11 @@ #ifndef LINUX_SSB_PCICORE_H_ #define LINUX_SSB_PCICORE_H_ +#include + +struct pci_dev; + + #ifdef CONFIG_SSB_DRIVER_PCICORE /* PCI core registers. */ @@ -88,6 +93,9 @@ extern void ssb_pcicore_init(struct ssb_pcicore *pc); extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, struct ssb_device *dev); +int ssb_pcicore_plat_dev_init(struct pci_dev *d); +int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); + #else /* CONFIG_SSB_DRIVER_PCICORE */ @@ -107,5 +115,16 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, return 0; } +static inline +int ssb_pcicore_plat_dev_init(struct pci_dev *d) +{ + return -ENODEV; +} +static inline +int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return -ENODEV; +} + #endif /* CONFIG_SSB_DRIVER_PCICORE */ #endif /* LINUX_SSB_PCICORE_H_ */ -- cgit v1.2.3 From db8dac20d5199307dcfcf4e01dac4bda5edf9e89 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 6 Mar 2008 16:22:02 -0800 Subject: [UDP]: Revert udplite and code split. This reverts commit db1ed684f6c430c4cdad67d058688b8a1b5e607c ("[IPV6] UDP: Rename IPv6 UDP files."), commit 8be8af8fa4405652e6c0797db5465a4be8afb998 ("[IPV4] UDP: Move IPv4-specific bits to other file.") and commit e898d4db2749c6052072e9bc4448e396cbdeb06a ("[UDP]: Allow users to configure UDP-Lite."). First, udplite is of such small cost, and it is a core protocol just like TCP and normal UDP are. We spent enormous amounts of effort to make udplite share as much code with core UDP as possible. All of that work is less valuable if we're just going to slap a config option on udplite support. It is also causing build failures, as reported on linux-next, showing that the changeset was not tested very well. In fact, this is the second build failure resulting from the udplite change. Finally, the config options provided was a bool, instead of a modular option. Meaning the udplite code does not even get build tested by allmodconfig builds, and furthermore the user is not presented with a reasonable modular build option which is particularly needed by distribution vendors. Signed-off-by: David S. Miller --- include/linux/udp.h | 10 - include/net/ipv6.h | 5 - include/net/transp_v6.h | 5 - include/net/udplite.h | 9 +- net/ipv4/Kconfig | 10 - net/ipv4/Makefile | 3 +- net/ipv4/af_inet.c | 7 +- net/ipv4/proc.c | 5 +- net/ipv4/udp.c | 1090 +++++++++++++++++++++++++++++++++++++++++++- net/ipv4/udp_ipv4.c | 1134 ---------------------------------------------- net/ipv4/udplite.c | 121 +++++ net/ipv4/udplite_ipv4.c | 121 ----- net/ipv6/Makefile | 3 +- net/ipv6/af_inet6.c | 14 - net/ipv6/ipv6_sockglue.c | 6 +- net/ipv6/proc.c | 6 - net/ipv6/udp.c | 1065 +++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udp_ipv6.c | 1065 ------------------------------------------- net/ipv6/udplite.c | 125 +++++ net/ipv6/udplite_ipv6.c | 125 ----- 20 files changed, 2404 insertions(+), 2525 deletions(-) delete mode 100644 net/ipv4/udp_ipv4.c create mode 100644 net/ipv4/udplite.c delete mode 100644 net/ipv4/udplite_ipv4.c create mode 100644 net/ipv6/udp.c delete mode 100644 net/ipv6/udp_ipv6.c create mode 100644 net/ipv6/udplite.c delete mode 100644 net/ipv6/udplite_ipv6.c (limited to 'include/linux') diff --git a/include/linux/udp.h b/include/linux/udp.h index 4144664d69d9..1e7b7cb5703b 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -70,10 +70,8 @@ struct udp_sock { #define UDPLITE_BIT 0x1 /* set by udplite proto init function */ #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ -#ifdef CONFIG_IP_UDPLITE __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ __u8 unused[3]; -#endif /* * For encapsulation sockets. */ @@ -85,15 +83,7 @@ static inline struct udp_sock *udp_sk(const struct sock *sk) return (struct udp_sock *)sk; } -#ifdef CONFIG_IP_UDPLITE #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) -#define IS_PROTO_UDPLITE(__proto) ((__proto) == IPPROTO_UDPLITE) -#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP || (level) == SOL_UDPLITE) -#else -#define IS_UDPLITE(__sk) 0 -#define IS_PROTO_UDPLITE(__proto) 0 -#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP) -#endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5f6df50a33a9..8db06af1efbb 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -599,13 +599,8 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); -#ifdef CONFIG_IP_UDPLITE extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); -#else -static inline int udplite6_proc_init(void) { return 0; } -static inline void udplite6_proc_exit(void) { } -#endif extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 902e6c6bc793..27394e0447d8 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -27,13 +27,8 @@ extern int rawv6_init(void); extern void rawv6_exit(void); extern int udpv6_init(void); extern void udpv6_exit(void); -#ifdef CONFIG_IP_UDPLITE extern int udplitev6_init(void); extern void udplitev6_exit(void); -#else -static inline int udplitev6_init(void) { return 0; } -static inline void udplitev6_exit(void) { } -#endif extern int tcpv6_init(void); extern void tcpv6_exit(void); diff --git a/include/net/udplite.h b/include/net/udplite.h index 01ddb2c20264..b76b2e377af4 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -25,9 +25,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, /* Designate sk as UDP-Lite socket */ static inline int udplite_sk_init(struct sock *sk) { -#ifdef CONFIG_IP_UDPLITE udp_sk(sk)->pcflag = UDPLITE_BIT; -#endif return 0; } @@ -71,7 +69,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) { int cscov = up->len; -#ifdef CONFIG_IP_UDPLITE + /* * Sender has set `partial coverage' option on UDP-Lite socket */ @@ -95,15 +93,13 @@ static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) * illegal, we fall back to the defaults here. */ } -#endif return cscov; } static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) { - __wsum csum = 0; -#ifdef CONFIG_IP_UDPLITE int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); + __wsum csum = 0; skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ @@ -116,7 +112,6 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) if ((cscov -= len) <= 0) break; } -#endif return csum; } diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5098fd2ff4d0..9c7e5ffb223d 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -632,15 +632,5 @@ config TCP_MD5SIG If unsure, say N. -config IP_UDPLITE - bool "IP: UDP-Lite Protocol (RFC 3828)" - default n - ---help--- - UDP-Lite (RFC 3828) is a UDP-like protocol with variable-length - checksum. Read for - details. - - If unsure, say N. - source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index d5226241d5ed..ad40ef3f9ebc 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o udp_ipv4.o \ + datagram.o raw.o udp.o udplite.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o \ inet_fragment.o @@ -49,7 +49,6 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o -obj-$(CONFIG_IP_UDPLITE) += udplite_ipv4.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 25871c6c7444..4cb8a1385539 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1317,18 +1317,15 @@ static int __init init_ipv4_mibs(void) if (snmp_mib_init((void **)udp_statistics, sizeof(struct udp_mib)) < 0) goto err_udp_mib; -#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_statistics, sizeof(struct udp_mib)) < 0) goto err_udplite_mib; -#endif + tcp_mib_init(); return 0; -#ifdef CONFIG_IP_UDPLITE err_udplite_mib: -#endif snmp_mib_free((void **)udp_statistics); err_udp_mib: snmp_mib_free((void **)tcp_statistics); @@ -1426,10 +1423,8 @@ static int __init inet_init(void) /* Setup UDP memory threshold */ udp_init(); -#ifdef CONFIG_IP_UDPLITE /* Add UDP-Lite (RFC 3828) */ udplite4_register(); -#endif /* * Set the ICMP layer up diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d75ddb7fa4b8..d63474c6b400 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -59,9 +59,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot), atomic_read(&udp_memory_allocated)); -#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot)); -#endif seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); @@ -351,7 +349,6 @@ static int snmp_seq_show(struct seq_file *seq, void *v) snmp_fold_field((void **)udp_statistics, snmp4_udp_list[i].entry)); -#ifdef CONFIG_IP_UDPLITE /* the UDP and UDP-Lite MIBs are the same */ seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) @@ -362,7 +359,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %lu", snmp_fold_field((void **)udplite_statistics, snmp4_udp_list[i].entry)); -#endif + seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index c53d7673b57d..7ea1b67b6de1 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -246,6 +246,553 @@ int udp_get_port(struct sock *sk, unsigned short snum, return __udp_lib_get_port(sk, snum, udp_hash, scmp); } +int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +{ + struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); + + return ( !ipv6_only_sock(sk2) && + (!inet1->rcv_saddr || !inet2->rcv_saddr || + inet1->rcv_saddr == inet2->rcv_saddr )); +} + +static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +/* UDP is nearly always wildcards out the wazoo, it makes no sense to try + * harder than this. -DaveM + */ +static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, + __be16 sport, __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + !ipv6_only_sock(sk)) { + int score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { + if (inet->rcv_saddr != daddr) + continue; + score+=2; + } + if (inet->daddr) { + if (inet->daddr != saddr) + continue; + score+=2; + } + if (inet->dport) { + if (inet->dport != sport) + continue; + score+=2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score+=2; + } + if (score == 9) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +static inline struct sock *udp_v4_mcast_next(struct sock *sk, + __be16 loc_port, __be32 loc_addr, + __be16 rmt_port, __be32 rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short hnum = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash != hnum || + (inet->daddr && inet->daddr != rmt_addr) || + (inet->dport != rmt_port && inet->dport) || + (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + ipv6_only_sock(s) || + (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) + continue; + if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) + continue; + goto found; + } + s = NULL; +found: + return s; +} + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. If err < 0 then the socket should + * be closed and the error returned to the user. If err > 0 + * it's just the icmp type << 8 | icmp code. + * Header points to the ip header of the error packet. We move + * on past this. Then (as it used to claim before adjustment) + * header points to the first 8 bytes of the udp header. We need + * to find the appropriate port. + */ + +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) +{ + struct inet_sock *inet; + struct iphdr *iph = (struct iphdr*)skb->data; + struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; + struct sock *sk; + int harderr; + int err; + + sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, + iph->saddr, uh->source, skb->dev->ifindex, udptable); + if (sk == NULL) { + ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + return; /* No socket for error */ + } + + err = 0; + harderr = 0; + inet = inet_sk(sk); + + switch (type) { + default: + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + case ICMP_SOURCE_QUENCH: + goto out; + case ICMP_PARAMETERPROB: + err = EPROTO; + harderr = 1; + break; + case ICMP_DEST_UNREACH: + if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ + if (inet->pmtudisc != IP_PMTUDISC_DONT) { + err = EMSGSIZE; + harderr = 1; + break; + } + goto out; + } + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + } + + /* + * RFC1122: OK. Passes ICMP errors back to application, as per + * 4.1.3.3. + */ + if (!inet->recverr) { + if (!harderr || sk->sk_state != TCP_ESTABLISHED) + goto out; + } else { + ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); + } + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +void udp_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udp_hash); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip_flush_pending_frames(sk); + } +} + +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int offset; + struct udphdr *uh = udp_hdr(skb); + __wsum csum = 0; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb_transport_offset(skb); + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } +} + +/* + * Push out all pending data as one UDP datagram. Socket is locked. + */ +static int udp_push_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + struct sk_buff *skb; + struct udphdr *uh; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + + skb->ip_summed = CHECKSUM_NONE; + goto send; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ + + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + +send: + err = ip_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len) +{ + struct inet_sock *inet = inet_sk(sk); + struct udp_sock *up = udp_sk(sk); + int ulen = len; + struct ipcm_cookie ipc; + struct rtable *rt = NULL; + int free = 0; + int connected = 0; + __be32 daddr, faddr, saddr; + __be16 dport; + u8 tos; + int err, is_udplite = IS_UDPLITE(sk); + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + if (len > 0xFFFF) + return -EMSGSIZE; + + /* + * Check the flags. + */ + + if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ + return -EOPNOTSUPP; + + ipc.opt = NULL; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET)) { + release_sock(sk); + return -EINVAL; + } + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + /* + * Get and verify the address. + */ + if (msg->msg_name) { + struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; + if (msg->msg_namelen < sizeof(*usin)) + return -EINVAL; + if (usin->sin_family != AF_INET) { + if (usin->sin_family != AF_UNSPEC) + return -EAFNOSUPPORT; + } + + daddr = usin->sin_addr.s_addr; + dport = usin->sin_port; + if (dport == 0) + return -EINVAL; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = inet->daddr; + dport = inet->dport; + /* Open fast path for connected socket. + Route will not be used, if at least one option is set. + */ + connected = 1; + } + ipc.addr = inet->saddr; + + ipc.oif = sk->sk_bound_dev_if; + if (msg->msg_controllen) { + err = ip_cmsg_send(msg, &ipc); + if (err) + return err; + if (ipc.opt) + free = 1; + connected = 0; + } + if (!ipc.opt) + ipc.opt = inet->opt; + + saddr = ipc.addr; + ipc.addr = faddr = daddr; + + if (ipc.opt && ipc.opt->srr) { + if (!daddr) + return -EINVAL; + faddr = ipc.opt->faddr; + connected = 0; + } + tos = RT_TOS(inet->tos); + if (sock_flag(sk, SOCK_LOCALROUTE) || + (msg->msg_flags & MSG_DONTROUTE) || + (ipc.opt && ipc.opt->is_strictroute)) { + tos |= RTO_ONLINK; + connected = 0; + } + + if (ipv4_is_multicast(daddr)) { + if (!ipc.oif) + ipc.oif = inet->mc_index; + if (!saddr) + saddr = inet->mc_addr; + connected = 0; + } + + if (connected) + rt = (struct rtable*)sk_dst_check(sk, 0); + + if (rt == NULL) { + struct flowi fl = { .oif = ipc.oif, + .nl_u = { .ip4_u = + { .daddr = faddr, + .saddr = saddr, + .tos = tos } }, + .proto = sk->sk_protocol, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = dport } } }; + security_sk_classify_flow(sk, &fl); + err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); + if (err) { + if (err == -ENETUNREACH) + IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + goto out; + } + + err = -EACCES; + if ((rt->rt_flags & RTCF_BROADCAST) && + !sock_flag(sk, SOCK_BROADCAST)) + goto out; + if (connected) + sk_dst_set(sk, dst_clone(&rt->u.dst)); + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + saddr = rt->rt_src; + if (!ipc.addr) + daddr = ipc.addr = rt->rt_dst; + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + /* + * Now cork the socket to pend data. + */ + inet->cork.fl.fl4_dst = daddr; + inet->cork.fl.fl_ip_dport = dport; + inet->cork.fl.fl4_src = saddr; + inet->cork.fl.fl_ip_sport = inet->sport; + up->pending = AF_INET; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_flush_pending_frames(sk); + else if (!corkreq) + err = udp_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + release_sock(sk); + +out: + ip_rt_put(rt); + if (free) + kfree(ipc.opt); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(&rt->u.dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) +{ + struct udp_sock *up = udp_sk(sk); + int ret; + + if (!up->pending) { + struct msghdr msg = { .msg_flags = flags|MSG_MORE }; + + /* Call udp_sendmsg to specify destination address which + * sendpage interface can't pass. + * This will succeed only when the socket is connected. + */ + ret = udp_sendmsg(NULL, sk, &msg, 0); + if (ret < 0) + return ret; + } + + lock_sock(sk); + + if (unlikely(!up->pending)) { + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); + return -EINVAL; + } + + ret = ip_append_page(sk, page, offset, size, flags); + if (ret == -EOPNOTSUPP) { + release_sock(sk); + return sock_no_sendpage(sk->sk_socket, page, offset, + size, flags); + } + if (ret < 0) { + udp_flush_pending_frames(sk); + goto out; + } + + up->len += size; + if (!(up->corkflag || (flags&MSG_MORE))) + ret = udp_push_pending_frames(sk); + if (!ret) + ret = size; +out: + release_sock(sk); + return ret; +} + /* * IOCTL requests applicable to the UDP protocol */ @@ -286,6 +833,107 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return 0; } +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + struct inet_sock *inet = inet_sk(sk); + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + /* + * Check any passed addresses + */ + if (addr_len) + *addr_len=sizeof(*sin); + + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + + if (err == -EINVAL) + goto csum_copy_err; + } + + if (err) + goto out_free; + + if (!peeked) + UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (sin) + { + sin->sin_family = AF_INET; + sin->sin_port = udp_hdr(skb)->source; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (noblock) + return -EAGAIN; + goto try_again; +} + + int udp_disconnect(struct sock *sk, int flags) { struct inet_sock *inet = inet_sk(sk); @@ -308,6 +956,319 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } +/* returns: + * -1: error + * 0: success + * >0: "udp encap" protocol resubmission + * + * Note that in the success and error cases, the skb is assumed to + * have either been requeued or freed. + */ +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + /* + * Charge it to the socket, dropping if the queue is full. + */ + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + if (up->encap_type) { + /* + * This is an encapsulation socket so pass the skb to + * the socket's udp_encap_rcv() hook. Otherwise, just + * fall through and pass this up the UDP socket. + * up->encap_rcv() returns the following value: + * =0 if skb was successfully passed to the encap + * handler or was discarded by it. + * >0 if skb should be passed on to UDP. + * <0 if skb should be resubmitted as proto -N + */ + + /* if we're overly short, let UDP handle it */ + if (skb->len > sizeof(struct udphdr) && + up->encap_rcv != NULL) { + int ret; + + ret = (*up->encap_rcv)(sk, skb); + if (ret <= 0) { + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, + is_udplite); + return -ret; + } + } + + /* FALLTHROUGH -- it's a UDP Packet */ + } + + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +/* + * Multicasts and broadcasts go to each listener. + * + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) +{ + struct sock *sk; + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = skb->dev->ifindex; + sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (sk) { + struct sock *sknext = NULL; + + do { + struct sk_buff *skb1 = skb; + + sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, + uh->source, saddr, dif); + if (sknext) + skb1 = skb_clone(skb, GFP_ATOMIC); + + if (skb1) { + int ret = 0; + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb1); + else + sk_add_backlog(sk, skb1); + bh_unlock_sock(sk); + + if (ret > 0) + /* we should probably re-process instead + * of dropping packets here. */ + kfree_skb(skb1); + } + sk = sknext; + } while (sknext); + } else + kfree_skb(skb); + read_unlock(&udp_hash_lock); + return 0; +} + +/* Initialize UDP checksum. If exited with zero value (success), + * CHECKSUM_UNNECESSARY means, that no more checks are required. + * Otherwise, csum completion requires chacksumming packet body, + * including udp header and folding it to skb->csum. + */ +static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + const struct iphdr *iph; + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (proto == IPPROTO_UDPLITE) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + iph = ip_hdr(skb); + if (uh->check == 0) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if (skb->ip_summed == CHECKSUM_COMPLETE) { + if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, + proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + if (!skb_csum_unnecessary(skb)) + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, + skb->len, proto, 0); + /* Probably, we should checksum udp header (it should be in cache + * in any case) and data in tiny packets (< rx copybreak). + */ + + return 0; +} + +/* + * All we need to do is get the socket, and then do a checksum. + */ + +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh = udp_hdr(skb); + unsigned short ulen; + struct rtable *rt = (struct rtable*)skb->dst; + __be32 saddr = ip_hdr(skb)->saddr; + __be32 daddr = ip_hdr(skb)->daddr; + + /* + * Validate the packet. + */ + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto drop; /* No space for header. */ + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (proto == IPPROTO_UDP) { + /* UDP validates ulen. */ + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; + uh = udp_hdr(skb); + } + + if (udp4_csum_init(skb, uh, proto)) + goto csum_error; + + if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); + + sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, + uh->dest, inet_iif(skb), udptable); + + if (sk != NULL) { + int ret = 0; + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + + /* a return value > 0 means to resubmit the input, but + * it wants the return to be -protocol, or 0 + */ + if (ret > 0) + return -ret; + return 0; + } + + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + /* No socket. Drop packet silently, if checksum is wrong */ + if (udp_lib_checksum_complete(skb)) + goto csum_error; + + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + + /* + * Hmm. We got an UDP packet to a port to which we + * don't wanna listen. Ignore it. + */ + kfree_skb(skb); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + ulen, + skb->len, + NIPQUAD(daddr), + ntohs(uh->dest)); + goto drop; + +csum_error: + /* + * RFC1122: OK. Discards the bad packet silently (as far as + * the network is concerned, anyway) as per 4.1.3.4 (MUST). + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + NIPQUAD(daddr), + ntohs(uh->dest), + ulen); +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + kfree_skb(skb); + return 0; +} + +int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +int udp_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_flush_pending_frames(sk); + release_sock(sk); + return 0; +} + /* * Socket option code for UDP */ @@ -318,9 +1279,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, struct udp_sock *up = udp_sk(sk); int val; int err = 0; -#ifdef CONFIG_IP_UDPLITE int is_udplite = IS_UDPLITE(sk); -#endif if (optlenpcrlen = val; up->pcflag |= UDPLITE_RECV_CC; break; -#endif default: err = -ENOPROTOOPT; @@ -392,6 +1349,26 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, return err; } +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return ip_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); +} +#endif + int udp_lib_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -436,6 +1413,23 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, return 0; } +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); +} +#endif /** * udp_poll - wait for a UDP event. * @file - file struct @@ -480,6 +1474,36 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } +DEFINE_PROTO_INUSE(udp) + +struct proto udp_prot = { + .name = "UDP", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v4_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udp) +}; /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS @@ -612,6 +1636,62 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo) proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } + +/* ------------------------------------------------------------------------ */ +static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; + __u16 destp = ntohs(inet->dport); + __u16 srcp = ntohs(inet->sport); + + sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", + bucket, src, srcp, dest, destp, sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp4_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%-127s\n", + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode"); + else { + char tmpbuf[129]; + struct udp_iter_state *state = seq->private; + + udp4_format_sock(v, tmpbuf, state->bucket); + seq_printf(seq, "%-127s\n", tmpbuf); + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +static struct file_operations udp4_seq_fops; +static struct udp_seq_afinfo udp4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp", + .family = AF_INET, + .hashtable = udp_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udp4_seq_fops, +}; + +int __init udp4_proc_init(void) +{ + return udp_proc_register(&udp4_seq_afinfo); +} + +void udp4_proc_exit(void) +{ + udp_proc_unregister(&udp4_seq_afinfo); +} #endif /* CONFIG_PROC_FS */ void __init udp_init(void) @@ -638,6 +1718,8 @@ EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_get_port); +EXPORT_SYMBOL(udp_prot); +EXPORT_SYMBOL(udp_sendmsg); EXPORT_SYMBOL(udp_lib_getsockopt); EXPORT_SYMBOL(udp_lib_setsockopt); EXPORT_SYMBOL(udp_poll); diff --git a/net/ipv4/udp_ipv4.c b/net/ipv4/udp_ipv4.c deleted file mode 100644 index fd14c2c50ed4..000000000000 --- a/net/ipv4/udp_ipv4.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * UDP for IPv4. - * - * For full credits, see net/ipv4/udp.c. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "udp_impl.h" - -int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) -{ - struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - - return ( !ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr )); -} - -static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -/* UDP is nearly always wildcards out the wazoo, it makes no sense to try - * harder than this. -DaveM - */ -static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - __be16 sport, __be32 daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - !ipv6_only_sock(sk)) { - int score = (sk->sk_family == PF_INET ? 1 : 0); - if (inet->rcv_saddr) { - if (inet->rcv_saddr != daddr) - continue; - score+=2; - } - if (inet->daddr) { - if (inet->daddr != saddr) - continue; - score+=2; - } - if (inet->dport) { - if (inet->dport != sport) - continue; - score+=2; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score+=2; - } - if (score == 9) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -static inline struct sock *udp_v4_mcast_next(struct sock *sk, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short hnum = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash != hnum || - (inet->daddr && inet->daddr != rmt_addr) || - (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || - ipv6_only_sock(s) || - (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) - continue; - if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) - continue; - goto found; - } - s = NULL; -found: - return s; -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. - * Header points to the ip header of the error packet. We move - * on past this. Then (as it used to claim before adjustment) - * header points to the first 8 bytes of the udp header. We need - * to find the appropriate port. - */ - -void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) -{ - struct inet_sock *inet; - struct iphdr *iph = (struct iphdr*)skb->data; - struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - struct sock *sk; - int harderr; - int err; - - sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, - iph->saddr, uh->source, skb->dev->ifindex, udptable); - if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); - return; /* No socket for error */ - } - - err = 0; - harderr = 0; - inet = inet_sk(sk); - - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - goto out; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - if (inet->pmtudisc != IP_PMTUDISC_DONT) { - err = EMSGSIZE; - harderr = 1; - break; - } - goto out; - } - err = EHOSTUNREACH; - if (code <= NR_ICMP_UNREACH) { - harderr = icmp_err_convert[code].fatal; - err = icmp_err_convert[code].errno; - } - break; - } - - /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. - */ - if (!inet->recverr) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else { - ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); - } - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -void udp_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udp_hash); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip_flush_pending_frames(sk); - } -} - -/** - * udp4_hwcsum_outgoing - handle outgoing HW checksumming - * @sk: socket we are sending on - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - */ -static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, int len ) -{ - unsigned int offset; - struct udphdr *uh = udp_hdr(skb); - __wsum csum = 0; - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); - } else { - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together - */ - offset = skb_transport_offset(skb); - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); - - skb->ip_summed = CHECKSUM_NONE; - - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - - uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } -} - -/* - * Push out all pending data as one UDP datagram. Socket is locked. - */ -static int udp_push_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - struct sk_buff *skb; - struct udphdr *uh; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) /* UDP-Lite */ - csum = udplite_csum_outgoing(sk, skb); - - else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ - - skb->ip_summed = CHECKSUM_NONE; - goto send; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - - udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); - goto send; - - } else /* `normal' UDP */ - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, - sk->sk_protocol, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - -send: - err = ip_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - int ulen = len; - struct ipcm_cookie ipc; - struct rtable *rt = NULL; - int free = 0; - int connected = 0; - __be32 daddr, faddr, saddr; - __be16 dport; - u8 tos; - int err, is_udplite = IS_UDPLITE(sk); - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - if (len > 0xFFFF) - return -EMSGSIZE; - - /* - * Check the flags. - */ - - if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ - return -EOPNOTSUPP; - - ipc.opt = NULL; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET)) { - release_sock(sk); - return -EINVAL; - } - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - /* - * Get and verify the address. - */ - if (msg->msg_name) { - struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; - if (msg->msg_namelen < sizeof(*usin)) - return -EINVAL; - if (usin->sin_family != AF_INET) { - if (usin->sin_family != AF_UNSPEC) - return -EAFNOSUPPORT; - } - - daddr = usin->sin_addr.s_addr; - dport = usin->sin_port; - if (dport == 0) - return -EINVAL; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = inet->daddr; - dport = inet->dport; - /* Open fast path for connected socket. - Route will not be used, if at least one option is set. - */ - connected = 1; - } - ipc.addr = inet->saddr; - - ipc.oif = sk->sk_bound_dev_if; - if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); - if (err) - return err; - if (ipc.opt) - free = 1; - connected = 0; - } - if (!ipc.opt) - ipc.opt = inet->opt; - - saddr = ipc.addr; - ipc.addr = faddr = daddr; - - if (ipc.opt && ipc.opt->srr) { - if (!daddr) - return -EINVAL; - faddr = ipc.opt->faddr; - connected = 0; - } - tos = RT_TOS(inet->tos); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->is_strictroute)) { - tos |= RTO_ONLINK; - connected = 0; - } - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - connected = 0; - } - - if (connected) - rt = (struct rtable*)sk_dst_check(sk, 0); - - if (rt == NULL) { - struct flowi fl = { .oif = ipc.oif, - .nl_u = { .ip4_u = - { .daddr = faddr, - .saddr = saddr, - .tos = tos } }, - .proto = sk->sk_protocol, - .uli_u = { .ports = - { .sport = inet->sport, - .dport = dport } } }; - security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); - if (err) { - if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - err = -EACCES; - if ((rt->rt_flags & RTCF_BROADCAST) && - !sock_flag(sk, SOCK_BROADCAST)) - goto out; - if (connected) - sk_dst_set(sk, dst_clone(&rt->u.dst)); - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - saddr = rt->rt_src; - if (!ipc.addr) - daddr = ipc.addr = rt->rt_dst; - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - /* - * Now cork the socket to pend data. - */ - inet->cork.fl.fl4_dst = daddr; - inet->cork.fl.fl_ip_dport = dport; - inet->cork.fl.fl4_src = saddr; - inet->cork.fl.fl_ip_sport = inet->sport; - up->pending = AF_INET; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_flush_pending_frames(sk); - else if (!corkreq) - err = udp_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - release_sock(sk); - -out: - ip_rt_put(rt); - if (free) - kfree(ipc.opt); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(&rt->u.dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct udp_sock *up = udp_sk(sk); - int ret; - - if (!up->pending) { - struct msghdr msg = { .msg_flags = flags|MSG_MORE }; - - /* Call udp_sendmsg to specify destination address which - * sendpage interface can't pass. - * This will succeed only when the socket is connected. - */ - ret = udp_sendmsg(NULL, sk, &msg, 0); - if (ret < 0) - return ret; - } - - lock_sock(sk); - - if (unlikely(!up->pending)) { - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); - return -EINVAL; - } - - ret = ip_append_page(sk, page, offset, size, flags); - if (ret == -EOPNOTSUPP) { - release_sock(sk); - return sock_no_sendpage(sk->sk_socket, page, offset, - size, flags); - } - if (ret < 0) { - udp_flush_pending_frames(sk); - goto out; - } - - up->len += size; - if (!(up->corkflag || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk); - if (!ret) - ret = size; -out: - release_sock(sk); - return ret; -} - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - /* - * Check any passed addresses - */ - if (addr_len) - *addr_len=sizeof(*sin); - - if (flags & MSG_ERRQUEUE) - return ip_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - - if (err == -EINVAL) - goto csum_copy_err; - } - - if (err) - goto out_free; - - if (!peeked) - UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (sin) - { - sin->sin_family = AF_INET; - sin->sin_port = udp_hdr(skb)->source; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (noblock) - return -EAGAIN; - goto try_again; -} - - -/* returns: - * -1: error - * 0: success - * >0: "udp encap" protocol resubmission - * - * Note that in the success and error cases, the skb is assumed to - * have either been requeued or freed. - */ -int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - /* - * Charge it to the socket, dropping if the queue is full. - */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - if (up->encap_type) { - /* - * This is an encapsulation socket so pass the skb to - * the socket's udp_encap_rcv() hook. Otherwise, just - * fall through and pass this up the UDP socket. - * up->encap_rcv() returns the following value: - * =0 if skb was successfully passed to the encap - * handler or was discarded by it. - * >0 if skb should be passed on to UDP. - * <0 if skb should be resubmitted as proto -N - */ - - /* if we're overly short, let UDP handle it */ - if (skb->len > sizeof(struct udphdr) && - up->encap_rcv != NULL) { - int ret; - - ret = (*up->encap_rcv)(sk, skb); - if (ret <= 0) { - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, - is_udplite); - return -ret; - } - } - - /* FALLTHROUGH -- it's a UDP Packet */ - } - - /* - * UDP-Lite specific tests, ignored on UDP sockets - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - /* - * MIB statistics other than incrementing the error count are - * disabled for the following two types of errors: these depend - * on the application settings, not on the functioning of the - * protocol stack as such. - * - * RFC 3828 here recommends (sec 3.3): "There should also be a - * way ... to ... at least let the receiving application block - * delivery of packets with coverage values less than a value - * provided by the application." - */ - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " - "%d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - /* The next case involves violating the min. coverage requested - * by the receiver. This is subtle: if receiver wants x and x is - * greater than the buffersize/MTU then receiver will complain - * that it wants x while sender emits packets of smaller size y. - * Therefore the above ...()->partial_cov statement is essential. - */ - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING - "UDPLITE: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; - -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -/* - * Multicasts and broadcasts go to each listener. - * - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp4_lib_mcast_deliver(struct sk_buff *skb, - struct udphdr *uh, - __be32 saddr, __be32 daddr, - struct hlist_head udptable[]) -{ - struct sock *sk; - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = skb->dev->ifindex; - sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (sk) { - struct sock *sknext = NULL; - - do { - struct sk_buff *skb1 = skb; - - sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, - uh->source, saddr, dif); - if (sknext) - skb1 = skb_clone(skb, GFP_ATOMIC); - - if (skb1) { - int ret = 0; - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb1); - else - sk_add_backlog(sk, skb1); - bh_unlock_sock(sk); - - if (ret > 0) - /* we should probably re-process instead - * of dropping packets here. */ - kfree_skb(skb1); - } - sk = sknext; - } while (sknext); - } else - kfree_skb(skb); - read_unlock(&udp_hash_lock); - return 0; -} - -/* Initialize UDP checksum. If exited with zero value (success), - * CHECKSUM_UNNECESSARY means, that no more checks are required. - * Otherwise, csum completion requires chacksumming packet body, - * including udp header and folding it to skb->csum. - */ -static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - const struct iphdr *iph; - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - iph = ip_hdr(skb); - if (uh->check == 0) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, - proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (!skb_csum_unnecessary(skb)) - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb->len, proto, 0); - /* Probably, we should checksum udp header (it should be in cache - * in any case) and data in tiny packets (< rx copybreak). - */ - - return 0; -} - -/* - * All we need to do is get the socket, and then do a checksum. - */ - -int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh = udp_hdr(skb); - unsigned short ulen; - struct rtable *rt = skb->rtable; - __be32 saddr = ip_hdr(skb)->saddr; - __be32 daddr = ip_hdr(skb)->daddr; - - /* - * Validate the packet. - */ - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto drop; /* No space for header. */ - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (IS_PROTO_UDPLITE(proto)) { - /* UDP validates ulen. */ - if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) - goto short_packet; - uh = udp_hdr(skb); - } - - if (udp4_csum_init(skb, uh, proto)) - goto csum_error; - - if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - - sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, - uh->dest, inet_iif(skb), udptable); - - if (sk != NULL) { - int ret = 0; - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ - if (ret > 0) - return -ret; - return 0; - } - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - /* - * Hmm. We got an UDP packet to a port to which we - * don't wanna listen. Ignore it. - */ - kfree_skb(skb); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - ulen, - skb->len, - NIPQUAD(daddr), - ntohs(uh->dest)); - goto drop; - -csum_error: - /* - * RFC1122: OK. Discards the bad packet silently (as far as - * the network is concerned, anyway) as per 4.1.3.4 (MUST). - */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - NIPQUAD(daddr), - ntohs(uh->dest), - ulen); -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -int udp_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -int udp_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_flush_pending_frames(sk); - release_sock(sk); - return 0; -} - -int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return ip_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return compat_ip_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ip_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ip_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -/* ------------------------------------------------------------------------ */ -DEFINE_PROTO_INUSE(udp) - -struct proto udp_prot = { - .name = "UDP", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v4_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udp) -}; - -/* ------------------------------------------------------------------------ */ -static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->daddr; - __be32 src = inet->rcv_saddr; - __u16 destp = ntohs(inet->dport); - __u16 srcp = ntohs(inet->sport); - - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - bucket, src, srcp, dest, destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp4_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "%-127s\n", - " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); - else { - char tmpbuf[129]; - struct udp_iter_state *state = seq->private; - - udp4_format_sock(v, tmpbuf, state->bucket); - seq_printf(seq, "%-127s\n", tmpbuf); - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS -static struct file_operations udp4_seq_fops; -static struct udp_seq_afinfo udp4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp", - .family = AF_INET, - .hashtable = udp_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udp4_seq_fops, -}; - -int __init udp4_proc_init(void) -{ - return udp_proc_register(&udp4_seq_afinfo); -} - -void udp4_proc_exit(void) -{ - udp_proc_unregister(&udp4_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -EXPORT_SYMBOL(udp_prot); -EXPORT_SYMBOL(udp_sendmsg); - diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..d49c6d68c8a9 --- /dev/null +++ b/net/ipv4/udplite.c @@ -0,0 +1,121 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * 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 "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; + +int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, c); +} + +static int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +static int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplite_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +DEFINE_PROTO_INUSE(udplite) + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udplite) +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/udplite_ipv4.c b/net/ipv4/udplite_ipv4.c deleted file mode 100644 index d49c6d68c8a9..000000000000 --- a/net/ipv4/udplite_ipv4.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). - * - * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * 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 "udp_impl.h" -DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; - -struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; - -int udplite_get_port(struct sock *sk, unsigned short p, - int (*c)(const struct sock *, const struct sock *)) -{ - return __udp_lib_get_port(sk, p, udplite_hash, c); -} - -static int udplite_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -static int udplite_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplite_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udplite_hash); -} - -static struct net_protocol udplite_protocol = { - .handler = udplite_rcv, - .err_handler = udplite_err, - .no_policy = 1, -}; - -DEFINE_PROTO_INUSE(udplite) - -struct proto udplite_prot = { - .name = "UDP-Lite", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v4_get_port, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udplite) -}; - -static struct inet_protosw udplite4_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplite_prot, - .ops = &inet_dgram_ops, - .capability = -1, - .no_check = 0, /* must checksum (RFC 3828) */ - .flags = INET_PROTOSW_PERMANENT, -}; - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite4_seq_fops; -static struct udp_seq_afinfo udplite4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite", - .family = AF_INET, - .hashtable = udplite_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udplite4_seq_fops, -}; -#endif - -void __init udplite4_register(void) -{ - if (proto_register(&udplite_prot, 1)) - goto out_register_err; - - if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) - goto out_unregister_proto; - - inet_register_protosw(&udplite4_protosw); - -#ifdef CONFIG_PROC_FS - if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ - printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); -#endif - return; - -out_unregister_proto: - proto_unregister(&udplite_prot); -out_register_err: - printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); -} - -EXPORT_SYMBOL(udplite_hash); -EXPORT_SYMBOL(udplite_prot); -EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 107051f7c227..ae14617e607f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp_ipv6.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o @@ -17,7 +17,6 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o -ipv6-$(CONFIG_IP_UDPLITE) += udplite_ipv6.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index afe9276d0420..730a861b8f41 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -813,16 +813,12 @@ static int __init init_ipv6_mibs(void) goto err_icmpmsg_mib; if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udp_mib; -#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udplite_mib; -#endif return 0; -#ifdef CONFIG_IP_UDPLITE err_udplite_mib: -#endif snmp_mib_free((void **)udp_stats_in6); err_udp_mib: snmp_mib_free((void **)icmpv6msg_statistics); @@ -841,9 +837,7 @@ static void cleanup_ipv6_mibs(void) snmp_mib_free((void **)icmpv6_statistics); snmp_mib_free((void **)icmpv6msg_statistics); snmp_mib_free((void **)udp_stats_in6); -#ifdef CONFIG_IP_UDPLITE snmp_mib_free((void **)udplite_stats_in6); -#endif } static int inet6_net_init(struct net *net) @@ -888,11 +882,9 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; -#ifdef CONFIG_IP_UDPLITE err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; -#endif err = proto_register(&rawv6_prot, 1); if (err) @@ -1063,10 +1055,8 @@ out_sock_register_fail: out_unregister_raw_proto: proto_unregister(&rawv6_prot); out_unregister_udplite_proto: -#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); out_unregister_udp_proto: -#endif proto_unregister(&udpv6_prot); out_unregister_tcp_proto: proto_unregister(&tcpv6_prot); @@ -1085,9 +1075,7 @@ static void __exit inet6_exit(void) ipv6_sysctl_unregister(); #endif udpv6_exit(); -#ifdef CONFIG_IP_UDPLITE udplitev6_exit(); -#endif tcpv6_exit(); /* Cleanup code parts. */ @@ -1117,9 +1105,7 @@ static void __exit inet6_exit(void) unregister_pernet_subsys(&inet6_net_ops); cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); -#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); -#endif proto_unregister(&udpv6_prot); proto_unregister(&tcpv6_prot); } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 3bbfdff698d2..5eea6fa506e5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -127,9 +127,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && -#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && -#endif sk->sk_protocol != IPPROTO_TCP) break; @@ -169,7 +167,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } else { struct proto *prot = &udp_prot; - if (IS_PROTO_UDPLITE(sk->sk_protocol)) + if (sk->sk_protocol == IPPROTO_UDPLITE) prot = &udplite_prot; local_bh_disable(); sock_prot_inuse_add(sk->sk_prot, -1); @@ -734,9 +732,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && -#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && -#endif sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 2453f2229ef7..8a5be290c710 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -39,10 +39,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", sock_prot_inuse_get(&udpv6_prot)); -#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE6: inuse %d\n", sock_prot_inuse_get(&udplitev6_prot)); -#endif seq_printf(seq, "RAW6: inuse %d\n", sock_prot_inuse_get(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -113,7 +111,6 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; -#ifdef CONFIG_IP_UDPLITE static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), @@ -121,7 +118,6 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; -#endif static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) { @@ -180,9 +176,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); -#ifdef CONFIG_IP_UDPLITE snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); -#endif } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c new file mode 100644 index 000000000000..53739de829db --- /dev/null +++ b/net/ipv6/udp.c @@ -0,0 +1,1065 @@ +/* + * UDP over IPv6 + * Linux INET6 implementation + * + * Authors: + * Pedro Roque + * + * Based on linux/ipv4/udp.c + * + * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ + * + * Fixes: + * Hideaki YOSHIFUJI : sin6_scope_id support + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. + * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data + * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udp_impl.h" + +static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +static struct sock *__udp6_lib_lookup(struct net *net, + struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + int score = 0; + if (inet->dport) { + if (inet->dport != sport) + continue; + score++; + } + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + continue; + score++; + } + if (!ipv6_addr_any(&np->daddr)) { + if (!ipv6_addr_equal(&np->daddr, saddr)) + continue; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score++; + } + if (score == 4) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + if (addr_len) + *addr_len=sizeof(struct sockaddr_in6); + + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + if (err == -EINVAL) + goto csum_copy_err; + } + if (err) + goto out_free; + + if (!peeked) + UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (msg->msg_name) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) msg->msg_name; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = udp_hdr(skb)->source; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + + if (skb->protocol == htons(ETH_P_IP)) + ipv6_addr_set(&sin6->sin6_addr, 0, 0, + htonl(0xffff), ip_hdr(skb)->saddr); + else { + ipv6_addr_copy(&sin6->sin6_addr, + &ipv6_hdr(skb)->saddr); + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; + } + + } + if (skb->protocol == htons(ETH_P_IP)) { + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + } else { + if (np->rxopt.all) + datagram_recv_ctl(sk, msg, skb); + } + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (flags & MSG_DONTWAIT) + return -EAGAIN; + goto try_again; +} + +void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info, + struct hlist_head udptable[] ) +{ + struct ipv6_pinfo *np; + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; + struct in6_addr *saddr = &hdr->saddr; + struct in6_addr *daddr = &hdr->daddr; + struct udphdr *uh = (struct udphdr*)(skb->data+offset); + struct sock *sk; + int err; + + sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, + saddr, uh->source, inet6_iif(skb), udptable); + if (sk == NULL) + return; + + np = inet6_sk(sk); + + if (!icmpv6_err_convert(type, code, &err) && !np->recverr) + goto out; + + if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) + goto out; + + if (np->recverr) + ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); + + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +static __inline__ void udpv6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, int type, + int code, int offset, __be32 info ) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); +} + +int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + + /* + * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" + " %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " + "too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; +drop: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +static struct sock *udp_v6_mcast_next(struct sock *sk, + __be16 loc_port, struct in6_addr *loc_addr, + __be16 rmt_port, struct in6_addr *rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short num = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash == num && s->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(s); + if (inet->dport) { + if (inet->dport != rmt_port) + continue; + } + if (!ipv6_addr_any(&np->daddr) && + !ipv6_addr_equal(&np->daddr, rmt_addr)) + continue; + + if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) + continue; + + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + continue; + } + if (!inet6_mc_check(s, loc_addr, rmt_addr)) + continue; + return s; + } + } + return NULL; +} + +/* + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, + struct in6_addr *daddr, struct hlist_head udptable[]) +{ + struct sock *sk, *sk2; + const struct udphdr *uh = udp_hdr(skb); + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = inet6_iif(skb); + sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (!sk) { + kfree_skb(skb); + goto out; + } + + sk2 = sk; + while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, + uh->source, saddr, dif))) { + struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); + if (buff) { + bh_lock_sock_nested(sk2); + if (!sock_owned_by_user(sk2)) + udpv6_queue_rcv_skb(sk2, buff); + else + sk_add_backlog(sk2, buff); + bh_unlock_sock(sk2); + } + } + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); +out: + read_unlock(&udp_hash_lock); + return 0; +} + +static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (proto == IPPROTO_UDPLITE) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + if (uh->check == 0) { + /* RFC 2460 section 8.1 says that we SHOULD log + this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); + return 1; + } + if (skb->ip_summed == CHECKSUM_COMPLETE && + !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->len, proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (!skb_csum_unnecessary(skb)) + skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len, proto, 0)); + + return 0; +} + +int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh; + struct net_device *dev = skb->dev; + struct in6_addr *saddr, *daddr; + u32 ulen = 0; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto short_packet; + + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (proto == IPPROTO_UDP) { + /* UDP validates ulen. */ + + /* Check for jumbo payload */ + if (ulen == 0) + ulen = skb->len; + + if (ulen < sizeof(*uh)) + goto short_packet; + + if (ulen < skb->len) { + if (pskb_trim_rcsum(skb, ulen)) + goto short_packet; + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + } + } + + if (udp6_csum_init(skb, uh, proto)) + goto discard; + + /* + * Multicast receive code + */ + if (ipv6_addr_is_multicast(daddr)) + return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); + + /* Unicast */ + + /* + * check socket cache ... must talk to Alan about his plans + * for sock caches... i'll skip this for now. + */ + sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, + daddr, uh->dest, inet6_iif(skb), udptable); + + if (sk == NULL) { + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard; + + if (udp_lib_checksum_complete(skb)) + goto discard; + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); + + kfree_skb(skb); + return 0; + } + + /* deliver */ + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + ulen, skb->len); + +discard: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + kfree_skb(skb); + return 0; +} + +static __inline__ int udpv6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_v6_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip6_flush_pending_frames(sk); + } +} + +/* + * Sending + */ + +static int udp_v6_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb; + struct udphdr *uh; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) + csum = udplite_csum_outgoing(sk, skb); + else + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, + up->len, fl->proto, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + + err = ip6_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len) +{ + struct ipv6_txoptions opt_space; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *final_p = NULL, final; + struct ipv6_txoptions *opt = NULL; + struct ip6_flowlabel *flowlabel = NULL; + struct flowi fl; + struct dst_entry *dst; + int addr_len = msg->msg_namelen; + int ulen = len; + int hlimit = -1; + int tclass = -1; + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int err; + int connected = 0; + int is_udplite = IS_UDPLITE(sk); + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + /* destination address check */ + if (sin6) { + if (addr_len < offsetof(struct sockaddr, sa_data)) + return -EINVAL; + + switch (sin6->sin6_family) { + case AF_INET6: + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; + daddr = &sin6->sin6_addr; + break; + case AF_INET: + goto do_udp_sendmsg; + case AF_UNSPEC: + msg->msg_name = sin6 = NULL; + msg->msg_namelen = addr_len = 0; + daddr = NULL; + break; + default: + return -EINVAL; + } + } else if (!up->pending) { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = &np->daddr; + } else + daddr = NULL; + + if (daddr) { + if (ipv6_addr_v4mapped(daddr)) { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; + sin.sin_addr.s_addr = daddr->s6_addr32[3]; + msg->msg_name = &sin; + msg->msg_namelen = sizeof(sin); +do_udp_sendmsg: + if (__ipv6_only_sock(sk)) + return -ENETUNREACH; + return udp_sendmsg(iocb, sk, msg, len); + } + } + + if (up->pending == AF_INET) + return udp_sendmsg(iocb, sk, msg, len); + + /* Rough check on arithmetic overflow, + better check is made in ip6_append_data(). + */ + if (len > INT_MAX - sizeof(struct udphdr)) + return -EMSGSIZE; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET6)) { + release_sock(sk); + return -EAFNOSUPPORT; + } + dst = NULL; + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + memset(&fl, 0, sizeof(fl)); + + if (sin6) { + if (sin6->sin6_port == 0) + return -EINVAL; + + fl.fl_ip_dport = sin6->sin6_port; + daddr = &sin6->sin6_addr; + + if (np->sndflow) { + fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; + if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + daddr = &flowlabel->dst; + } + } + + /* + * Otherwise it will be difficult to maintain + * sk->sk_dst_cache. + */ + if (sk->sk_state == TCP_ESTABLISHED && + ipv6_addr_equal(daddr, &np->daddr)) + daddr = &np->daddr; + + if (addr_len >= sizeof(struct sockaddr_in6) && + sin6->sin6_scope_id && + ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) + fl.oif = sin6->sin6_scope_id; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + + fl.fl_ip_dport = inet->dport; + daddr = &np->daddr; + fl.fl6_flowlabel = np->flow_label; + connected = 1; + } + + if (!fl.oif) + fl.oif = sk->sk_bound_dev_if; + + if (msg->msg_controllen) { + opt = &opt_space; + memset(opt, 0, sizeof(struct ipv6_txoptions)); + opt->tot_len = sizeof(*opt); + + err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); + if (err < 0) { + fl6_sock_release(flowlabel); + return err; + } + if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + } + if (!(opt->opt_nflen|opt->opt_flen)) + opt = NULL; + connected = 0; + } + if (opt == NULL) + opt = np->opt; + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); + + fl.proto = sk->sk_protocol; + ipv6_addr_copy(&fl.fl6_dst, daddr); + if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) + ipv6_addr_copy(&fl.fl6_src, &np->saddr); + fl.fl_ip_sport = inet->sport; + + /* merge ip6_build_xmit from ip6_output */ + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + connected = 0; + } + + if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { + fl.oif = np->mcast_oif; + connected = 0; + } + + security_sk_classify_flow(sk, &fl); + + err = ip6_sk_dst_lookup(sk, &dst, &fl); + if (err) + goto out; + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + + if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(&fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = dst_metric(dst, RTAX_HOPLIMIT); + if (hlimit < 0) + hlimit = ipv6_get_hoplimit(dst->dev); + } + + if (tclass < 0) { + tclass = np->tclass; + if (tclass < 0) + tclass = 0; + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + + up->pending = AF_INET6; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), hlimit, tclass, opt, &fl, + (struct rt6_info*)dst, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_v6_flush_pending_frames(sk); + else if (!corkreq) + err = udp_v6_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + + if (dst) { + if (connected) { + ip6_dst_store(sk, dst, + ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? + &np->daddr : NULL, +#ifdef CONFIG_IPV6_SUBTREES + ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? + &np->saddr : +#endif + NULL); + } else { + dst_release(dst); + } + } + + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); +out: + fl6_sock_release(flowlabel); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udpv6_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_v6_flush_pending_frames(sk); + release_sock(sk); + + inet6_destroy_sock(sk); + + return 0; +} + +/* + * Socket option code for UDP + */ +int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return ipv6_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); +} +#endif + +int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ipv6_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); +} +#endif + +static struct inet6_protocol udpv6_protocol = { + .handler = udpv6_rcv, + .err_handler = udpv6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +/* ------------------------------------------------------------------------ */ +#ifdef CONFIG_PROC_FS + +static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + struct ipv6_pinfo *np = inet6_sk(sp); + struct in6_addr *dest, *src; + __u16 destp, srcp; + + dest = &np->daddr; + src = &np->rcv_saddr; + destp = ntohs(inet->dport); + srcp = ntohs(inet->sport); + seq_printf(seq, + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", + bucket, + src->s6_addr32[0], src->s6_addr32[1], + src->s6_addr32[2], src->s6_addr32[3], srcp, + dest->s6_addr32[0], dest->s6_addr32[1], + dest->s6_addr32[2], dest->s6_addr32[3], destp, + sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp6_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, + " sl " + "local_address " + "remote_address " + "st tx_queue rx_queue tr tm->when retrnsmt" + " uid timeout inode\n"); + else + udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); + return 0; +} + +static struct file_operations udp6_seq_fops; +static struct udp_seq_afinfo udp6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp6", + .family = AF_INET6, + .hashtable = udp_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udp6_seq_fops, +}; + +int __init udp6_proc_init(void) +{ + return udp_proc_register(&udp6_seq_afinfo); +} + +void udp6_proc_exit(void) { + udp_proc_unregister(&udp6_seq_afinfo); +} +#endif /* CONFIG_PROC_FS */ + +/* ------------------------------------------------------------------------ */ + +DEFINE_PROTO_INUSE(udpv6) + +struct proto udpv6_prot = { + .name = "UDPv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udpv6) +}; + +static struct inet_protosw udpv6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDP, + .prot = &udpv6_prot, + .ops = &inet6_dgram_ops, + .capability =-1, + .no_check = UDP_CSUM_DEFAULT, + .flags = INET_PROTOSW_PERMANENT, +}; + + +int __init udpv6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); + if (ret) + goto out; + + ret = inet6_register_protosw(&udpv6_protosw); + if (ret) + goto out_udpv6_protocol; +out: + return ret; + +out_udpv6_protocol: + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); + goto out; +} + +void udpv6_exit(void) +{ + inet6_unregister_protosw(&udpv6_protosw); + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); +} diff --git a/net/ipv6/udp_ipv6.c b/net/ipv6/udp_ipv6.c deleted file mode 100644 index 55feac7ba717..000000000000 --- a/net/ipv6/udp_ipv6.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * UDP over IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/ipv4/udp.c - * - * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data - * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udp_impl.h" - -static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -static struct sock *__udp6_lib_lookup(struct net *net, - struct in6_addr *saddr, __be16 sport, - struct in6_addr *daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - int score = 0; - if (inet->dport) { - if (inet->dport != sport) - continue; - score++; - } - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - continue; - score++; - } - if (!ipv6_addr_any(&np->daddr)) { - if (!ipv6_addr_equal(&np->daddr, saddr)) - continue; - score++; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score++; - } - if (score == 4) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - if (addr_len) - *addr_len=sizeof(struct sockaddr_in6); - - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - if (err == -EINVAL) - goto csum_copy_err; - } - if (err) - goto out_free; - - if (!peeked) - UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (msg->msg_name) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *) msg->msg_name; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = udp_hdr(skb)->source; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - - if (skb->protocol == htons(ETH_P_IP)) - ipv6_addr_set(&sin6->sin6_addr, 0, 0, - htonl(0xffff), ip_hdr(skb)->saddr); - else { - ipv6_addr_copy(&sin6->sin6_addr, - &ipv6_hdr(skb)->saddr); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = IP6CB(skb)->iif; - } - - } - if (skb->protocol == htons(ETH_P_IP)) { - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - } else { - if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); - } - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (flags & MSG_DONTWAIT) - return -EAGAIN; - goto try_again; -} - -void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info, - struct hlist_head udptable[] ) -{ - struct ipv6_pinfo *np; - struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; - struct in6_addr *saddr = &hdr->saddr; - struct in6_addr *daddr = &hdr->daddr; - struct udphdr *uh = (struct udphdr*)(skb->data+offset); - struct sock *sk; - int err; - - sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, - saddr, uh->source, inet6_iif(skb), udptable); - if (sk == NULL) - return; - - np = inet6_sk(sk); - - if (!icmpv6_err_convert(type, code, &err) && !np->recverr) - goto out; - - if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) - goto out; - - if (np->recverr) - ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -static __inline__ void udpv6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, int type, - int code, int offset, __be32 info ) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); -} - -int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - /* - * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" - " %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " - "too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; -drop: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -static struct sock *udp_v6_mcast_next(struct sock *sk, - __be16 loc_port, struct in6_addr *loc_addr, - __be16 rmt_port, struct in6_addr *rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short num = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash == num && s->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(s); - if (inet->dport) { - if (inet->dport != rmt_port) - continue; - } - if (!ipv6_addr_any(&np->daddr) && - !ipv6_addr_equal(&np->daddr, rmt_addr)) - continue; - - if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) - continue; - - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) - continue; - } - if (!inet6_mc_check(s, loc_addr, rmt_addr)) - continue; - return s; - } - } - return NULL; -} - -/* - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, - struct in6_addr *daddr, struct hlist_head udptable[]) -{ - struct sock *sk, *sk2; - const struct udphdr *uh = udp_hdr(skb); - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = inet6_iif(skb); - sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (!sk) { - kfree_skb(skb); - goto out; - } - - sk2 = sk; - while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, - uh->source, saddr, dif))) { - struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) { - bh_lock_sock_nested(sk2); - if (!sock_owned_by_user(sk2)) - udpv6_queue_rcv_skb(sk2, buff); - else - sk_add_backlog(sk2, buff); - bh_unlock_sock(sk2); - } - } - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); -out: - read_unlock(&udp_hash_lock); - return 0; -} - -static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); - return 1; - } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->len, proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (!skb_csum_unnecessary(skb)) - skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, proto, 0)); - - return 0; -} - -int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh; - struct net_device *dev = skb->dev; - struct in6_addr *saddr, *daddr; - u32 ulen = 0; - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto short_packet; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (proto == IPPROTO_UDP) { - /* UDP validates ulen. */ - - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; - - if (ulen < sizeof(*uh)) - goto short_packet; - - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - } - } - - if (udp6_csum_init(skb, uh, proto)) - goto discard; - - /* - * Multicast receive code - */ - if (ipv6_addr_is_multicast(daddr)) - return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); - - /* Unicast */ - - /* - * check socket cache ... must talk to Alan about his plans - * for sock caches... i'll skip this for now. - */ - sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, - daddr, uh->dest, inet6_iif(skb), udptable); - - if (sk == NULL) { - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard; - - if (udp_lib_checksum_complete(skb)) - goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); - - kfree_skb(skb); - return 0; - } - - /* deliver */ - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - ulen, skb->len); - -discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -static __inline__ int udpv6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_v6_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip6_flush_pending_frames(sk); - } -} - -/* - * Sending - */ - -static int udp_v6_push_pending_frames(struct sock *sk) -{ - struct sk_buff *skb; - struct udphdr *uh; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) - csum = udplite_csum_outgoing(sk, skb); - else - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, - up->len, fl->proto, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - err = ip6_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len) -{ - struct ipv6_txoptions opt_space; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; - struct in6_addr *daddr, *final_p = NULL, final; - struct ipv6_txoptions *opt = NULL; - struct ip6_flowlabel *flowlabel = NULL; - struct flowi fl; - struct dst_entry *dst; - int addr_len = msg->msg_namelen; - int ulen = len; - int hlimit = -1; - int tclass = -1; - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int err; - int connected = 0; - int is_udplite = IS_UDPLITE(sk); - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - /* destination address check */ - if (sin6) { - if (addr_len < offsetof(struct sockaddr, sa_data)) - return -EINVAL; - - switch (sin6->sin6_family) { - case AF_INET6: - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - daddr = &sin6->sin6_addr; - break; - case AF_INET: - goto do_udp_sendmsg; - case AF_UNSPEC: - msg->msg_name = sin6 = NULL; - msg->msg_namelen = addr_len = 0; - daddr = NULL; - break; - default: - return -EINVAL; - } - } else if (!up->pending) { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = &np->daddr; - } else - daddr = NULL; - - if (daddr) { - if (ipv6_addr_v4mapped(daddr)) { - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; - sin.sin_addr.s_addr = daddr->s6_addr32[3]; - msg->msg_name = &sin; - msg->msg_namelen = sizeof(sin); -do_udp_sendmsg: - if (__ipv6_only_sock(sk)) - return -ENETUNREACH; - return udp_sendmsg(iocb, sk, msg, len); - } - } - - if (up->pending == AF_INET) - return udp_sendmsg(iocb, sk, msg, len); - - /* Rough check on arithmetic overflow, - better check is made in ip6_append_data(). - */ - if (len > INT_MAX - sizeof(struct udphdr)) - return -EMSGSIZE; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET6)) { - release_sock(sk); - return -EAFNOSUPPORT; - } - dst = NULL; - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - memset(&fl, 0, sizeof(fl)); - - if (sin6) { - if (sin6->sin6_port == 0) - return -EINVAL; - - fl.fl_ip_dport = sin6->sin6_port; - daddr = &sin6->sin6_addr; - - if (np->sndflow) { - fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - daddr = &flowlabel->dst; - } - } - - /* - * Otherwise it will be difficult to maintain - * sk->sk_dst_cache. - */ - if (sk->sk_state == TCP_ESTABLISHED && - ipv6_addr_equal(daddr, &np->daddr)) - daddr = &np->daddr; - - if (addr_len >= sizeof(struct sockaddr_in6) && - sin6->sin6_scope_id && - ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) - fl.oif = sin6->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - - fl.fl_ip_dport = inet->dport; - daddr = &np->daddr; - fl.fl6_flowlabel = np->flow_label; - connected = 1; - } - - if (!fl.oif) - fl.oif = sk->sk_bound_dev_if; - - if (msg->msg_controllen) { - opt = &opt_space; - memset(opt, 0, sizeof(struct ipv6_txoptions)); - opt->tot_len = sizeof(*opt); - - err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); - if (err < 0) { - fl6_sock_release(flowlabel); - return err; - } - if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - } - if (!(opt->opt_nflen|opt->opt_flen)) - opt = NULL; - connected = 0; - } - if (opt == NULL) - opt = np->opt; - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); - opt = ipv6_fixup_options(&opt_space, opt); - - fl.proto = sk->sk_protocol; - ipv6_addr_copy(&fl.fl6_dst, daddr); - if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) - ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.fl_ip_sport = inet->sport; - - /* merge ip6_build_xmit from ip6_output */ - if (opt && opt->srcrt) { - struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - connected = 0; - } - - if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { - fl.oif = np->mcast_oif; - connected = 0; - } - - security_sk_classify_flow(sk, &fl); - - err = ip6_sk_dst_lookup(sk, &dst, &fl); - if (err) - goto out; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); - - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { - if (err == -EREMOTE) - err = ip6_dst_blackhole(sk, &dst, &fl); - if (err < 0) - goto out; - } - - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl.fl6_dst)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); - } - - if (tclass < 0) { - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - - up->pending = AF_INET6; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), hlimit, tclass, opt, &fl, - (struct rt6_info*)dst, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_v6_flush_pending_frames(sk); - else if (!corkreq) - err = udp_v6_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - - if (dst) { - if (connected) { - ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? - &np->daddr : NULL, -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? - &np->saddr : -#endif - NULL); - } else { - dst_release(dst); - } - } - - if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; - release_sock(sk); -out: - fl6_sock_release(flowlabel); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udpv6_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_v6_flush_pending_frames(sk); - release_sock(sk); - - inet6_destroy_sock(sk); - - return 0; -} - -/* - * Socket option code for UDP - */ -int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return ipv6_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ipv6_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static struct inet6_protocol udpv6_protocol = { - .handler = udpv6_rcv, - .err_handler = udpv6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS - -static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; - __u16 destp, srcp; - - dest = &np->daddr; - src = &np->rcv_saddr; - destp = ntohs(inet->dport); - srcp = ntohs(inet->sport); - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", - bucket, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, - sock_i_uid(sp), 0, - sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, - " sl " - "local_address " - "remote_address " - "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); - else - udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); - return 0; -} - -static struct file_operations udp6_seq_fops; -static struct udp_seq_afinfo udp6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp6", - .family = AF_INET6, - .hashtable = udp_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udp6_seq_fops, -}; - -int __init udp6_proc_init(void) -{ - return udp_proc_register(&udp6_seq_afinfo); -} - -void udp6_proc_exit(void) { - udp_proc_unregister(&udp6_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -/* ------------------------------------------------------------------------ */ - -DEFINE_PROTO_INUSE(udpv6) - -struct proto udpv6_prot = { - .name = "UDPv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v6_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udpv6) -}; - -static struct inet_protosw udpv6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDP, - .prot = &udpv6_prot, - .ops = &inet6_dgram_ops, - .capability =-1, - .no_check = UDP_CSUM_DEFAULT, - .flags = INET_PROTOSW_PERMANENT, -}; - - -int __init udpv6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); - if (ret) - goto out; - - ret = inet6_register_protosw(&udpv6_protosw); - if (ret) - goto out_udpv6_protocol; -out: - return ret; - -out_udpv6_protocol: - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); - goto out; -} - -void udpv6_exit(void) -{ - inet6_unregister_protosw(&udpv6_protosw); - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); -} diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c new file mode 100644 index 000000000000..87d4202522ee --- /dev/null +++ b/net/ipv6/udplite.c @@ -0,0 +1,125 @@ +/* + * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. + * See also net/ipv4/udplite.c + * + * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * 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 "udp_impl.h" + +DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; + +static int udplitev6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplitev6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); +} + +static struct inet6_protocol udplitev6_protocol = { + .handler = udplitev6_rcv, + .err_handler = udplitev6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static int udplite_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +DEFINE_PROTO_INUSE(udplitev6) + +struct proto udplitev6_prot = { + .name = "UDPLITEv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v6_get_port, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udplitev6) +}; + +static struct inet_protosw udplite6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplitev6_prot, + .ops = &inet6_dgram_ops, + .capability = -1, + .no_check = 0, + .flags = INET_PROTOSW_PERMANENT, +}; + +int __init udplitev6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + if (ret) + goto out; + + ret = inet6_register_protosw(&udplite6_protosw); + if (ret) + goto out_udplitev6_protocol; +out: + return ret; + +out_udplitev6_protocol: + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + goto out; +} + +void udplitev6_exit(void) +{ + inet6_unregister_protosw(&udplite6_protosw); + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); +} + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite6_seq_fops; +static struct udp_seq_afinfo udplite6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite6", + .family = AF_INET6, + .hashtable = udplite_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udplite6_seq_fops, +}; + +int __init udplite6_proc_init(void) +{ + return udp_proc_register(&udplite6_seq_afinfo); +} + +void udplite6_proc_exit(void) +{ + udp_proc_unregister(&udplite6_seq_afinfo); +} +#endif diff --git a/net/ipv6/udplite_ipv6.c b/net/ipv6/udplite_ipv6.c deleted file mode 100644 index 87d4202522ee..000000000000 --- a/net/ipv6/udplite_ipv6.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. - * See also net/ipv4/udplite.c - * - * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * 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 "udp_impl.h" - -DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; - -static int udplitev6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplitev6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); -} - -static struct inet6_protocol udplitev6_protocol = { - .handler = udplitev6_rcv, - .err_handler = udplitev6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -static int udplite_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -DEFINE_PROTO_INUSE(udplitev6) - -struct proto udplitev6_prot = { - .name = "UDPLITEv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v6_get_port, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udplitev6) -}; - -static struct inet_protosw udplite6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplitev6_prot, - .ops = &inet6_dgram_ops, - .capability = -1, - .no_check = 0, - .flags = INET_PROTOSW_PERMANENT, -}; - -int __init udplitev6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - if (ret) - goto out; - - ret = inet6_register_protosw(&udplite6_protosw); - if (ret) - goto out_udplitev6_protocol; -out: - return ret; - -out_udplitev6_protocol: - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - goto out; -} - -void udplitev6_exit(void) -{ - inet6_unregister_protosw(&udplite6_protosw); - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); -} - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite6_seq_fops; -static struct udp_seq_afinfo udplite6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite6", - .family = AF_INET6, - .hashtable = udplite_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udplite6_seq_fops, -}; - -int __init udplite6_proc_init(void) -{ - return udp_proc_register(&udplite6_seq_afinfo); -} - -void udplite6_proc_exit(void) -{ - udp_proc_unregister(&udplite6_seq_afinfo); -} -#endif -- cgit v1.2.3 From e7ec2e3230633a858af1b0b359f6c4670dbeb997 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 10 Mar 2008 17:26:32 +0100 Subject: ssb: Add SPROM/invariants support for PCMCIA devices This adds support for reading/writing the SPROM invariants for PCMCIA based devices. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 6 + drivers/ssb/Makefile | 1 + drivers/ssb/main.c | 23 +- drivers/ssb/pci.c | 113 +--------- drivers/ssb/pcmcia.c | 518 ++++++++++++++++++++++++++++++++++++++++------ drivers/ssb/sprom.c | 133 ++++++++++++ drivers/ssb/ssb_private.h | 17 ++ include/linux/ssb/ssb.h | 4 +- 8 files changed, 648 insertions(+), 167 deletions(-) create mode 100644 drivers/ssb/sprom.c (limited to 'include/linux') diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index f69ef0ba2613..0f7cce2560d1 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -20,6 +20,10 @@ config SSB If unsure, say N. +# Common SPROM support routines +config SSB_SPROM + bool + config SSB_PCIHOST_POSSIBLE bool depends on SSB && (PCI = y || PCI = SSB) @@ -28,6 +32,7 @@ config SSB_PCIHOST_POSSIBLE config SSB_PCIHOST bool "Support for SSB on PCI-bus host" depends on SSB_PCIHOST_POSSIBLE + select SSB_SPROM default y help Support for a Sonics Silicon Backplane on top @@ -48,6 +53,7 @@ config SSB_PCMCIAHOST_POSSIBLE config SSB_PCMCIAHOST bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)" depends on SSB_PCMCIAHOST_POSSIBLE + select SSB_SPROM help Support for a Sonics Silicon Backplane on top of a PCMCIA device. diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index 910f35e32fc9..6f255e9c5af9 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -1,6 +1,7 @@ # core ssb-y += main.o scan.o ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o +ssb-$(CONFIG_SSB_SPROM) += sprom.o # host support ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 49d7bbb9bea7..e12371916444 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -69,6 +69,25 @@ found: } #endif /* CONFIG_SSB_PCIHOST */ +#ifdef CONFIG_SSB_PCMCIAHOST +struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_PCMCIA && + bus->host_pcmcia == pdev) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_PCMCIAHOST */ + int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { @@ -398,7 +417,7 @@ void ssb_bus_unregister(struct ssb_bus *bus) list_del(&bus->list); ssb_buses_unlock(); - /* ssb_pcmcia_exit(bus); */ + ssb_pcmcia_exit(bus); ssb_pci_exit(bus); ssb_iounmap(bus); } @@ -663,7 +682,7 @@ out: err_dequeue: list_del(&bus->list); err_pcmcia_exit: -/* ssb_pcmcia_exit(bus); */ + ssb_pcmcia_exit(bus); err_pci_exit: ssb_pci_exit(bus); err_unmap: diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 1facc7620fc8..f1514b33cfae 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -227,7 +227,7 @@ static u8 ssb_sprom_crc(const u16 *sprom, u16 size) return crc; } -static int sprom_check_crc(const u16 *sprom, u16 size) +static int sprom_check_crc(const u16 *sprom, size_t size) { u8 crc; u8 expected_crc; @@ -242,12 +242,14 @@ static int sprom_check_crc(const u16 *sprom, u16 size) return 0; } -static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) +static int sprom_do_read(struct ssb_bus *bus, u16 *sprom) { int i; for (i = 0; i < bus->sprom_size; i++) sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2)); + + return 0; } static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) @@ -660,71 +662,18 @@ const struct ssb_bus_ops ssb_pci_ops = { .write32 = ssb_pci_write32, }; -static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size) -{ - int i, pos = 0; - - for (i = 0; i < size; i++) - pos += snprintf(buf + pos, buf_len - pos - 1, - "%04X", swab16(sprom[i]) & 0xFFFF); - pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); - - return pos + 1; -} - -static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size) -{ - char tmp[5] = { 0 }; - int cnt = 0; - unsigned long parsed; - - if (len < size * 2) - return -EINVAL; - - while (cnt < size) { - memcpy(tmp, dump, 4); - dump += 4; - parsed = simple_strtoul(tmp, NULL, 16); - sprom[cnt++] = swab16((u16)parsed); - } - - return 0; -} - static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); struct ssb_bus *bus; - u16 *sprom; - int err = -ENODEV; - ssize_t count = 0; bus = ssb_pci_dev_to_bus(pdev); if (!bus) - goto out; - err = -ENOMEM; - sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); - if (!sprom) - goto out; + return -ENODEV; - /* Use interruptible locking, as the SPROM write might - * be holding the lock for several seconds. So allow userspace - * to cancel operation. */ - err = -ERESTARTSYS; - if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) - goto out_kfree; - sprom_do_read(bus, sprom); - mutex_unlock(&bus->pci_sprom_mutex); - - count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size); - err = 0; - -out_kfree: - kfree(sprom); -out: - return err ? err : count; + return ssb_attr_sprom_show(bus, buf, sprom_do_read); } static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, @@ -733,55 +682,13 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, { struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); struct ssb_bus *bus; - u16 *sprom; - int res = 0, err = -ENODEV; bus = ssb_pci_dev_to_bus(pdev); if (!bus) - goto out; - err = -ENOMEM; - sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); - if (!sprom) - goto out; - err = hex2sprom(sprom, buf, count, bus->sprom_size); - if (err) { - err = -EINVAL; - goto out_kfree; - } - err = sprom_check_crc(sprom, bus->sprom_size); - if (err) { - err = -EINVAL; - goto out_kfree; - } + return -ENODEV; - /* Use interruptible locking, as the SPROM write might - * be holding the lock for several seconds. So allow userspace - * to cancel operation. */ - err = -ERESTARTSYS; - if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) - goto out_kfree; - err = ssb_devices_freeze(bus); - if (err == -EOPNOTSUPP) { - ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " - "No suspend support. Is CONFIG_PM enabled?\n"); - goto out_unlock; - } - if (err) { - ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); - goto out_unlock; - } - res = sprom_do_write(bus, sprom); - err = ssb_devices_thaw(bus); - if (err) - ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); -out_unlock: - mutex_unlock(&bus->pci_sprom_mutex); -out_kfree: - kfree(sprom); -out: - if (res) - return res; - return err ? err : count; + return ssb_attr_sprom_store(bus, buf, count, + sprom_check_crc, sprom_do_write); } static DEVICE_ATTR(ssb_sprom, 0600, @@ -808,7 +715,7 @@ int ssb_pci_init(struct ssb_bus *bus) return 0; pdev = bus->host_pci; - mutex_init(&bus->pci_sprom_mutex); + mutex_init(&bus->sprom_mutex); err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); if (err) goto out; diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 84b3a845a8a8..cd49f7c65531 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -3,7 +3,7 @@ * PCMCIA-Hostbus related functions * * Copyright 2006 Johannes Berg - * Copyright 2007 Michael Buesch + * Copyright 2007-2008 Michael Buesch * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -26,59 +27,132 @@ #define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0 +/* PCMCIA configuration registers */ +#define SSB_PCMCIA_CORECTL 0x00 +#define SSB_PCMCIA_CORECTL_RESET 0x80 /* Core reset */ +#define SSB_PCMCIA_CORECTL_IRQEN 0x04 /* IRQ enable */ +#define SSB_PCMCIA_CORECTL_FUNCEN 0x01 /* Function enable */ +#define SSB_PCMCIA_CORECTL2 0x80 +#define SSB_PCMCIA_ADDRESS0 0x2E +#define SSB_PCMCIA_ADDRESS1 0x30 +#define SSB_PCMCIA_ADDRESS2 0x32 +#define SSB_PCMCIA_MEMSEG 0x34 +#define SSB_PCMCIA_SPROMCTL 0x36 +#define SSB_PCMCIA_SPROMCTL_IDLE 0 +#define SSB_PCMCIA_SPROMCTL_WRITE 1 +#define SSB_PCMCIA_SPROMCTL_READ 2 +#define SSB_PCMCIA_SPROMCTL_WRITEEN 4 +#define SSB_PCMCIA_SPROMCTL_WRITEDIS 7 +#define SSB_PCMCIA_SPROMCTL_DONE 8 +#define SSB_PCMCIA_SPROM_DATALO 0x38 +#define SSB_PCMCIA_SPROM_DATAHI 0x3A +#define SSB_PCMCIA_SPROM_ADDRLO 0x3C +#define SSB_PCMCIA_SPROM_ADDRHI 0x3E + +/* Hardware invariants CIS tuples */ +#define SSB_PCMCIA_CIS 0x80 +#define SSB_PCMCIA_CIS_ID 0x01 +#define SSB_PCMCIA_CIS_BOARDREV 0x02 +#define SSB_PCMCIA_CIS_PA 0x03 +#define SSB_PCMCIA_CIS_PA_PA0B0_LO 0 +#define SSB_PCMCIA_CIS_PA_PA0B0_HI 1 +#define SSB_PCMCIA_CIS_PA_PA0B1_LO 2 +#define SSB_PCMCIA_CIS_PA_PA0B1_HI 3 +#define SSB_PCMCIA_CIS_PA_PA0B2_LO 4 +#define SSB_PCMCIA_CIS_PA_PA0B2_HI 5 +#define SSB_PCMCIA_CIS_PA_ITSSI 6 +#define SSB_PCMCIA_CIS_PA_MAXPOW 7 +#define SSB_PCMCIA_CIS_OEMNAME 0x04 +#define SSB_PCMCIA_CIS_CCODE 0x05 +#define SSB_PCMCIA_CIS_ANTENNA 0x06 +#define SSB_PCMCIA_CIS_ANTGAIN 0x07 +#define SSB_PCMCIA_CIS_BFLAGS 0x08 +#define SSB_PCMCIA_CIS_LEDS 0x09 + +/* PCMCIA SPROM size. */ +#define SSB_PCMCIA_SPROM_SIZE 256 +#define SSB_PCMCIA_SPROM_SIZE_BYTES (SSB_PCMCIA_SPROM_SIZE * sizeof(u16)) + + +/* Write to a PCMCIA configuration register. */ +static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value) +{ + conf_reg_t reg; + int res; + + memset(®, 0, sizeof(reg)); + reg.Offset = offset; + reg.Action = CS_WRITE; + reg.Value = value; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + return -EBUSY; + + return 0; +} + +/* Read from a PCMCIA configuration register. */ +static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value) +{ + conf_reg_t reg; + int res; + + memset(®, 0, sizeof(reg)); + reg.Offset = offset; + reg.Action = CS_READ; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + return -EBUSY; + *value = reg.Value; + + return 0; +} + int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, u8 coreidx) { - struct pcmcia_device *pdev = bus->host_pcmcia; int err; int attempts = 0; u32 cur_core; - conf_reg_t reg; u32 addr; u32 read_addr; + u8 val; addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; while (1) { - reg.Action = CS_WRITE; - reg.Offset = 0x2E; - reg.Value = (addr & 0x0000F000) >> 12; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS0, + (addr & 0x0000F000) >> 12); + if (err) goto error; - reg.Offset = 0x30; - reg.Value = (addr & 0x00FF0000) >> 16; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS1, + (addr & 0x00FF0000) >> 16); + if (err) goto error; - reg.Offset = 0x32; - reg.Value = (addr & 0xFF000000) >> 24; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS2, + (addr & 0xFF000000) >> 24); + if (err) goto error; read_addr = 0; - reg.Action = CS_READ; - reg.Offset = 0x2E; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS0, &val); + if (err) goto error; - read_addr |= ((u32)(reg.Value & 0x0F)) << 12; - reg.Offset = 0x30; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + read_addr |= ((u32)(val & 0x0F)) << 12; + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS1, &val); + if (err) goto error; - read_addr |= ((u32)reg.Value) << 16; - reg.Offset = 0x32; - err = pcmcia_access_configuration_register(pdev, ®); - if (err != CS_SUCCESS) + read_addr |= ((u32)val) << 16; + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS2, &val); + if (err) goto error; - read_addr |= ((u32)reg.Value) << 24; + read_addr |= ((u32)val) << 24; cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE; if (cur_core == coreidx) break; + err = -ETIMEDOUT; if (attempts++ > SSB_BAR0_MAX_RETRIES) goto error; udelay(10); @@ -87,7 +161,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, return 0; error: ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); - return -ENODEV; + return err; } int ssb_pcmcia_switch_core(struct ssb_bus *bus, @@ -112,27 +186,21 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) { int attempts = 0; - conf_reg_t reg; - int res; + int err; + u8 val; SSB_WARN_ON((seg != 0) && (seg != 1)); - reg.Offset = 0x34; - reg.Function = 0; while (1) { - reg.Action = CS_WRITE; - reg.Value = seg; - res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); - if (unlikely(res != CS_SUCCESS)) + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_MEMSEG, seg); + if (err) goto error; - reg.Value = 0xFF; - reg.Action = CS_READ; - res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); - if (unlikely(res != CS_SUCCESS)) + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_MEMSEG, &val); + if (err) goto error; - - if (reg.Value == seg) + if (val == seg) break; + err = -ETIMEDOUT; if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES)) goto error; udelay(10); @@ -142,7 +210,7 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) return 0; error: ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); - return -ENODEV; + return err; } static int select_core_and_segment(struct ssb_device *dev, @@ -276,18 +344,344 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { .write32 = ssb_pcmcia_write32, }; -#include +static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) +{ + unsigned int i; + int err; + u8 value; + + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command); + if (err) + return err; + for (i = 0; i < 1000; i++) { + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value); + if (err) + return err; + if (value & SSB_PCMCIA_SPROMCTL_DONE) + return 0; + udelay(10); + } + + return -ETIMEDOUT; +} + +/* offset is the 16bit word offset */ +static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value) +{ + int err; + u8 lo, hi; + + offset *= 2; /* Make byte offset */ + + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO, + (offset & 0x00FF)); + if (err) + return err; + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI, + (offset & 0xFF00) >> 8); + if (err) + return err; + err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ); + if (err) + return err; + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo); + if (err) + return err; + err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi); + if (err) + return err; + *value = (lo | (((u16)hi) << 8)); + + return 0; +} + +/* offset is the 16bit word offset */ +static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value) +{ + int err; + + offset *= 2; /* Make byte offset */ + + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO, + (offset & 0x00FF)); + if (err) + return err; + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI, + (offset & 0xFF00) >> 8); + if (err) + return err; + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO, + (value & 0x00FF)); + if (err) + return err; + err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI, + (value & 0xFF00) >> 8); + if (err) + return err; + err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE); + if (err) + return err; + msleep(20); + + return 0; +} + +/* Read the SPROM image. bufsize is in 16bit words. */ +static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom) +{ + int err, i; + + for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) { + err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]); + if (err) + return err; + } + + return 0; +} + +/* Write the SPROM image. size is in 16bit words. */ +static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom) +{ + int i, err; + bool failed = 0; + size_t size = SSB_PCMCIA_SPROM_SIZE; + + ssb_printk(KERN_NOTICE PFX + "Writing SPROM. Do NOT turn off the power! " + "Please stand by...\n"); + err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN); + if (err) { + ssb_printk(KERN_NOTICE PFX + "Could not enable SPROM write access.\n"); + return -EBUSY; + } + ssb_printk(KERN_NOTICE PFX "[ 0%%"); + msleep(500); + for (i = 0; i < size; i++) { + if (i == size / 4) + ssb_printk("25%%"); + else if (i == size / 2) + ssb_printk("50%%"); + else if (i == (size * 3) / 4) + ssb_printk("75%%"); + else if (i % 2) + ssb_printk("."); + err = ssb_pcmcia_sprom_write(bus, i, sprom[i]); + if (err) { + ssb_printk("\n" KERN_NOTICE PFX + "Failed to write to SPROM.\n"); + failed = 1; + break; + } + } + err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS); + if (err) { + ssb_printk("\n" KERN_NOTICE PFX + "Could not disable SPROM write access.\n"); + failed = 1; + } + msleep(500); + if (!failed) { + ssb_printk("100%% ]\n"); + ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); + } + + return failed ? -EBUSY : 0; +} + +static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size) +{ + //TODO + return 0; +} + +#define GOTO_ERROR_ON(condition, description) do { \ + if (unlikely(condition)) { \ + error_description = description; \ + goto error; \ + } \ + } while (0) + int ssb_pcmcia_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { - //TODO - random_ether_addr(iv->sprom.il0mac); + tuple_t tuple; + int res; + unsigned char buf[32]; + struct ssb_sprom *sprom = &iv->sprom; + struct ssb_boardinfo *bi = &iv->boardinfo; + const char *error_description; + + memset(sprom, 0xFF, sizeof(*sprom)); + sprom->revision = 1; + sprom->boardflags_lo = 0; + sprom->boardflags_hi = 0; + + /* First fetch the MAC address. */ + memset(&tuple, 0, sizeof(tuple)); + tuple.DesiredTuple = CISTPL_FUNCE; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl"); + res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl data"); + while (1) { + GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1"); + if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID) + break; + res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl"); + res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl data"); + } + GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size"); + memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN); + + /* Fetch the vendor specific tuples. */ + memset(&tuple, 0, sizeof(tuple)); + tuple.DesiredTuple = SSB_PCMCIA_CIS; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl"); + res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl data"); + while (1) { + GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1"); + switch (tuple.TupleData[0]) { + case SSB_PCMCIA_CIS_ID: + GOTO_ERROR_ON((tuple.TupleDataLen != 5) && + (tuple.TupleDataLen != 7), + "id tpl size"); + bi->vendor = tuple.TupleData[1] | + ((u16)tuple.TupleData[2] << 8); + break; + case SSB_PCMCIA_CIS_BOARDREV: + GOTO_ERROR_ON(tuple.TupleDataLen != 2, + "boardrev tpl size"); + sprom->board_rev = tuple.TupleData[1]; + break; + case SSB_PCMCIA_CIS_PA: + GOTO_ERROR_ON(tuple.TupleDataLen != 9, + "pa tpl size"); + sprom->pa0b0 = tuple.TupleData[1] | + ((u16)tuple.TupleData[2] << 8); + sprom->pa0b1 = tuple.TupleData[3] | + ((u16)tuple.TupleData[4] << 8); + sprom->pa0b2 = tuple.TupleData[5] | + ((u16)tuple.TupleData[6] << 8); + sprom->itssi_a = tuple.TupleData[7]; + sprom->itssi_bg = tuple.TupleData[7]; + sprom->maxpwr_a = tuple.TupleData[8]; + sprom->maxpwr_bg = tuple.TupleData[8]; + break; + case SSB_PCMCIA_CIS_OEMNAME: + /* We ignore this. */ + break; + case SSB_PCMCIA_CIS_CCODE: + GOTO_ERROR_ON(tuple.TupleDataLen != 2, + "ccode tpl size"); + sprom->country_code = tuple.TupleData[1]; + break; + case SSB_PCMCIA_CIS_ANTENNA: + GOTO_ERROR_ON(tuple.TupleDataLen != 2, + "ant tpl size"); + sprom->ant_available_a = tuple.TupleData[1]; + sprom->ant_available_bg = tuple.TupleData[1]; + break; + case SSB_PCMCIA_CIS_ANTGAIN: + GOTO_ERROR_ON(tuple.TupleDataLen != 2, + "antg tpl size"); + sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1]; + sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1]; + sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1]; + sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1]; + sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1]; + sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1]; + sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1]; + sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1]; + break; + case SSB_PCMCIA_CIS_BFLAGS: + GOTO_ERROR_ON(tuple.TupleDataLen != 3, + "bfl tpl size"); + sprom->boardflags_lo = tuple.TupleData[1] | + ((u16)tuple.TupleData[2] << 8); + break; + case SSB_PCMCIA_CIS_LEDS: + GOTO_ERROR_ON(tuple.TupleDataLen != 5, + "leds tpl size"); + sprom->gpio0 = tuple.TupleData[1]; + sprom->gpio1 = tuple.TupleData[2]; + sprom->gpio2 = tuple.TupleData[3]; + sprom->gpio3 = tuple.TupleData[4]; + break; + } + res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); + if (res == CS_NO_MORE_ITEMS) + break; + GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl"); + res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); + GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl data"); + } + return 0; +error: + ssb_printk(KERN_ERR PFX + "PCMCIA: Failed to fetch device invariants: %s\n", + error_description); + return -ENODEV; +} + +static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev, + struct device_attribute *attr, + char *buf) +{ + struct pcmcia_device *pdev = + container_of(pcmciadev, struct pcmcia_device, dev); + struct ssb_bus *bus; + + bus = ssb_pcmcia_dev_to_bus(pdev); + if (!bus) + return -ENODEV; + + return ssb_attr_sprom_show(bus, buf, + ssb_pcmcia_sprom_read_all); +} + +static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pcmcia_device *pdev = + container_of(pcmciadev, struct pcmcia_device, dev); + struct ssb_bus *bus; + + bus = ssb_pcmcia_dev_to_bus(pdev); + if (!bus) + return -ENODEV; + + return ssb_attr_sprom_store(bus, buf, count, + ssb_pcmcia_sprom_check_crc, + ssb_pcmcia_sprom_write_all); +} + +static DEVICE_ATTR(ssb_sprom, 0600, + ssb_pcmcia_attr_sprom_show, + ssb_pcmcia_attr_sprom_store); + +void ssb_pcmcia_exit(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_PCMCIA) + return; + + device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom); } int ssb_pcmcia_init(struct ssb_bus *bus) { - conf_reg_t reg; + u8 val, offset; int err; if (bus->bustype != SSB_BUSTYPE_PCMCIA) @@ -298,22 +692,26 @@ int ssb_pcmcia_init(struct ssb_bus *bus) ssb_pcmcia_switch_segment(bus, 0); /* Init IRQ routing */ - reg.Action = CS_READ; - reg.Function = 0; if (bus->chip_id == 0x4306) - reg.Offset = 0x00; + offset = SSB_PCMCIA_CORECTL; else - reg.Offset = 0x80; - err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); - if (err != CS_SUCCESS) + offset = SSB_PCMCIA_CORECTL2; + err = ssb_pcmcia_cfg_read(bus, offset, &val); + if (err) goto error; - reg.Action = CS_WRITE; - reg.Value |= 0x04 | 0x01; - err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); - if (err != CS_SUCCESS) + val |= SSB_PCMCIA_CORECTL_IRQEN | SSB_PCMCIA_CORECTL_FUNCEN; + err = ssb_pcmcia_cfg_write(bus, offset, val); + if (err) + goto error; + + bus->sprom_size = SSB_PCMCIA_SPROM_SIZE; + mutex_init(&bus->sprom_mutex); + err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom); + if (err) goto error; return 0; error: - return -ENODEV; + ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n"); + return err; } diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c new file mode 100644 index 000000000000..3668edb39315 --- /dev/null +++ b/drivers/ssb/sprom.c @@ -0,0 +1,133 @@ +/* + * Sonics Silicon Backplane + * Common SPROM support routines + * + * Copyright (C) 2005-2008 Michael Buesch + * Copyright (C) 2005 Martin Langer + * Copyright (C) 2005 Stefano Brivio + * Copyright (C) 2005 Danny van Dyk + * Copyright (C) 2005 Andreas Jaggi + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "ssb_private.h" + + +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, + size_t sprom_size_words) +{ + int i, pos = 0; + + for (i = 0; i < sprom_size_words; i++) + pos += snprintf(buf + pos, buf_len - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len, + size_t sprom_size_words) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < sprom_size_words * 2) + return -EINVAL; + + while (cnt < sprom_size_words) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + +/* Common sprom device-attribute show-handler */ +ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf, + int (*sprom_read)(struct ssb_bus *bus, u16 *sprom)) +{ + u16 *sprom; + int err = -ENOMEM; + ssize_t count = 0; + size_t sprom_size_words = bus->sprom_size; + + sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->sprom_mutex)) + goto out_kfree; + err = sprom_read(bus, sprom); + mutex_unlock(&bus->sprom_mutex); + + if (!err) + count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words); + +out_kfree: + kfree(sprom); +out: + return err ? err : count; +} + +/* Common sprom device-attribute store-handler */ +ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, + const char *buf, size_t count, + int (*sprom_check_crc)(const u16 *sprom, size_t size), + int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)) +{ + u16 *sprom; + int res = 0, err = -ENOMEM; + size_t sprom_size_words = bus->sprom_size; + + sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + err = hex2sprom(sprom, buf, count, sprom_size_words); + if (err) { + err = -EINVAL; + goto out_kfree; + } + err = sprom_check_crc(sprom, sprom_size_words); + if (err) { + err = -EINVAL; + goto out_kfree; + } + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->sprom_mutex)) + goto out_kfree; + err = ssb_devices_freeze(bus); + if (err == -EOPNOTSUPP) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " + "No suspend support. Is CONFIG_PM enabled?\n"); + goto out_unlock; + } + if (err) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); + goto out_unlock; + } + res = sprom_write(bus, sprom); + err = ssb_devices_thaw(bus); + if (err) + ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +out_unlock: + mutex_unlock(&bus->sprom_mutex); +out_kfree: + kfree(sprom); +out: + if (res) + return res; + return err ? err : count; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index d03b20983b1e..a83bf7a4d80b 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -81,6 +81,7 @@ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg); extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv); +extern void ssb_pcmcia_exit(struct ssb_bus *bus); extern int ssb_pcmcia_init(struct ssb_bus *bus); extern const struct ssb_bus_ops ssb_pcmcia_ops; #else /* CONFIG_SSB_PCMCIAHOST */ @@ -99,6 +100,9 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, { return 0; } +static inline void ssb_pcmcia_exit(struct ssb_bus *bus) +{ +} static inline int ssb_pcmcia_init(struct ssb_bus *bus) { return 0; @@ -113,6 +117,17 @@ extern int ssb_bus_scan(struct ssb_bus *bus, extern void ssb_iounmap(struct ssb_bus *ssb); +/* sprom.c */ +extern +ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf, + int (*sprom_read)(struct ssb_bus *bus, u16 *sprom)); +extern +ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, + const char *buf, size_t count, + int (*sprom_check_crc)(const u16 *sprom, size_t size), + int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); + + /* core.c */ extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); extern int ssb_devices_freeze(struct ssb_bus *bus); @@ -120,6 +135,8 @@ extern int ssb_devices_thaw(struct ssb_bus *bus); extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)); +extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); + /* b43_pci_bridge.c */ #ifdef CONFIG_SSB_B43_PCI_BRIDGE diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index b7c388972fcf..8644e03cf588 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -245,9 +245,9 @@ struct ssb_bus { /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ struct pcmcia_device *host_pcmcia; -#ifdef CONFIG_SSB_PCIHOST +#ifdef CONFIG_SSB_SPROM /* Mutex to protect the SPROM writing. */ - struct mutex pci_sprom_mutex; + struct mutex sprom_mutex; #endif /* ID information about the Chip. */ -- cgit v1.2.3 From 3e94794355724f77dc6cbb5ad956f7c72d8313a4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 22 Feb 2008 19:55:15 +0900 Subject: smc91x: introduce platform data flags V2 This patch introduces struct smc91x_platdata and modifies the driver so bus width is checked during run time using SMC_nBIT() instead of SMC_CAN_USE_nBIT. V2 keeps static configuration lean using SMC_DYNAMIC_BUS_CONFIG. Signed-off-by: Magnus Damm Acked-by: Nicolas Pitre Signed-off-by: Jeff Garzik --- drivers/net/smc91x.c | 34 +++++++++++++++++++++++++----- drivers/net/smc91x.h | 57 +++++++++++++++++++++++++++++++------------------- include/linux/smc91x.h | 13 ++++++++++++ 3 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 include/linux/smc91x.h (limited to 'include/linux') diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index d0ef80ae018a..97bdb2a43bc8 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1997,6 +1997,8 @@ err_out: static int smc_enable_device(struct platform_device *pdev) { + struct net_device *ndev = platform_get_drvdata(pdev); + struct smc_local *lp = netdev_priv(ndev); unsigned long flags; unsigned char ecor, ecsr; void __iomem *addr; @@ -2039,7 +2041,7 @@ static int smc_enable_device(struct platform_device *pdev) * Set the appropriate byte/word mode. */ ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; - if (!SMC_CAN_USE_16BIT) + if (!SMC_16BIT(lp)) ecsr |= ECSR_IOIS8; writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); local_irq_restore(flags); @@ -2124,10 +2126,11 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device * */ static int smc_drv_probe(struct platform_device *pdev) { + struct smc91x_platdata *pd = pdev->dev.platform_data; + struct smc_local *lp; struct net_device *ndev; struct resource *res, *ires; unsigned int __iomem *addr; - unsigned long irq_flags = SMC_IRQ_FLAGS; int ret; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); @@ -2152,6 +2155,27 @@ static int smc_drv_probe(struct platform_device *pdev) } SET_NETDEV_DEV(ndev, &pdev->dev); + /* get configuration from platform data, only allow use of + * bus width if both SMC_CAN_USE_xxx and SMC91X_USE_xxx are set. + */ + + lp = netdev_priv(ndev); + lp->cfg.irq_flags = SMC_IRQ_FLAGS; + +#ifdef SMC_DYNAMIC_BUS_CONFIG + if (pd) + memcpy(&lp->cfg, pd, sizeof(lp->cfg)); + else { + lp->cfg.flags = SMC91X_USE_8BIT; + lp->cfg.flags |= SMC91X_USE_16BIT; + lp->cfg.flags |= SMC91X_USE_32BIT; + } + + lp->cfg.flags &= ~(SMC_CAN_USE_8BIT ? 0 : SMC91X_USE_8BIT); + lp->cfg.flags &= ~(SMC_CAN_USE_16BIT ? 0 : SMC91X_USE_16BIT); + lp->cfg.flags &= ~(SMC_CAN_USE_32BIT ? 0 : SMC91X_USE_32BIT); +#endif + ndev->dma = (unsigned char)-1; ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -2162,7 +2186,7 @@ static int smc_drv_probe(struct platform_device *pdev) ndev->irq = ires->start; if (SMC_IRQ_FLAGS == -1) - irq_flags = ires->flags & IRQF_TRIGGER_MASK; + lp->cfg.irq_flags = ires->flags & IRQF_TRIGGER_MASK; ret = smc_request_attrib(pdev); if (ret) @@ -2170,6 +2194,7 @@ static int smc_drv_probe(struct platform_device *pdev) #if defined(CONFIG_SA1100_ASSABET) NCR_0 |= NCR_ENET_OSC_EN; #endif + platform_set_drvdata(pdev, ndev); ret = smc_enable_device(pdev); if (ret) goto out_release_attrib; @@ -2188,8 +2213,7 @@ static int smc_drv_probe(struct platform_device *pdev) } #endif - platform_set_drvdata(pdev, ndev); - ret = smc_probe(ndev, addr, irq_flags); + ret = smc_probe(ndev, addr, lp->cfg.irq_flags); if (ret != 0) goto out_iounmap; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 92ff9c42367e..e044b4de1397 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -34,6 +34,7 @@ #ifndef _SMC91X_H_ #define _SMC91X_H_ +#include /* * Define your architecture specific bus configuration parameters here. @@ -481,6 +482,7 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define RPC_LSA_DEFAULT RPC_LED_100_10 #define RPC_LSB_DEFAULT RPC_LED_TX_RX +#define SMC_DYNAMIC_BUS_CONFIG #endif @@ -526,8 +528,19 @@ struct smc_local { #endif void __iomem *base; void __iomem *datacs; + + struct smc91x_platdata cfg; }; +#ifdef SMC_DYNAMIC_BUS_CONFIG +#define SMC_8BIT(p) (((p)->cfg.flags & SMC91X_USE_8BIT) && SMC_CAN_USE_8BIT) +#define SMC_16BIT(p) (((p)->cfg.flags & SMC91X_USE_16BIT) && SMC_CAN_USE_16BIT) +#define SMC_32BIT(p) (((p)->cfg.flags & SMC91X_USE_32BIT) && SMC_CAN_USE_32BIT) +#else +#define SMC_8BIT(p) SMC_CAN_USE_8BIT +#define SMC_16BIT(p) SMC_CAN_USE_16BIT +#define SMC_32BIT(p) SMC_CAN_USE_32BIT +#endif #ifdef SMC_USE_PXA_DMA /* @@ -1108,41 +1121,41 @@ static const char * chip_ids[ 16 ] = { * * Enforce it on any 32-bit capable setup for now. */ -#define SMC_MUST_ALIGN_WRITE SMC_CAN_USE_32BIT +#define SMC_MUST_ALIGN_WRITE(lp) SMC_32BIT(lp) #define SMC_GET_PN(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, PN_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, PN_REG(lp))) \ : (SMC_inw(ioaddr, PN_REG(lp)) & 0xFF)) #define SMC_SET_PN(lp, x) \ do { \ - if (SMC_MUST_ALIGN_WRITE) \ + if (SMC_MUST_ALIGN_WRITE(lp)) \ SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 0, 2)); \ - else if (SMC_CAN_USE_8BIT) \ + else if (SMC_8BIT(lp)) \ SMC_outb(x, ioaddr, PN_REG(lp)); \ else \ SMC_outw(x, ioaddr, PN_REG(lp)); \ } while (0) #define SMC_GET_AR(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, AR_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, AR_REG(lp))) \ : (SMC_inw(ioaddr, PN_REG(lp)) >> 8)) #define SMC_GET_TXFIFO(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, TXFIFO_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, TXFIFO_REG(lp))) \ : (SMC_inw(ioaddr, TXFIFO_REG(lp)) & 0xFF)) #define SMC_GET_RXFIFO(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, RXFIFO_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, RXFIFO_REG(lp))) \ : (SMC_inw(ioaddr, TXFIFO_REG(lp)) >> 8)) #define SMC_GET_INT(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, INT_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, INT_REG(lp))) \ : (SMC_inw(ioaddr, INT_REG(lp)) & 0xFF)) #define SMC_ACK_INT(lp, x) \ do { \ - if (SMC_CAN_USE_8BIT) \ + if (SMC_8BIT(lp)) \ SMC_outb(x, ioaddr, INT_REG(lp)); \ else { \ unsigned long __flags; \ @@ -1155,12 +1168,12 @@ static const char * chip_ids[ 16 ] = { } while (0) #define SMC_GET_INT_MASK(lp) \ - (SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, IM_REG(lp))) \ + (SMC_8BIT(lp) ? (SMC_inb(ioaddr, IM_REG(lp))) \ : (SMC_inw(ioaddr, INT_REG(lp)) >> 8)) #define SMC_SET_INT_MASK(lp, x) \ do { \ - if (SMC_CAN_USE_8BIT) \ + if (SMC_8BIT(lp)) \ SMC_outb(x, ioaddr, IM_REG(lp)); \ else \ SMC_outw((x) << 8, ioaddr, INT_REG(lp)); \ @@ -1170,7 +1183,7 @@ static const char * chip_ids[ 16 ] = { #define SMC_SELECT_BANK(lp, x) \ do { \ - if (SMC_MUST_ALIGN_WRITE) \ + if (SMC_MUST_ALIGN_WRITE(lp)) \ SMC_outl((x)<<16, ioaddr, 12<> 16; \ @@ -1290,7 +1303,7 @@ static const char * chip_ids[ 16 ] = { #define SMC_PUSH_DATA(lp, p, l) \ do { \ - if (SMC_CAN_USE_32BIT) { \ + if (SMC_32BIT(lp)) { \ void *__ptr = (p); \ int __len = (l); \ void __iomem *__ioaddr = ioaddr; \ @@ -1308,15 +1321,15 @@ static const char * chip_ids[ 16 ] = { SMC_outw(*((u16 *)__ptr), ioaddr, \ DATA_REG(lp)); \ } \ - } else if (SMC_CAN_USE_16BIT) \ + } else if (SMC_16BIT(lp)) \ SMC_outsw(ioaddr, DATA_REG(lp), p, (l) >> 1); \ - else if (SMC_CAN_USE_8BIT) \ + else if (SMC_8BIT(lp)) \ SMC_outsb(ioaddr, DATA_REG(lp), p, l); \ } while (0) #define SMC_PULL_DATA(lp, p, l) \ do { \ - if (SMC_CAN_USE_32BIT) { \ + if (SMC_32BIT(lp)) { \ void *__ptr = (p); \ int __len = (l); \ void __iomem *__ioaddr = ioaddr; \ @@ -1343,9 +1356,9 @@ static const char * chip_ids[ 16 ] = { __ioaddr = lp->datacs; \ __len += 2; \ SMC_insl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \ - } else if (SMC_CAN_USE_16BIT) \ + } else if (SMC_16BIT(lp)) \ SMC_insw(ioaddr, DATA_REG(lp), p, (l) >> 1); \ - else if (SMC_CAN_USE_8BIT) \ + else if (SMC_8BIT(lp)) \ SMC_insb(ioaddr, DATA_REG(lp), p, l); \ } while (0) diff --git a/include/linux/smc91x.h b/include/linux/smc91x.h new file mode 100644 index 000000000000..8e0556b8781c --- /dev/null +++ b/include/linux/smc91x.h @@ -0,0 +1,13 @@ +#ifndef __SMC91X_H__ +#define __SMC91X_H__ + +#define SMC91X_USE_8BIT (1 << 0) +#define SMC91X_USE_16BIT (1 << 1) +#define SMC91X_USE_32BIT (1 << 2) + +struct smc91x_platdata { + unsigned long flags; + unsigned long irq_flags; /* IRQF_... */ +}; + +#endif /* __SMC91X_H__ */ -- cgit v1.2.3 From 82cc1a7a56872056af0ead6c7d695aa223f36695 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Fri, 21 Mar 2008 03:43:19 -0700 Subject: [NET]: Add per-connection option to set max TSO frame size Update: My mailer ate one of Jarek's feedback mails... Fixed the parameter in netif_set_gso_max_size() to be u32, not u16. Fixed the whitespace issue due to a patch import botch. Changed the types from u32 to unsigned int to be more consistent with other variables in the area. Also brought the patch up to the latest net-2.6.26 tree. Update: Made gso_max_size container 32 bits, not 16. Moved the location of gso_max_size within netdev to be less hotpath. Made more consistent names between the sock and netdev layers, and added a define for the max GSO size. Update: Respun for net-2.6.26 tree. Update: changed max_gso_frame_size and sk_gso_max_size from signed to unsigned - thanks Stephen! This patch adds the ability for device drivers to control the size of the TSO frames being sent to them, per TCP connection. By setting the netdevice's gso_max_size value, the socket layer will set the GSO frame size based on that value. This will propogate into the TCP layer, and send TSO's of that size to the hardware. This can be desirable to help tune the bursty nature of TSO on a per-adapter basis, where one may have 1 GbE and 10 GbE devices coexisting in a system, one running multiqueue and the other not, etc. This can also be desirable for devices that cannot support full 64 KB TSO's, but still want to benefit from some level of segmentation offloading. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: David S. Miller --- include/linux/netdevice.h | 10 ++++++++++ include/net/sock.h | 2 ++ net/core/dev.c | 1 + net/core/sock.c | 6 ++++-- net/ipv4/tcp_output.c | 4 ++-- 5 files changed, 19 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a2f003239c85..ced61f87660e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -724,6 +724,10 @@ struct net_device /* rtnetlink link ops */ const struct rtnl_link_ops *rtnl_link_ops; + /* for setting kernel sock attribute on TCP connection setup */ +#define GSO_MAX_SIZE 65536 + unsigned int gso_max_size; + /* The TX queue control structures */ unsigned int egress_subqueue_count; struct net_device_subqueue egress_subqueue[1]; @@ -1475,6 +1479,12 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); } +static inline void netif_set_gso_max_size(struct net_device *dev, + unsigned int size) +{ + dev->gso_max_size = size; +} + /* On bonding slaves other than the currently active slave, suppress * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and * ARP on active-backup slaves with arp_validate enabled. diff --git a/include/net/sock.h b/include/net/sock.h index 39112e75411c..8358fff002eb 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -151,6 +151,7 @@ struct sock_common { * @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) + * @sk_gso_max_size: Maximum GSO segment size to build * @sk_lingertime: %SO_LINGER l_linger setting * @sk_backlog: always used with the per-socket spinlock held * @sk_callback_lock: used with the callbacks in the end of this struct @@ -237,6 +238,7 @@ struct sock { gfp_t sk_allocation; int sk_route_caps; int sk_gso_type; + unsigned int sk_gso_max_size; int sk_rcvlowat; unsigned long sk_flags; unsigned long sk_lingertime; diff --git a/net/core/dev.c b/net/core/dev.c index fcdf03cf3b3f..f973e38b81af 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4021,6 +4021,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, } dev->egress_subqueue_count = queue_count; + dev->gso_max_size = GSO_MAX_SIZE; dev->get_stats = internal_stats; netpoll_netdev_init(dev); diff --git a/net/core/sock.c b/net/core/sock.c index bb5236aee643..b1a6ed4d33c1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1095,10 +1095,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; if (sk_can_gso(sk)) { - if (dst->header_len) + if (dst->header_len) { sk->sk_route_caps &= ~NETIF_F_GSO_MASK; - else + } else { sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; + sk->sk_gso_max_size = dst->dev->gso_max_size; + } } } EXPORT_SYMBOL_GPL(sk_setup_caps); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b4e11d834c9f..a627616314ba 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -998,7 +998,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) xmit_size_goal = mss_now; if (doing_tso) { - xmit_size_goal = (65535 - + xmit_size_goal = ((sk->sk_gso_max_size - 1) - inet_csk(sk)->icsk_af_ops->net_header_len - inet_csk(sk)->icsk_ext_hdr_len - tp->tcp_header_len); @@ -1282,7 +1282,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit = min(send_win, cong_win); /* If a full-sized TSO skb can be sent, do it. */ - if (limit >= 65536) + if (limit >= sk->sk_gso_max_size) goto send_now; if (sysctl_tcp_tso_win_divisor) { -- cgit v1.2.3 From ec3c0982a2dd1e671bad8e9d26c28dcba0039d87 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 21 Mar 2008 16:33:01 -0700 Subject: [TCP]: TCP_DEFER_ACCEPT updates - process as established Change TCP_DEFER_ACCEPT implementation so that it transitions a connection to ESTABLISHED after handshake is complete instead of leaving it in SYN-RECV until some data arrvies. Place connection in accept queue when first data packet arrives from slow path. Benefits: - established connection is now reset if it never makes it to the accept queue - diagnostic state of established matches with the packet traces showing completed handshake - TCP_DEFER_ACCEPT timeouts are expressed in seconds and can now be enforced with reasonable accuracy instead of rounding up to next exponential back-off of syn-ack retry. Signed-off-by: Patrick McManus Signed-off-by: David S. Miller --- include/linux/tcp.h | 7 +++++++ include/net/request_sock.h | 4 ++-- include/net/tcp.h | 1 + net/ipv4/inet_connection_sock.c | 11 +++------- net/ipv4/tcp.c | 18 +++++++--------- net/ipv4/tcp_input.c | 46 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 8 +++++++ net/ipv4/tcp_minisocks.c | 32 +++++++++++++++++----------- net/ipv4/tcp_timer.c | 5 +++++ 9 files changed, 99 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 08027f1d7f31..d96d9b122304 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -239,6 +239,11 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) return (struct tcp_request_sock *)req; } +struct tcp_deferred_accept_info { + struct sock *listen_sk; + struct request_sock *request; +}; + struct tcp_sock { /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; @@ -374,6 +379,8 @@ struct tcp_sock { unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; + struct tcp_deferred_accept_info defer_tcp_accept; + unsigned long last_synq_overflow; u32 tso_deferred; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 040780add355..0369f98e9f3a 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -115,8 +115,8 @@ struct request_sock_queue { struct request_sock *rskq_accept_head; struct request_sock *rskq_accept_tail; rwlock_t syn_wait_lock; - u8 rskq_defer_accept; - /* 3 bytes hole, try to pack */ + u16 rskq_defer_accept; + /* 2 bytes hole, try to pack */ struct listen_sock *listen_opt; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index 847e1634e1f4..67cc3956d29c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -139,6 +139,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_KEEPINTVL 32767 #define MAX_TCP_KEEPCNT 127 #define MAX_TCP_SYNCNT 127 +#define MAX_TCP_ACCEPT_DEFERRED 65535 #define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 8a45be988709..cc1a1859a61b 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -414,8 +414,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, struct inet_connection_sock *icsk = inet_csk(parent); struct request_sock_queue *queue = &icsk->icsk_accept_queue; struct listen_sock *lopt = queue->listen_opt; - int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; - int thresh = max_retries; + int thresh = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; unsigned long now = jiffies; struct request_sock **reqp, *req; int i, budget; @@ -451,9 +450,6 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, } } - if (queue->rskq_defer_accept) - max_retries = queue->rskq_defer_accept; - budget = 2 * (lopt->nr_table_entries / (timeout / interval)); i = lopt->clock_hand; @@ -461,9 +457,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) && - (inet_rsk(req)->acked || - !req->rsk_ops->rtx_syn_ack(parent, req))) { + if (req->retrans < thresh && + !req->rsk_ops->rtx_syn_ack(parent, req)) { unsigned long timeo; if (req->retrans++ == 0) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 071e83a894ad..e0fbc25ca816 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2105,15 +2105,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; case TCP_DEFER_ACCEPT: - icsk->icsk_accept_queue.rskq_defer_accept = 0; - if (val > 0) { - /* Translate value in seconds to number of - * retransmits */ - while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && - val > ((TCP_TIMEOUT_INIT / HZ) << - icsk->icsk_accept_queue.rskq_defer_accept)) - icsk->icsk_accept_queue.rskq_defer_accept++; - icsk->icsk_accept_queue.rskq_defer_accept++; + if (val < 0) { + err = -EINVAL; + } else { + if (val > MAX_TCP_ACCEPT_DEFERRED) + val = MAX_TCP_ACCEPT_DEFERRED; + icsk->icsk_accept_queue.rskq_defer_accept = val; } break; @@ -2295,8 +2292,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, val = (val ? : sysctl_tcp_fin_timeout) / HZ; break; case TCP_DEFER_ACCEPT: - val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : - ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); + val = icsk->icsk_accept_queue.rskq_defer_accept; break; case TCP_WINDOW_CLAMP: val = tp->window_clamp; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9cf446427cc2..6e46b4c0f28c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4451,6 +4451,49 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) } } +static int tcp_defer_accept_check(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (tp->defer_tcp_accept.request) { + int queued_data = tp->rcv_nxt - tp->copied_seq; + int hasfin = !skb_queue_empty(&sk->sk_receive_queue) ? + tcp_hdr((struct sk_buff *) + sk->sk_receive_queue.prev)->fin : 0; + + if (queued_data && hasfin) + queued_data--; + + if (queued_data && + tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) { + if (sock_flag(sk, SOCK_KEEPOPEN)) { + inet_csk_reset_keepalive_timer(sk, + keepalive_time_when(tp)); + } else { + inet_csk_delete_keepalive_timer(sk); + } + + inet_csk_reqsk_queue_add( + tp->defer_tcp_accept.listen_sk, + tp->defer_tcp_accept.request, + sk); + + tp->defer_tcp_accept.listen_sk->sk_data_ready( + tp->defer_tcp_accept.listen_sk, 0); + + sock_put(tp->defer_tcp_accept.listen_sk); + sock_put(sk); + tp->defer_tcp_accept.listen_sk = NULL; + tp->defer_tcp_accept.request = NULL; + } else if (hasfin || + tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) { + tcp_reset(sk); + return -1; + } + } + return 0; +} + static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) { struct tcp_sock *tp = tcp_sk(sk); @@ -4811,6 +4854,9 @@ step5: tcp_data_snd_check(sk); tcp_ack_snd_check(sk); + + if (tcp_defer_accept_check(sk)) + return -1; return 0; csum_error: diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ba6e911c979..167a0f557531 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1920,6 +1920,14 @@ int tcp_v4_destroy_sock(struct sock *sk) sk->sk_sndmsg_page = NULL; } + if (tp->defer_tcp_accept.request) { + reqsk_free(tp->defer_tcp_accept.request); + sock_put(tp->defer_tcp_accept.listen_sk); + sock_put(sk); + tp->defer_tcp_accept.listen_sk = NULL; + tp->defer_tcp_accept.request = NULL; + } + atomic_dec(&tcp_sockets_allocated); return 0; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 8245247a6ceb..019c8c16e5cc 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -571,10 +571,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, does sequence test, SYN is truncated, and thus we consider it a bare ACK. - If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this - bare ACK. Otherwise, we create an established connection. Both - ends (listening sockets) accept the new incoming connection and try - to talk to each other. 8-) + Both ends (listening sockets) accept the new incoming + connection and try to talk to each other. 8-) Note: This case is both harmless, and rare. Possibility is about the same as us discovering intelligent life on another plant tomorrow. @@ -642,13 +640,6 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, if (!(flg & TCP_FLAG_ACK)) return NULL; - /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ - if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && - TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { - inet_rsk(req)->acked = 1; - return NULL; - } - /* OK, ACK is valid, create big socket and * feed this segment to it. It will repeat all * the tests. THIS SEGMENT MUST MOVE SOCKET TO @@ -687,7 +678,24 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); - inet_csk_reqsk_queue_add(sk, req, child); + if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && + TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { + + /* the accept queue handling is done is est recv slow + * path so lets make sure to start there + */ + tcp_sk(child)->pred_flags = 0; + sock_hold(sk); + sock_hold(child); + tcp_sk(child)->defer_tcp_accept.listen_sk = sk; + tcp_sk(child)->defer_tcp_accept.request = req; + + inet_csk_reset_keepalive_timer(child, + inet_csk(sk)->icsk_accept_queue.rskq_defer_accept * HZ); + } else { + inet_csk_reqsk_queue_add(sk, req, child); + } + return child; listen_overflow: diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 803d758a2b12..160d16f9f4fc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -481,6 +481,11 @@ static void tcp_keepalive_timer (unsigned long data) goto death; } + if (tp->defer_tcp_accept.request && sk->sk_state == TCP_ESTABLISHED) { + tcp_send_active_reset(sk, GFP_ATOMIC); + goto death; + } + if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) goto out; -- cgit v1.2.3 From 0098b7273e968fb9989a6e1e4e4c024cd081fe0d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 22 Mar 2008 17:18:47 -0700 Subject: [NET]: NPROTO is redundant; it's equal to AF_MAX/PF_MAX. DaveM pointed out NPROTO exposed to userspace, so keep it around, just make sure it stays in sync. Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- include/linux/net.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/net.h b/include/linux/net.h index c414d90e647b..71f7dd559285 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -19,6 +19,7 @@ #define _LINUX_NET_H #include +#include #include struct poll_table_struct; @@ -26,7 +27,7 @@ struct pipe_inode_info; struct inode; struct net; -#define NPROTO 34 /* should be enough for now.. */ +#define NPROTO AF_MAX #define SYS_SOCKET 1 /* sys_socket(2) */ #define SYS_BIND 2 /* sys_bind(2) */ -- cgit v1.2.3 From 414f69d8a6ff0b30e7ea5ce10534b19f851e172e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 23 Mar 2008 22:04:31 -0700 Subject: [NET]: include/linux/atalk.h - remove duplicate include Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/atalk.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atalk.h b/include/linux/atalk.h index ced8a1ed080c..e9ebac2e2ecc 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -85,8 +85,6 @@ static inline struct atalk_sock *at_sk(struct sock *sk) return (struct atalk_sock *)sk; } -#include - struct ddpehdr { __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */ __be16 deh_sum; -- cgit v1.2.3 From cc32e05416b4023a5466a2f66e3c02236a771c5b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 23 Mar 2008 22:05:44 -0700 Subject: [NET]: include/linux/igmp.h - remove duplicate include Removed duplicate #include Combined #ifdef __KERNEL__ blocks Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/igmp.h | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index f510e7e382a8..f5a1a0db2e8e 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -80,27 +80,6 @@ struct igmpv3_query { __be32 srcs[0]; }; -#ifdef __KERNEL__ -#include - -static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb) -{ - return (struct igmphdr *)skb_transport_header(skb); -} - -static inline struct igmpv3_report * - igmpv3_report_hdr(const struct sk_buff *skb) -{ - return (struct igmpv3_report *)skb_transport_header(skb); -} - -static inline struct igmpv3_query * - igmpv3_query_hdr(const struct sk_buff *skb) -{ - return (struct igmpv3_query *)skb_transport_header(skb); -} -#endif - #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ #define IGMP_DVMRP 0x13 /* DVMRP routing */ @@ -151,6 +130,23 @@ static inline struct igmpv3_query * #include #include +static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb) +{ + return (struct igmphdr *)skb_transport_header(skb); +} + +static inline struct igmpv3_report * + igmpv3_report_hdr(const struct sk_buff *skb) +{ + return (struct igmpv3_report *)skb_transport_header(skb); +} + +static inline struct igmpv3_query * + igmpv3_query_hdr(const struct sk_buff *skb) +{ + return (struct igmpv3_query *)skb_transport_header(skb); +} + extern int sysctl_igmp_max_memberships; extern int sysctl_igmp_max_msf; -- cgit v1.2.3 From 310afe86af8ddd96a06b75aa61ef1af233f80e89 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 23 Mar 2008 22:06:51 -0700 Subject: [NET]: include/linux/udp.h - remove duplicate include Remove duplicate #include Combine #ifdef __KERNEL__ blocks Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/udp.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/udp.h b/include/linux/udp.h index 1e7b7cb5703b..581ca2c14c52 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -26,15 +26,6 @@ struct udphdr { __sum16 check; }; -#ifdef __KERNEL__ -#include - -static inline struct udphdr *udp_hdr(const struct sk_buff *skb) -{ - return (struct udphdr *)skb_transport_header(skb); -} -#endif - /* UDP socket options */ #define UDP_CORK 1 /* Never send partially complete segments */ #define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ @@ -45,9 +36,14 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb) #define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */ #ifdef __KERNEL__ -#include - #include +#include + +static inline struct udphdr *udp_hdr(const struct sk_buff *skb) +{ + return (struct udphdr *)skb_transport_header(skb); +} + #define UDP_HTABLE_SIZE 128 struct udp_sock { -- cgit v1.2.3 From c8cdaf998df221b01134a051aba38c570105061b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 10 Mar 2008 04:30:37 -0400 Subject: [IPV4,IPV6]: Share cork.rt between IPv4 and IPv6. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 1 - include/net/inet_sock.h | 2 +- net/ipv4/ip_output.c | 14 ++++++-------- net/ipv6/ip6_output.c | 12 ++++++------ 4 files changed, 13 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4aaefc349a4b..2102d8b67c01 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -315,7 +315,6 @@ struct ipv6_pinfo { struct sk_buff *pktoptions; struct { struct ipv6_txoptions *opt; - struct rt6_info *rt; int hop_limit; int tclass; } cork; diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b6db16d2766a..a42cd63d241a 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -136,7 +136,7 @@ struct inet_sock { unsigned int flags; unsigned int fragsize; struct ip_options *opt; - struct rtable *rt; + struct dst_entry *dst; int length; /* Total length of all frames */ __be32 addr; struct flowi fl; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 349fae58c1a3..913266cd9902 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -825,7 +825,7 @@ int ip_append_data(struct sock *sk, inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ? rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path); - inet->cork.rt = rt; + inet->cork.dst = &rt->u.dst; inet->cork.length = 0; sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; @@ -834,7 +834,7 @@ int ip_append_data(struct sock *sk, transhdrlen += exthdrlen; } } else { - rt = inet->cork.rt; + rt = (struct rtable *)inet->cork.dst; if (inet->cork.flags & IPCORK_OPT) opt = inet->cork.opt; @@ -1083,7 +1083,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, if (skb_queue_empty(&sk->sk_write_queue)) return -EINVAL; - rt = inet->cork.rt; + rt = (struct rtable *)inet->cork.dst; if (inet->cork.flags & IPCORK_OPT) opt = inet->cork.opt; @@ -1208,10 +1208,8 @@ static void ip_cork_release(struct inet_sock *inet) inet->cork.flags &= ~IPCORK_OPT; kfree(inet->cork.opt); inet->cork.opt = NULL; - if (inet->cork.rt) { - ip_rt_put(inet->cork.rt); - inet->cork.rt = NULL; - } + dst_release(inet->cork.dst); + inet->cork.dst = NULL; } /* @@ -1224,7 +1222,7 @@ int ip_push_pending_frames(struct sock *sk) struct sk_buff **tail_skb; struct inet_sock *inet = inet_sk(sk); struct ip_options *opt = NULL; - struct rtable *rt = inet->cork.rt; + struct rtable *rt = (struct rtable *)inet->cork.dst; struct iphdr *iph; __be16 df = 0; __u8 ttl; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 98762fde2b65..ed6482667a25 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1115,7 +1115,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, /* need source address above miyazawa*/ } dst_hold(&rt->u.dst); - np->cork.rt = rt; + inet->cork.dst = &rt->u.dst; inet->cork.fl = *fl; np->cork.hop_limit = hlimit; np->cork.tclass = tclass; @@ -1136,7 +1136,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, length += exthdrlen; transhdrlen += exthdrlen; } else { - rt = np->cork.rt; + rt = (struct rt6_info *)inet->cork.dst; fl = &inet->cork.fl; if (inet->cork.flags & IPCORK_OPT) opt = np->cork.opt; @@ -1381,9 +1381,9 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) inet->cork.flags &= ~IPCORK_OPT; kfree(np->cork.opt); np->cork.opt = NULL; - if (np->cork.rt) { - dst_release(&np->cork.rt->u.dst); - np->cork.rt = NULL; + if (inet->cork.dst) { + dst_release(inet->cork.dst); + inet->cork.dst = NULL; inet->cork.flags &= ~IPCORK_ALLFRAG; } memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); @@ -1398,7 +1398,7 @@ int ip6_push_pending_frames(struct sock *sk) struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6hdr *hdr; struct ipv6_txoptions *opt = np->cork.opt; - struct rt6_info *rt = np->cork.rt; + struct rt6_info *rt = (struct rt6_info *)inet->cork.dst; struct flowi *fl = &inet->cork.fl; unsigned char proto = fl->proto; int err = 0; -- cgit v1.2.3 From 4725474584d6aa2f07b3d47442dfbc4f6544f65e Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 10 Mar 2008 04:41:33 -0400 Subject: [IPV6]: Convert cork.hop_limit and cork.tclass into u8 instead of int. Values of those fields are always between 0 and 255 (inclusive), so use u8 and save some memory on 32bit systems. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 2102d8b67c01..9b59e37afad9 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -315,8 +315,8 @@ struct ipv6_pinfo { struct sk_buff *pktoptions; struct { struct ipv6_txoptions *opt; - int hop_limit; - int tclass; + u8 hop_limit; + u8 tclass; } cork; }; -- cgit v1.2.3 From 1d5d236d309ab90fa6aedf712f586b3595721373 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 10 Mar 2008 10:56:55 -0400 Subject: [IPV6]: Use bitfields for hop_limit and mcast_hops. Save some bits for future extensions. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 9b59e37afad9..87ae4e389ce1 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -274,8 +274,29 @@ struct ipv6_pinfo { __be32 flow_label; __u32 frag_size; - __s16 hop_limit; - __s16 mcast_hops; + + /* + * Packed in 16bits. + * Omit one shift by by putting the signed field at MSB. + */ +#if defined(__BIG_ENDIAN_BITFIELD) + __s16 hop_limit:9; + __u16 __unused_1:7; +#else + __u16 __unused_1:7; + __s16 hop_limit:9; +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + /* Packed in 16bits. */ + __s16 mcast_hops:9; + __u16 __unused_2:6, + mc_loop:1; +#else + __u16 mc_loop:1, + __unused_2:6; + __s16 mcast_hops:9; +#endif int mcast_oif; /* pktoption flags */ @@ -298,8 +319,7 @@ struct ipv6_pinfo { } rxopt; /* sockopt flags */ - __u8 mc_loop:1, - recverr:1, + __u8 recverr:1, sndflow:1, pmtudisc:2, ipv6only:1; -- cgit v1.2.3 From 7cbca67c073263c179f605bdbbdc565ab29d801d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 25 Mar 2008 09:37:42 +0900 Subject: [IPV6]: Support Source Address Selection API (RFC5014). Signed-off-by: YOSHIFUJI Hideaki --- include/linux/in6.h | 11 +++++++ include/linux/ipv6.h | 6 +++- include/net/addrconf.h | 1 + include/net/ip6_route.h | 9 ++++-- net/ipv6/addrconf.c | 17 +++++++++-- net/ipv6/fib6_rules.c | 12 +++++++- net/ipv6/ip6_output.c | 4 ++- net/ipv6/ipv6_sockglue.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ndisc.c | 4 ++- net/ipv6/route.c | 11 ++++++- net/ipv6/xfrm6_policy.c | 2 +- net/sctp/ipv6.c | 4 ++- 12 files changed, 146 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index 2a61c82af115..f674000c6c99 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -249,4 +249,15 @@ struct in6_flowlabel_req * IP6T_SO_GET_REVISION_TARGET 69 */ +/* RFC5014: Source address selection */ +#define IPV6_ADDR_PREFERENCES 72 + +#define IPV6_PREFER_SRC_TMP 0x0001 +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +#define IPV6_PREFER_SRC_COA 0x0004 +#define IPV6_PREFER_SRC_HOME 0x0400 +#define IPV6_PREFER_SRC_CGA 0x0008 +#define IPV6_PREFER_SRC_NONCGA 0x0800 + #endif diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 87ae4e389ce1..c9ba0da16ce9 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -322,7 +322,11 @@ struct ipv6_pinfo { __u8 recverr:1, sndflow:1, pmtudisc:2, - ipv6only:1; + ipv6only:1, + srcprefs:3; /* 001: prefer temporary address + * 010: prefer public address + * 100: prefer care-of address + */ __u8 tclass; __u32 dst_cookie; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index edcb4bbaab7d..c9276c72764d 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -78,6 +78,7 @@ extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, + unsigned int srcprefs, struct in6_addr *saddr); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 5c3b67c86aef..3ae6799c2b14 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -30,9 +30,12 @@ struct route_info { #include #include -#define RT6_LOOKUP_F_IFACE 0x1 -#define RT6_LOOKUP_F_REACHABLE 0x2 -#define RT6_LOOKUP_F_HAS_SADDR 0x4 +#define RT6_LOOKUP_F_IFACE 0x00000001 +#define RT6_LOOKUP_F_REACHABLE 0x00000002 +#define RT6_LOOKUP_F_HAS_SADDR 0x00000004 +#define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 +#define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 +#define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 extern struct rt6_info *ip6_null_entry; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 787e90af166c..89954885dee1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -909,6 +909,7 @@ struct ipv6_saddr_dst { int ifindex; int scope; int label; + unsigned int prefs; }; static inline int ipv6_saddr_preferred(int type) @@ -984,9 +985,12 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, break; #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: + { /* Rule 4: Prefer home address */ - ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS); + int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA); + ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; break; + } #endif case IPV6_SADDR_RULE_OIF: /* Rule 5: Prefer outgoing interface */ @@ -1000,11 +1004,16 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, break; #ifdef CONFIG_IPV6_PRIVACY case IPV6_SADDR_RULE_PRIVACY: + { /* Rule 7: Prefer public address * Note: prefer temprary address if use_tempaddr >= 2 */ - ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2); + int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? + !!(dst->prefs & IPV6_PREFER_SRC_TMP) : + score->ifa->idev->cnf.use_tempaddr >= 2; + ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; break; + } #endif case IPV6_SADDR_RULE_ORCHID: /* Rule 8-: Prefer ORCHID vs ORCHID or @@ -1030,7 +1039,8 @@ out: } int ipv6_dev_get_saddr(struct net_device *dst_dev, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) { struct ipv6_saddr_score scores[2], *score = &scores[0], *hiscore = &scores[1]; @@ -1044,6 +1054,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, dst.ifindex = dst_dev ? dst_dev->ifindex : 0; dst.scope = __ipv6_addr_src_scope(dst_type); dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); + dst.prefs = prefs; hiscore->rule = -1; hiscore->ifa = NULL; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 55137408f054..e7a7fe26cebf 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -84,8 +84,18 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, if ((rule->flags & FIB_RULE_FIND_SADDR) && r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { struct in6_addr saddr; + unsigned int srcprefs = 0; + + if (flags & RT6_LOOKUP_F_SRCPREF_TMP) + srcprefs |= IPV6_PREFER_SRC_TMP; + if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC) + srcprefs |= IPV6_PREFER_SRC_PUBLIC; + if (flags & RT6_LOOKUP_F_SRCPREF_COA) + srcprefs |= IPV6_PREFER_SRC_COA; + if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, - &flp->fl6_dst, &saddr)) + &flp->fl6_dst, srcprefs, + &saddr)) goto again; if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2a4f08c8a02d..d34aa61353bb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -920,7 +920,9 @@ static int ip6_dst_lookup_tail(struct sock *sk, if (ipv6_addr_any(&fl->fl6_src)) { err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev, - &fl->fl6_dst, &fl->fl6_src); + &fl->fl6_dst, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl->fl6_src); if (err) goto out_err_release; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 8e29fb1d1df6..dc6695cc5767 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -617,7 +617,67 @@ done: retv = xfrm_user_policy(sk, optname, optval, optlen); break; + case IPV6_ADDR_PREFERENCES: + { + unsigned int pref = 0; + unsigned int prefmask = ~0; + + retv = -EINVAL; + + /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ + switch (val & (IPV6_PREFER_SRC_PUBLIC| + IPV6_PREFER_SRC_TMP| + IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { + case IPV6_PREFER_SRC_PUBLIC: + pref |= IPV6_PREFER_SRC_PUBLIC; + break; + case IPV6_PREFER_SRC_TMP: + pref |= IPV6_PREFER_SRC_TMP; + break; + case IPV6_PREFER_SRC_PUBTMP_DEFAULT: + break; + case 0: + goto pref_skip_pubtmp; + default: + goto e_inval; + } + + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC| + IPV6_PREFER_SRC_TMP); +pref_skip_pubtmp: + + /* check HOME/COA conflicts */ + switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) { + case IPV6_PREFER_SRC_HOME: + break; + case IPV6_PREFER_SRC_COA: + pref |= IPV6_PREFER_SRC_COA; + case 0: + goto pref_skip_coa; + default: + goto e_inval; + } + + prefmask &= ~IPV6_PREFER_SRC_COA; +pref_skip_coa: + + /* check CGA/NONCGA conflicts */ + switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { + case IPV6_PREFER_SRC_CGA: + case IPV6_PREFER_SRC_NONCGA: + case 0: + break; + default: + goto e_inval; + } + + np->srcprefs = (np->srcprefs & prefmask) | pref; + retv = 0; + + break; + } } + release_sock(sk); return retv; @@ -932,6 +992,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->sndflow; break; + case IPV6_ADDR_PREFERENCES: + val = 0; + + if (np->srcprefs & IPV6_PREFER_SRC_TMP) + val |= IPV6_PREFER_SRC_TMP; + else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC) + val |= IPV6_PREFER_SRC_PUBLIC; + else { + /* XXX: should we return system default? */ + val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; + } + + if (np->srcprefs & IPV6_PREFER_SRC_COA) + val |= IPV6_PREFER_SRC_COA; + else + val |= IPV6_PREFER_SRC_HOME; + break; + default: return -ENOPROTOOPT; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e7d8e74704c1..3f68a6eae7b2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -546,7 +546,9 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, override = 0; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev, daddr, + inet6_sk(dev->nd_net->ipv6.ndisc_sk)->srcprefs, + &tmpaddr)) return; src_addr = &tmpaddr; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aa3f08718e44..06faa46920e1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -782,6 +782,15 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, if (!ipv6_addr_any(&fl->fl6_src)) flags |= RT6_LOOKUP_F_HAS_SADDR; + else if (sk) { + unsigned int prefs = inet6_sk(sk)->srcprefs; + if (prefs & IPV6_PREFER_SRC_TMP) + flags |= RT6_LOOKUP_F_SRCPREF_TMP; + if (prefs & IPV6_PREFER_SRC_PUBLIC) + flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC; + if (prefs & IPV6_PREFER_SRC_COA) + flags |= RT6_LOOKUP_F_SRCPREF_COA; + } return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); } @@ -2162,7 +2171,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, else if (dst) { struct in6_addr saddr_buf; if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, - dst, &saddr_buf) == 0) + dst, 0, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index e96dafdc7032..d92d1fceb8cf 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -58,7 +58,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) return -EHOSTUNREACH; ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev, - (struct in6_addr *)&daddr->a6, + (struct in6_addr *)&daddr->a6, 0, (struct in6_addr *)&saddr->a6); dst_release(dst); return 0; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 46c5b3c5cb99..dc71d0d83753 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -316,7 +316,9 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, if (!asoc) { ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, &saddr->v6.sin6_addr); + &daddr->v6.sin6_addr, + inet6_sk(asoc->base.sk)->srcprefs, + &saddr->v6.sin6_addr); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; -- cgit v1.2.3 From c346dca10840a874240c78efe3f39acf4312a1f2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 25 Mar 2008 21:47:49 +0900 Subject: [NET] NETNS: Omit net_device->nd_net without CONFIG_NET_NS. Introduce per-net_device inlines: dev_net(), dev_net_set(). Without CONFIG_NET_NS, no namespace other than &init_net exists. Let's explicitly define them to help compiler optimizations. Signed-off-by: YOSHIFUJI Hideaki --- arch/ia64/hp/sim/simeth.c | 2 +- drivers/block/aoe/aoenet.c | 2 +- drivers/net/bonding/bond_3ad.c | 2 +- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/bonding/bond_main.c | 6 ++--- drivers/net/hamradio/bpqether.c | 4 ++-- drivers/net/loopback.c | 2 +- drivers/net/macvlan.c | 2 +- drivers/net/pppoe.c | 6 ++--- drivers/net/veth.c | 2 +- drivers/net/via-velocity.c | 2 +- drivers/net/wan/dlci.c | 2 +- drivers/net/wan/hdlc.c | 4 ++-- drivers/net/wan/lapbether.c | 4 ++-- drivers/net/wan/syncppp.c | 2 +- drivers/s390/net/qeth_l3_main.c | 2 +- include/linux/inetdevice.h | 6 ++--- include/linux/netdevice.h | 25 ++++++++++++++++++++- net/8021q/vlan.c | 2 +- net/8021q/vlan_dev.c | 2 +- net/appletalk/aarp.c | 4 ++-- net/appletalk/ddp.c | 6 ++--- net/atm/clip.c | 2 +- net/atm/mpc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/ax25/ax25_in.c | 2 +- net/bridge/br_notify.c | 2 +- net/bridge/br_stp_bpdu.c | 2 +- net/can/af_can.c | 4 ++-- net/can/bcm.c | 2 +- net/can/raw.c | 2 +- net/core/dev.c | 22 +++++++++---------- net/core/dst.c | 2 +- net/core/fib_rules.c | 2 +- net/core/neighbour.c | 12 +++++----- net/core/pktgen.c | 2 +- net/core/rtnetlink.c | 4 ++-- net/decnet/af_decnet.c | 2 +- net/decnet/dn_route.c | 2 +- net/econet/af_econet.c | 4 ++-- net/ipv4/arp.c | 14 ++++++------ net/ipv4/devinet.c | 10 ++++----- net/ipv4/fib_frontend.c | 12 +++++----- net/ipv4/icmp.c | 8 +++---- net/ipv4/igmp.c | 16 +++++++------- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_input.c | 6 ++--- net/ipv4/ip_options.c | 2 +- net/ipv4/ipconfig.c | 4 ++-- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_MASQUERADE.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 28 +++++++++++------------ net/ipv4/tcp_ipv4.c | 6 ++--- net/ipv4/udp.c | 4 ++-- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 44 ++++++++++++++++++------------------- net/ipv6/icmp.c | 4 ++-- net/ipv6/ip6_output.c | 2 +- net/ipv6/mcast.c | 6 ++--- net/ipv6/ndisc.c | 24 ++++++++++---------- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/proc.c | 2 +- net/ipv6/raw.c | 4 ++-- net/ipv6/reassembly.c | 2 +- net/ipv6/route.c | 40 ++++++++++++++++----------------- net/ipv6/tcp_ipv6.c | 10 ++++----- net/ipv6/udp.c | 4 ++-- net/ipv6/xfrm6_policy.c | 2 +- net/ipx/af_ipx.c | 4 ++-- net/irda/irlap_frame.c | 2 +- net/llc/llc_input.c | 2 +- net/netfilter/core.c | 2 +- net/netfilter/nfnetlink_queue.c | 2 +- net/netlabel/netlabel_unlabeled.c | 2 +- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 8 +++---- net/rose/af_rose.c | 2 +- net/sctp/protocol.c | 2 +- net/tipc/eth_media.c | 4 ++-- net/wireless/wext.c | 2 +- net/x25/af_x25.c | 2 +- net/x25/x25_dev.c | 2 +- net/xfrm/xfrm_policy.c | 4 ++-- security/selinux/netif.c | 2 +- 87 files changed, 251 insertions(+), 228 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 969fe9f443c4..3d47839a0c48 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -294,7 +294,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) return NOTIFY_DONE; } - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 8460ef736d56..18d243c73eee 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -115,7 +115,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct aoe_hdr *h; u32 n; - if (ifp->nd_net != &init_net) + if (dev_net(ifp) != &init_net) goto exit; skb = skb_share_check(skb, GFP_ATOMIC); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index cb3c6faa7888..457d81f73e39 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2429,7 +2429,7 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac struct slave *slave = NULL; int ret = NET_RX_DROP; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; if (!(dev->flags & IFF_MASTER)) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b57bc9467dbe..b986dacf5d33 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -345,7 +345,7 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; - if (bond_dev->nd_net != &init_net) + if (dev_net(bond_dev) != &init_net) goto out; if (!(bond_dev->flags & IFF_MASTER)) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5fc9d8d58ece..ac688fcb27d7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2629,7 +2629,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; __be32 sip, tip; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) @@ -3470,7 +3470,7 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v { struct net_device *event_dev = (struct net_device *)ptr; - if (event_dev->nd_net != &init_net) + if (dev_net(event_dev) != &init_net) return NOTIFY_DONE; dprintk("event_dev: %s, event: %lx\n", @@ -3508,7 +3508,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, struct bonding *bond, *bond_next; struct vlan_entry *vlan, *vlan_next; - if (ifa->ifa_dev->dev->nd_net != &init_net) + if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 5ddf8b0c34f9..5f4b4c6c9f76 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -172,7 +172,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -553,7 +553,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f2a6e7132241..41b774baac4d 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -258,7 +258,7 @@ static __net_init int loopback_net_init(struct net *net) if (!dev) goto out; - dev->nd_net = net; + dev_net_set(dev, net); err = register_netdev(dev); if (err) goto out_free_netdev; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f651a816b280..2056cfc624dc 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -402,7 +402,7 @@ static int macvlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK])); + lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); if (lowerdev == NULL) return -ENODEV; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ac0ac98b19cd..4fad4ddb3504 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -301,7 +301,7 @@ static int pppoe_device_event(struct notifier_block *this, { struct net_device *dev = (struct net_device *) ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Only look at sockets that are using this specific device. */ @@ -392,7 +392,7 @@ static int pppoe_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) @@ -424,7 +424,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct pppoe_hdr *ph; struct pppox_sock *po; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto abort; if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index e2ad98bee6e7..31cd817f33f9 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -375,7 +375,7 @@ static int veth_newlink(struct net_device *dev, else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); - peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp); if (IS_ERR(peer)) return PTR_ERR(peer); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 1525e8a89844..ed1afaf683a4 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3464,7 +3464,7 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi struct velocity_info *vptr; unsigned long flags; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; spin_lock_irqsave(&velocity_dev_list_lock, flags); diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 96b232446c0b..b14242768fad 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -517,7 +517,7 @@ static int dlci_dev_event(struct notifier_block *unused, { struct net_device *dev = (struct net_device *) ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_UNREGISTER) { diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 39951d0c34d6..9a83c9d5b8cf 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -68,7 +68,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, { struct hdlc_device *hdlc = dev_to_hdlc(dev); - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } @@ -105,7 +105,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->get_stats != hdlc_get_stats) diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index fb37b8095231..629c909e05f9 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -91,7 +91,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe int len, err; struct lapbethdev *lapbeth; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -393,7 +393,7 @@ static int lapbeth_device_event(struct notifier_block *this, struct lapbethdev *lapbeth; struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 61e24b7a45a3..29b4b94e4947 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -1444,7 +1444,7 @@ static void sppp_print_bytes (u_char *p, u16 len) static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a856cb47fc78..21c439046b3c 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3250,7 +3250,7 @@ static int qeth_l3_ip_event(struct notifier_block *this, struct qeth_ipaddr *addr; struct qeth_card *card; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; QETH_DBF_TEXT(trace, 3, "ipevent"); diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index da05ab47ff2f..7009b0cdd06f 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -70,13 +70,13 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) ipv4_devconf_set((in_dev), NET_IPV4_CONF_ ## attr, (val)) #define IN_DEV_ANDCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr) && \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) && \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_ORCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr) || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) || \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_MAXCONF(in_dev, attr) \ - (max(IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr), \ + (max(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr), \ IN_DEV_CONF_GET((in_dev), attr))) #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ced61f87660e..d146be40f46c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -708,8 +708,10 @@ struct net_device void (*poll_controller)(struct net_device *dev); #endif +#ifdef CONFIG_NET_NS /* Network namespace this network device is inside */ struct net *nd_net; +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -737,6 +739,27 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) +/* + * Net namespace inlines + */ +static inline +struct net *dev_net(const struct net_device *dev) +{ +#ifdef CONFIG_NET_NS + return dev->nd_net; +#else + return &init_net; +#endif +} + +static inline +void dev_net_set(struct net_device *dev, const struct net *net) +{ +#ifdef CONFIG_NET_NS + dev->nd_dev = net; +#endif +} + /** * netdev_priv - access network device private data * @dev: network device @@ -813,7 +836,7 @@ static inline struct net_device *next_net_device(struct net_device *dev) struct list_head *lh; struct net *net; - net = dev->nd_net; + net = dev_net(dev); lh = dev->dev_list.next; return lh == &net->dev_base_head ? NULL : net_device_entry(lh); } diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index dbc81b965096..c35dc230365c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -382,7 +382,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, int i, flgs; struct net_device *vlandev; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!grp) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 1e5c9904571d..e536162b1ebc 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -153,7 +153,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct net_device_stats *stats; unsigned short vlan_TCI; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto err_free; skb = skb_share_check(skb, GFP_ATOMIC); diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 61166f66479f..25aa37ce9430 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -333,7 +333,7 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; int ct; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) { @@ -716,7 +716,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_addr sa, *ma, da; struct atalk_iface *ifa; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out0; /* We only do Ethernet SNAP AARP. */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 3be55c8ca4ef..44cd42f7786b 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -648,7 +648,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) @@ -1405,7 +1405,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, int origlen; __u16 len_hops; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto freeit; /* Don't mangle buffer if shared */ @@ -1493,7 +1493,7 @@ freeit: static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto freeit; /* Expand any short form frames */ diff --git a/net/atm/clip.c b/net/atm/clip.c index e82da6746723..6f8223ebf551 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -612,7 +612,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = arg; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_UNREGISTER) { diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 9c7f712fc7e9..9db332e7a6c0 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -964,7 +964,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo dev = (struct net_device *)dev_ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->name == NULL || strncmp(dev->name, "lec", 3)) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 48bfcc741f25..ee9dd83e7561 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -116,7 +116,7 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Reject non AX.25 devices */ diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index d1be080dcb25..33790a8efbc8 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -451,7 +451,7 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, skb->sk = NULL; /* Initially we don't know who it's for */ skb->destructor = NULL; /* Who initializes this, dammit?! */ - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 07ac3ae68d8f..00644a544e3c 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -37,7 +37,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge_port *p = dev->br_port; struct net_bridge *br; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* not a port of a bridge */ diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 0edbd2a1c3f3..8deab645ef75 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -142,7 +142,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, struct net_bridge *br; const unsigned char *buf; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto err; if (!p) diff --git a/net/can/af_can.c b/net/can/af_can.c index 36b9f22ed83a..2759b76f731c 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -599,7 +599,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, struct dev_rcv_lists *d; int matches; - if (dev->type != ARPHRD_CAN || dev->nd_net != &init_net) { + if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } @@ -710,7 +710,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, struct net_device *dev = (struct net_device *)data; struct dev_rcv_lists *d; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/bcm.c b/net/can/bcm.c index bd4282dae754..e9f99b2c6bc9 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1285,7 +1285,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, struct bcm_op *op; int notify_enodev = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/raw.c b/net/can/raw.c index 94cd7f27c444..ead50c7c0d40 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -210,7 +210,7 @@ static int raw_notifier(struct notifier_block *nb, struct raw_sock *ro = container_of(nb, struct raw_sock, notifier); struct sock *sk = &ro->sk; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/core/dev.c b/net/core/dev.c index aebd08606040..812534828914 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -216,7 +216,7 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) /* Device list insertion */ static int list_netdevice(struct net_device *dev) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); ASSERT_RTNL(); @@ -852,8 +852,8 @@ int dev_alloc_name(struct net_device *dev, const char *name) struct net *net; int ret; - BUG_ON(!dev->nd_net); - net = dev->nd_net; + BUG_ON(!dev_net(dev)); + net = dev_net(dev); ret = __dev_alloc_name(net, name, buf); if (ret >= 0) strlcpy(dev->name, buf, IFNAMSIZ); @@ -877,9 +877,9 @@ int dev_change_name(struct net_device *dev, char *newname) struct net *net; ASSERT_RTNL(); - BUG_ON(!dev->nd_net); + BUG_ON(!dev_net(dev)); - net = dev->nd_net; + net = dev_net(dev); if (dev->flags & IFF_UP) return -EBUSY; @@ -2615,7 +2615,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_puts(seq, "Type Device Function\n"); - else if (pt->dev == NULL || pt->dev->nd_net == seq_file_net(seq)) { + else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) { if (pt->type == htons(ETH_P_ALL)) seq_puts(seq, "ALL "); else @@ -3689,8 +3689,8 @@ int register_netdevice(struct net_device *dev) /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); - BUG_ON(!dev->nd_net); - net = dev->nd_net; + BUG_ON(!dev_net(dev)); + net = dev_net(dev); spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->_xmit_lock); @@ -4011,7 +4011,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; - dev->nd_net = &init_net; + dev_net_set(dev, &init_net); if (sizeof_priv) { dev->priv = ((char *)dev + @@ -4136,7 +4136,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Get out if there is nothing todo */ err = 0; - if (dev->nd_net == net) + if (dev_net(dev) == net) goto out; /* Pick the destination device name, and ensure @@ -4187,7 +4187,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char dev_addr_discard(dev); /* Actually switch the network namespace */ - dev->nd_net = net; + dev_net_set(dev, net); /* Assign the new device name */ if (destname != dev->name) diff --git a/net/core/dst.c b/net/core/dst.c index 3a01a819ba47..694cd2a3f6d2 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -279,7 +279,7 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = dst->dev->nd_net->loopback_dev; + dst->dev = dev_net(dst->dev)->loopback_dev; dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 42ccaf5b8509..942be93a2eb0 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -618,7 +618,7 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct fib_rules_ops *ops; ASSERT_RTNL(); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 23c0a10c0c37..c978bd1cd659 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -388,7 +388,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, hash_val = tbl->hash(pkey, NULL); for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len) && - (net == n->dev->nd_net)) { + dev_net(n->dev) == net) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); break; @@ -1298,7 +1298,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_parms *p, *ref; struct net *net; - net = dev->nd_net; + net = dev_net(dev); ref = lookup_neigh_params(tbl, net, 0); if (!ref) return NULL; @@ -2050,7 +2050,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, s_idx = 0; for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { int lidx; - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) continue; lidx = idx++; if (lidx < s_idx) @@ -2155,7 +2155,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq) n = tbl->hash_buckets[bucket]; while (n) { - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) goto next; if (state->neigh_sub_iter) { loff_t fakep = 0; @@ -2198,7 +2198,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, while (1) { while (n) { - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) goto next; if (state->neigh_sub_iter) { void *v = state->neigh_sub_iter(state, n, pos); @@ -2482,7 +2482,7 @@ static inline size_t neigh_nlmsg_size(void) static void __neigh_notify(struct neighbour *n, int type, int flags) { - struct net *net = n->dev->nd_net; + struct net *net = dev_net(n->dev); struct sk_buff *skb; int err = -ENOBUFS; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 20e63b302ba6..a803b442234c 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1874,7 +1874,7 @@ static int pktgen_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* It is OK that we do not hold the group lock right now, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2bd9c5f7627d..09250a0800f6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -972,7 +972,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, goto err_free; } - dev->nd_net = net; + dev_net_set(dev, net); dev->rtnl_link_ops = ops; if (tb[IFLA_MTU]) @@ -1198,7 +1198,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sk_buff *skb; int err = -ENOBUFS; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 23fd95a7ad15..3554fb3d251c 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2089,7 +2089,7 @@ static int dn_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch(event) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 9dc0abb50eaf..0a46b6c10e51 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -580,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto dump_it; if (dn == NULL) diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index bc0f6252613f..68d154480043 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1064,7 +1064,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet struct sock *sk; struct ec_device *edev = dev->ec_ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if (skb->pkt_type == PACKET_OTHERHOST) @@ -1121,7 +1121,7 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void struct net_device *dev = (struct net_device *)data; struct ec_device *edev; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch (msg) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 832473e30b36..3ce2e137e7bc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -242,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh) return -EINVAL; } - neigh->type = inet_addr_type(dev->nd_net, addr); + neigh->type = inet_addr_type(dev_net(dev), addr); parms = in_dev->arp_parms; __neigh_parms_put(neigh->parms); @@ -341,14 +341,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { default: case 0: /* By default announce any local IP */ - if (skb && inet_addr_type(dev->nd_net, ip_hdr(skb)->saddr) == RTN_LOCAL) + if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL) saddr = ip_hdr(skb)->saddr; break; case 1: /* Restrict announcements of saddr in same subnet */ if (!skb) break; saddr = ip_hdr(skb)->saddr; - if (inet_addr_type(dev->nd_net, saddr) == RTN_LOCAL) { + if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) { /* saddr should be known to target */ if (inet_addr_onlink(in_dev, target, saddr)) break; @@ -424,7 +424,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) int flag = 0; /*unsigned long now; */ - if (ip_route_output_key(dev->nd_net, &rt, &fl) < 0) + if (ip_route_output_key(dev_net(dev), &rt, &fl) < 0) return 1; if (rt->u.dst.dev != dev) { NET_INC_STATS_BH(LINUX_MIB_ARPFILTER); @@ -477,7 +477,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) paddr = skb->rtable->rt_gateway; - if (arp_set_predefined(inet_addr_type(dev->nd_net, paddr), haddr, paddr, dev)) + if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); @@ -709,7 +709,7 @@ static int arp_process(struct sk_buff *skb) u16 dev_type = dev->type; int addr_type; struct neighbour *n; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. @@ -858,7 +858,7 @@ static int arp_process(struct sk_buff *skb) n = __neigh_lookup(&arp_tbl, &sip, dev, 0); - if (IPV4_DEVCONF_ALL(dev->nd_net, ARP_ACCEPT)) { + if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) { /* Unsolicited ARP is not accepted by default. It is possible, that this option should be enabled for some devices (strip is candidate) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 4a10dbbbe0a1..823c724a8593 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -165,7 +165,7 @@ static struct in_device *inetdev_init(struct net_device *dev) if (!in_dev) goto out; INIT_RCU_HEAD(&in_dev->rcu_head); - memcpy(&in_dev->cnf, dev->nd_net->ipv4.devconf_dflt, + memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; @@ -872,7 +872,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) { __be32 addr = 0; struct in_device *in_dev; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -974,7 +974,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev, if (scope != RT_SCOPE_LINK) return confirm_addr_indev(in_dev, dst, local, scope); - net = in_dev->dev->nd_net; + net = dev_net(in_dev->dev); read_lock(&dev_base_lock); rcu_read_lock(); for_each_netdev(net, dev) { @@ -1203,7 +1203,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, int err = -ENOBUFS; struct net *net; - net = ifa->ifa_dev->dev->nd_net; + net = dev_net(ifa->ifa_dev->dev); skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); if (skb == NULL) goto errout; @@ -1517,7 +1517,7 @@ static void devinet_sysctl_register(struct in_device *idev) { neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL, NULL); - __devinet_sysctl_register(idev->dev->nd_net, idev->dev->name, + __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, idev->dev->ifindex, &idev->cnf); } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 86ff2711fc95..0e4b34b07cb5 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -257,7 +257,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, if (in_dev == NULL) goto e_inval; - net = dev->nd_net; + net = dev_net(dev); if (fib_lookup(net, &fl, &res)) goto last_resort; if (res.type != RTN_UNICAST) @@ -674,7 +674,7 @@ out: static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) { - struct net *net = ifa->ifa_dev->dev->nd_net; + struct net *net = dev_net(ifa->ifa_dev->dev); struct fib_table *tb; struct fib_config cfg = { .fc_protocol = RTPROT_KERNEL, @@ -801,15 +801,15 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); /* Check, that this local address finally disappeared. */ - if (inet_addr_type(dev->nd_net, ifa->ifa_local) != RTN_LOCAL) { + if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { /* And the last, but not the least thing. We must flush stray FIB entries. First of all, we scan fib_info list searching for stray nexthop entries, then ignite fib_flush. */ - if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local)) - fib_flush(dev->nd_net); + if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local)) + fib_flush(dev_net(dev)); } } #undef LOCAL_OK @@ -899,7 +899,7 @@ static void nl_fib_lookup_exit(struct net *net) static void fib_disable_ip(struct net_device *dev, int force) { if (fib_sync_down_dev(dev, force)) - fib_flush(dev->nd_net); + fib_flush(dev_net(dev)); rt_cache_flush(0); arp_ifdown(dev); } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index ff9a8e643fcc..f38f093ef751 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -351,7 +351,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, struct sock *sk; struct sk_buff *skb; - sk = icmp_sk(rt->u.dst.dev->nd_net); + sk = icmp_sk(dev_net(rt->u.dst.dev)); if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, @@ -382,7 +382,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; struct rtable *rt = skb->rtable; - struct net *net = rt->u.dst.dev->nd_net; + struct net *net = dev_net(rt->u.dst.dev); struct sock *sk = icmp_sk(net); struct inet_sock *inet = inet_sk(sk); __be32 daddr; @@ -447,7 +447,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (!rt) goto out; - net = rt->u.dst.dev->nd_net; + net = dev_net(rt->u.dst.dev); sk = icmp_sk(net); /* @@ -677,7 +677,7 @@ static void icmp_unreach(struct sk_buff *skb) u32 info = 0; struct net *net; - net = skb->dst->dev->nd_net; + net = dev_net(skb->dst->dev); /* * Incomplete header ? diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6a4ee8da6994..682f632bfb77 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -130,12 +130,12 @@ */ #define IGMP_V1_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 1 || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \ ((in_dev)->mr_v1_seen && \ time_before(jiffies, (in_dev)->mr_v1_seen))) #define IGMP_V2_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 2 || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \ ((in_dev)->mr_v2_seen && \ time_before(jiffies, (in_dev)->mr_v2_seen))) @@ -1198,7 +1198,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (im=in_dev->mc_list; im; im=im->next) { @@ -1280,7 +1280,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { @@ -1310,7 +1310,7 @@ void ip_mc_down(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (i=in_dev->mc_list; i; i=i->next) @@ -1333,7 +1333,7 @@ void ip_mc_init_dev(struct in_device *in_dev) { ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; in_dev->mc_tomb = NULL; @@ -1359,7 +1359,7 @@ void ip_mc_up(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); @@ -1378,7 +1378,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; /* Deactivate timers */ diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 8b448c4b9080..fcb60e76b234 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -571,7 +571,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); - net = skb->dev ? skb->dev->nd_net : skb->dst->dev->nd_net; + net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); /* Start by cleaning up the memory. */ if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh) ip_evictor(net); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f9ee84420cb3..50972b397a9a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1190,7 +1190,7 @@ static int ipgre_close(struct net_device *dev) struct ip_tunnel *t = netdev_priv(dev); if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { struct in_device *in_dev; - in_dev = inetdev_by_index(dev->nd_net, t->mlink); + in_dev = inetdev_by_index(dev_net(dev), t->mlink); if (in_dev) { ip_mc_dec_group(in_dev, t->parms.iph.daddr); in_dev_put(in_dev); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2aeea5d15425..26685c83a146 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -172,7 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb) if (sk && inet_sk(sk)->num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && - sk->sk_net == dev->nd_net) { + sk->sk_net == dev_net(dev)) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); @@ -199,7 +199,7 @@ int ip_call_ra_chain(struct sk_buff *skb) static int ip_local_deliver_finish(struct sk_buff *skb) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); __skb_pull(skb, ip_hdrlen(skb)); @@ -291,7 +291,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) opt = &(IPCB(skb)->opt); opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - if (ip_options_compile(dev->nd_net, opt, skb)) { + if (ip_options_compile(dev_net(dev), opt, skb)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 87cc1222c600..d107543d3f81 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -145,7 +145,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) __be32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(skb->dst->dev->nd_net, addr) != RTN_LOCAL) { + if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 96138b128de8..08e8fb60d315 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -434,7 +434,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -854,7 +854,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str struct ic_device *d; int len, ext_len; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* Perform verifications before taking the lock. */ diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7d63d74ef62a..e54bc1364473 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1089,7 +1089,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v struct vif_device *v; int ct; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_UNREGISTER) diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index fe05da41d6ba..500998a2dec1 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -481,7 +481,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index c6817b18366a..84c26dd27d81 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -120,7 +120,7 @@ static int masq_device_event(struct notifier_block *this, { const struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 3f68a937b602..8756d502a47f 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -168,7 +168,7 @@ static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) if (hlist_empty(head)) goto out; - net = skb->dev->nd_net; + net = dev_net(skb->dev); sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); @@ -276,7 +276,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); if (raw_sk != NULL) { iph = (struct iphdr *)skb->data; - net = skb->dev->nd_net; + net = dev_net(skb->dev); while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, iph->daddr, iph->saddr, diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2941ef21f203..7768d718e199 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -284,7 +284,7 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) rcu_read_lock_bh(); r = rcu_dereference(rt_hash_table[st->bucket].chain); while (r) { - if (r->u.dst.dev->nd_net == st->p.net && + if (dev_net(r->u.dst.dev) == st->p.net && r->rt_genid == st->genid) return r; r = rcu_dereference(r->u.dst.rt_next); @@ -312,7 +312,7 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r) { while ((r = __rt_cache_get_next(st, r)) != NULL) { - if (r->u.dst.dev->nd_net != st->p.net) + if (dev_net(r->u.dst.dev) != st->p.net) continue; if (r->rt_genid == st->genid) break; @@ -680,7 +680,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) static inline int compare_netns(struct rtable *rt1, struct rtable *rt2) { - return rt1->u.dst.dev->nd_net == rt2->u.dst.dev->nd_net; + return dev_net(rt1->u.dst.dev) == dev_net(rt2->u.dst.dev); } /* @@ -1164,7 +1164,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, if (!in_dev) return; - net = dev->nd_net; + net = dev_net(dev); if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || ipv4_is_zeronet(new_gw)) @@ -1195,7 +1195,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rth->fl.oif != ikeys[k] || rth->fl.iif != 0 || rth->rt_genid != atomic_read(&rt_genid) || - rth->u.dst.dev->nd_net != net) { + dev_net(rth->u.dst.dev) != net) { rthp = &rth->u.dst.rt_next; continue; } @@ -1454,7 +1454,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, rth->rt_src == iph->saddr && rth->fl.iif == 0 && !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { unsigned short mtu = new_mtu; @@ -1530,9 +1530,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != dev->nd_net->loopback_dev && idev && idev->dev == dev) { + if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) { struct in_device *loopback_idev = - in_dev_get(dev->nd_net->loopback_dev); + in_dev_get(dev_net(dev)->loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1576,7 +1576,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) if (rt->fl.iif == 0) src = rt->rt_src; - else if (fib_lookup(rt->u.dst.dev->nd_net, &rt->fl, &res) == 0) { + else if (fib_lookup(dev_net(rt->u.dst.dev), &rt->fl, &res) == 0) { src = FIB_RES_PREFSRC(res); fib_res_put(&res); } else @@ -1900,7 +1900,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, __be32 spec_dst; int err = -EINVAL; int free_res = 0; - struct net * net = dev->nd_net; + struct net * net = dev_net(dev); /* IP on this device is disabled. */ @@ -2071,7 +2071,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, int iif = dev->ifindex; struct net *net; - net = dev->nd_net; + net = dev_net(dev); tos &= IPTOS_RT_MASK; hash = rt_hash(daddr, saddr, iif); @@ -2084,7 +2084,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.oif == 0 && rth->fl.mark == skb->mark && rth->fl.fl4_tos == tos && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); @@ -2486,7 +2486,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, rth->fl.mark == flp->mark && !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(out_hit); @@ -2795,7 +2795,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock_bh(); for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.dst.rt_next), idx++) { - if (rt->u.dst.dev->nd_net != net || idx < s_idx) + if (dev_net(rt->u.dst.dev) != net || idx < s_idx) continue; if (rt->rt_genid != atomic_read(&rt_genid)) continue; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 649d00a50cb1..28bece6f281b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -353,7 +353,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) return; } - sk = inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->daddr, th->dest, + sk = inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest, iph->saddr, th->source, inet_iif(skb)); if (!sk) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); @@ -1644,7 +1644,7 @@ int tcp_v4_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = iph->tos; TCP_SKB_CB(skb)->sacked = 0; - sk = __inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->saddr, + sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->saddr, th->source, iph->daddr, th->dest, inet_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1718,7 +1718,7 @@ do_time_wait: } switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { case TCP_TW_SYN: { - struct sock *sk2 = inet_lookup_listener(skb->dev->nd_net, + struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest, inet_iif(skb)); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b37581dfd029..e2cd93481359 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -357,7 +357,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) int harderr; int err; - sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, + sk = __udp4_lib_lookup(dev_net(skb->dev), iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex, udptable); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); @@ -1181,7 +1181,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, + sk = __udp4_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr, uh->dest, inet_iif(skb), udptable); if (sk != NULL) { diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 10ed70491434..c63de0a72aba 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -221,7 +221,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { struct in_device *loopback_idev = - in_dev_get(dev->nd_net->loopback_dev); + in_dev_get(dev_net(dev)->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 89954885dee1..d1de9ec74261 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -335,7 +335,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) rwlock_init(&ndev->lock); ndev->dev = dev; - memcpy(&ndev->cnf, dev->nd_net->ipv6.devconf_dflt, sizeof(ndev->cnf)); + memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); ndev->cnf.mtu6 = dev->mtu; ndev->cnf.sysctl = NULL; ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); @@ -561,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, write_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ - if (ipv6_chk_same_addr(idev->dev->nd_net, addr, idev->dev)) { + if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { ADBG(("ipv6_add_addr: already assigned\n")); err = -EEXIST; goto out; @@ -751,7 +751,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { struct in6_addr prefix; struct rt6_info *rt; - struct net *net = ifp->idev->dev->nd_net; + struct net *net = dev_net(ifp->idev->dev); ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); @@ -1044,7 +1044,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, { struct ipv6_saddr_score scores[2], *score = &scores[0], *hiscore = &scores[1]; - struct net *net = dst_dev->nd_net; + struct net *net = dev_net(dst_dev); struct ipv6_saddr_dst dst; struct net_device *dev; int dst_type; @@ -1217,7 +1217,7 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { @@ -1239,7 +1239,7 @@ int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, u8 hash = ipv6_addr_hash(addr); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) @@ -1257,7 +1257,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev || @@ -1559,7 +1559,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, .fc_expires = expires, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_copy(&cfg.fc_dst, pfx); @@ -1586,7 +1586,7 @@ static void addrconf_add_mroute(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); @@ -1603,7 +1603,7 @@ static void sit_route_add(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 96, .fc_flags = RTF_UP | RTF_NONEXTHOP, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; /* prefix length - 96 bits "::d.d.d.d" */ @@ -1704,7 +1704,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (pinfo->onlink) { struct rt6_info *rt; - rt = rt6_lookup(dev->nd_net, &pinfo->prefix, NULL, + rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { @@ -1748,7 +1748,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ok: - ifp = ipv6_get_ifaddr(dev->nd_net, &addr, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; @@ -2071,7 +2071,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int scope; ASSERT_RTNL(); @@ -2261,7 +2261,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) static void ip6_tnl_add_linklocal(struct inet6_dev *idev) { struct net_device *link_dev; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && @@ -2442,7 +2442,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); int i; ASSERT_RTNL(); @@ -2771,7 +2771,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; - while (ifa && ifa->idev->dev->nd_net != net) + while (ifa && dev_net(ifa->idev->dev) != net) ifa = ifa->lst_next; if (ifa) break; @@ -2787,7 +2787,7 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifad ifa = ifa->lst_next; try_again: if (ifa) { - if (ifa->idev->dev->nd_net != net) { + if (dev_net(ifa->idev->dev) != net) { ifa = ifa->lst_next; goto try_again; } @@ -2905,7 +2905,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) u8 hash = ipv6_addr_hash(addr); read_lock_bh(&addrconf_hash_lock); for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && (ifp->flags & IFA_F_HOMEADDRESS)) { @@ -3469,7 +3469,7 @@ errout: static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) { struct sk_buff *skb; - struct net *net = ifa->idev->dev->nd_net; + struct net *net = dev_net(ifa->idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); @@ -3675,7 +3675,7 @@ cont: void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); @@ -3745,7 +3745,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); @@ -4157,7 +4157,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev) NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change, NULL); - __addrconf_sysctl_register(idev->dev->nd_net, idev->dev->name, + __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, idev->dev->ifindex, idev, &idev->cnf); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 86332417b402..50857662e6b7 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -306,7 +306,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, struct net_device *dev) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; @@ -507,7 +507,7 @@ EXPORT_SYMBOL(icmpv6_send); static void icmpv6_echo_reply(struct sk_buff *skb) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d34aa61353bb..556300f0eba5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -402,7 +402,7 @@ int ip6_forward(struct sk_buff *skb) struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); - struct net *net = dst->dev->nd_net; + struct net *net = dev_net(dst->dev); if (ipv6_devconf.forwarding == 0) goto error; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 957ac7e9e929..0357de8e78c8 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1400,7 +1400,7 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) static struct sk_buff *mld_newpack(struct net_device *dev, int size) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.igmp_sk; struct sk_buff *skb; struct mld2_report *pmr; @@ -1448,7 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb) (struct mld2_report *)skb_transport_header(skb); int payload_len, mldlen; struct inet6_dev *idev = in6_dev_get(skb->dev); - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); int err; struct flowi fl; @@ -1762,7 +1762,7 @@ static void mld_send_cr(struct inet6_dev *idev) static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.igmp_sk; struct inet6_dev *idev; struct sk_buff *skb; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3f68a6eae7b2..79af57f586e8 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -447,7 +447,7 @@ static void __ndisc_send(struct net_device *dev, { struct flowi fl; struct dst_entry *dst; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; @@ -539,7 +539,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, }; /* for anycast or proxy, solicited_addr != src_addr */ - ifp = ipv6_get_ifaddr(dev->nd_net, solicited_addr, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) @@ -547,7 +547,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, in6_ifa_put(ifp); } else { if (ipv6_dev_get_saddr(dev, daddr, - inet6_sk(dev->nd_net->ipv6.ndisc_sk)->srcprefs, + inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, &tmpaddr)) return; src_addr = &tmpaddr; @@ -601,7 +601,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, * suppress the inclusion of the sllao. */ if (send_sllao) { - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev->nd_net, saddr, + struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, dev, 1); if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { @@ -639,7 +639,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && ipv6_chk_addr(dev->nd_net, &ipv6_hdr(skb)->saddr, dev, 1)) + if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) saddr = &ipv6_hdr(skb)->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -727,7 +727,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) inc = ipv6_addr_is_multicast(daddr); - ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { @@ -776,7 +776,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (ipv6_chk_acast_addr(dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh = pneigh_lookup(&nd_tbl, dev->nd_net, + (pneigh = pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) != NULL)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && @@ -886,7 +886,7 @@ static void ndisc_recv_na(struct sk_buff *skb) return; } } - ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { if (ifp->flags & IFA_F_TENTATIVE) { addrconf_dad_failure(ifp); @@ -918,7 +918,7 @@ static void ndisc_recv_na(struct sk_buff *skb) */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && - pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) { + pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ goto out; } @@ -1008,7 +1008,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) struct sk_buff *skb; struct nlmsghdr *nlh; struct nduseroptmsg *ndmsg; - struct net *net = ra->dev->nd_net; + struct net *net = dev_net(ra->dev); int err; int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + (opt->nd_opt_len << 3)); @@ -1395,7 +1395,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, struct in6_addr *target) { struct net_device *dev = skb->dev; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); struct sk_buff *buff; @@ -1597,7 +1597,7 @@ int ndisc_rcv(struct sk_buff *skb) static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); switch (event) { case NETDEV_CHANGEADDR: diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index cc2f9afcf808..a6d30626b47c 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -484,7 +484,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 8a5be290c710..364dc332532c 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -214,7 +214,7 @@ int snmp6_register_dev(struct inet6_dev *idev) if (!idev || !idev->dev) return -EINVAL; - if (idev->dev->nd_net != &init_net) + if (dev_net(idev->dev) != &init_net) return 0; if (!proc_net_devsnmp6) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 548d0763f4d3..efb0047f6880 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -176,7 +176,7 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) if (sk == NULL) goto out; - net = skb->dev->nd_net; + net = dev_net(skb->dev); sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); while (sk) { @@ -363,7 +363,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, if (sk != NULL) { saddr = &ipv6_hdr(skb)->saddr; daddr = &ipv6_hdr(skb)->daddr; - net = skb->dev->nd_net; + net = dev_net(skb->dev); while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, IP6CB(skb)->iif))) { diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f936d045a39d..4e1447634f36 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -600,7 +600,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return 1; } - net = skb->dev->nd_net; + net = dev_net(skb->dev); if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) ip6_evictor(net, ip6_dst_idev(skb->dst)); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 06faa46920e1..65053fba8c1a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -208,7 +208,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; struct net_device *loopback_dev = - dev->nd_net->loopback_dev; + dev_net(dev)->loopback_dev; if (dev != loopback_dev && idev != NULL && idev->dev == dev) { struct inet6_dev *loopback_idev = @@ -433,7 +433,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) RT6_TRACE("%s() => %p\n", __func__, match); - net = rt0->rt6i_dev->nd_net; + net = dev_net(rt0->rt6i_dev); return (match ? match : net->ipv6.ip6_null_entry); } @@ -441,7 +441,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, struct in6_addr *gwaddr) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; unsigned int pref; @@ -607,7 +607,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) int ip6_ins_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = rt->rt6i_dev->nd_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_ins_rt(rt, &info); } @@ -745,7 +745,7 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table * void ip6_route_input(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, @@ -928,7 +928,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); if (unlikely(idev == NULL)) return NULL; @@ -1252,7 +1252,7 @@ install_route: rt->rt6i_idev = idev; rt->rt6i_table = table; - cfg->fc_nlinfo.nl_net = dev->nd_net; + cfg->fc_nlinfo.nl_net = dev_net(dev); return __ip6_ins_rt(rt, &cfg->fc_nlinfo); @@ -1270,7 +1270,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) { int err; struct fib6_table *table; - struct net *net = rt->rt6i_dev->nd_net; + struct net *net = dev_net(rt->rt6i_dev); if (rt == net->ipv6.ip6_null_entry) return -ENOENT; @@ -1289,7 +1289,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) int ip6_del_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = rt->rt6i_dev->nd_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_del_rt(rt, &info); } @@ -1401,7 +1401,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, struct net_device *dev) { int flags = RT6_LOOKUP_F_HAS_SADDR; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1428,7 +1428,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, { struct rt6_info *rt, *nrt = NULL; struct netevent_redirect netevent; - struct net *net = neigh->dev->nd_net; + struct net *net = dev_net(neigh->dev); rt = ip6_route_redirect(dest, src, saddr, neigh->dev); @@ -1477,7 +1477,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, nrt->rt6i_nexthop = neigh_clone(neigh); /* Reset pmtu, it may be better */ nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); - nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(neigh->dev->nd_net, + nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), dst_mtu(&nrt->u.dst)); if (ip6_ins_rt(nrt)) @@ -1506,7 +1506,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct rt6_info *rt, *nrt; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); int allfrag = 0; rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0); @@ -1583,7 +1583,7 @@ out: static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { - struct net *net = ort->rt6i_dev->nd_net; + struct net *net = dev_net(ort->rt6i_dev); struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt) { @@ -1682,7 +1682,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(dev->nd_net, RT6_TABLE_DFLT); + table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); if (table == NULL) return NULL; @@ -1713,7 +1713,7 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, RTF_UP | RTF_EXPIRES | RTF_PREF(pref), .fc_nlinfo.pid = 0, .fc_nlinfo.nlh = NULL, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_copy(&cfg.fc_gateway, gwaddr); @@ -1862,7 +1862,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, int anycast) { - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt == NULL) @@ -1939,7 +1939,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) { struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; struct inet6_dev *idev; - struct net *net = arg->dev->nd_net; + struct net *net = dev_net(arg->dev); /* In IPv6 pmtu discovery is not optional, so that RTAX_MTU lock cannot disable it. @@ -1983,7 +1983,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) .mtu = mtu, }; - fib6_clean_all(dev->nd_net, rt6_mtu_change_route, 0, &arg); + fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg); } static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { @@ -2321,7 +2321,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, unsigned long event, void *data) { struct net_device *dev = (struct net_device *)data; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { net->ipv6.ip6_null_entry->u.dst.dev = dev; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8dd72966ff78..086deffff9c9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -321,7 +321,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct tcp_sock *tp; __u32 seq; - sk = inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, &hdr->daddr, + sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -988,7 +988,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = skb->dst->dev->nd_net; + struct net *net = dev_net(skb->dst->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(*th); #ifdef CONFIG_TCP_MD5SIG @@ -1093,7 +1093,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; @@ -1739,7 +1739,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); TCP_SKB_CB(skb)->sacked = 0; - sk = __inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, + sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); @@ -1822,7 +1822,7 @@ do_time_wait: { struct sock *sk2; - sk2 = inet6_lookup_listener(skb->dev->nd_net, &tcp_hashinfo, + sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); if (sk2 != NULL) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 593d3efadaf9..6683c04b427e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -235,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; - sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, + sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest, saddr, uh->source, inet6_iif(skb), udptable); if (sk == NULL) return; @@ -483,7 +483,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, + sk = __udp6_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index d92d1fceb8cf..8f1e0543b3c4 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -247,7 +247,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { struct inet6_dev *loopback_idev = - in6_dev_get(dev->nd_net->loopback_dev); + in6_dev_get(dev_net(dev)->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index c76a9523091b..81ae8735f5e3 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -335,7 +335,7 @@ static int ipxitf_device_event(struct notifier_block *notifier, struct net_device *dev = ptr; struct ipx_interface *i, *tmp; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN && event != NETDEV_UP) @@ -1636,7 +1636,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty u16 ipx_pktsize; int rc = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* Not ours */ diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index a38b231c8689..90894534f3cc 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1326,7 +1326,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int command; __u8 control; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; /* FIXME: should we get our own field? */ diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index b9143d2a04e1..a69c5c427fe3 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -146,7 +146,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* diff --git a/net/netfilter/core.c b/net/netfilter/core.c index ec05684c56d7..292fa28146fb 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -168,7 +168,7 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, #ifdef CONFIG_NET_NS struct net *net; - net = indev == NULL ? outdev->nd_net : indev->nd_net; + net = indev == NULL ? dev_net(outdev) : dev_net(indev); if (net != &init_net) return 1; #endif diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 012cb6910820..81fb048add88 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -557,7 +557,7 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 4478f2f6079d..a547c6320eb3 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -954,7 +954,7 @@ static int netlbl_unlhsh_netdev_handler(struct notifier_block *this, struct net_device *dev = ptr; struct netlbl_unlhsh_iface *iface = NULL; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */ diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 972250c974f1..a270ebf9f765 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -106,7 +106,7 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a56ed2120e07..baa290d3444a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -263,7 +263,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct if (skb->pkt_type == PACKET_LOOPBACK) goto out; - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto out; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -451,7 +451,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto drop; skb->dev = dev; @@ -568,7 +568,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto drop; if (dev->header_ops) { @@ -1450,7 +1450,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void struct sock *sk; struct hlist_node *node; struct net_device *dev = data; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); read_lock(&net->packet.sklist_lock); sk_for_each(sk, node, &net->packet.sklist) { diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 4a31a81059ab..1a7f143cf741 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -197,7 +197,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index beea2fb18b15..2faa0d8839eb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -630,7 +630,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, struct sctp_sockaddr_entry *temp; int found = 0; - if (ifa->ifa_dev->dev->nd_net != &init_net) + if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; switch (ev) { diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 3bbef2ab22ae..9cd35eec3e7f 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -101,7 +101,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; u32 size; - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(buf); return 0; } @@ -198,7 +198,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, struct eth_bearer *eb_ptr = ð_bearers[0]; struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; while ((eb_ptr->dev != dev)) { diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 2c569b63e7d8..947188a5b937 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1157,7 +1157,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) struct sk_buff *skb; int err; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 339ca4a8e89e..7a46ea73fe2d 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -191,7 +191,7 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct x25_neigh *nb; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type == ARPHRD_X25 diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index f0679d283110..3ff206c0ae94 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -95,7 +95,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct sk_buff *nskb; struct x25_neigh *nb; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; nskb = skb_copy(skb, GFP_ATOMIC); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 8e588f20c60c..15d73e47cc2c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2079,7 +2079,7 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = dev->nd_net->loopback_dev; + dst->dev = dev_net(dev)->loopback_dev; dev_hold(dst->dev); dev_put(dev); } @@ -2350,7 +2350,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch (event) { diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 013d3117a86b..9c8a82aa8baf 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -281,7 +281,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) -- cgit v1.2.3 From 3b1e0a655f8eba44ab1ee2a1068d169ccfb853b9 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 02:26:21 +0900 Subject: [NET] NETNS: Omit sock->sk_net without CONFIG_NET_NS. Introduce per-sock inlines: sock_net(), sock_net_set() and per-inet_timewait_sock inlines: twsk_net(), twsk_net_set(). Without CONFIG_NET_NS, no namespace other than &init_net exists. Let's explicitly define them to help compiler optimizations. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 4 ++-- include/net/inet_hashtables.h | 8 ++++---- include/net/inet_timewait_sock.h | 18 ++++++++++++++++++ include/net/route.h | 4 ++-- include/net/sock.h | 24 ++++++++++++++++++++++-- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bluetooth/l2cap.c | 2 +- net/bluetooth/rfcomm/sock.c | 2 +- net/bluetooth/sco.c | 2 +- net/bridge/br_netlink.c | 4 ++-- net/core/fib_rules.c | 6 +++--- net/core/neighbour.c | 10 +++++----- net/core/rtnetlink.c | 12 ++++++------ net/core/sock.c | 10 +++++----- net/decnet/af_decnet.c | 2 +- net/decnet/dn_dev.c | 6 +++--- net/decnet/dn_fib.c | 4 ++-- net/decnet/dn_route.c | 4 ++-- net/decnet/dn_table.c | 2 +- net/ipv4/af_inet.c | 6 +++--- net/ipv4/devinet.c | 6 +++--- net/ipv4/fib_frontend.c | 8 ++++---- net/ipv4/fib_rules.c | 2 +- net/ipv4/igmp.c | 14 +++++++------- net/ipv4/inet_connection_sock.c | 4 ++-- net/ipv4/inet_hashtables.c | 8 ++++---- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv4/ip_sockglue.c | 6 +++--- net/ipv4/ipmr.c | 4 ++-- net/ipv4/netfilter/arp_tables.c | 16 ++++++++-------- net/ipv4/netfilter/ip_tables.c | 16 ++++++++-------- net/ipv4/raw.c | 12 ++++++------ net/ipv4/route.c | 4 ++-- net/ipv4/tcp_ipv4.c | 14 +++++++------- net/ipv4/udp.c | 16 ++++++++-------- net/ipv6/addrconf.c | 10 +++++----- net/ipv6/addrlabel.c | 6 +++--- net/ipv6/af_inet6.c | 4 ++-- net/ipv6/fib6_rules.c | 2 +- net/ipv6/icmp.c | 2 +- net/ipv6/inet6_hashtables.c | 4 ++-- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ip6_output.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/mcast.c | 12 ++++++------ net/ipv6/netfilter/ip6_tables.c | 16 ++++++++-------- net/ipv6/raw.c | 6 +++--- net/ipv6/route.c | 4 ++-- net/ipv6/tcp_ipv6.c | 2 +- net/ipv6/udp.c | 4 ++-- net/irda/af_irda.c | 2 +- net/llc/llc_conn.c | 2 +- net/netfilter/nf_sockopt.c | 2 +- net/netlink/af_netlink.c | 30 +++++++++++++++--------------- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 28 ++++++++++++++-------------- net/rose/af_rose.c | 2 +- net/sched/act_api.c | 4 ++-- net/sched/cls_api.c | 4 ++-- net/sched/sch_api.c | 10 +++++----- net/sctp/ipv6.c | 2 +- net/sctp/protocol.c | 2 +- net/socket.c | 4 ++-- net/tipc/socket.c | 2 +- net/unix/af_unix.c | 20 ++++++++++---------- net/x25/af_x25.c | 2 +- 69 files changed, 253 insertions(+), 215 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c9ba0da16ce9..b90d3d461d4e 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -481,7 +481,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ ((__sk)->sk_family == AF_INET6) && \ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ @@ -489,7 +489,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET6_TW_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (*((__portpair *)&(inet_twsk(__sk)->tw_dport)) == (__ports)) && \ ((__sk)->sk_family == PF_INET6) && \ (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr))) && \ diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index d99c1ba2ece0..5525227c5e92 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -314,25 +314,25 @@ typedef __u64 __bitwise __addrpair; ((__force __u64)(__be32)(__saddr))); #endif /* __BIG_ENDIAN */ #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (inet_sk(__sk)->daddr == (__saddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 296547bfb0b7..07fe0d1a4f03 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -207,4 +207,22 @@ extern void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo, const int timewait_len); extern void inet_twsk_deschedule(struct inet_timewait_sock *tw, struct inet_timewait_death_row *twdr); + +static inline +struct net *twsk_net(const struct inet_timewait_sock *twsk) +{ +#ifdef CONFIG_NET_NS + return twsk->tw_net; +#else + return &init_net; +#endif +} + +static inline +void twsk_net_set(struct inet_timewait_sock *twsk, const struct net *net) +{ +#ifdef CONFIG_NET_NS + twsk->tw_net = net; +#endif +} #endif /* _INET_TIMEWAIT_SOCK_ */ diff --git a/include/net/route.h b/include/net/route.h index 28dba925663c..c6338802e8f1 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -160,7 +160,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, .dport = dport } } }; int err; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (!dst || !src) { err = __ip_route_output_key(net, rp, &fl); if (err) @@ -188,7 +188,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol, ip_rt_put(*rp); *rp = NULL; security_sk_classify_flow(sk, &fl); - return ip_route_output_flow(sk->sk_net, rp, &fl, sk, 0); + return ip_route_output_flow(sock_net(sk), rp, &fl, sk, 0); } return 0; } diff --git a/include/net/sock.h b/include/net/sock.h index b433b1ed203d..7e0d4a0c4d12 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -126,7 +126,9 @@ struct sock_common { atomic_t skc_refcnt; unsigned int skc_hash; struct proto *skc_prot; +#ifdef CONFIG_NET_NS struct net *skc_net; +#endif }; /** @@ -1345,6 +1347,24 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e } #endif +static inline +struct net *sock_net(const struct sock *sk) +{ +#ifdef CONFIG_NET_NS + return sk->sk_net; +#else + return &init_net; +#endif +} + +static inline +void sock_net_set(struct sock *sk, const struct net *net) +{ +#ifdef CONFIG_NET_NS + sk->sk_net = net; +#endif +} + /* * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. * They should not hold a referrence to a namespace in order to allow @@ -1353,8 +1373,8 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e */ static inline void sk_change_net(struct sock *sk, struct net *net) { - put_net(sk->sk_net); - sk->sk_net = net; + put_net(sock_net(sk)); + sock_net_set(sk, net); } extern void sock_enable_timestamp(struct sock *sk); diff --git a/net/atm/svc.c b/net/atm/svc.c index daf9a48a7db0..de1e4f2f3a43 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -326,7 +326,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) lock_sock(sk); - error = svc_create(sk->sk_net, newsock,0); + error = svc_create(sock_net(sk), newsock,0); if (error) goto out; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index ee9dd83e7561..2712544cf0ca 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -869,7 +869,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot); if (sk == NULL) return NULL; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 34f8bf98bc05..6b995ac832f5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1499,7 +1499,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC); + sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC); if (!sk) goto response; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c46d51035e77..c103fa02893b 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -868,7 +868,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * goto done; } - sk = rfcomm_sock_alloc(parent->sk_net, NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC); if (!sk) goto done; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index b91d3c81a73c..2a5953b4405d 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -803,7 +803,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); - sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC); + sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f5d69336d97b..f155e6ce8a21 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -108,7 +108,7 @@ errout: */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct net_device *dev; int idx; @@ -140,7 +140,7 @@ skip: */ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *protinfo; struct net_device *dev; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 942be93a2eb0..540c07283e31 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -214,7 +214,7 @@ errout: static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *r, *last = NULL; @@ -352,7 +352,7 @@ errout: static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *tmp; @@ -534,7 +534,7 @@ skip: static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rules_ops *ops; int idx = 0, family; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c978bd1cd659..065fbac7ecd3 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1478,7 +1478,7 @@ int neigh_table_clear(struct neigh_table *tbl) static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ndmsg *ndm; struct nlattr *dst_attr; struct neigh_table *tbl; @@ -1544,7 +1544,7 @@ out: static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; @@ -1812,7 +1812,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct neigh_table *tbl; struct ndtmsg *ndtmsg; struct nlattr *tb[NDTA_MAX+1]; @@ -1937,7 +1937,7 @@ errout: static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int family, tidx, nidx = 0; int tbl_skip = cb->args[0]; int neigh_skip = cb->args[1]; @@ -2037,7 +2037,7 @@ static void neigh_update_notify(struct neighbour *neigh) static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb) { - struct net * net = skb->sk->sk_net; + struct net * net = sock_net(skb->sk); struct neighbour *n; int rc, h, s_h = cb->args[1]; int idx, s_idx = idx = cb->args[2]; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 09250a0800f6..da99ac0871bf 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -662,7 +662,7 @@ nla_put_failure: static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx; int s_idx = cb->args[0]; struct net_device *dev; @@ -879,7 +879,7 @@ errout: static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct net_device *dev; int err; @@ -921,7 +921,7 @@ errout: static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1000,7 +1000,7 @@ err: static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1132,7 +1132,7 @@ replay: static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; @@ -1227,7 +1227,7 @@ static int rtattr_max; static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); rtnl_doit_func doit; int sz_idx, kind; int min_len; diff --git a/net/core/sock.c b/net/core/sock.c index b1a6ed4d33c1..3ee95060dbd0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -372,7 +372,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) { int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); char devname[IFNAMSIZ]; int index; @@ -958,7 +958,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); - sk->sk_net = get_net(net); + sock_net_set(sk, get_net(net)); } return sk; @@ -983,7 +983,7 @@ void sk_free(struct sock *sk) printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", __func__, atomic_read(&sk->sk_omem_alloc)); - put_net(sk->sk_net); + put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } @@ -1001,7 +1001,7 @@ void sk_release_kernel(struct sock *sk) sock_hold(sk); sock_release(sk->sk_socket); - sk->sk_net = get_net(&init_net); + sock_net_set(sk, get_net(&init_net)); sock_put(sk); } EXPORT_SYMBOL(sk_release_kernel); @@ -1017,7 +1017,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) sock_copy(newsk, sk); /* SANITY */ - get_net(newsk->sk_net); + get_net(sock_net(newsk)); sk_node_init(&newsk->sk_node); sock_lock_init(newsk); bh_lock_sock(newsk); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 3554fb3d251c..fc2efe899e91 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1094,7 +1094,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; - newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation); + newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 1bbfce5f7a2d..2f0ac3c3eb71 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -625,7 +625,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = { static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct dn_dev *dn_db; struct ifaddrmsg *ifm; @@ -663,7 +663,7 @@ errout: static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct net_device *dev; struct dn_dev *dn_db; @@ -779,7 +779,7 @@ errout: static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, dn_idx = 0, skip_ndevs, skip_naddr; struct net_device *dev; struct dn_dev *dn_db; diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 4aa9a423e606..27ea2e9b080a 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -504,7 +504,7 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); @@ -524,7 +524,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 0a46b6c10e51..2f665a516476 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1512,7 +1512,7 @@ rtattr_failure: */ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct rtattr **rta = arg; struct rtmsg *rtm = NLMSG_DATA(nlh); struct dn_route *rt = NULL; @@ -1601,7 +1601,7 @@ out_free: */ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_route *rt; int h, s_h; int idx, s_idx; diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index e09d915dbd77..3a2830ac89c2 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -463,7 +463,7 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct dn_fib_table *tb; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 06cfb0bed631..5882a1316441 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -464,7 +464,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -802,7 +802,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); switch (cmd) { case SIOCGSTAMP: @@ -1132,7 +1132,7 @@ int inet_sk_rebuild_header(struct sock *sk) }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0); } if (!err) sk_setup_caps(sk, &rt->u.dst); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 823c724a8593..6848e4760f34 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -437,7 +437,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct in_device *in_dev; struct ifaddrmsg *ifm; @@ -552,7 +552,7 @@ errout: static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct in_ifaddr *ifa; ASSERT_RTNL(); @@ -1158,7 +1158,7 @@ nla_put_failure: static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, ip_idx; struct net_device *dev; struct in_device *in_dev; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 0e4b34b07cb5..0f1557a4ac7a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -583,7 +583,7 @@ errout: static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_config cfg; struct fib_table *tb; int err; @@ -605,7 +605,7 @@ errout: static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_config cfg; struct fib_table *tb; int err; @@ -627,7 +627,7 @@ errout: static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct fib_table *tb; @@ -857,7 +857,7 @@ static void nl_fib_input(struct sk_buff *skb) struct fib_table *tb; u32 pid; - net = skb->sk->sk_net; + net = sock_net(skb->sk); nlh = nlmsg_hdr(skb); if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 19274d01afa4..1fb56876be54 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -137,7 +137,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlmsghdr *nlh, struct fib_rule_hdr *frh, struct nlattr **tb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int err = -EINVAL; struct fib4_rule *rule4 = (struct fib4_rule *) rule; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 682f632bfb77..6250f4239b61 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1762,7 +1762,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1833,7 +1833,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) u32 ifindex; int ret = -EADDRNOTAVAIL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1881,7 +1881,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2017,7 +2017,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) msf->imsf_fmode != MCAST_EXCLUDE) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2100,7 +2100,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2165,7 +2165,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2252,7 +2252,7 @@ void ip_mc_drop_socket(struct sock *sk) if (inet->mc_list == NULL) return; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return; rtnl_lock(); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d13c5f12bb32..a7fcaf205644 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -85,7 +85,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) struct hlist_node *node; struct inet_bind_bucket *tb; int ret; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); local_bh_disable(); if (!snum) { @@ -333,7 +333,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, .dport = ireq->rmt_port } } }; security_req_classify_flow(req, &fl); - if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) { + if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); return NULL; } diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 8cd1ad9b9111..1064111e5b96 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -139,7 +139,7 @@ static struct sock *inet_lookup_listener_slow(struct net *net, sk_for_each(sk, node, head) { const struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && inet->num == hnum && + if (sock_net(sk) == net && inet->num == hnum && !ipv6_only_sock(sk)) { const __be32 rcv_saddr = inet->rcv_saddr; int score = sk->sk_family == PF_INET ? 1 : 0; @@ -182,7 +182,7 @@ struct sock *__inet_lookup_listener(struct net *net, if (inet->num == hnum && !sk->sk_node.next && (!inet->rcv_saddr || inet->rcv_saddr == daddr) && (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && - !sk->sk_bound_dev_if && sk->sk_net == net) + !sk->sk_bound_dev_if && sock_net(sk) == net) goto sherry_cache; sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif); } @@ -254,7 +254,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); @@ -406,7 +406,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct inet_bind_hashbucket *head; struct inet_bind_bucket *tb; int ret; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (!snum) { int i, remaining, low, high, port; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 717c411a5c6b..f12bc24de46f 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -124,7 +124,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat tw->tw_hash = sk->sk_hash; tw->tw_ipv6only = 0; tw->tw_prot = sk->sk_prot_creator; - tw->tw_net = sk->sk_net; + twsk_net_set(tw, sock_net(sk)); atomic_set(&tw->tw_refcnt, 1); inet_twsk_dead_node_init(tw); __module_get(tw->tw_prot->owner); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 26685c83a146..4be00959b748 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -172,7 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb) if (sk && inet_sk(sk)->num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && - sk->sk_net == dev_net(dev)) { + sock_net(sk) == dev_net(dev)) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 913266cd9902..08349267ceb4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -351,7 +351,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) * itself out. */ security_sk_classify_flow(sk, &fl); - if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) + if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) goto no_route; } sk_setup_caps(sk, &rt->u.dst); @@ -1382,7 +1382,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar .dport = tcp_hdr(skb)->source } }, .proto = sk->sk_protocol }; security_skb_classify_flow(skb, &fl); - if (ip_route_output_key(sk->sk_net, &rt, &fl)) + if (ip_route_output_key(sock_net(sk), &rt, &fl)) return; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index b854431047a4..d6e76f5229cc 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -449,7 +449,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; - err = ip_options_get_from_user(sk->sk_net, &opt, + err = ip_options_get_from_user(sock_net(sk), &opt, optval, optlen); if (err) break; @@ -590,13 +590,13 @@ static int do_ip_setsockopt(struct sock *sk, int level, err = 0; break; } - dev = ip_dev_find(sk->sk_net, mreq.imr_address.s_addr); + dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr); if (dev) { mreq.imr_ifindex = dev->ifindex; dev_put(dev); } } else - dev = __dev_get_by_index(sk->sk_net, mreq.imr_ifindex); + dev = __dev_get_by_index(sock_net(sk), mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e54bc1364473..11700a4dcd95 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -849,7 +849,7 @@ static void mrtsock_destruct(struct sock *sk) { rtnl_lock(); if (sk == mroute_socket) { - IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)--; + IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)--; write_lock_bh(&mrt_lock); mroute_socket=NULL; @@ -898,7 +898,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt mroute_socket=sk; write_unlock_bh(&mrt_lock); - IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)++; + IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++; } rtnl_unlock(); return ret; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 756bc0e1a7c6..1563f29b5117 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1496,11 +1496,11 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case ARPT_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case ARPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1644,10 +1644,10 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case ARPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case ARPT_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_arpt_get_ctl(sk, cmd, user, len); @@ -1665,11 +1665,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned switch (cmd) { case ARPT_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case ARPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -1689,11 +1689,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len switch (cmd) { case ARPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case ARPT_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case ARPT_SO_GET_REVISION_TARGET: { diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 85a75e186b4b..a819d191e1aa 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1852,11 +1852,11 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case IPT_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case IPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1963,10 +1963,10 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case IPT_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_ipt_get_ctl(sk, cmd, user, len); @@ -1985,11 +1985,11 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) switch (cmd) { case IPT_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case IPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -2010,11 +2010,11 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case IPT_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case IPT_SO_GET_REVISION_MATCH: diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 8756d502a47f..be19a4048d7c 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -117,7 +117,7 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, sk_for_each_from(sk, node) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && inet->num == num && + if (sock_net(sk) == net && inet->num == num && !(inet->daddr && inet->daddr != raddr) && !(inet->rcv_saddr && inet->rcv_saddr != laddr) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) @@ -499,7 +499,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(sk->sk_net, msg, &ipc); + err = ip_cmsg_send(sock_net(sk), msg, &ipc); if (err) goto out; if (ipc.opt) @@ -553,7 +553,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); } if (err) goto done; @@ -620,7 +620,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); ret = -EADDRNOTAVAIL; if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) @@ -856,7 +856,7 @@ static struct sock *raw_get_first(struct seq_file *seq) struct hlist_node *node; sk_for_each(sk, node, &state->h->ht[state->bucket]) - if (sk->sk_net == state->p.net) + if (sock_net(sk) == state->p.net) goto found; } sk = NULL; @@ -872,7 +872,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_net != state->p.net); + } while (sk && sock_net(sk) != state->p.net); if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { sk = sk_head(&state->h->ht[state->bucket]); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7768d718e199..194f5cca3121 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2689,7 +2689,7 @@ nla_put_failure: static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct rtmsg *rtm; struct nlattr *tb[RTA_MAX+1]; struct rtable *rt = NULL; @@ -2785,7 +2785,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) int idx, s_idx; struct net *net; - net = skb->sk->sk_net; + net = sock_net(skb->sk); s_h = cb->args[0]; if (s_h < 0) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 28bece6f281b..46847e600a46 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1486,7 +1486,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) if (req) return tcp_check_req(sk, skb, req, prev); - nsk = inet_lookup_established(sk->sk_net, &tcp_hashinfo, iph->saddr, + nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, th->source, iph->daddr, th->dest, inet_iif(skb)); if (nsk) { @@ -1974,7 +1974,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) while (1) { while (req) { if (req->rsk_ops->family == st->family && - req->sk->sk_net == net) { + sock_net(req->sk) == net) { cur = req; goto out; } @@ -1998,7 +1998,7 @@ get_req: } get_sk: sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sk->sk_net == net) { + if (sk->sk_family == st->family && sock_net(sk) == net) { cur = sk; goto out; } @@ -2049,7 +2049,7 @@ static void *established_get_first(struct seq_file *seq) read_lock_bh(lock); sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { if (sk->sk_family != st->family || - sk->sk_net != net) { + sock_net(sk) != net) { continue; } rc = sk; @@ -2059,7 +2059,7 @@ static void *established_get_first(struct seq_file *seq) inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { if (tw->tw_family != st->family || - tw->tw_net != net) { + twsk_net(tw) != net) { continue; } rc = tw; @@ -2086,7 +2086,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && (tw->tw_family != st->family || tw->tw_net != net)) { + while (tw && (tw->tw_family != st->family || twsk_net(tw) != net)) { tw = tw_next(tw); } if (tw) { @@ -2107,7 +2107,7 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sk->sk_net == net) + if (sk->sk_family == st->family && sock_net(sk) == net) goto found; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e2cd93481359..76d52d37d6ac 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -137,7 +137,7 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, struct hlist_node *node; sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) - if (sk->sk_net == net && sk->sk_hash == num) + if (sock_net(sk) == net && sk->sk_hash == num) return 1; return 0; } @@ -158,7 +158,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, struct hlist_head *head; struct sock *sk2; int error = 1; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&udp_hash_lock); @@ -218,7 +218,7 @@ gotit: sk_for_each(sk2, node, head) if (sk2->sk_hash == snum && sk2 != sk && - sk2->sk_net == net && + sock_net(sk2) == net && (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && @@ -269,7 +269,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && sk->sk_hash == hnum && + if (sock_net(sk) == net && sk->sk_hash == hnum && !ipv6_only_sock(sk)) { int score = (sk->sk_family == PF_INET ? 1 : 0); if (inet->rcv_saddr) { @@ -607,7 +607,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(sk->sk_net, msg, &ipc); + err = ip_cmsg_send(sock_net(sk), msg, &ipc); if (err) return err; if (ipc.opt) @@ -656,7 +656,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .sport = inet->sport, .dport = dport } } }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); @@ -1511,7 +1511,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; sk_for_each(sk, node, state->hashtable + state->bucket) { - if (sk->sk_net != net) + if (sock_net(sk) != net) continue; if (sk->sk_family == state->family) goto found; @@ -1531,7 +1531,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && (sk->sk_net != net || sk->sk_family != state->family)); + } while (sk && (sock_net(sk) != net || sk->sk_family != state->family)); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d1de9ec74261..f2c90f145cbb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3054,7 +3054,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { static int inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *pfx; @@ -3112,7 +3112,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, static int inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *pfx; @@ -3322,7 +3322,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, struct inet6_ifaddr *ifa; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; @@ -3418,7 +3418,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *addr = NULL; @@ -3645,7 +3645,7 @@ nla_put_failure: static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, err; int s_idx = cb->args[0]; struct net_device *dev; diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index de371b5997fe..9bfa8846f262 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -364,7 +364,7 @@ static const struct nla_policy ifal_policy[IFAL_MAX+1] = { static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrlblmsg *ifal; struct nlattr *tb[IFAL_MAX+1]; struct in6_addr *pfx; @@ -452,7 +452,7 @@ static int ip6addrlbl_fill(struct sk_buff *skb, static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ip6addrlbl_entry *p; struct hlist_node *pos; int idx = 0, s_idx = cb->args[0]; @@ -490,7 +490,7 @@ static inline int ip6addrlbl_msgsize(void) static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct ifaddrlblmsg *ifal; struct nlattr *tb[IFAL_MAX+1]; struct in6_addr *addr; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f52bdaed8a1b..12f04e9d3e88 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -245,7 +245,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); __be32 v4addr = 0; unsigned short snum; int addr_type = 0; @@ -438,7 +438,7 @@ EXPORT_SYMBOL(inet6_getname); int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); switch(cmd) { diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index e7a7fe26cebf..cac580749ebe 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -154,7 +154,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlattr **tb) { int err = -EINVAL; - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib6_rule *rule6 = (struct fib6_rule *) rule; if (rule->action == FR_ACT_TO_TBL) { diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 50857662e6b7..63309d10df3a 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -163,7 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, struct flowi *fl) { struct dst_entry *dst; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int res = 0; /* Informational messages are not limited. */ diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index c0c8d2d17682..21c467675412 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -105,7 +105,7 @@ struct sock *inet6_lookup_listener(struct net *net, read_lock(&hashinfo->lhash_lock); sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { - if (sk->sk_net == net && inet_sk(sk)->num == hnum && + if (sock_net(sk) == net && inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { const struct ipv6_pinfo *np = inet6_sk(sk); @@ -172,7 +172,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b0814b0082e7..b3f6e03c454c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -346,7 +346,7 @@ end: static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct rt6_rtnl_dump_arg arg; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 556300f0eba5..a8b4da25b0a7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -910,7 +910,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { int err; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (*dst == NULL) *dst = ip6_route_output(net, sk, fl); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index dc6695cc5767..d3d93d752e10 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -107,7 +107,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int val, valbool; int retv = -ENOPROTOOPT; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0357de8e78c8..20a3d8e2f6c6 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -181,7 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) struct net_device *dev = NULL; struct ipv6_mc_socklist *mc_lst; struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int err; if (!ipv6_addr_is_multicast(addr)) @@ -255,7 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst, **lnk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&ipv6_sk_mc_lock); for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { @@ -327,7 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&ipv6_sk_mc_lock); while ((mc_lst = np->ipv6_mc_list) != NULL) { @@ -365,7 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int i, j, rv; int leavegroup = 0; int pmclocked = 0; @@ -505,7 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *newpsl, *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int leavegroup = 0; int i, err; @@ -598,7 +598,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, struct net_device *dev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index af1ec7ba757c..70ef0d276cc0 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1879,11 +1879,11 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case IP6T_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case IP6T_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1990,10 +1990,10 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IP6T_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case IP6T_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_ip6t_get_ctl(sk, cmd, user, len); @@ -2012,11 +2012,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) switch (cmd) { case IP6T_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case IP6T_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -2037,11 +2037,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IP6T_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case IP6T_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case IP6T_SO_GET_REVISION_MATCH: diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index efb0047f6880..12c7a1560977 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -76,7 +76,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, if (inet_sk(sk)->num == num) { struct ipv6_pinfo *np = inet6_sk(sk); - if (sk->sk_net != net) + if (sock_net(sk) != net) continue; if (!ipv6_addr_any(&np->daddr) && @@ -280,7 +280,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!sk->sk_bound_dev_if) goto out; - dev = dev_get_by_index(sk->sk_net, sk->sk_bound_dev_if); + dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; @@ -293,7 +293,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { err = -EADDRNOTAVAIL; - if (!ipv6_chk_addr(sk->sk_net, &addr->sin6_addr, + if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, dev, 0)) { if (dev) dev_put(dev); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 65053fba8c1a..ac4428371432 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2020,7 +2020,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; cfg->fc_nlinfo.nlh = nlh; - cfg->fc_nlinfo.nl_net = skb->sk->sk_net; + cfg->fc_nlinfo.nl_net = sock_net(skb->sk); if (tb[RTA_GATEWAY]) { nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16); @@ -2216,7 +2216,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct nlattr *tb[RTA_MAX+1]; struct rt6_info *rt; struct sk_buff *skb; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 086deffff9c9..323c7e06ef43 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1218,7 +1218,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) if (req) return tcp_check_req(sk, skb, req, prev); - nsk = __inet6_lookup_established(sk->sk_net, &tcp_hashinfo, + nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6683c04b427e..db266ff297e5 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -70,7 +70,7 @@ static struct sock *__udp6_lib_lookup(struct net *net, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && sk->sk_hash == hnum && + if (sock_net(sk) == net && sk->sk_hash == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); int score = 0; @@ -323,7 +323,7 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, sk_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); - if (s->sk_net != sk->sk_net) + if (sock_net(s) != sock_net(sk)) continue; if (s->sk_hash == num && s->sk_family == PF_INET6) { diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 6f21a53cb3e7..ae54b20d0470 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -837,7 +837,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __func__); - err = irda_create(sk->sk_net, newsock, sk->sk_protocol); + err = irda_create(sock_net(sk), newsock, sk->sk_protocol); if (err) return err; diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 5ebfd93ff5e7..5c6d89c6d51d 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -700,7 +700,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk, struct llc_addr *saddr, struct llc_addr *daddr) { - struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC, + struct sock *newsk = llc_sk_alloc(sock_net(sk), sk->sk_family, GFP_ATOMIC, sk->sk_prot); struct llc_sock *newllc, *llc = llc_sk(sk); diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 3dd4b3c76d81..69d699f95f4c 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -65,7 +65,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf, { struct nf_sockopt_ops *ops; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return ERR_PTR(-ENOPROTOOPT); if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 86bd8660a8f2..712a7bff8560 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -228,7 +228,7 @@ static inline struct sock *netlink_lookup(struct net *net, int protocol, read_lock(&nl_table_lock); head = nl_pid_hashfn(hash, pid); sk_for_each(sk, node, head) { - if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { + if (sock_net(sk) == net && (nlk_sk(sk)->pid == pid)) { sock_hold(sk); goto found; } @@ -348,7 +348,7 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 pid) head = nl_pid_hashfn(hash, pid); len = 0; sk_for_each(osk, node, head) { - if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) + if (sock_net(osk) == net && (nlk_sk(osk)->pid == pid)) break; len++; } @@ -486,7 +486,7 @@ static int netlink_release(struct socket *sock) if (nlk->pid && !nlk->subscriptions) { struct netlink_notify n = { - .net = sk->sk_net, + .net = sock_net(sk), .protocol = sk->sk_protocol, .pid = nlk->pid, }; @@ -518,7 +518,7 @@ static int netlink_release(struct socket *sock) static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; struct sock *osk; @@ -532,7 +532,7 @@ retry: netlink_table_grab(); head = nl_pid_hashfn(hash, pid); sk_for_each(osk, node, head) { - if ((osk->sk_net != net)) + if (sock_net(osk) != net) continue; if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ @@ -611,7 +611,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; @@ -720,7 +720,7 @@ static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) struct sock *sock; struct netlink_sock *nlk; - sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid); + sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); @@ -962,7 +962,7 @@ static inline int do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; - if ((sk->sk_net != p->net)) + if (sock_net(sk) != p->net) goto out; if (p->failure) { @@ -1006,7 +1006,7 @@ out: int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation) { - struct net *net = ssk->sk_net; + struct net *net = sock_net(ssk); struct netlink_broadcast_data info; struct hlist_node *node; struct sock *sk; @@ -1064,7 +1064,7 @@ static inline int do_one_set_err(struct sock *sk, if (sk == p->exclude_sk) goto out; - if (sk->sk_net != p->exclude_sk->sk_net) + if (sock_net(sk) != sock_net(p->exclude_sk)) goto out; if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || @@ -1601,7 +1601,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -1643,7 +1643,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) if (!skb) { struct sock *sk; - sk = netlink_lookup(in_skb->sk->sk_net, + sk = netlink_lookup(sock_net(in_skb->sk), in_skb->sk->sk_protocol, NETLINK_CB(in_skb).pid); if (sk) { @@ -1758,7 +1758,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { - if (iter->p.net != s->sk_net) + if (sock_net(s) != iter->p.net) continue; if (off == pos) { iter->link = i; @@ -1794,7 +1794,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) s = v; do { s = sk_next(s); - } while (s && (iter->p.net != s->sk_net)); + } while (s && (sock_net(s) != iter->p.net)); if (s) return s; @@ -1806,7 +1806,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && (iter->p.net != s->sk_net)) + while (s && sock_net(s) != iter->p.net) s = sk_next(s); if (s) { iter->link = i; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index a270ebf9f765..4bae8b998cab 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -466,7 +466,7 @@ static struct sock *nr_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(osk->sk_net, PF_NETROM, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot); if (sk == NULL) return NULL; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index baa290d3444a..25070240d4ae 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -263,7 +263,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct if (skb->pkt_type == PACKET_LOOPBACK) goto out; - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto out; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -337,7 +337,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(sk->sk_net, saddr->spkt_device); + dev = dev_get_by_name(sock_net(sk), saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -451,7 +451,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto drop; skb->dev = dev; @@ -568,7 +568,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto drop; if (dev->header_ops) { @@ -728,7 +728,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, } - dev = dev_get_by_index(sk->sk_net, ifindex); + dev = dev_get_by_index(sock_net(sk), ifindex); err = -ENXIO; if (dev == NULL) goto out_unlock; @@ -800,7 +800,7 @@ static int packet_release(struct socket *sock) if (!sk) return 0; - net = sk->sk_net; + net = sock_net(sk); po = pkt_sk(sk); write_lock_bh(&net->packet.sklist_lock); @@ -914,7 +914,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); - dev = dev_get_by_name(sk->sk_net, name); + dev = dev_get_by_name(sock_net(sk), name); if (dev) { err = packet_do_bind(sk, dev, pkt_sk(sk)->num); dev_put(dev); @@ -941,7 +941,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len if (sll->sll_ifindex) { err = -ENODEV; - dev = dev_get_by_index(sk->sk_net, sll->sll_ifindex); + dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex); if (dev == NULL) goto out; } @@ -1135,7 +1135,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr, return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(sk->sk_net, pkt_sk(sk)->ifindex); + dev = dev_get_by_index(sock_net(sk), pkt_sk(sk)->ifindex); if (dev) { strlcpy(uaddr->sa_data, dev->name, 15); dev_put(dev); @@ -1160,7 +1160,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(sk->sk_net, po->ifindex); + dev = dev_get_by_index(sock_net(sk), po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1212,7 +1212,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) rtnl_lock(); err = -ENODEV; - dev = __dev_get_by_index(sk->sk_net, mreq->mr_ifindex); + dev = __dev_get_by_index(sock_net(sk), mreq->mr_ifindex); if (!dev) goto done; @@ -1266,7 +1266,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(sk->sk_net, ml->ifindex); + dev = dev_get_by_index(sock_net(sk), ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); @@ -1294,7 +1294,7 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(sk->sk_net, ml->ifindex)) != NULL) { + if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } @@ -1540,7 +1540,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -ENOIOCTLCMD; return inet_dgram_ops.ioctl(sock, cmd, arg); #endif diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 1a7f143cf741..92d85c38e4d2 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -551,7 +551,7 @@ static struct sock *rose_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(osk->sk_net, PF_ROSE, GFP_ATOMIC, &rose_proto); + sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto); if (sk == NULL) return NULL; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 0b8eb235bc13..74e662cbb2c5 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -951,7 +951,7 @@ done: static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_ACT_MAX + 1]; u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = 0, ovr = 0; @@ -1029,7 +1029,7 @@ find_dump_kind(struct nlmsghdr *n) static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); struct nlattr *nest; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 0fbedcabf111..1086df7478bc 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -118,7 +118,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp) static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; struct tcmsg *t; u32 protocol; @@ -389,7 +389,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int t; int s_t; struct net_device *dev; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 7e3c048ba9b1..15b91a9ee8e8 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -605,7 +605,7 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -674,7 +674,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm; struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -893,7 +893,7 @@ err_out: static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, q_idx; int s_idx, s_q_idx; struct net_device *dev; @@ -945,7 +945,7 @@ done: static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -1139,7 +1139,7 @@ static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walk static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int t; int s_t; struct net_device *dev; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index dc71d0d83753..036bfcc8d15b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -636,7 +636,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; - newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot); + newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot); if (!newsk) goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 2faa0d8839eb..5aea91137fbb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -554,7 +554,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, { struct inet_sock *inet = inet_sk(sk); struct inet_sock *newinet; - struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL, + struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL, sk->sk_prot); if (!newsk) diff --git a/net/socket.c b/net/socket.c index 9d3fbfbc8535..79e5382fd110 100644 --- a/net/socket.c +++ b/net/socket.c @@ -857,7 +857,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) sock = file->private_data; sk = sock->sk; - net = sk->sk_net; + net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { err = dev_ioctl(net, cmd, argp); } else @@ -1375,7 +1375,7 @@ asmlinkage long sys_listen(int fd, int backlog) sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { - somaxconn = sock->sk->sk_net->sysctl_somaxconn; + somaxconn = sock_net(sock->sk)->sysctl_somaxconn; if ((unsigned)backlog > somaxconn) backlog = somaxconn; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3220d5cb5b5d..ae45df060e3a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1375,7 +1375,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } buf = skb_peek(&sock->sk->sk_receive_queue); - res = tipc_create(sock->sk->sk_net, newsock, 0); + res = tipc_create(sock_net(sock->sk), newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ae584356852c..cb9d0cb5f270 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -252,7 +252,7 @@ static struct sock *__unix_find_socket_byname(struct net *net, sk_for_each(s, node, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); - if (s->sk_net != net) + if (sock_net(s) != net) continue; if (u->addr->len == len && @@ -289,7 +289,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->dentry; - if (s->sk_net != net) + if (sock_net(s) != net) continue; if(dentry && dentry->d_inode == i) @@ -654,7 +654,7 @@ static int unix_release(struct socket *sock) static int unix_autobind(struct socket *sock) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); static u32 ordernum = 1; struct unix_address * addr; @@ -758,7 +758,7 @@ fail: static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct dentry * dentry = NULL; @@ -899,7 +899,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr; struct sock *other; unsigned hash; @@ -996,7 +996,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, { struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk), *newu, *otheru; struct sock *newsk = NULL; struct sock *other = NULL; @@ -1025,7 +1025,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, err = -ENOMEM; /* create new sock for complete connection */ - newsk = unix_create1(sk->sk_net, NULL); + newsk = unix_create1(sock_net(sk), NULL); if (newsk == NULL) goto out; @@ -1312,7 +1312,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, { struct sock_iocb *siocb = kiocb_to_siocb(kiocb); struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=msg->msg_name; struct sock *other = NULL; @@ -2022,7 +2022,7 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) struct sock *s; for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (s->sk_net != iter->p.net) + if (sock_net(s) != iter->p.net) continue; if (off == pos) return s; @@ -2050,7 +2050,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sk->sk_net != iter->p.net)) + while (sk && (sock_net(sk) != iter->p.net)) sk = next_unix_socket(&iter->i, sk); return sk; } diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 7a46ea73fe2d..6ba67c523c16 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -549,7 +549,7 @@ static struct sock *x25_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) goto out; - if ((sk = x25_alloc_socket(osk->sk_net)) == NULL) + if ((sk = x25_alloc_socket(sock_net(osk))) == NULL) goto out; x25 = x25_sk(sk); -- cgit v1.2.3 From 1218854afa6f659be90b748cf1bc7badee954a35 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 02:36:06 +0900 Subject: [NET] NETNS: Omit seq_net_private->net without CONFIG_NET_NS. Without CONFIG_NET_NS, no namespace other than &init_net exists, no need to store net in seq_net_private. Signed-off-by: YOSHIFUJI Hideaki --- fs/proc/proc_net.c | 6 +++--- include/linux/seq_file.h | 7 +++++++ net/core/neighbour.c | 8 ++++---- net/ipv4/fib_hash.c | 5 ++--- net/ipv4/fib_trie.c | 13 ++++++------- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 29 +++++++++++++++-------------- net/ipv6/addrconf.c | 4 ++-- net/ipv6/mcast.c | 4 ++-- net/netfilter/x_tables.c | 4 ++-- net/netlink/af_netlink.c | 6 +++--- net/unix/af_unix.c | 10 +++++----- 12 files changed, 53 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 4caa5f774fb7..13cd7835d0df 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -44,7 +44,9 @@ int seq_open_net(struct inode *ino, struct file *f, put_net(net); return -ENOMEM; } +#ifdef CONFIG_NET_NS p->net = net; +#endif return 0; } EXPORT_SYMBOL_GPL(seq_open_net); @@ -52,12 +54,10 @@ EXPORT_SYMBOL_GPL(seq_open_net); int seq_release_net(struct inode *ino, struct file *f) { struct seq_file *seq; - struct seq_net_private *p; seq = f->private_data; - p = seq->private; - put_net(p->net); + put_net(seq_file_net(seq)); seq_release_private(ino, f); return 0; } diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 67c2563961f3..d870a8253769 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -5,6 +5,7 @@ #include #include #include +#include struct seq_operations; struct file; @@ -64,7 +65,9 @@ extern struct list_head *seq_list_next(void *v, struct list_head *head, struct net; struct seq_net_private { +#ifdef CONFIG_NET_NS struct net *net; +#endif }; int seq_open_net(struct inode *, struct file *, @@ -72,7 +75,11 @@ int seq_open_net(struct inode *, struct file *, int seq_release_net(struct inode *, struct file *); static inline struct net *seq_file_net(struct seq_file *seq) { +#ifdef CONFIG_NET_NS return ((struct seq_net_private *)seq->private)->net; +#else + return &init_net; +#endif } #endif diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 065fbac7ecd3..b8d491fb4b42 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2145,7 +2145,7 @@ EXPORT_SYMBOL(__neigh_for_each_release); static struct neighbour *neigh_get_first(struct seq_file *seq) { struct neigh_seq_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; struct neighbour *n = NULL; int bucket = state->bucket; @@ -2186,7 +2186,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, loff_t *pos) { struct neigh_seq_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; if (state->neigh_sub_iter) { @@ -2246,7 +2246,7 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) { struct neigh_seq_state *state = seq->private; - struct net * net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; struct pneigh_entry *pn = NULL; int bucket = state->bucket; @@ -2269,7 +2269,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, loff_t *pos) { struct neigh_seq_state *state = seq->private; - struct net * net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; pn = pn->next; diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 8d58d85dfac6..02088deb0461 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -821,7 +821,7 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) struct fib_table *main_table; struct fn_hash *table; - main_table = fib_get_table(iter->p.net, RT_TABLE_MAIN); + main_table = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); table = (struct fn_hash *)main_table->tb_data; iter->bucket = 0; @@ -959,11 +959,10 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos) static void *fib_seq_start(struct seq_file *seq, loff_t *pos) __acquires(fib_hash_lock) { - struct fib_iter_state *iter = seq->private; void *v = NULL; read_lock(&fib_hash_lock); - if (fib_get_table(iter->p.net, RT_TABLE_MAIN)) + if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN)) v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; return v; } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ce6cb34e28e1..9e491e70e855 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2279,9 +2279,10 @@ static const struct file_operations fib_triestat_fops = { .release = fib_triestat_seq_release, }; -static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) +static struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) { - struct net *net = iter->p.net; + struct fib_trie_iter *iter = seq->private; + struct net *net = seq_file_net(seq); loff_t idx = 0; unsigned int h; @@ -2309,16 +2310,14 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) { - struct fib_trie_iter *iter = seq->private; - rcu_read_lock(); - return fib_trie_get_idx(iter, *pos); + return fib_trie_get_idx(seq, *pos); } static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct fib_trie_iter *iter = seq->private; - struct net *net = iter->p.net; + struct net *net = seq_file_net(seq); struct fib_table *tb = iter->tb; struct hlist_node *tb_node; unsigned int h; @@ -2513,7 +2512,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) struct fib_table *tb; rcu_read_lock(); - tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); + tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); if (!tb) return NULL; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index be19a4048d7c..25dc8b38cac3 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -856,7 +856,7 @@ static struct sock *raw_get_first(struct seq_file *seq) struct hlist_node *node; sk_for_each(sk, node, &state->h->ht[state->bucket]) - if (sock_net(sk) == state->p.net) + if (sock_net(sk) == seq_file_net(seq)) goto found; } sk = NULL; @@ -872,7 +872,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sock_net(sk) != state->p.net); + } while (sk && sock_net(sk) != seq_file_net(seq)); if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { sk = sk_head(&state->h->ht[state->bucket]); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 194f5cca3121..eab8d75e5222 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -276,15 +276,16 @@ struct rt_cache_iter_state { int genid; }; -static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) +static struct rtable *rt_cache_get_first(struct seq_file *seq) { + struct rt_cache_iter_state *st = seq->private; struct rtable *r = NULL; for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { rcu_read_lock_bh(); r = rcu_dereference(rt_hash_table[st->bucket].chain); while (r) { - if (dev_net(r->u.dst.dev) == st->p.net && + if (dev_net(r->u.dst.dev) == seq_file_net(seq) && r->rt_genid == st->genid) return r; r = rcu_dereference(r->u.dst.rt_next); @@ -294,9 +295,10 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) return r; } -static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st, +static struct rtable *__rt_cache_get_next(struct seq_file *seq, struct rtable *r) { + struct rt_cache_iter_state *st = seq->private; r = r->u.dst.rt_next; while (!r) { rcu_read_unlock_bh(); @@ -308,11 +310,12 @@ static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st, return rcu_dereference(r); } -static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, +static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r) { - while ((r = __rt_cache_get_next(st, r)) != NULL) { - if (dev_net(r->u.dst.dev) != st->p.net) + struct rt_cache_iter_state *st = seq->private; + while ((r = __rt_cache_get_next(seq, r)) != NULL) { + if (dev_net(r->u.dst.dev) != seq_file_net(seq)) continue; if (r->rt_genid == st->genid) break; @@ -320,12 +323,12 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, return r; } -static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos) +static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos) { - struct rtable *r = rt_cache_get_first(st); + struct rtable *r = rt_cache_get_first(seq); if (r) - while (pos && (r = rt_cache_get_next(st, r))) + while (pos && (r = rt_cache_get_next(seq, r))) --pos; return pos ? NULL : r; } @@ -333,9 +336,8 @@ static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t po static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) { struct rt_cache_iter_state *st = seq->private; - if (*pos) - return rt_cache_get_idx(st, *pos - 1); + return rt_cache_get_idx(seq, *pos - 1); st->genid = atomic_read(&rt_genid); return SEQ_START_TOKEN; } @@ -343,12 +345,11 @@ static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct rtable *r; - struct rt_cache_iter_state *st = seq->private; if (v == SEQ_START_TOKEN) - r = rt_cache_get_first(st); + r = rt_cache_get_first(seq); else - r = rt_cache_get_next(st, v); + r = rt_cache_get_next(seq, v); ++*pos; return r; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2c90f145cbb..ac5d4f4b6312 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2766,7 +2766,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) { struct inet6_ifaddr *ifa = NULL; struct if6_iter_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; @@ -2782,7 +2782,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa) { struct if6_iter_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); ifa = ifa->lst_next; try_again: diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 20a3d8e2f6c6..d810cff818cf 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2355,7 +2355,7 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) { struct ifmcaddr6 *im = NULL; struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); state->idev = NULL; for_each_netdev(net, state->dev) { @@ -2486,7 +2486,7 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) struct ip6_sf_list *psf = NULL; struct ifmcaddr6 *im = NULL; struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); state->idev = NULL; state->im = NULL; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a6792089fcf9..0bd95680a494 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -727,7 +727,7 @@ struct xt_names_priv { static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) { struct xt_names_priv *priv = seq->private; - struct net *net = priv->p.net; + struct net *net = seq_file_net(seq); int af = priv->af; mutex_lock(&xt[af].mutex); @@ -737,7 +737,7 @@ static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct xt_names_priv *priv = seq->private; - struct net *net = priv->p.net; + struct net *net = seq_file_net(seq); int af = priv->af; return seq_list_next(v, &net->xt.tables[af], pos); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 712a7bff8560..1d16d95dfaaf 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1758,7 +1758,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { - if (sock_net(s) != iter->p.net) + if (sock_net(s) != seq_file_net(seq)) continue; if (off == pos) { iter->link = i; @@ -1794,7 +1794,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) s = v; do { s = sk_next(s); - } while (s && (sock_net(s) != iter->p.net)); + } while (s && sock_net(s) != seq_file_net(seq)); if (s) return s; @@ -1806,7 +1806,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && sock_net(s) != iter->p.net) + while (s && sock_net(s) != seq_file_net(seq)) s = sk_next(s); if (s) { iter->link = i; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index cb9d0cb5f270..4a4793051bcb 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2016,13 +2016,14 @@ struct unix_iter_state { struct seq_net_private p; int i; }; -static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) +static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) { + struct unix_iter_state *iter = seq->private; loff_t off = 0; struct sock *s; for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (sock_net(s) != iter->p.net) + if (sock_net(s) != seq_file_net(seq)) continue; if (off == pos) return s; @@ -2035,9 +2036,8 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) static void *unix_seq_start(struct seq_file *seq, loff_t *pos) __acquires(unix_table_lock) { - struct unix_iter_state *iter = seq->private; spin_lock(&unix_table_lock); - return *pos ? unix_seq_idx(iter, *pos - 1) : ((void *) 1); + return *pos ? unix_seq_idx(seq, *pos - 1) : ((void *) 1); } static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) @@ -2050,7 +2050,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sock_net(sk) != iter->p.net)) + while (sk && (sock_net(sk) != seq_file_net(seq))) sk = next_unix_socket(&iter->i, sk); return sk; } -- cgit v1.2.3 From b8beedd25d3913d45b8330a08ab88fdf90eb54b8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:09:33 -0700 Subject: [NETFILTER]: Add nf_inet_addr_cmp() Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 9 +++++++++ include/net/netfilter/nf_conntrack_tuple.h | 15 +++------------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index f0680c2bee73..89e6c72ad295 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -61,6 +61,15 @@ union nf_inet_addr { #ifdef __KERNEL__ #ifdef CONFIG_NETFILTER +static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1, + const union nf_inet_addr *a2) +{ + return a1->all[0] == a2->all[0] && + a1->all[1] == a2->all[1] && + a1->all[2] == a2->all[2] && + a1->all[3] == a2->all[3]; +} + extern void netfilter_init(void); /* Largest hook number + 1 */ diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index d9b53dd601ad..168c91754d89 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -163,10 +163,7 @@ struct nf_conntrack_tuple_hash static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, const struct nf_conntrack_tuple *t2) { - return (t1->src.u3.all[0] == t2->src.u3.all[0] && - t1->src.u3.all[1] == t2->src.u3.all[1] && - t1->src.u3.all[2] == t2->src.u3.all[2] && - t1->src.u3.all[3] == t2->src.u3.all[3] && + return (nf_inet_addr_cmp(&t1->src.u3, &t2->src.u3) && t1->src.u.all == t2->src.u.all && t1->src.l3num == t2->src.l3num); } @@ -174,10 +171,7 @@ static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, static inline int __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, const struct nf_conntrack_tuple *t2) { - return (t1->dst.u3.all[0] == t2->dst.u3.all[0] && - t1->dst.u3.all[1] == t2->dst.u3.all[1] && - t1->dst.u3.all[2] == t2->dst.u3.all[2] && - t1->dst.u3.all[3] == t2->dst.u3.all[3] && + return (nf_inet_addr_cmp(&t1->dst.u3, &t2->dst.u3) && t1->dst.u.all == t2->dst.u.all && t1->dst.protonum == t2->dst.protonum); } @@ -192,10 +186,7 @@ static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1, const struct nf_conntrack_tuple_mask *m2) { - return (m1->src.u3.all[0] == m2->src.u3.all[0] && - m1->src.u3.all[1] == m2->src.u3.all[1] && - m1->src.u3.all[2] == m2->src.u3.all[2] && - m1->src.u3.all[3] == m2->src.u3.all[3] && + return (nf_inet_addr_cmp(&m1->src.u3, &m2->src.u3) && m1->src.u.all == m2->src.u.all); } -- cgit v1.2.3 From 2a6cfb22ae002330d445f734668d9158db9e90de Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:16:54 -0700 Subject: [NETFILTER]: nf_conntrack_sip: adjust dptr and datalen after packet mangling After mangling the packet, the pointer to the data and the length of the data portion may change and need to be adjusted. Use double data pointers and a pointer to the length everywhere and add a helper function to the NAT helper for performing the adjustments. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 6 +- net/ipv4/netfilter/nf_nat_sip.c | 91 ++++++++++++++++-------------- net/netfilter/nf_conntrack_sip.c | 14 +++-- 3 files changed, 60 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 8e5ce1ca7bfc..9d0dbfb26300 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -24,11 +24,13 @@ enum sip_header_pos { extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr); + const char **dptr, + unsigned int *datalen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr); + const char **dptr, + unsigned int *datalen); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 84d8b4982cdf..e77122e65283 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -60,15 +60,35 @@ static void addr_map_init(const struct nf_conn *ct, struct addr_map *map) } } +static unsigned int mangle_packet(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int matchoff, unsigned int matchlen, + const char *buffer, unsigned int buflen) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + + if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen, + buffer, buflen)) + return 0; + + /* Reload data pointer and adjust datalen value */ + *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); + *datalen += buflen - matchlen; + return 1; +} + static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, size_t dlen, + struct nf_conn *ct, + const char **dptr, unsigned int *datalen, enum sip_header_pos pos, struct addr_map *map) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff, addrlen; char *addr; - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) return 1; if ((matchlen == map->addr[dir].srciplen || @@ -84,26 +104,19 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, } else return 1; - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, addr, addrlen)) - return 0; - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); - return 1; - + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + addr, addrlen); } static unsigned int ip_nat_sip(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr) + const char **dptr, unsigned int *datalen) { enum sip_header_pos pos; struct addr_map map; - int dataoff, datalen; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); - datalen = skb->len - dataoff; - if (datalen < sizeof("SIP/2.0") - 1) + if (*datalen < sizeof("SIP/2.0") - 1) return NF_ACCEPT; addr_map_init(ct, &map); @@ -115,7 +128,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, * The "userinfo" and "@" components of the SIP URI MUST NOT * be present. */ - if (datalen >= sizeof("REGISTER") - 1 && + if (*datalen >= sizeof("REGISTER") - 1 && strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) pos = POS_REG_REQ_URI; else @@ -136,51 +149,45 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, static unsigned int mangle_sip_packet(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr, size_t dlen, + const char **dptr, unsigned int *datalen, char *buffer, int bufflen, enum sip_header_pos pos) { unsigned int matchlen, matchoff; - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; - - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) return 0; - /* We need to reload this. Thanks Patrick. */ - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); - return 1; + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, bufflen); } static int mangle_content_len(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char *dptr) + const char **dptr, unsigned int *datalen) { - unsigned int dataoff, matchoff, matchlen; + unsigned int matchoff, matchlen; char buffer[sizeof("65536")]; int bufflen; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); - /* Get actual SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ - int c_len = skb->len - dataoff - matchoff + 2; + int c_len = *datalen - matchoff + 2; /* Now, update SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); - return nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, - buffer, bufflen); + return mangle_packet(skb, dptr, datalen, + matchoff, matchlen, + buffer, bufflen); } } return 0; @@ -190,30 +197,28 @@ static unsigned int mangle_sdp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, __be32 newip, u_int16_t port, - const char *dptr) + const char **dptr, unsigned int *datalen) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; - unsigned int dataoff, bufflen; - - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); + unsigned int bufflen; /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_OWNER_IP4)) return 0; - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_CONNECTION_IP4)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_MEDIA)) return 0; - return mangle_content_len(skb, ctinfo, ct, dptr); + return mangle_content_len(skb, ctinfo, ct, dptr, datalen); } static void ip_nat_sdp_expect(struct nf_conn *ct, @@ -242,7 +247,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, static unsigned int ip_nat_sdp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr) + const char **dptr, unsigned int *datalen) { struct nf_conn *ct = exp->master; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -275,7 +280,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, if (port == 0) return NF_DROP; - if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) { + if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { nf_ct_unexpect_related(exp); return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 016e1c1aafe4..fa0d5599ff24 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -39,13 +39,15 @@ MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr) __read_mostly; + const char **dptr, + unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr) __read_mostly; + const char **dptr, + unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int digits_len(const struct nf_conn *, const char *, const char *, int *); @@ -369,7 +371,7 @@ static int set_expected_rtp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, union nf_inet_addr *addr, __be16 port, - const char *dptr) + const char **dptr, unsigned int *datalen) { struct nf_conntrack_expect *exp; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -386,7 +388,7 @@ static int set_expected_rtp(struct sk_buff *skb, nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, ctinfo, exp, dptr); + ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen); else { if (nf_ct_expect_related(exp) != 0) ret = NF_DROP; @@ -429,7 +431,7 @@ static int sip_help(struct sk_buff *skb, nf_nat_sip = rcu_dereference(nf_nat_sip_hook); if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) { + if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) { ret = NF_DROP; goto out; } @@ -466,7 +468,7 @@ static int sip_help(struct sk_buff *skb, goto out; } ret = set_expected_rtp(skb, ct, ctinfo, &addr, - htons(port), dptr); + htons(port), &dptr, &datalen); } } out: -- cgit v1.2.3 From 212440a7d04a12ee13787afecc6c86c7fc4e6184 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:17:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: remove redundant function arguments The conntrack reference and ctinfo can be derived from the packet. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 7 ++--- net/ipv4/netfilter/nf_nat_sip.c | 49 +++++++++++++++--------------- net/netfilter/nf_conntrack_sip.c | 24 ++++++--------- 3 files changed, 37 insertions(+), 43 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 9d0dbfb26300..b94de3d60303 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -22,15 +22,12 @@ enum sip_header_pos { }; extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, const char **dptr, - unsigned int *datalen); + unsigned int *datalen, + struct nf_conntrack_expect *exp); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index e77122e65283..acaa7d4569fa 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -78,11 +78,12 @@ static unsigned int mangle_packet(struct sk_buff *skb, return 1; } -static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, - struct nf_conn *ct, +static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, enum sip_header_pos pos, struct addr_map *map) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff, addrlen; char *addr; @@ -109,10 +110,10 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, } static unsigned int ip_nat_sip(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum sip_header_pos pos; struct addr_map map; @@ -134,25 +135,25 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, else pos = POS_REQ_URI; - if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map)) + if (!map_sip_addr(skb, dptr, datalen, pos, &map)) return NF_DROP; } - if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_TO, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(skb, dptr, datalen, POS_TO, &map) || + !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map)) return NF_DROP; return NF_ACCEPT; } static unsigned int mangle_sip_packet(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen, char *buffer, int bufflen, enum sip_header_pos pos) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, @@ -164,10 +165,10 @@ static unsigned int mangle_sip_packet(struct sk_buff *skb, } static int mangle_content_len(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchoff, matchlen; char buffer[sizeof("65536")]; int bufflen; @@ -204,21 +205,21 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_OWNER_IP4)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_OWNER_IP4)) return 0; - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_CONNECTION_IP4)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_CONNECTION_IP4)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_MEDIA)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_MEDIA)) return 0; - return mangle_content_len(skb, ctinfo, ct, dptr, datalen); + return mangle_content_len(skb, dptr, datalen); } static void ip_nat_sdp_expect(struct nf_conn *ct, @@ -245,11 +246,11 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + struct nf_conntrack_expect *exp) { - struct nf_conn *ct = exp->master; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); __be32 newip; u_int16_t port; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index fa0d5599ff24..38e1e7a05334 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -37,17 +37,14 @@ module_param(sip_timeout, uint, 0600); MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, const char **dptr, - unsigned int *datalen) __read_mostly; + unsigned int *datalen, + struct nf_conntrack_expect *exp) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int digits_len(const struct nf_conn *, const char *, const char *, int *); @@ -367,13 +364,12 @@ int ct_sip_get_info(const struct nf_conn *ct, EXPORT_SYMBOL_GPL(ct_sip_get_info); static int set_expected_rtp(struct sk_buff *skb, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - union nf_inet_addr *addr, - __be16 port, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + union nf_inet_addr *addr, __be16 port) { struct nf_conntrack_expect *exp; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); int family = ct->tuplehash[!dir].tuple.src.l3num; int ret; @@ -388,7 +384,7 @@ static int set_expected_rtp(struct sk_buff *skb, nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen); + ret = nf_nat_sdp(skb, dptr, datalen, exp); else { if (nf_ct_expect_related(exp) != 0) ret = NF_DROP; @@ -431,7 +427,7 @@ static int sip_help(struct sk_buff *skb, nf_nat_sip = rcu_dereference(nf_nat_sip_hook); if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) { + if (!nf_nat_sip(skb, &dptr, &datalen)) { ret = NF_DROP; goto out; } @@ -467,8 +463,8 @@ static int sip_help(struct sk_buff *skb, ret = NF_DROP; goto out; } - ret = set_expected_rtp(skb, ct, ctinfo, &addr, - htons(port), &dptr, &datalen); + ret = set_expected_rtp(skb, &dptr, &datalen, + &addr, htons(port)); } } out: -- cgit v1.2.3 From 3e9b4600b4e71beaa9d943251bfe9c25f6a97b8c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:17:55 -0700 Subject: [NETFILTER]: nf_conntrack_sip: add seperate SDP header parsing function SDP and SIP headers are quite different, SIP can have continuation lines, leading and trailing whitespace after the colon and is mostly case-insensitive while SDP headers always begin on a new line and are followed by an equal sign and the value, without any whitespace. Introduce new SDP header parsing function and convert all users that used the SIP header parsing function. This will allow to properly deal with the special SIP cases in the SIP header parsing function later. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 49 +++++++-- net/ipv4/netfilter/nf_nat_sip.c | 69 ++++++------- net/netfilter/nf_conntrack_sip.c | 159 +++++++++++++++++------------ 3 files changed, 169 insertions(+), 108 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index b94de3d60303..9131cbc9b9de 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -13,12 +13,42 @@ enum sip_header_pos { POS_VIA, POS_CONTACT, POS_CONTENT, - POS_MEDIA, - POS_OWNER_IP4, - POS_CONNECTION_IP4, - POS_OWNER_IP6, - POS_CONNECTION_IP6, - POS_SDP_HEADER, +}; + +struct sip_header { + const char *name; + const char *cname; + const char *search; + unsigned int len; + unsigned int clen; + unsigned int slen; + int (*match_len)(const struct nf_conn *ct, + const char *dptr, const char *limit, + int *shift); +}; + +#define __SIP_HDR(__name, __cname, __search, __match) \ +{ \ + .name = (__name), \ + .len = sizeof(__name) - 1, \ + .cname = (__cname), \ + .clen = (__cname) ? sizeof(__cname) - 1 : 0, \ + .search = (__search), \ + .slen = (__search) ? sizeof(__search) - 1 : 0, \ + .match_len = (__match), \ +} + +#define SDP_HDR(__name, __search, __match) \ + __SIP_HDR(__name, NULL, __search, __match) + +enum sdp_header_types { + SDP_HDR_UNSPEC, + SDP_HDR_VERSION, + SDP_HDR_OWNER_IP4, + SDP_HDR_CONNECTION_IP4, + SDP_HDR_OWNER_IP6, + SDP_HDR_CONNECTION_IP6, + SDP_HDR_MEDIA, }; extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, @@ -36,5 +66,12 @@ extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, size_t needle_len, size_t haystack_len, int case_sensitive); + +extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen); + #endif /* __KERNEL__ */ #endif /* __NF_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index dd1b2d86deee..aa8a4f492baf 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -147,51 +147,46 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, return NF_ACCEPT; } -static unsigned int mangle_sip_packet(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - char *buffer, int bufflen, - enum sip_header_pos pos) +static int mangle_content_len(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - unsigned int matchlen, matchoff; + unsigned int matchoff, matchlen; + char buffer[sizeof("65536")]; + int buflen, c_len; + /* Get actual SDP length */ + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + SDP_HDR_VERSION, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return 0; + c_len = *datalen - matchoff + strlen("v="); + + /* Now, update SDP length */ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) + POS_CONTENT) <= 0) return 0; + buflen = sprintf(buffer, "%u", c_len); return mangle_packet(skb, dptr, datalen, matchoff, matchlen, - buffer, bufflen); + buffer, buflen); } -static int mangle_content_len(struct sk_buff *skb, - const char **dptr, unsigned int *datalen) +static unsigned mangle_sdp_packet(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + enum sdp_header_types type, + char *buffer, int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - unsigned int matchoff, matchlen; - char buffer[sizeof("65536")]; - int bufflen; + unsigned int matchlen, matchoff; - /* Get actual SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, - &matchlen, POS_SDP_HEADER) > 0) { - - /* since ct_sip_get_info() give us a pointer passing 'v=' - we need to add 2 bytes in this count. */ - int c_len = *datalen - matchoff + 2; - - /* Now, update SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, - &matchlen, POS_CONTENT) > 0) { - - bufflen = sprintf(buffer, "%u", c_len); - return mangle_packet(skb, dptr, datalen, - matchoff, matchlen, - buffer, bufflen); - } - } - return 0; + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return 0; + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen); } static unsigned int mangle_sdp(struct sk_buff *skb, @@ -205,18 +200,18 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_OWNER_IP4)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, + buffer, bufflen)) return 0; - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_CONNECTION_IP4)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, + buffer, bufflen)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_MEDIA)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, + buffer, bufflen)) return 0; return mangle_content_len(skb, dptr, datalen); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index cf19a7082a75..801fcb3c749f 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -124,66 +124,6 @@ static const struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof(":") - 1, .match_len = skp_digits_len }, - [POS_MEDIA] = { /* SDP media info */ - .case_sensitive = 1, - .lname = "\nm=", - .lnlen = sizeof("\nm=") - 1, - .sname = "\rm=", - .snlen = sizeof("\rm=") - 1, - .ln_str = "audio ", - .ln_strlen = sizeof("audio ") - 1, - .match_len = digits_len - }, - [POS_OWNER_IP4] = { /* SDP owner address*/ - .case_sensitive = 1, - .lname = "\no=", - .lnlen = sizeof("\no=") - 1, - .sname = "\ro=", - .snlen = sizeof("\ro=") - 1, - .ln_str = "IN IP4 ", - .ln_strlen = sizeof("IN IP4 ") - 1, - .match_len = epaddr_len - }, - [POS_CONNECTION_IP4] = {/* SDP connection info */ - .case_sensitive = 1, - .lname = "\nc=", - .lnlen = sizeof("\nc=") - 1, - .sname = "\rc=", - .snlen = sizeof("\rc=") - 1, - .ln_str = "IN IP4 ", - .ln_strlen = sizeof("IN IP4 ") - 1, - .match_len = epaddr_len - }, - [POS_OWNER_IP6] = { /* SDP owner address*/ - .case_sensitive = 1, - .lname = "\no=", - .lnlen = sizeof("\no=") - 1, - .sname = "\ro=", - .snlen = sizeof("\ro=") - 1, - .ln_str = "IN IP6 ", - .ln_strlen = sizeof("IN IP6 ") - 1, - .match_len = epaddr_len - }, - [POS_CONNECTION_IP6] = {/* SDP connection info */ - .case_sensitive = 1, - .lname = "\nc=", - .lnlen = sizeof("\nc=") - 1, - .sname = "\rc=", - .snlen = sizeof("\rc=") - 1, - .ln_str = "IN IP6 ", - .ln_strlen = sizeof("IN IP6 ") - 1, - .match_len = epaddr_len - }, - [POS_SDP_HEADER] = { /* SDP version header */ - .case_sensitive = 1, - .lname = "\nv=", - .lnlen = sizeof("\nv=") - 1, - .sname = "\rv=", - .snlen = sizeof("\rv=") - 1, - .ln_str = "=", - .ln_strlen = sizeof("=") - 1, - .match_len = digits_len - } }; /* get line length until first CR or LF seen. */ @@ -363,6 +303,92 @@ int ct_sip_get_info(const struct nf_conn *ct, } EXPORT_SYMBOL_GPL(ct_sip_get_info); +/* SDP header parsing: a SDP session description contains an ordered set of + * headers, starting with a section containing general session parameters, + * optionally followed by multiple media descriptions. + * + * SDP headers always start at the beginning of a line. According to RFC 2327: + * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should + * be tolerant and also accept records terminated with a single newline + * character". We handle both cases. + */ +static const struct sip_header ct_sdp_hdrs[] = { + [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), + [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), + [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), + [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), + [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), + [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len), +}; + +/* Linear string search within SDP header values */ +static const char *ct_sdp_header_search(const char *dptr, const char *limit, + const char *needle, unsigned int len) +{ + for (limit -= len; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') + break; + if (strncmp(dptr, needle, len) == 0) + return dptr; + } + return NULL; +} + +/* Locate a SDP header (optionally a substring within the header value), + * optionally stopping at the first occurence of the term header, parse + * it and return the offset and length of the data we're interested in. + */ +int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sdp_hdrs[type]; + const struct sip_header *thdr = &ct_sdp_hdrs[term]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + for (dptr += dataoff; dptr < limit; dptr++) { + /* Find beginning of line */ + if (*dptr != '\r' && *dptr != '\n') + continue; + if (++dptr >= limit) + break; + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + break; + } + + if (term != SDP_HDR_UNSPEC && + limit - dptr >= thdr->len && + strnicmp(dptr, thdr->name, thdr->len) == 0) + break; + else if (limit - dptr >= hdr->len && + strnicmp(dptr, hdr->name, hdr->len) == 0) + dptr += hdr->len; + else + continue; + + *matchoff = dptr - start; + if (hdr->search) { + dptr = ct_sdp_header_search(dptr, limit, hdr->search, + hdr->slen); + if (!dptr) + return -1; + dptr += hdr->slen; + } + + *matchlen = hdr->match_len(ct, dptr, limit, &shift); + if (!*matchlen) + return -1; + *matchoff = dptr - start + shift; + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); + static int set_expected_rtp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, union nf_inet_addr *addr, __be16 port) @@ -408,7 +434,7 @@ static int sip_help(struct sk_buff *skb, int ret = NF_ACCEPT; unsigned int matchoff, matchlen; u_int16_t port; - enum sip_header_pos pos; + enum sdp_header_types type; typeof(nf_nat_sip_hook) nf_nat_sip; /* No Data ? */ @@ -446,8 +472,10 @@ static int sip_help(struct sk_buff *skb, goto out; } /* Get address and port from SDP packet. */ - pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6; - if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) { + type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; + if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC, + &matchoff, &matchlen) > 0) { /* We'll drop only if there are parse problems. */ if (!parse_addr(ct, dptr + matchoff, NULL, &addr, @@ -455,8 +483,9 @@ static int sip_help(struct sk_buff *skb, ret = NF_DROP; goto out; } - if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, - POS_MEDIA) > 0) { + if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &matchoff, &matchlen) > 0) { port = simple_strtoul(dptr + matchoff, NULL, 10); if (port < 1024) { -- cgit v1.2.3 From ac3677406d4e36e86b1eb5a453997a3b3e0c089a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:18:40 -0700 Subject: [NETFILTER]: nf_conntrack_sip: kill request URI "header" definitions The request URI is not a header and needs to be treated differently than real SIP headers. Add a seperate function for parsing it and get rid of the POS_REQ_URI/POS_REG_REQ_URI definitions. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 5 ++- net/ipv4/netfilter/nf_nat_sip.c | 46 +++++++++++---------- net/netfilter/nf_conntrack_sip.c | 64 +++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 9131cbc9b9de..480b26f40ce4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -6,8 +6,6 @@ #define SIP_TIMEOUT 3600 enum sip_header_pos { - POS_REG_REQ_URI, - POS_REQ_URI, POS_FROM, POS_TO, POS_VIA, @@ -59,6 +57,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, unsigned int *datalen, struct nf_conntrack_expect *exp); +extern int ct_sip_parse_request(const struct nf_conn *ct, + const char *dptr, unsigned int datalen, + unsigned int *matchoff, unsigned int *matchlen); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, enum sip_header_pos pos); diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index aa8a4f492baf..60151b5901a5 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -78,20 +78,17 @@ static unsigned int mangle_packet(struct sk_buff *skb, return 1; } -static int map_sip_addr(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - enum sip_header_pos pos, struct addr_map *map) +static int map_addr(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int matchoff, unsigned int matchlen, + struct addr_map *map) { enum ip_conntrack_info ctinfo; - struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int matchlen, matchoff, addrlen; + unsigned int addrlen; char *addr; - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) - return 1; - if ((matchlen == map->addr[dir].srciplen || matchlen == map->addr[dir].srclen) && strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { @@ -109,13 +106,27 @@ static int map_sip_addr(struct sk_buff *skb, addr, addrlen); } +static int map_sip_addr(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) + return 1; + return map_addr(skb, dptr, datalen, matchoff, matchlen, map); +} + static unsigned int ip_nat_sip(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - enum sip_header_pos pos; struct addr_map map; + unsigned int matchoff, matchlen; if (*datalen < strlen("SIP/2.0")) return NF_ACCEPT; @@ -124,18 +135,9 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { - /* 10.2: Constructing the REGISTER Request: - * - * The "userinfo" and "@" components of the SIP URI MUST NOT - * be present. - */ - if (*datalen >= strlen("REGISTER") && - strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0) - pos = POS_REG_REQ_URI; - else - pos = POS_REQ_URI; - - if (!map_sip_addr(skb, dptr, datalen, pos, &map)) + if (ct_sip_parse_request(ct, *dptr, *datalen, + &matchoff, &matchlen) > 0 && + !map_addr(skb, dptr, datalen, matchoff, matchlen, &map)) return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 801fcb3c749f..bb4396155681 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -65,20 +65,6 @@ struct sip_header_nfo { }; static const struct sip_header_nfo ct_sip_hdrs[] = { - [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .ln_str = ":", - .ln_strlen = sizeof(":") - 1, - .match_len = epaddr_len, - }, - [POS_REQ_URI] = { /* SIP request URI */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .ln_str = "@", - .ln_strlen = sizeof("@") - 1, - .match_len = epaddr_len, - }, [POS_FROM] = { /* SIP From header */ .lname = "From:", .lnlen = sizeof("From:") - 1, @@ -164,6 +150,18 @@ const char *ct_sip_search(const char *needle, const char *haystack, } EXPORT_SYMBOL_GPL(ct_sip_search); +static int string_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = 0; + + while (dptr < limit && isalpha(*dptr)) { + dptr++; + len++; + } + return len; +} + static int digits_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { @@ -258,6 +256,44 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, return epaddr_len(ct, dptr, limit, shift); } +/* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF + * + * and return the offset and length of the address contained in the Request-URI. + */ +int ct_sip_parse_request(const struct nf_conn *ct, + const char *dptr, unsigned int datalen, + unsigned int *matchoff, unsigned int *matchlen) +{ + const char *start = dptr, *limit = dptr + datalen; + unsigned int mlen; + int shift = 0; + + /* Skip method and following whitespace */ + mlen = string_len(ct, dptr, limit, NULL); + if (!mlen) + return 0; + dptr += mlen; + if (++dptr >= limit) + return 0; + + /* Find SIP URI */ + limit -= strlen("sip:"); + for (; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') + return -1; + if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) + break; + } + *matchlen = skp_epaddr_len(ct, dptr, limit, &shift); + if (!*matchlen) + return 0; + *matchoff = dptr - start + shift; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_request); + /* Returns 0 if not found, -1 error parsing. */ int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, -- cgit v1.2.3 From ea45f12a2766dae54e5426a23e8f4bafdbe2782e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:18:57 -0700 Subject: [NETFILTER]: nf_conntrack_sip: parse SIP headers properly Introduce new function for SIP header parsing that properly deals with continuation lines and whitespace in headers and use it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 30 ++-- net/ipv4/netfilter/nf_nat_sip.c | 18 +- net/netfilter/nf_conntrack_sip.c | 271 ++++++++++++++--------------- 3 files changed, 151 insertions(+), 168 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 480b26f40ce4..ccc701422963 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,14 +5,6 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 -enum sip_header_pos { - POS_FROM, - POS_TO, - POS_VIA, - POS_CONTACT, - POS_CONTENT, -}; - struct sip_header { const char *name; const char *cname; @@ -36,9 +28,20 @@ struct sip_header { .match_len = (__match), \ } +#define SIP_HDR(__name, __cname, __search, __match) \ + __SIP_HDR(__name, __cname, __search, __match) + #define SDP_HDR(__name, __search, __match) \ __SIP_HDR(__name, NULL, __search, __match) +enum sip_header_types { + SIP_HDR_FROM, + SIP_HDR_TO, + SIP_HDR_CONTACT, + SIP_HDR_VIA, + SIP_HDR_CONTENT_LENGTH, +}; + enum sdp_header_types { SDP_HDR_UNSPEC, SDP_HDR_VERSION, @@ -60,13 +63,10 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, unsigned int *matchoff, unsigned int *matchlen); -extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, - size_t dlen, unsigned int *matchoff, - unsigned int *matchlen, enum sip_header_pos pos); -extern int ct_sip_lnlen(const char *line, const char *limit); -extern const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len, - int case_sensitive); +extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 60151b5901a5..c13e43862361 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -108,14 +108,14 @@ static int map_addr(struct sk_buff *skb, static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - enum sip_header_pos pos, struct addr_map *map) + enum sip_header_types type, struct addr_map *map) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) + if (ct_sip_get_header(ct, *dptr, 0, *datalen, type, + &matchoff, &matchlen) <= 0) return 1; return map_addr(skb, dptr, datalen, matchoff, matchlen, map); } @@ -141,10 +141,10 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, return NF_DROP; } - if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) || - !map_sip_addr(skb, dptr, datalen, POS_TO, &map) || - !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) || - !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map)) return NF_DROP; return NF_ACCEPT; } @@ -166,8 +166,8 @@ static int mangle_content_len(struct sk_buff *skb, c_len = *datalen - matchoff + strlen("v="); /* Now, update SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - POS_CONTENT) <= 0) + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, + &matchoff, &matchlen) <= 0) return 0; buflen = sprintf(buffer, "%u", c_len); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index bb4396155681..cbc91598acee 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -47,109 +47,6 @@ unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, struct nf_conntrack_expect *exp) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); -static int digits_len(const struct nf_conn *, const char *, const char *, int *); -static int epaddr_len(const struct nf_conn *, const char *, const char *, int *); -static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *); -static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *); - -struct sip_header_nfo { - const char *lname; - const char *sname; - const char *ln_str; - size_t lnlen; - size_t snlen; - size_t ln_strlen; - int case_sensitive; - int (*match_len)(const struct nf_conn *, const char *, - const char *, int *); -}; - -static const struct sip_header_nfo ct_sip_hdrs[] = { - [POS_FROM] = { /* SIP From header */ - .lname = "From:", - .lnlen = sizeof("From:") - 1, - .sname = "\r\nf:", - .snlen = sizeof("\r\nf:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len, - }, - [POS_TO] = { /* SIP To header */ - .lname = "To:", - .lnlen = sizeof("To:") - 1, - .sname = "\r\nt:", - .snlen = sizeof("\r\nt:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len - }, - [POS_VIA] = { /* SIP Via header */ - .lname = "Via:", - .lnlen = sizeof("Via:") - 1, - .sname = "\r\nv:", - .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ - .ln_str = "UDP ", - .ln_strlen = sizeof("UDP ") - 1, - .match_len = epaddr_len, - }, - [POS_CONTACT] = { /* SIP Contact header */ - .lname = "Contact:", - .lnlen = sizeof("Contact:") - 1, - .sname = "\r\nm:", - .snlen = sizeof("\r\nm:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len - }, - [POS_CONTENT] = { /* SIP Content length header */ - .lname = "Content-Length:", - .lnlen = sizeof("Content-Length:") - 1, - .sname = "\r\nl:", - .snlen = sizeof("\r\nl:") - 1, - .ln_str = ":", - .ln_strlen = sizeof(":") - 1, - .match_len = skp_digits_len - }, -}; - -/* get line length until first CR or LF seen. */ -int ct_sip_lnlen(const char *line, const char *limit) -{ - const char *k = line; - - while ((line < limit) && (*line == '\r' || *line == '\n')) - line++; - - while (line < limit) { - if (*line == '\r' || *line == '\n') - break; - line++; - } - return line - k; -} -EXPORT_SYMBOL_GPL(ct_sip_lnlen); - -/* Linear string search, case sensitive. */ -const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len, - int case_sensitive) -{ - const char *limit = haystack + (haystack_len - needle_len); - - while (haystack < limit) { - if (case_sensitive) { - if (strncmp(haystack, needle, needle_len) == 0) - return haystack; - } else { - if (strnicmp(haystack, needle, needle_len) == 0) - return haystack; - } - haystack++; - } - return NULL; -} -EXPORT_SYMBOL_GPL(ct_sip_search); - static int string_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { @@ -173,16 +70,6 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, return len; } -/* get digits length, skipping blank spaces. */ -static int skp_digits_len(const struct nf_conn *ct, const char *dptr, - const char *limit, int *shift) -{ - for (; dptr < limit && *dptr == ' '; dptr++) - (*shift)++; - - return digits_len(ct, dptr, limit, shift); -} - static int parse_addr(const struct nf_conn *ct, const char *cp, const char **endp, union nf_inet_addr *addr, const char *limit) @@ -294,50 +181,146 @@ int ct_sip_parse_request(const struct nf_conn *ct, } EXPORT_SYMBOL_GPL(ct_sip_parse_request); -/* Returns 0 if not found, -1 error parsing. */ -int ct_sip_get_info(const struct nf_conn *ct, - const char *dptr, size_t dlen, - unsigned int *matchoff, - unsigned int *matchlen, - enum sip_header_pos pos) +/* SIP header parsing: SIP headers are located at the beginning of a line, but + * may span several lines, in which case the continuation lines begin with a + * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or + * CRLF, RFC 3261 allows only CRLF, we support both. + * + * Headers are followed by (optionally) whitespace, a colon, again (optionally) + * whitespace and the values. Whitespace in this context means any amount of + * tabs, spaces and continuation lines, which are treated as a single whitespace + * character. + */ +static const struct sip_header ct_sip_hdrs[] = { + [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), + [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), + [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), + [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), +}; + +static const char *sip_follow_continuation(const char *dptr, const char *limit) { - const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; - const char *limit, *aux, *k = dptr; - int shift = 0; + /* Walk past newline */ + if (++dptr >= limit) + return NULL; + + /* Skip '\n' in CR LF */ + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + return NULL; + } + + /* Continuation line? */ + if (*dptr != ' ' && *dptr != '\t') + return NULL; + + /* skip leading whitespace */ + for (; dptr < limit; dptr++) { + if (*dptr != ' ' && *dptr != '\t') + break; + } + return dptr; +} + +static const char *sip_skip_whitespace(const char *dptr, const char *limit) +{ + for (; dptr < limit; dptr++) { + if (*dptr == ' ') + continue; + if (*dptr != '\r' && *dptr != '\n') + break; + dptr = sip_follow_continuation(dptr, limit); + if (dptr == NULL) + return NULL; + } + return dptr; +} - limit = dptr + (dlen - hnfo->lnlen); +/* Search within a SIP header value, dealing with continuation lines */ +static const char *ct_sip_header_search(const char *dptr, const char *limit, + const char *needle, unsigned int len) +{ + for (limit -= len; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') { + dptr = sip_follow_continuation(dptr, limit); + if (dptr == NULL) + break; + continue; + } - while (dptr < limit) { - if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hnfo->sname == NULL || - strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { - dptr++; + if (strnicmp(dptr, needle, len) == 0) + return dptr; + } + return NULL; +} + +int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sip_hdrs[type]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + for (dptr += dataoff; dptr < limit; dptr++) { + /* Find beginning of line */ + if (*dptr != '\r' && *dptr != '\n') continue; + if (++dptr >= limit) + break; + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + break; } - aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, - ct_sip_lnlen(dptr, limit), - hnfo->case_sensitive); - if (!aux) { - pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str, - hnfo->lname); - return -1; + + /* Skip continuation lines */ + if (*dptr == ' ' || *dptr == '\t') + continue; + + /* Find header. Compact headers must be followed by a + * non-alphabetic character to avoid mismatches. */ + if (limit - dptr >= hdr->len && + strnicmp(dptr, hdr->name, hdr->len) == 0) + dptr += hdr->len; + else if (hdr->cname && limit - dptr >= hdr->clen + 1 && + strnicmp(dptr, hdr->cname, hdr->clen) == 0 && + !isalpha(*(dptr + hdr->clen + 1))) + dptr += hdr->clen; + else + continue; + + /* Find and skip colon */ + dptr = sip_skip_whitespace(dptr, limit); + if (dptr == NULL) + break; + if (*dptr != ':' || ++dptr >= limit) + break; + + /* Skip whitespace after colon */ + dptr = sip_skip_whitespace(dptr, limit); + if (dptr == NULL) + break; + + *matchoff = dptr - start; + if (hdr->search) { + dptr = ct_sip_header_search(dptr, limit, hdr->search, + hdr->slen); + if (!dptr) + return -1; + dptr += hdr->slen; } - aux += hnfo->ln_strlen; - *matchlen = hnfo->match_len(ct, aux, limit, &shift); + *matchlen = hdr->match_len(ct, dptr, limit, &shift); if (!*matchlen) return -1; - - *matchoff = (aux - k) + shift; - - pr_debug("%s match succeeded! - len: %u\n", hnfo->lname, - *matchlen); + *matchoff = dptr - start + shift; return 1; } - pr_debug("%s header not found.\n", hnfo->lname); return 0; } -EXPORT_SYMBOL_GPL(ct_sip_get_info); +EXPORT_SYMBOL_GPL(ct_sip_get_header); /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, -- cgit v1.2.3 From 05e3ced297fe755093140e7487e292fb7603316e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:19:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper Introduce a helper function to parse a SIP-URI in a header value, optionally iterating through all headers of this kind. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 5 ++ net/netfilter/nf_conntrack_sip.c | 107 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index ccc701422963..87bc6f79efc4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -67,6 +67,11 @@ extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, enum sip_header_types type, unsigned int *matchoff, unsigned int *matchlen); +extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + unsigned int *dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index cbc91598acee..a74d76a97312 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -190,6 +190,9 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); * whitespace and the values. Whitespace in this context means any amount of * tabs, spaces and continuation lines, which are treated as a single whitespace * character. + * + * Some headers may appear multiple times. A comma seperated list of values is + * equivalent to multiple headers. */ static const struct sip_header ct_sip_hdrs[] = { [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), @@ -322,6 +325,110 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_header); +/* Get next header field in a list of comma seperated values */ +static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sip_hdrs[type]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + dptr += dataoff; + + dptr = ct_sip_header_search(dptr, limit, ",", strlen(",")); + if (!dptr) + return 0; + + dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen); + if (!dptr) + return 0; + dptr += hdr->slen; + + *matchoff = dptr - start; + *matchlen = hdr->match_len(ct, dptr, limit, &shift); + if (!*matchlen) + return -1; + *matchoff += shift; + return 1; +} + +/* Walk through headers until a parsable one is found or no header of the + * given type is left. */ +static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen) +{ + int ret; + + if (in_header && *in_header) { + while (1) { + ret = ct_sip_next_header(ct, dptr, dataoff, datalen, + type, matchoff, matchlen); + if (ret > 0) + return ret; + if (ret == 0) + break; + dataoff += *matchoff; + } + *in_header = 0; + } + + while (1) { + ret = ct_sip_get_header(ct, dptr, dataoff, datalen, + type, matchoff, matchlen); + if (ret > 0) + break; + if (ret == 0) + return ret; + dataoff += *matchoff; + } + + if (in_header) + *in_header = 1; + return 1; +} + +/* Locate a SIP header, parse the URI and return the offset and length of + * the address as well as the address and port themselves. A stream of + * headers can be parsed by handing in a non-NULL datalen and in_header + * pointer. + */ +int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + unsigned int *dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port) +{ + const char *c, *limit = dptr + datalen; + unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, + type, in_header, matchoff, matchlen); + WARN_ON(ret < 0); + if (ret == 0) + return ret; + + if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit)) + return -1; + if (*c == ':') { + c++; + p = simple_strtoul(c, (char **)&c, 10); + if (p < 1024 || p > 65535) + return -1; + *port = htons(p); + } else + *port = htons(SIP_PORT); + + if (dataoff) + *dataoff = c - dptr; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); + /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, * optionally followed by multiple media descriptions. -- cgit v1.2.3 From 624f8b7bba98c27a1464f5f858c4a861d5d3e8d7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:19:30 -0700 Subject: [NETFILTER]: nf_nat_sip: get rid of text based header translation Use the URI parsing helper to get the numerical addresses and get rid of the text based header translation. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 3 +- net/ipv4/netfilter/nf_nat_sip.c | 100 +++++++++++------------------ net/netfilter/nf_conntrack_sip.c | 27 ++++++-- 3 files changed, 62 insertions(+), 68 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 87bc6f79efc4..68a0d6a41733 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -62,7 +62,8 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, - unsigned int *matchoff, unsigned int *matchlen); + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port); extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, enum sip_header_types type, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index c13e43862361..5b4a5cd23f39 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -26,39 +26,6 @@ MODULE_AUTHOR("Christian Hentschel "); MODULE_DESCRIPTION("SIP NAT helper"); MODULE_ALIAS("ip_nat_sip"); -struct addr_map { - struct { - char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - unsigned int srclen, srciplen; - unsigned int dstlen, dstiplen; - } addr[IP_CT_DIR_MAX]; -}; - -static void addr_map_init(const struct nf_conn *ct, struct addr_map *map) -{ - const struct nf_conntrack_tuple *t; - enum ip_conntrack_dir dir; - unsigned int n; - - for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { - t = &ct->tuplehash[dir].tuple; - - n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", - NIPQUAD(t->src.u3.ip)); - map->addr[dir].srciplen = n; - n += sprintf(map->addr[dir].src + n, ":%u", - ntohs(t->src.u.udp.port)); - map->addr[dir].srclen = n; - - n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", - NIPQUAD(t->dst.u3.ip)); - map->addr[dir].dstiplen = n; - n += sprintf(map->addr[dir].dst + n, ":%u", - ntohs(t->dst.u.udp.port)); - map->addr[dir].dstlen = n; - } -} static unsigned int mangle_packet(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -81,43 +48,51 @@ static unsigned int mangle_packet(struct sk_buff *skb, static int map_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, - struct addr_map *map) + union nf_inet_addr *addr, __be16 port) { enum ip_conntrack_info ctinfo; - struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo); + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int addrlen; - char *addr; - - if ((matchlen == map->addr[dir].srciplen || - matchlen == map->addr[dir].srclen) && - strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { - addr = map->addr[!dir].dst; - addrlen = map->addr[!dir].dstlen; - } else if ((matchlen == map->addr[dir].dstiplen || - matchlen == map->addr[dir].dstlen) && - strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { - addr = map->addr[!dir].src; - addrlen = map->addr[!dir].srclen; + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int buflen; + __be32 newaddr; + __be16 newport; + + if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip && + ct->tuplehash[dir].tuple.src.u.udp.port == port) { + newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip; + newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; + } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip && + ct->tuplehash[dir].tuple.dst.u.udp.port == port) { + newaddr = ct->tuplehash[!dir].tuple.src.u3.ip; + newport = ct->tuplehash[!dir].tuple.src.u.udp.port; } else return 1; + if (newaddr == addr->ip && newport == port) + return 1; + + buflen = sprintf(buffer, "%u.%u.%u.%u:%u", + NIPQUAD(newaddr), ntohs(newport)); + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, - addr, addrlen); + buffer, buflen); } static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - enum sip_header_types type, struct addr_map *map) + enum sip_header_types type) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; + union nf_inet_addr addr; + __be16 port; - if (ct_sip_get_header(ct, *dptr, 0, *datalen, type, - &matchoff, &matchlen) <= 0) + if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, + &matchoff, &matchlen, &addr, &port) <= 0) return 1; - return map_addr(skb, dptr, datalen, matchoff, matchlen, map); + return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port); } static unsigned int ip_nat_sip(struct sk_buff *skb, @@ -125,26 +100,27 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - struct addr_map map; unsigned int matchoff, matchlen; + union nf_inet_addr addr; + __be16 port; if (*datalen < strlen("SIP/2.0")) return NF_ACCEPT; - addr_map_init(ct, &map); - /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { if (ct_sip_parse_request(ct, *dptr, *datalen, - &matchoff, &matchlen) > 0 && - !map_addr(skb, dptr, datalen, matchoff, matchlen, &map)) + &matchoff, &matchlen, + &addr, &port) > 0 && + !map_addr(skb, dptr, datalen, matchoff, matchlen, + &addr, port)) return NF_DROP; } - if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT)) return NF_DROP; return NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index a74d76a97312..f20fa2d94c0a 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -151,10 +151,12 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, */ int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, - unsigned int *matchoff, unsigned int *matchlen) + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port) { - const char *start = dptr, *limit = dptr + datalen; + const char *start = dptr, *limit = dptr + datalen, *end; unsigned int mlen; + unsigned int p; int shift = 0; /* Skip method and following whitespace */ @@ -173,10 +175,25 @@ int ct_sip_parse_request(const struct nf_conn *ct, if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) break; } - *matchlen = skp_epaddr_len(ct, dptr, limit, &shift); - if (!*matchlen) + if (!skp_epaddr_len(ct, dptr, limit, &shift)) return 0; - *matchoff = dptr - start + shift; + dptr += shift; + + if (!parse_addr(ct, dptr, &end, addr, limit)) + return -1; + if (end < limit && *end == ':') { + end++; + p = simple_strtoul(end, (char **)&end, 10); + if (p < 1024 || p > 65535) + return -1; + *port = htons(p); + } else + *port = htons(SIP_PORT); + + if (end == dptr) + return 0; + *matchoff = dptr - start; + *matchlen = end - dptr; return 1; } EXPORT_SYMBOL_GPL(ct_sip_parse_request); -- cgit v1.2.3 From 30f33e6dee80c6ded917f978e4f377d1069d519d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:22:20 -0700 Subject: [NETFILTER]: nf_conntrack_sip: support method specific request/response handling Add support for per-method request/response handlers and perform SDP parsing for INVITE/UPDATE requests and for all informational and successful responses. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 20 ++++++ net/netfilter/nf_conntrack_sip.c | 107 ++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 68a0d6a41733..da93e80804c2 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,6 +5,25 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 +struct sip_handler { + const char *method; + unsigned int len; + int (*request)(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq); + int (*response)(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code); +}; + +#define SIP_HANDLER(__method, __request, __response) \ +{ \ + .method = (__method), \ + .len = sizeof(__method) - 1, \ + .request = (__request), \ + .response = (__response), \ +} + struct sip_header { const char *name; const char *cname; @@ -35,6 +54,7 @@ struct sip_header { __SIP_HDR(__name, NULL, __search, __match) enum sip_header_types { + SIP_HDR_CSEQ, SIP_HDR_FROM, SIP_HDR_TO, SIP_HDR_CONTACT, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 96bedb52bd4b..1be949febab7 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -212,6 +212,7 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); * equivalent to multiple headers. */ static const struct sip_header ct_sip_hdrs[] = { + [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len), [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), @@ -566,7 +567,8 @@ static int set_expected_rtp(struct sk_buff *skb, } static int process_sdp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + unsigned int cseq) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); @@ -600,6 +602,96 @@ static int process_sdp(struct sk_buff *skb, return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); } +static int process_invite_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + if ((code >= 100 && code <= 199) || + (code >= 200 && code <= 299)) + return process_sdp(skb, dptr, datalen, cseq); + + return NF_ACCEPT; +} + +static int process_update_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + if ((code >= 100 && code <= 199) || + (code >= 200 && code <= 299)) + return process_sdp(skb, dptr, datalen, cseq); + + return NF_ACCEPT; +} + +static const struct sip_handler sip_handlers[] = { + SIP_HANDLER("INVITE", process_sdp, process_invite_response), + SIP_HANDLER("UPDATE", process_sdp, process_update_response), +}; + +static int process_sip_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) +{ + static const struct sip_handler *handler; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen; + unsigned int code, cseq, dataoff, i; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; + code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); + if (!code) + return NF_DROP; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, + &matchoff, &matchlen) <= 0) + return NF_DROP; + cseq = simple_strtoul(*dptr + matchoff, NULL, 10); + if (!cseq) + return NF_DROP; + dataoff = matchoff + matchlen + 1; + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + handler = &sip_handlers[i]; + if (handler->response == NULL) + continue; + if (*datalen < dataoff + handler->len || + strnicmp(*dptr + dataoff, handler->method, handler->len)) + continue; + return handler->response(skb, dptr, datalen, cseq, code); + } + return NF_ACCEPT; +} + +static int process_sip_request(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) +{ + static const struct sip_handler *handler; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen; + unsigned int cseq, i; + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + handler = &sip_handlers[i]; + if (handler->request == NULL) + continue; + if (*datalen < handler->len || + strnicmp(*dptr, handler->method, handler->len)) + continue; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, + &matchoff, &matchlen) <= 0) + return NF_DROP; + cseq = simple_strtoul(*dptr + matchoff, NULL, 10); + if (!cseq) + return NF_DROP; + + return handler->request(skb, dptr, datalen, cseq); + } + return NF_ACCEPT; +} static int sip_help(struct sk_buff *skb, unsigned int protoff, @@ -634,15 +726,10 @@ static int sip_help(struct sk_buff *skb, if (datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; - /* RTP info only in some SDP pkts */ - if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && - strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && - strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && - strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && - strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) - return NF_ACCEPT; - - return process_sdp(skb, &dptr, &datalen); + if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) + return process_sip_request(skb, &dptr, &datalen); + else + return process_sip_response(skb, &dptr, &datalen); } static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; -- cgit v1.2.3 From 2bbb21168a90c788e12fe722eb66f27e611e7df7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:24:24 -0700 Subject: [NETFILTER]: nf_conntrack_sip: introduce URI and header parameter parsing helpers Introduce URI and header parameter parsing helpers. These are needed by the conntrack helper to parse expiration values in Contact: header parameters and by the NAT helper to properly update the Via-header rport=, received= and maddr= parameters. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 10 ++++++ net/netfilter/nf_conntrack_sip.c | 58 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index da93e80804c2..87e402825dba 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -93,6 +93,16 @@ extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, enum sip_header_types type, int *in_header, unsigned int *matchoff, unsigned int *matchlen, union nf_inet_addr *addr, __be16 *port); +extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr); +extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + unsigned int off, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchen, + unsigned int *val); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 8e7e5b465ffb..126f30842d60 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -448,6 +448,64 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); +/* Parse address from header parameter and return address, offset and length */ +int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr) +{ + const char *limit = dptr + datalen; + const char *start, *end; + + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); + if (!limit) + limit = dptr + datalen; + + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); + if (!start) + return 0; + + start += strlen(name); + if (!parse_addr(ct, start, &end, addr, limit)) + return 0; + *matchoff = start - dptr; + *matchlen = end - start; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_address_param); + +/* Parse numerical header parameter and return value, offset and length */ +int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + unsigned int *val) +{ + const char *limit = dptr + datalen; + const char *start; + char *end; + + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); + if (!limit) + limit = dptr + datalen; + + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); + if (!start) + return 0; + + start += strlen(name); + *val = simple_strtoul(start, &end, 0); + if (start == end) + return 0; + if (matchoff && matchlen) { + *matchoff = start - dptr; + *matchlen = end - start; + } + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); + /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, * optionally followed by multiple media descriptions. -- cgit v1.2.3 From 0f32a40fc91a9ebbbf66e826ac2a829ab37d9cf8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:25:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: create signalling expectations Create expectations for incoming signalling connections when seeing a REGISTER request. This is needed when the registrar uses a different source port number for signalling messages and for receiving incoming calls from other endpoints than the registrar. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 18 +++ include/net/netfilter/nf_conntrack.h | 4 +- net/ipv4/netfilter/nf_nat_sip.c | 111 +++++++++++--- net/netfilter/nf_conntrack_sip.c | 232 +++++++++++++++++++++++++++-- 4 files changed, 332 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 87e402825dba..7cc84ed0c5da 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,6 +5,17 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 +struct nf_ct_sip_master { + unsigned int register_cseq; +}; + +enum sip_expectation_classes { + SIP_EXPECT_SIGNALLING, + SIP_EXPECT_AUDIO, + __SIP_EXPECT_MAX +}; +#define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) + struct sip_handler { const char *method; unsigned int len; @@ -59,6 +70,7 @@ enum sip_header_types { SIP_HDR_TO, SIP_HDR_CONTACT, SIP_HDR_VIA, + SIP_HDR_EXPIRES, SIP_HDR_CONTENT_LENGTH, }; @@ -75,6 +87,12 @@ enum sdp_header_types { extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen); +extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 922877133598..4a4f870d2a5e 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -46,6 +46,7 @@ union nf_conntrack_expect_proto { #include #include #include +#include /* per conntrack: application helper private data */ union nf_conntrack_help { @@ -54,6 +55,7 @@ union nf_conntrack_help { struct nf_ct_pptp_master ct_pptp_info; struct nf_ct_h323_master ct_h323_info; struct nf_ct_sane_master ct_sane_info; + struct nf_ct_sip_master ct_sip_info; }; #include @@ -76,7 +78,7 @@ do { \ struct nf_conntrack_helper; /* Must be kept in sync with the classes defined by helpers */ -#define NF_CT_MAX_EXPECT_CLASSES 1 +#define NF_CT_MAX_EXPECT_CLASSES 2 /* nf_conn feature for connections that have a helper */ struct nf_conn_help { diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b443618a857f..4b85e21a2a4a 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -205,6 +205,91 @@ next: return NF_ACCEPT; } +/* Handles expected signalling connections and media streams */ +static void ip_nat_sip_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip = exp->saved_ip; + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); + + /* Change src to where master sends to, but only if the connection + * actually came from the same source. */ + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == + ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); + } +} + +static unsigned int ip_nat_sip_expect(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + __be32 newip; + u_int16_t port; + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned buflen; + + /* Connection will come from reply */ + if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) + newip = exp->tuple.dst.u3.ip; + else + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + + /* If the signalling port matches the connection's source port in the + * original direction, try to use the destination port in the opposite + * direction. */ + if (exp->tuple.dst.u.udp.port == + ct->tuplehash[dir].tuple.src.u.udp.port) + port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); + else + port = ntohs(exp->tuple.dst.u.udp.port); + + exp->saved_ip = exp->tuple.dst.u3.ip; + exp->tuple.dst.u3.ip = newip; + exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; + exp->dir = !dir; + exp->expectfn = ip_nat_sip_expected; + + for (; port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_ct_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (exp->tuple.dst.u3.ip != exp->saved_ip || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { + buflen = sprintf(buffer, "%u.%u.%u.%u:%u", + NIPQUAD(newip), port); + if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen)) + goto err; + } + return NF_ACCEPT; + +err: + nf_ct_unexpect_related(exp); + return NF_DROP; +} + static int mangle_content_len(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { @@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb, return mangle_content_len(skb, dptr, datalen); } -static void ip_nat_sdp_expect(struct nf_conn *ct, - struct nf_conntrack_expect *exp) -{ - struct nf_nat_range range; - - /* This must be a fresh one. */ - BUG_ON(ct->status & IPS_NAT_DONE_MASK); - - /* For DST manip, map port here to where it's expected. */ - range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); - range.min = range.max = exp->saved_proto; - range.min_ip = range.max_ip = exp->saved_ip; - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); - - /* Change src to where master sends to */ - range.flags = IP_NAT_RANGE_MAP_IPS; - range.min_ip = range.max_ip - = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); -} - /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, @@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, /* When you see the packet, we need to NAT it the same as the this one. */ - exp->expectfn = ip_nat_sdp_expect; + exp->expectfn = ip_nat_sip_expected; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { @@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, static void __exit nf_nat_sip_fini(void) { rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sdp_hook, NULL); synchronize_rcu(); } @@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void) static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); + BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sdp_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); return 0; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 126f30842d60..043aa557e7a8 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -37,11 +37,24 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; module_param(sip_timeout, uint, 0600); MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); +static int sip_direct_signalling __read_mostly = 1; +module_param(sip_direct_signalling, int, 0600); +MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " + "only (default 1)"); + unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); +unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); + unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -218,6 +231,7 @@ static const struct sip_header ct_sip_hdrs[] = { [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), }; @@ -592,18 +606,50 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); -static void flush_expectations(struct nf_conn *ct) +static int refresh_signalling_expectation(struct nf_conn *ct, + union nf_inet_addr *addr, + __be16 port, + unsigned int expires) { struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_expect *exp; struct hlist_node *n, *next; + int found = 0; spin_lock_bh(&nf_conntrack_lock); hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { + if (exp->class != SIP_EXPECT_SIGNALLING || + !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || + exp->tuple.dst.u.udp.port != port) + continue; + if (!del_timer(&exp->timeout)) + continue; + exp->flags &= ~NF_CT_EXPECT_INACTIVE; + exp->timeout.expires = jiffies + expires * HZ; + add_timer(&exp->timeout); + found = 1; + break; + } + spin_unlock_bh(&nf_conntrack_lock); + return found; +} + +static void flush_expectations(struct nf_conn *ct, bool media) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_expect *exp; + struct hlist_node *n, *next; + + spin_lock_bh(&nf_conntrack_lock); + hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { + if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) + continue; if (!del_timer(&exp->timeout)) continue; nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); + if (!media) + break; } spin_unlock_bh(&nf_conntrack_lock); } @@ -623,7 +669,7 @@ static int set_expected_rtp(struct sk_buff *skb, exp = nf_ct_expect_alloc(ct); if (exp == NULL) return NF_DROP; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, &ct->tuplehash[!dir].tuple.src.u3, addr, IPPROTO_UDP, NULL, &port); @@ -688,7 +734,7 @@ static int process_invite_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -704,7 +750,7 @@ static int process_update_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -720,7 +766,7 @@ static int process_prack_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -732,7 +778,165 @@ static int process_bye_request(struct sk_buff *skb, enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - flush_expectations(ct); + flush_expectations(ct, true); + return NF_ACCEPT; +} + +/* Parse a REGISTER request and create a permanent expectation for incoming + * signalling connections. The expectation is marked inactive and is activated + * when receiving a response indicating success from the registrar. + */ +static int process_register_request(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + unsigned int matchoff, matchlen; + struct nf_conntrack_expect *exp; + union nf_inet_addr *saddr, daddr; + __be16 port; + unsigned int expires = 0; + int ret; + typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; + + /* Expected connections can not register again. */ + if (ct->status & IPS_EXPECTED) + return NF_ACCEPT; + + /* We must check the expiration time: a value of zero signals the + * registrar to release the binding. We'll remove our expectation + * when receiving the new bindings in the response, but we don't + * want to create new ones. + * + * The expiration time may be contained in Expires: header, the + * Contact: header parameters or the URI parameters. + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) + expires = simple_strtoul(*dptr + matchoff, NULL, 10); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, + &matchoff, &matchlen, &daddr, &port); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + return NF_ACCEPT; + + /* We don't support third-party registrations */ + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) + return NF_ACCEPT; + + if (ct_sip_parse_numerical_param(ct, *dptr, + matchoff + matchlen, *datalen, + "expires=", NULL, NULL, &expires) < 0) + return NF_DROP; + + if (expires == 0) { + ret = NF_ACCEPT; + goto store_cseq; + } + + exp = nf_ct_expect_alloc(ct); + if (!exp) + return NF_DROP; + + saddr = NULL; + if (sip_direct_signalling) + saddr = &ct->tuplehash[!dir].tuple.src.u3; + + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr, + IPPROTO_UDP, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; + exp->helper = nfct_help(ct)->helper; + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); + if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) + ret = nf_nat_sip_expect(skb, dptr, datalen, exp, + matchoff, matchlen); + else { + if (nf_ct_expect_related(exp) != 0) + ret = NF_DROP; + else + ret = NF_ACCEPT; + } + nf_ct_expect_put(exp); + +store_cseq: + if (ret == NF_ACCEPT) + help->help.ct_sip_info.register_cseq = cseq; + return ret; +} + +static int process_register_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + union nf_inet_addr addr; + __be16 port; + unsigned int matchoff, matchlen, dataoff = 0; + unsigned int expires = 0; + int in_contact = 0, ret; + + /* According to RFC 3261, "UAs MUST NOT send a new registration until + * they have received a final response from the registrar for the + * previous one or the previous REGISTER request has timed out". + * + * However, some servers fail to detect retransmissions and send late + * responses, so we store the sequence number of the last valid + * request and compare it here. + */ + if (help->help.ct_sip_info.register_cseq != cseq) + return NF_ACCEPT; + + if (code >= 100 && code <= 199) + return NF_ACCEPT; + if (code < 200 || code > 299) + goto flush; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) + expires = simple_strtoul(*dptr + matchoff, NULL, 10); + + while (1) { + unsigned int c_expires = expires; + + ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, + SIP_HDR_CONTACT, &in_contact, + &matchoff, &matchlen, + &addr, &port); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + break; + + /* We don't support third-party registrations */ + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) + continue; + + ret = ct_sip_parse_numerical_param(ct, *dptr, + matchoff + matchlen, + *datalen, "expires=", + NULL, NULL, &c_expires); + if (ret < 0) + return NF_DROP; + if (c_expires == 0) + break; + if (refresh_signalling_expectation(ct, &addr, port, c_expires)) + return NF_ACCEPT; + } + +flush: + flush_expectations(ct, false); return NF_ACCEPT; } @@ -742,6 +946,7 @@ static const struct sip_handler sip_handlers[] = { SIP_HANDLER("ACK", process_sdp, NULL), SIP_HANDLER("PRACK", process_sdp, process_prack_response), SIP_HANDLER("BYE", process_bye_request, NULL), + SIP_HANDLER("REGISTER", process_register_request, process_register_response), }; static int process_sip_response(struct sk_buff *skb, @@ -853,9 +1058,15 @@ static int sip_help(struct sk_buff *skb, static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; -static const struct nf_conntrack_expect_policy sip_exp_policy = { - .max_expected = 2, - .timeout = 3 * 60, +static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { + [SIP_EXPECT_SIGNALLING] = { + .max_expected = 1, + .timeout = 3 * 60, + }, + [SIP_EXPECT_AUDIO] = { + .max_expected = IP_CT_DIR_MAX, + .timeout = 3 * 60, + }, }; static void nf_conntrack_sip_fini(void) @@ -887,7 +1098,8 @@ static int __init nf_conntrack_sip_init(void) for (j = 0; j < 2; j++) { sip[i][j].tuple.dst.protonum = IPPROTO_UDP; sip[i][j].tuple.src.u.udp.port = htons(ports[i]); - sip[i][j].expect_policy = &sip_exp_policy; + sip[i][j].expect_policy = sip_exp_policy; + sip[i][j].expect_class_max = SIP_EXPECT_MAX; sip[i][j].me = THIS_MODULE; sip[i][j].help = sip_help; -- cgit v1.2.3 From a9c1d35917c0c95c8f95a8e497fb91e301419693 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:25:49 -0700 Subject: [NETFILTER]: nf_conntrack_sip: create RTCP expectations Create expectations for the RTCP connections in addition to RTP connections. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 3 +- net/ipv4/netfilter/nf_nat_sip.c | 42 +++++++++++++--------- net/netfilter/nf_conntrack_sip.c | 58 +++++++++++++++++++----------- 3 files changed, 66 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 7cc84ed0c5da..6ddf95f51fb5 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -96,7 +96,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp); + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp); extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4b85e21a2a4a..f73ab4883b75 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb, Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp) + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); @@ -375,31 +376,40 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, /* Connection will come from reply */ if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) - newip = exp->tuple.dst.u3.ip; + newip = rtp_exp->tuple.dst.u3.ip; else newip = ct->tuplehash[!dir].tuple.dst.u3.ip; - exp->saved_ip = exp->tuple.dst.u3.ip; - exp->tuple.dst.u3.ip = newip; - exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; - exp->dir = !dir; - - /* When you see the packet, we need to NAT it the same as the - this one. */ - exp->expectfn = ip_nat_sip_expected; - - /* Try to get same port: if not, try to change it. */ - for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { - exp->tuple.dst.u.udp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; + rtp_exp->tuple.dst.u3.ip = newip; + rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; + rtp_exp->dir = !dir; + rtp_exp->expectfn = ip_nat_sip_expected; + + rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; + rtcp_exp->tuple.dst.u3.ip = newip; + rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; + rtcp_exp->dir = !dir; + rtcp_exp->expectfn = ip_nat_sip_expected; + + /* Try to get same pair of ports: if not, try to change them. */ + for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); + port != 0; port += 2) { + rtp_exp->tuple.dst.u.udp.port = htons(port); + if (nf_ct_expect_related(rtp_exp) != 0) + continue; + rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); + if (nf_ct_expect_related(rtcp_exp) == 0) break; + nf_ct_unexpect_related(rtp_exp); } if (port == 0) return NF_DROP; if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { - nf_ct_unexpect_related(exp); + nf_ct_unexpect_related(rtp_exp); + nf_ct_unexpect_related(rtcp_exp); return NF_DROP; } return NF_ACCEPT; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 813aa8c67e4c..217262e23403 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp) __read_mostly; + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) + __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int string_len(const struct nf_conn *ct, const char *dptr, @@ -659,18 +661,20 @@ static void flush_expectations(struct nf_conn *ct, bool media) spin_unlock_bh(&nf_conntrack_lock); } -static int set_expected_rtp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - union nf_inet_addr *daddr, __be16 port) +static int set_expected_rtp_rtcp(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + union nf_inet_addr *daddr, __be16 port) { - struct nf_conntrack_expect *exp; + struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); union nf_inet_addr *saddr; struct nf_conntrack_tuple tuple; int family = ct->tuplehash[!dir].tuple.src.l3num; - int skip_expect = 0, ret; + int skip_expect = 0, ret = NF_DROP; + u_int16_t base_port; + __be16 rtp_port, rtcp_port; typeof(nf_nat_sdp_hook) nf_nat_sdp; saddr = NULL; @@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb, if (skip_expect) return NF_ACCEPT; - exp = nf_ct_expect_alloc(ct); - if (exp == NULL) - return NF_DROP; - nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr, - IPPROTO_UDP, NULL, &port); + base_port = ntohs(tuple.dst.u.udp.port) & ~1; + rtp_port = htons(base_port); + rtcp_port = htons(base_port + 1); + + rtp_exp = nf_ct_expect_alloc(ct); + if (rtp_exp == NULL) + goto err1; + nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + IPPROTO_UDP, NULL, &rtp_port); + + rtcp_exp = nf_ct_expect_alloc(ct); + if (rtcp_exp == NULL) + goto err2; + nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, dptr, datalen, exp); + ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); else { - if (nf_ct_expect_related(exp) != 0) - ret = NF_DROP; - else - ret = NF_ACCEPT; + if (nf_ct_expect_related(rtp_exp) == 0) { + if (nf_ct_expect_related(rtcp_exp) != 0) + nf_ct_unexpect_related(rtp_exp); + else + ret = NF_ACCEPT; + } } - nf_ct_expect_put(exp); - + nf_ct_expect_put(rtcp_exp); +err2: + nf_ct_expect_put(rtp_exp); +err1: return ret; } @@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb, if (port < 1024 || port > 65535) return NF_DROP; - return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); + return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); } static int process_invite_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -1101,7 +1119,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 .timeout = 3 * 60, }, [SIP_EXPECT_AUDIO] = { - .max_expected = IP_CT_DIR_MAX, + .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, }; -- cgit v1.2.3 From 4ab9e64e5e3c0516577818804aaf13a630d67bc9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:08 -0700 Subject: [NETFILTER]: nf_nat_sip: split up SDP mangling The SDP connection addresses may be contained in the payload multiple times (in the session description and/or once per media description), currently only the session description is properly updated. Split up SDP mangling so the function setting up expectations only updates the media port, update connection addresses from media descriptions while parsing them and at the end update the session description when the final addresses are known. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 25 ++++- net/ipv4/netfilter/nf_nat_sip.c | 121 ++++++++++++++++-------- net/netfilter/nf_conntrack_sip.c | 142 +++++++++++++++++++++++------ 3 files changed, 219 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 6ddf95f51fb5..eca3ad3f28dc 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -93,11 +93,26 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, struct nf_conntrack_expect *exp, unsigned int matchoff, unsigned int matchlen); -extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp); +extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr); extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index f73ab4883b75..4429069d9b42 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -316,45 +316,77 @@ static int mangle_content_len(struct sk_buff *skb, buffer, buflen); } -static unsigned mangle_sdp_packet(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, +static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, unsigned int *datalen, enum sdp_header_types type, + enum sdp_header_types term, char *buffer, int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; - if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, + if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term, &matchoff, &matchlen) <= 0) return 0; return mangle_packet(skb, dptr, datalen, matchoff, matchlen, buffer, buflen); } -static unsigned int mangle_sdp(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, - __be32 newip, u_int16_t port, - const char **dptr, unsigned int *datalen) +static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; - unsigned int bufflen; + unsigned int buflen; - /* Mangle owner and contact info. */ - bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, - buffer, bufflen)) + buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, + buffer, buflen)) return 0; - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, - buffer, bufflen)) + return mangle_content_len(skb, dptr, datalen); +} + +static unsigned int ip_nat_sdp_port(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port) +{ + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + + buflen = sprintf(buffer, "%u", port); + if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen)) return 0; - /* Mangle media port. */ - bufflen = sprintf(buffer, "%u", port); - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, - buffer, bufflen)) + return mangle_content_len(skb, dptr, datalen); +} + +static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ + buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip)); + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, + SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, + buffer, buflen)) + return 0; + + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, + SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, + buffer, buflen)) return 0; return mangle_content_len(skb, dptr, datalen); @@ -362,32 +394,35 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ -static unsigned int ip_nat_sdp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp) +static unsigned int ip_nat_sdp_media(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - __be32 newip; u_int16_t port; /* Connection will come from reply */ if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) - newip = rtp_exp->tuple.dst.u3.ip; + rtp_addr->ip = rtp_exp->tuple.dst.u3.ip; else - newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; - rtp_exp->tuple.dst.u3.ip = newip; + rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; rtp_exp->dir = !dir; rtp_exp->expectfn = ip_nat_sip_expected; rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; - rtcp_exp->tuple.dst.u3.ip = newip; + rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; rtcp_exp->dir = !dir; rtcp_exp->expectfn = ip_nat_sip_expected; @@ -405,21 +440,29 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, } if (port == 0) - return NF_DROP; + goto err1; + + /* Update media port. */ + if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && + !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port)) + goto err2; - if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { - nf_ct_unexpect_related(rtp_exp); - nf_ct_unexpect_related(rtcp_exp); - return NF_DROP; - } return NF_ACCEPT; + +err2: + nf_ct_unexpect_related(rtp_exp); + nf_ct_unexpect_related(rtcp_exp); +err1: + return NF_DROP; } static void __exit nf_nat_sip_fini(void) { rcu_assign_pointer(nf_nat_sip_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); - rcu_assign_pointer(nf_nat_sdp_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); synchronize_rcu(); } @@ -427,10 +470,14 @@ static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL); - BUG_ON(nf_nat_sdp_hook != NULL); + BUG_ON(nf_nat_sdp_addr_hook != NULL); + BUG_ON(nf_nat_sdp_session_hook != NULL); + BUG_ON(nf_nat_sdp_media_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); - rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); + rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); + rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); + rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); return 0; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 217262e23403..f929add324f3 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -60,13 +60,34 @@ unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, unsigned int matchlen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); -unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp) - __read_mostly; -EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); +unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); + +unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); + +unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); static int string_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) @@ -613,6 +634,26 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); +static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr) +{ + int ret; + + ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term, + matchoff, matchlen); + if (ret <= 0) + return ret; + + if (!parse_addr(ct, dptr + *matchoff, NULL, addr, + dptr + *matchoff + *matchlen)) + return -1; + return 1; +} + static int refresh_signalling_expectation(struct nf_conn *ct, union nf_inet_addr *addr, __be16 port, @@ -663,7 +704,8 @@ static void flush_expectations(struct nf_conn *ct, bool media) static int set_expected_rtp_rtcp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - union nf_inet_addr *daddr, __be16 port) + union nf_inet_addr *daddr, __be16 port, + unsigned int mediaoff, unsigned int medialen) { struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; enum ip_conntrack_info ctinfo; @@ -675,7 +717,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, int skip_expect = 0, ret = NF_DROP; u_int16_t base_port; __be16 rtp_port, rtcp_port; - typeof(nf_nat_sdp_hook) nf_nat_sdp; + typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; saddr = NULL; if (sip_direct_media) { @@ -724,9 +766,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, IPPROTO_UDP, NULL, &rtcp_port); - nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); - if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); + nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); + if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, + mediaoff, medialen, daddr); else { if (nf_ct_expect_related(rtp_exp) == 0) { if (nf_ct_expect_related(rtcp_exp) != 0) @@ -750,33 +793,78 @@ static int process_sdp(struct sk_buff *skb, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; unsigned int matchoff, matchlen; - union nf_inet_addr addr; + unsigned int mediaoff, medialen; + unsigned int sdpoff; + unsigned int caddr_len, maddr_len; + union nf_inet_addr caddr, maddr, rtp_addr; unsigned int port; - enum sdp_header_types type; + enum sdp_header_types c_hdr; + int ret; + typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; + typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; - /* Get address and port from SDP packet. */ - type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : - SDP_HDR_CONNECTION_IP6; + c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; + /* Find beginning of session description */ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, - type, SDP_HDR_UNSPEC, + SDP_HDR_VERSION, SDP_HDR_UNSPEC, &matchoff, &matchlen) <= 0) return NF_ACCEPT; - - /* We'll drop only if there are parse problems. */ - if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen)) - return NF_DROP; - - if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + sdpoff = matchoff; + + /* The connection information is contained in the session description + * and/or once per media description. The first media description marks + * the end of the session description. */ + caddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &caddr) > 0) + caddr_len = matchlen; + + if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, SDP_HDR_MEDIA, SDP_HDR_UNSPEC, - &matchoff, &matchlen) <= 0) + &mediaoff, &medialen) <= 0) return NF_ACCEPT; - port = simple_strtoul(*dptr + matchoff, NULL, 10); + port = simple_strtoul(*dptr + mediaoff, NULL, 10); if (port < 1024 || port > 65535) return NF_DROP; - return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); + /* The media description overrides the session description. */ + maddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &maddr) > 0) { + maddr_len = matchlen; + memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); + } else if (caddr_len) + memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); + else + return NF_DROP; + + ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), + mediaoff, medialen); + if (ret != NF_ACCEPT) + return ret; + + /* Update media connection address if present */ + if (maddr_len) { + nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); + if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { + ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, + c_hdr, SDP_HDR_MEDIA, &rtp_addr); + if (ret != NF_ACCEPT) + return ret; + } + } + + /* Update session connection and owner addresses */ + nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); + if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr); + + return ret; } static int process_invite_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, -- cgit v1.2.3 From 0d0ab0378d67517a4f4ae3497706c13d9dd24af1 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:24 -0700 Subject: [NETFILTER]: nf_conntrack_sip: support multiple media channels Add support for multiple media channels and use it to create expectations for video streams when present. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 14 ++++ include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_sip.c | 121 +++++++++++++++++++++-------- 3 files changed, 105 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index eca3ad3f28dc..71fa3eb5f485 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -12,10 +12,24 @@ struct nf_ct_sip_master { enum sip_expectation_classes { SIP_EXPECT_SIGNALLING, SIP_EXPECT_AUDIO, + SIP_EXPECT_VIDEO, __SIP_EXPECT_MAX }; #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) +struct sdp_media_type { + const char *name; + unsigned int len; + enum sip_expectation_classes class; +}; + +#define SDP_MEDIA_TYPE(__name, __class) \ +{ \ + .name = (__name), \ + .len = sizeof(__name) - 1, \ + .class = (__class), \ +} + struct sip_handler { const char *method; unsigned int len; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 4a4f870d2a5e..a3567a7a6d67 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -78,7 +78,7 @@ do { \ struct nf_conntrack_helper; /* Must be kept in sync with the classes defined by helpers */ -#define NF_CT_MAX_EXPECT_CLASSES 2 +#define NF_CT_MAX_EXPECT_CLASSES 3 /* nf_conn feature for connections that have a helper */ struct nf_conn_help { diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f929add324f3..f40a525732d1 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -112,6 +112,21 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, return len; } +/* get media type + port length */ +static int media_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = string_len(ct, dptr, limit, shift); + + dptr += len; + if (dptr >= limit || *dptr != ' ') + return 0; + len++; + dptr++; + + return len + digits_len(ct, dptr, limit, shift); +} + static int parse_addr(const struct nf_conn *ct, const char *cp, const char **endp, union nf_inet_addr *addr, const char *limit) @@ -563,7 +578,7 @@ static const struct sip_header ct_sdp_hdrs[] = { [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), - [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len), + [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), }; /* Linear string search within SDP header values */ @@ -705,6 +720,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) static int set_expected_rtp_rtcp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, union nf_inet_addr *daddr, __be16 port, + enum sip_expectation_classes class, unsigned int mediaoff, unsigned int medialen) { struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; @@ -743,7 +759,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, exp = __nf_ct_expect_find(&tuple); if (exp && exp->master != ct && nfct_help(exp->master)->helper == nfct_help(ct)->helper && - exp->class == SIP_EXPECT_AUDIO) + exp->class == class) skip_expect = 1; rcu_read_unlock(); @@ -757,13 +773,13 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, rtp_exp = nf_ct_expect_alloc(ct); if (rtp_exp == NULL) goto err1; - nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + nf_ct_expect_init(rtp_exp, class, family, saddr, daddr, IPPROTO_UDP, NULL, &rtp_port); rtcp_exp = nf_ct_expect_alloc(ct); if (rtcp_exp == NULL) goto err2; - nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr, IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); @@ -785,6 +801,28 @@ err1: return ret; } +static const struct sdp_media_type sdp_media_types[] = { + SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO), + SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO), +}; + +static const struct sdp_media_type *sdp_media_type(const char *dptr, + unsigned int matchoff, + unsigned int matchlen) +{ + const struct sdp_media_type *t; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) { + t = &sdp_media_types[i]; + if (matchlen < t->len || + strncmp(dptr + matchoff, t->name, t->len)) + continue; + return t; + } + return NULL; +} + static int process_sdp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int cseq) @@ -796,13 +834,16 @@ static int process_sdp(struct sk_buff *skb, unsigned int mediaoff, medialen; unsigned int sdpoff; unsigned int caddr_len, maddr_len; + unsigned int i; union nf_inet_addr caddr, maddr, rtp_addr; unsigned int port; enum sdp_header_types c_hdr; - int ret; + const struct sdp_media_type *t; + int ret = NF_ACCEPT; typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; + nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : SDP_HDR_CONNECTION_IP6; @@ -822,41 +863,55 @@ static int process_sdp(struct sk_buff *skb, &matchoff, &matchlen, &caddr) > 0) caddr_len = matchlen; - if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, - SDP_HDR_MEDIA, SDP_HDR_UNSPEC, - &mediaoff, &medialen) <= 0) - return NF_ACCEPT; + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) + break; - port = simple_strtoul(*dptr + mediaoff, NULL, 10); - if (port < 1024 || port > 65535) - return NF_DROP; + /* Get media type and port number. A media port value of zero + * indicates an inactive stream. */ + t = sdp_media_type(*dptr, mediaoff, medialen); + if (!t) { + mediaoff += medialen; + continue; + } + mediaoff += t->len; + medialen -= t->len; - /* The media description overrides the session description. */ - maddr_len = 0; - if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, - c_hdr, SDP_HDR_MEDIA, - &matchoff, &matchlen, &maddr) > 0) { - maddr_len = matchlen; - memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); - } else if (caddr_len) - memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); - else - return NF_DROP; + port = simple_strtoul(*dptr + mediaoff, NULL, 10); + if (port == 0) + continue; + if (port < 1024 || port > 65535) + return NF_DROP; - ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), - mediaoff, medialen); - if (ret != NF_ACCEPT) - return ret; + /* The media description overrides the session description. */ + maddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &maddr) > 0) { + maddr_len = matchlen; + memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); + } else if (caddr_len) + memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); + else + return NF_DROP; + + ret = set_expected_rtp_rtcp(skb, dptr, datalen, + &rtp_addr, htons(port), t->class, + mediaoff, medialen); + if (ret != NF_ACCEPT) + return ret; - /* Update media connection address if present */ - if (maddr_len) { - nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); - if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { + /* Update media connection address if present */ + if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, c_hdr, SDP_HDR_MEDIA, &rtp_addr); if (ret != NF_ACCEPT) return ret; } + i++; } /* Update session connection and owner addresses */ @@ -1210,6 +1265,10 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, + [SIP_EXPECT_VIDEO] = { + .max_expected = 2 * IP_CT_DIR_MAX, + .timeout = 3 * 60, + }, }; static void nf_conntrack_sip_fini(void) -- cgit v1.2.3 From c7f485abd618e0d249bdd1abdc586bd10fee1954 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:43 -0700 Subject: [NETFILTER]: nf_conntrack_sip: RTP routing optimization Optimize call routing between NATed endpoints: when an external registrar sends a media description that contains an existing RTP expectation from a different SNATed connection, the gatekeeper is trying to route the call directly between the two endpoints. We assume both endpoints can reach each other directly and "un-NAT" the addresses, which makes the media stream go between the two endpoints directly. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 6 +++ net/ipv4/netfilter/nf_nat_sip.c | 3 ++ net/netfilter/nf_conntrack_sip.c | 59 +++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 71fa3eb5f485..5da04e586a3f 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port); extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, const char **dptr, unsigned int dataoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4429069d9b42..bcddccddf768 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void) rcu_assign_pointer(nf_nat_sip_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); synchronize_rcu(); @@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void) BUG_ON(nf_nat_sip_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sdp_addr_hook != NULL); + BUG_ON(nf_nat_sdp_port_hook != NULL); BUG_ON(nf_nat_sdp_session_hook != NULL); BUG_ON(nf_nat_sdp_media_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); + rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); return 0; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f40a525732d1..57de22c770a3 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); +unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); + unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, const char **dptr, unsigned int dataoff, @@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, union nf_inet_addr *saddr; struct nf_conntrack_tuple tuple; int family = ct->tuplehash[!dir].tuple.src.l3num; - int skip_expect = 0, ret = NF_DROP; + int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; u_int16_t base_port; __be16 rtp_port, rtcp_port; + typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port; typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; saddr = NULL; @@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, * to register it since we can see the same media description multiple * times on different connections in case multiple endpoints receive * the same call. + * + * RTP optimization: if we find a matching media channel expectation + * and both the expectation and this connection are SNATed, we assume + * both sides can reach each other directly and use the final + * destination address from the expectation. We still need to keep + * the NATed expectations for media that might arrive from the + * outside, and additionally need to expect the direct RTP stream + * in case it passes through us even without NAT. */ memset(&tuple, 0, sizeof(tuple)); if (saddr) @@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, tuple.dst.u.udp.port = port; rcu_read_lock(); - exp = __nf_ct_expect_find(&tuple); - if (exp && exp->master != ct && - nfct_help(exp->master)->helper == nfct_help(ct)->helper && - exp->class == class) - skip_expect = 1; - rcu_read_unlock(); + do { + exp = __nf_ct_expect_find(&tuple); - if (skip_expect) - return NF_ACCEPT; + if (!exp || exp->master == ct || + nfct_help(exp->master)->helper != nfct_help(ct)->helper || + exp->class != class) + break; + + if (exp->tuple.src.l3num == AF_INET && !direct_rtp && + (exp->saved_ip != exp->tuple.dst.u3.ip || + exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) && + ct->status & IPS_NAT_MASK) { + daddr->ip = exp->saved_ip; + tuple.dst.u3.ip = exp->saved_ip; + tuple.dst.u.udp.port = exp->saved_proto.udp.port; + direct_rtp = 1; + } else + skip_expect = 1; + } while (!skip_expect); + rcu_read_unlock(); base_port = ntohs(tuple.dst.u.udp.port) & ~1; rtp_port = htons(base_port); rtcp_port = htons(base_port + 1); + if (direct_rtp) { + nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); + if (nf_nat_sdp_port && + !nf_nat_sdp_port(skb, dptr, datalen, + mediaoff, medialen, ntohs(rtp_port))) + goto err1; + } + + if (skip_expect) + return NF_ACCEPT; + rtp_exp = nf_ct_expect_alloc(ct); if (rtp_exp == NULL) goto err1; @@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); - if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) + if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, mediaoff, medialen, daddr); else { -- cgit v1.2.3 From 9c2f5746b9cd536f0007709196d85a7e7d0070fa Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 26 Mar 2008 00:47:14 -0700 Subject: [NETNS]: Compilation fix for include/linux/netdevice.h. Commit commit c346dca10840a874240c78efe3f39acf4312a1f2 ([NET] NETNS: Omit net_device->nd_net without CONFIG_NET_NS) breaks compilation with CONFIG_NET_NS set. Fix the typo. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d146be40f46c..06ca84d71db4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -756,7 +756,7 @@ static inline void dev_net_set(struct net_device *dev, const struct net *net) { #ifdef CONFIG_NET_NS - dev->nd_dev = net; + dev->nd_net = net; #endif } -- cgit v1.2.3 From f5aa23fd49063745f85644dd7a9330acd706add6 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 26 Mar 2008 00:48:17 -0700 Subject: [NETNS]: Compilation warnings under CONFIG_NET_NS. Recent commits from YOSHIFUJI Hideaki have been introduced a several compilation warnings 'assignment discards qualifiers from pointer target type' due to extra const modifier in the inline call parameters of {dev|sock|twsk}_net_set. Drop it. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/net/inet_timewait_sock.h | 2 +- include/net/sock.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 06ca84d71db4..15fa84a15c27 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -753,7 +753,7 @@ struct net *dev_net(const struct net_device *dev) } static inline -void dev_net_set(struct net_device *dev, const struct net *net) +void dev_net_set(struct net_device *dev, struct net *net) { #ifdef CONFIG_NET_NS dev->nd_net = net; diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 07fe0d1a4f03..95c660c9719b 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -219,7 +219,7 @@ struct net *twsk_net(const struct inet_timewait_sock *twsk) } static inline -void twsk_net_set(struct inet_timewait_sock *twsk, const struct net *net) +void twsk_net_set(struct inet_timewait_sock *twsk, struct net *net) { #ifdef CONFIG_NET_NS twsk->tw_net = net; diff --git a/include/net/sock.h b/include/net/sock.h index 7e0d4a0c4d12..1c9d059223ee 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1358,7 +1358,7 @@ struct net *sock_net(const struct sock *sk) } static inline -void sock_net_set(struct sock *sk, const struct net *net) +void sock_net_set(struct sock *sk, struct net *net) { #ifdef CONFIG_NET_NS sk->sk_net = net; -- cgit v1.2.3 From 67727184f28c38d06013c6659560bb046c1d9f9c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 16:27:22 -0700 Subject: [VLAN]: Reduce memory consumed by vlan_groups Currently each vlan_groupd contains 8 pointers on arrays with 512 pointers on struct net_device each :) Such a construction "in many cases ... wastes memory". My proposal is to allow for some of these arrays pointers be NULL, meaning that there are no devices in it. When a new device is added to the vlan_group, the appropriate array is allocated. The check in vlan_group_get_device's is safe, since the pointer vg->vlan_devices_arrays[x] can only switch from NULL to not-NULL. The vlan_group_prealloc_vid() is guarded with rtnl lock and is also safe. I've checked (I hope that) all the places, that use these arrays and found, that the register_vlan_dev is the only place, that can put a vlan device on an empty vlan_group. Rough calculations shows, that after the patch a setup with a single vlan dev (or up to 512 vlans with sequential vids) will occupy approximately 8 times less memory. The question I have is - does this patch makes sense, or a totally new structures are required to store the vlan_devs? Signed-off-by: Pavel Emelyanov Signed-off-by: Patrick McHardy --- include/linux/if_vlan.h | 2 +- net/8021q/vlan.c | 36 +++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 79504b22a932..edd55af7ebd6 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -93,7 +93,7 @@ static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, { struct net_device **array; array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; - return array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]; + return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; } static inline void vlan_group_set_device(struct vlan_group *vg, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index c35dc230365c..694be86e4490 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -106,29 +106,35 @@ static void vlan_group_free(struct vlan_group *grp) static struct vlan_group *vlan_group_alloc(int ifindex) { struct vlan_group *grp; - unsigned int size; - unsigned int i; grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL); if (!grp) return NULL; - size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; - - for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) { - grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL); - if (!grp->vlan_devices_arrays[i]) - goto err; - } - grp->real_dev_ifindex = ifindex; hlist_add_head_rcu(&grp->hlist, &vlan_group_hash[vlan_grp_hashfn(ifindex)]); return grp; +} -err: - vlan_group_free(grp); - return NULL; +static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid) +{ + struct net_device **array; + unsigned int size; + + ASSERT_RTNL(); + + array = vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN]; + if (array != NULL) + return 0; + + size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; + array = kzalloc(size, GFP_KERNEL); + if (array == NULL) + return -ENOBUFS; + + vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN] = array; + return 0; } static void vlan_rcu_free(struct rcu_head *rcu) @@ -247,6 +253,10 @@ int register_vlan_dev(struct net_device *dev) return -ENOBUFS; } + err = vlan_group_prealloc_vid(grp, vlan_id); + if (err < 0) + goto out_free_group; + err = register_netdevice(dev); if (err < 0) goto out_free_group; -- cgit v1.2.3 From 0e5f8be1388093edc324a78ebf241170b258eba3 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 27 Mar 2008 14:25:53 -0700 Subject: [NETNS]: Compile NET /proc support only if CONFIG_NET is set. This fix broken compilation for 'allnoconfig'. This was introduced by Introduced by commit 1218854afa6f659be90b748cf1bc7badee954a35 ("[NET] NETNS: Omit seq_net_private->net without CONFIG_NET_NS.") Signed-off-by: Denis V. Lunev Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- fs/proc/proc_net.c | 2 ++ include/linux/seq_file.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'include/linux') diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 13cd7835d0df..7034facf8b8f 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -51,6 +51,7 @@ int seq_open_net(struct inode *ino, struct file *f, } EXPORT_SYMBOL_GPL(seq_open_net); +#ifdef CONFIG_NET int seq_release_net(struct inode *ino, struct file *f) { struct seq_file *seq; @@ -218,3 +219,4 @@ int __init proc_net_init(void) return register_pernet_subsys(&proc_net_ns_ops); } +#endif /* CONFIG_NET */ diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index d870a8253769..5da70c3f4417 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -63,6 +63,7 @@ extern struct list_head *seq_list_start_head(struct list_head *head, extern struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); +#ifdef CONFIG_NET struct net; struct seq_net_private { #ifdef CONFIG_NET_NS @@ -81,6 +82,7 @@ static inline struct net *seq_file_net(struct seq_file *seq) return &init_net; #endif } +#endif /* CONFIG_NET */ #endif #endif -- cgit v1.2.3 From 0dde3e16485dca16eb682dd59da1a598bf62e284 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:43:41 -0700 Subject: [NET]: uninline skb_put, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): ~500 files changed ... 869 funcs, 198 +, 111003 -, diff: -110805 --- skb_put skb_put | +104 Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -60744 855 funcs, 861 +, 61605 -, diff: -60744 --- skb_put skb_put | +57 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 21 +-------------------- net/core/skbuff.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7beb239d2ee0..f085955cb5a7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -892,6 +892,7 @@ static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset) /* * Add data to an sk_buff */ +extern unsigned char *skb_put(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp = skb_tail_pointer(skb); @@ -901,26 +902,6 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) return tmp; } -/** - * skb_put - add data to a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer. If this would - * exceed the total buffer size the kernel will panic. A pointer to the - * first byte of the extra data is returned. - */ -static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) -{ - unsigned char *tmp = skb_tail_pointer(skb); - SKB_LINEAR_ASSERT(skb); - skb->tail += len; - skb->len += len; - if (unlikely(skb->tail > skb->end)) - skb_over_panic(skb, len, current_text_addr()); - return tmp; -} - static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0d0fd28a9041..3402eca768f8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -857,6 +857,27 @@ free_skb: return err; } +/** + * skb_put - add data to a buffer + * @skb: buffer to use + * @len: amount of data to add + * + * This function extends the used data area of the buffer. If this would + * exceed the total buffer size the kernel will panic. A pointer to the + * first byte of the extra data is returned. + */ +unsigned char *skb_put(struct sk_buff *skb, unsigned int len) +{ + unsigned char *tmp = skb_tail_pointer(skb); + SKB_LINEAR_ASSERT(skb); + skb->tail += len; + skb->len += len; + if (unlikely(skb->tail > skb->end)) + skb_over_panic(skb, len, __builtin_return_address(0)); + return tmp; +} +EXPORT_SYMBOL(skb_put); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3 From 6be8ac2fdc5e69dec53913a42312a92dbfbd4907 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:47:24 -0700 Subject: [NET]: uninline skb_pull, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -28162 354 funcs, 3005 +, 31167 -, diff: -28162 --- skb_pull Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -9697 338 funcs, 221 +, 9918 -, diff: -9697 --- skb_pull skb_pull | +44 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 +--------------- net/core/skbuff.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f085955cb5a7..6d6cde7b243c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -927,6 +927,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) return skb->data; } +extern unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; @@ -934,21 +935,6 @@ static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) return skb->data += len; } -/** - * skb_pull - remove data from the start of a buffer - * @skb: buffer to use - * @len: amount of data to remove - * - * This function removes data from the start of a buffer, returning - * the memory to the headroom. A pointer to the next data in the buffer - * is returned. Once the data has been pulled future pushes will overwrite - * the old data. - */ -static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) -{ - return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); -} - extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta); static inline unsigned char *__pskb_pull(struct sk_buff *skb, unsigned int len) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3402eca768f8..cf489b6329e8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -878,6 +878,22 @@ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_put); +/** + * skb_pull - remove data from the start of a buffer + * @skb: buffer to use + * @len: amount of data to remove + * + * This function removes data from the start of a buffer, returning + * the memory to the headroom. A pointer to the next data in the buffer + * is returned. Once the data has been pulled future pushes will overwrite + * the old data. + */ +unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) +{ + return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); +} +EXPORT_SYMBOL(skb_pull); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3 From f58518e678e5eef430c8d5cdcc7cd28d285f1980 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:51:31 -0700 Subject: [NET]: uninline dev_alloc_skb, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -23668 392 funcs, 104 +, 23772 -, diff: -23668 --- dev_alloc_skb Without many debug CONFIGs (v2.6.25-rc2-mm1): -12178 382 funcs, 157 +, 12335 -, diff: -12178 --- dev_alloc_skb dev_alloc_skb | +37 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 17 +---------------- net/core/skbuff.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6d6cde7b243c..01a11b0c0291 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1272,22 +1272,7 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length, return skb; } -/** - * dev_alloc_skb - allocate an skbuff for receiving - * @length: length to allocate - * - * Allocate a new &sk_buff and assign it a usage count of one. The - * buffer has unspecified headroom built in. Users should allocate - * the headroom they think they need without accounting for the - * built in space. The built in space is used for optimisations. - * - * %NULL is returned if there is no free memory. Although this function - * allocates memory it can be called from an interrupt. - */ -static inline struct sk_buff *dev_alloc_skb(unsigned int length) -{ - return __dev_alloc_skb(length, GFP_ATOMIC); -} +extern struct sk_buff *dev_alloc_skb(unsigned int length); extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, gfp_t gfp_mask); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index cf489b6329e8..0daf5c0e5b8d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -263,6 +263,24 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, return skb; } +/** + * dev_alloc_skb - allocate an skbuff for receiving + * @length: length to allocate + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. Although this function + * allocates memory it can be called from an interrupt. + */ +struct sk_buff *dev_alloc_skb(unsigned int length) +{ + return __dev_alloc_skb(length, GFP_ATOMIC); +} +EXPORT_SYMBOL(dev_alloc_skb); + static void skb_drop_list(struct sk_buff **listp) { struct sk_buff *list = *listp; -- cgit v1.2.3 From c2aa270ad73d385bd6cdebf5d741bdf18a3e17ad Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:52:40 -0700 Subject: [NET]: uninline skb_push, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -21593 356 funcs, 2418 +, 24011 -, diff: -21593 --- skb_push Without many debug related CONFIGs (v2.6.25-rc2-mm1): -13890 341 funcs, 189 +, 14079 -, diff: -13890 --- skb_push skb_push | +46 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 19 +------------------ net/core/skbuff.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 01a11b0c0291..1baf4d43bb2d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -902,6 +902,7 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) return tmp; } +extern unsigned char *skb_push(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; @@ -909,24 +910,6 @@ static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) return skb->data; } -/** - * skb_push - add data to the start of a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer at the buffer - * start. If this would exceed the total buffer headroom the kernel will - * panic. A pointer to the first byte of the extra data is returned. - */ -static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) -{ - skb->data -= len; - skb->len += len; - if (unlikely(skb->datahead)) - skb_under_panic(skb, len, current_text_addr()); - return skb->data; -} - extern unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0daf5c0e5b8d..a37127b5899c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -896,6 +896,25 @@ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_put); +/** + * skb_push - add data to the start of a buffer + * @skb: buffer to use + * @len: amount of data to add + * + * This function extends the used data area of the buffer at the buffer + * start. If this would exceed the total buffer headroom the kernel will + * panic. A pointer to the first byte of the extra data is returned. + */ +unsigned char *skb_push(struct sk_buff *skb, unsigned int len) +{ + skb->data -= len; + skb->len += len; + if (unlikely(skb->datahead)) + skb_under_panic(skb, len, __builtin_return_address(0)); + return skb->data; +} +EXPORT_SYMBOL(skb_push); + /** * skb_pull - remove data from the start of a buffer * @skb: buffer to use -- cgit v1.2.3 From 419ae74ecc9494e58928a5c6652f4c072f3ca744 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:54:01 -0700 Subject: [NET]: uninline skb_trim, de-bloats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -10976 209 funcs, 123 +, 11099 -, diff: -10976 --- skb_trim Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -7360 192 funcs, 131 +, 7491 -, diff: -7360 --- skb_trim skb_trim | +42 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 +--------------- net/core/skbuff.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1baf4d43bb2d..ff72145d5d9e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1158,21 +1158,7 @@ static inline void __skb_trim(struct sk_buff *skb, unsigned int len) skb_set_tail_pointer(skb, len); } -/** - * skb_trim - remove end from a buffer - * @skb: buffer to alter - * @len: new length - * - * Cut the length of a buffer down by removing data from the tail. If - * the buffer is already under the length specified it is not modified. - * The skb must be linear. - */ -static inline void skb_trim(struct sk_buff *skb, unsigned int len) -{ - if (skb->len > len) - __skb_trim(skb, len); -} - +extern void skb_trim(struct sk_buff *skb, unsigned int len); static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a37127b5899c..86e5682728be 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -931,6 +931,22 @@ unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_pull); +/** + * skb_trim - remove end from a buffer + * @skb: buffer to alter + * @len: new length + * + * Cut the length of a buffer down by removing data from the tail. If + * the buffer is already under the length specified it is not modified. + * The skb must be linear. + */ +void skb_trim(struct sk_buff *skb, unsigned int len) +{ + if (skb->len > len) + __skb_trim(skb, len); +} +EXPORT_SYMBOL(skb_trim); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3 From 1567ca7eec7664b8be3b07755ac59dc1b1ec76cb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 28 Mar 2008 15:53:11 -0700 Subject: [NET]: Protect device namespace inlines with CONFIG_NET Include sites should not be bothered by whether CONFIG_NET is set or not when trying to include benign files like linux/etherdevice.h et al. From a report by Stephen Rothwell. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3b54f8a2c055..8576ca928dae 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,6 +741,7 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) +#ifdef CONFIG_NET /* * Net namespace inlines */ @@ -761,6 +762,7 @@ void dev_net_set(struct net_device *dev, struct net *net) dev->nd_net = net; #endif } +#endif /** * netdev_priv - access network device private data -- cgit v1.2.3 From 095d911201b0741e7f326d269a005dba55985acf Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Mar 2008 16:39:58 -0700 Subject: [LIB]: Drop the pcounter itself. The knock-out. The pcounter abstraction is not used any longer in the kernel. Not sure whether this should go via netdev tree, but as far as I remember it was added via this one, and besides Eric thinks that Andrew shouldn't mind this. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/linux/pcounter.h | 74 ------------------------------------------------ lib/Makefile | 1 - lib/pcounter.c | 58 ------------------------------------- 3 files changed, 133 deletions(-) delete mode 100644 include/linux/pcounter.h delete mode 100644 lib/pcounter.c (limited to 'include/linux') diff --git a/include/linux/pcounter.h b/include/linux/pcounter.h deleted file mode 100644 index a82d9f2628ca..000000000000 --- a/include/linux/pcounter.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef __LINUX_PCOUNTER_H -#define __LINUX_PCOUNTER_H -/* - * Using a dynamic percpu 'int' variable has a cost : - * 1) Extra dereference - * Current per_cpu_ptr() implementation uses an array per 'percpu variable'. - * 2) memory cost of NR_CPUS*(32+sizeof(void *)) instead of num_possible_cpus()*4 - * - * This pcounter implementation is an abstraction to be able to use - * either a static or a dynamic per cpu variable. - * One dynamic per cpu variable gets a fast & cheap implementation, we can - * change pcounter implementation too. - */ -struct pcounter { -#ifdef CONFIG_SMP - void (*add)(struct pcounter *self, int inc); - int (*getval)(const struct pcounter *self, int cpu); - int *per_cpu_values; -#else - int val; -#endif -}; - -#ifdef CONFIG_SMP -#include - -#define DEFINE_PCOUNTER(NAME) \ -static DEFINE_PER_CPU(int, NAME##_pcounter_values); \ -static void NAME##_pcounter_add(struct pcounter *self, int val) \ -{ \ - __get_cpu_var(NAME##_pcounter_values) += val; \ -} \ -static int NAME##_pcounter_getval(const struct pcounter *self, int cpu) \ -{ \ - return per_cpu(NAME##_pcounter_values, cpu); \ -} \ - -#define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER) \ - MEMBER = { \ - .add = NAME##_pcounter_add, \ - .getval = NAME##_pcounter_getval, \ - } - - -static inline void pcounter_add(struct pcounter *self, int inc) -{ - self->add(self, inc); -} - -extern int pcounter_getval(const struct pcounter *self); -extern int pcounter_alloc(struct pcounter *self); -extern void pcounter_free(struct pcounter *self); - - -#else /* CONFIG_SMP */ - -static inline void pcounter_add(struct pcounter *self, int inc) -{ - self->val += inc; -} - -static inline int pcounter_getval(const struct pcounter *self) -{ - return self->val; -} - -#define DEFINE_PCOUNTER(NAME) -#define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER) -#define pcounter_alloc(self) 0 -#define pcounter_free(self) - -#endif /* CONFIG_SMP */ - -#endif /* __LINUX_PCOUNTER_H */ diff --git a/lib/Makefile b/lib/Makefile index 23de261a4c83..4d059d469554 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o obj-$(CONFIG_SMP) += percpu_counter.o -obj-$(CONFIG_SMP) += pcounter.o obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o diff --git a/lib/pcounter.c b/lib/pcounter.c deleted file mode 100644 index 9b56807da93b..000000000000 --- a/lib/pcounter.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Define default pcounter functions - * Note that often used pcounters use dedicated functions to get a speed increase. - * (see DEFINE_PCOUNTER/REF_PCOUNTER_MEMBER) - */ - -#include -#include -#include -#include - -static void pcounter_dyn_add(struct pcounter *self, int inc) -{ - per_cpu_ptr(self->per_cpu_values, smp_processor_id())[0] += inc; -} - -static int pcounter_dyn_getval(const struct pcounter *self, int cpu) -{ - return per_cpu_ptr(self->per_cpu_values, cpu)[0]; -} - -int pcounter_getval(const struct pcounter *self) -{ - int res = 0, cpu; - - for_each_possible_cpu(cpu) - res += self->getval(self, cpu); - - return res; -} -EXPORT_SYMBOL_GPL(pcounter_getval); - -int pcounter_alloc(struct pcounter *self) -{ - int rc = 0; - if (self->add == NULL) { - self->per_cpu_values = alloc_percpu(int); - if (self->per_cpu_values != NULL) { - self->add = pcounter_dyn_add; - self->getval = pcounter_dyn_getval; - } else - rc = 1; - } - return rc; -} -EXPORT_SYMBOL_GPL(pcounter_alloc); - -void pcounter_free(struct pcounter *self) -{ - if (self->per_cpu_values != NULL) { - free_percpu(self->per_cpu_values); - self->per_cpu_values = NULL; - self->getval = NULL; - self->add = NULL; - } -} -EXPORT_SYMBOL_GPL(pcounter_free); - -- cgit v1.2.3 From 9307b570a745da4f2d83195f5337927e98221bb2 Mon Sep 17 00:00:00 2001 From: "S.Caglar Onur" Date: Fri, 28 Mar 2008 14:41:24 -0700 Subject: drivers/net/arcnet/arcnet.c: use time_* macros The functions time_before, time_before_eq, time_after, and time_after_eq are more robust for comparing jiffies against other values. So use the time_after() macro, defined in linux/jiffies.h, which deals with wrapping correctly. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: S.Caglar Onur Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/arcnet/arcnet.c | 5 +++-- include/linux/arcdevice.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index c59c8067de99..bdc4c0bb56d9 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -940,7 +940,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) /* is the RECON info empty or old? */ if (!lp->first_recon || !lp->last_recon || - jiffies - lp->last_recon > HZ * 10) { + time_after(jiffies, lp->last_recon + HZ * 10)) { if (lp->network_down) BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); lp->first_recon = lp->last_recon = jiffies; @@ -974,7 +974,8 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) lp->num_recons = 1; } } - } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { + } else if (lp->network_down && + time_after(jiffies, lp->last_recon + HZ * 10)) { if (lp->network_down) BUGMSG(D_NORMAL, "cabling restored?\n"); lp->first_recon = lp->last_recon = 0; diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index fde675872c56..a1916078fd08 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -283,8 +283,8 @@ struct arcnet_local { int next_buf, first_free_buf; /* network "reconfiguration" handling */ - time_t first_recon, /* time of "first" RECON message to count */ - last_recon; /* time of most recent RECON */ + unsigned long first_recon; /* time of "first" RECON message to count */ + unsigned long last_recon; /* time of most recent RECON */ int num_recons; /* number of RECONs between first and last. */ bool network_down; /* do we think the network is down? */ -- cgit v1.2.3 From 3edf8fa5ccf10688a9280b5cbca8ed3947c42866 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 31 Mar 2008 00:28:14 -0700 Subject: [NET]: Fix allnoconfig build on powerpc and avr32 As reported by Haavard Skinnemoen and Stephen Rothwell: > allnoconfig fails with > > include/linux/netdevice.h:843: error: implicit declaration of function 'dev_net' > > which seems to be because the definition of dev_net is inside #ifdef > CONFIG_NET, while next_net_device, which calls it, is not. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8576ca928dae..993758f924be 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -827,6 +827,7 @@ struct packet_type { extern rwlock_t dev_base_lock; /* Device list lock */ +#ifdef CONFIG_NET #define for_each_netdev(net, d) \ list_for_each_entry(d, &(net)->dev_base_head, dev_list) #define for_each_netdev_safe(net, d, n) \ @@ -850,6 +851,7 @@ static inline struct net_device *first_net_device(struct net *net) return list_empty(&net->dev_base_head) ? NULL : net_device_entry(net->dev_base_head.next); } +#endif extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); -- cgit v1.2.3 From 58e9fee13e579df44922172dbe3c9e3ba3edf7a3 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 14 Mar 2008 13:52:52 -0500 Subject: [GFS2] Invalidate cache at correct point GFS2 wasn't invalidating its cache before it called into the lock manager with a request that could potentially drop a lock. This was leaving a window where the lock could be actually be held by another node, but the file's page cache would still appear valid, causing coherency problems. This patch moves the cache invalidation to before the lock manager call when dropping a lock. It also adds the option to the lock_dlm lock manager to not use conversion mode deadlock avoidance, which, on a conversion from shared to exclusive, could internally drop the lock, and then reacquire in. GFS2 now asks lock_dlm to not do this. Instead, GFS2 manually drops the lock and reacquires it. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 35 +++++++++++++++++++++-------------- fs/gfs2/incore.h | 1 + fs/gfs2/locking/dlm/lock.c | 3 ++- fs/gfs2/locking/dlm/thread.c | 10 +++++++++- fs/gfs2/ops_fstype.c | 2 +- include/linux/lm_interface.h | 10 ++++++++++ 6 files changed, 44 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 63981e2fb835..d636b3e80f5d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -764,7 +764,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) static void drop_bh(struct gfs2_glock *gl, unsigned int ret) { struct gfs2_sbd *sdp = gl->gl_sbd; - const struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_holder *gh = gl->gl_req_gh; gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -772,8 +772,14 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) state_change(gl, LM_ST_UNLOCKED); - if (glops->go_inval) - glops->go_inval(gl, DIO_METADATA); + if (test_and_clear_bit(GLF_CONV_DEADLK, &gl->gl_flags)) { + spin_lock(&gl->gl_spin); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + gfs2_glock_xmote_th(gl, gl->gl_req_gh); + gfs2_glock_put(gl); + return; + } spin_lock(&gl->gl_spin); gfs2_demote_wake(gl); @@ -794,7 +800,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_glock_operations *glops = gl->gl_ops; struct gfs2_holder *gh = gl->gl_req_gh; - int prev_state = gl->gl_state; int op_done = 1; if (!gh && (ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) { @@ -808,16 +813,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) state_change(gl, ret & LM_OUT_ST_MASK); - if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) { - if (glops->go_inval) - glops->go_inval(gl, DIO_METADATA); - } else if (gl->gl_state == LM_ST_DEFERRED) { - /* We might not want to do this here. - Look at moving to the inode glops. */ - if (glops->go_inval) - glops->go_inval(gl, 0); - } - /* Deal with each possible exit condition */ if (!gh) { @@ -837,6 +832,14 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) } } else { spin_lock(&gl->gl_spin); + if (ret & LM_OUT_CONV_DEADLK) { + gh->gh_error = 0; + set_bit(GLF_CONV_DEADLK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + gfs2_glock_drop_th(gl); + gfs2_glock_put(gl); + return; + } list_del_init(&gh->gh_list); gh->gh_error = -EIO; if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) @@ -910,6 +913,8 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) if (glops->go_xmote_th) glops->go_xmote_th(gl); + if (state == LM_ST_DEFERRED && glops->go_inval) + glops->go_inval(gl, DIO_METADATA); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -952,6 +957,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) if (glops->go_xmote_th) glops->go_xmote_th(gl); + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 4ba2ea63119d..9c2c0b90b22a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -167,6 +167,7 @@ enum { GLF_DEMOTE_IN_PROGRESS = 6, GLF_LFLUSH = 7, GLF_WAITERS2 = 8, + GLF_CONV_DEADLK = 9, }; struct gfs2_glock { diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 542a797ac89a..53a6ab3c0919 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -137,7 +137,8 @@ static inline unsigned int make_flags(struct gdlm_lock *lp, /* Conversion deadlock avoidance by DLM */ - if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) && + if (!(lp->ls->fsflags & LM_MFLAG_CONV_NODROP) && + !test_bit(LFL_FORCE_PROMOTE, &lp->flags) && !(lkf & DLM_LKF_NOQUEUE) && cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req) lkf |= DLM_LKF_CONVDEADLK; diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 521694fc19d6..e53db6fd28ab 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -135,7 +135,15 @@ static void process_complete(struct gdlm_lock *lp) lp->lksb.sb_status, lp->lockname.ln_type, (unsigned long long)lp->lockname.ln_number, lp->flags); - return; + if (lp->lksb.sb_status == -EDEADLOCK && + lp->ls->fsflags & LM_MFLAG_CONV_NODROP) { + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CONV_DEADLK; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } else + return; } /* diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5b518f73497a..ef9c6c4f80f6 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -723,7 +723,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) { char *proto = sdp->sd_proto_name; char *table = sdp->sd_table_name; - int flags = 0; + int flags = LM_MFLAG_CONV_NODROP; int error; if (sdp->sd_args.ar_spectator) diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h index 1418fdc9ac02..f274997bc283 100644 --- a/include/linux/lm_interface.h +++ b/include/linux/lm_interface.h @@ -21,9 +21,15 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); * modify the filesystem. The lock module shouldn't assign a journal to the FS * mount. It shouldn't send recovery callbacks to the FS mount. If the node * dies or withdraws, all locks can be wiped immediately. + * + * LM_MFLAG_CONV_NODROP + * Do not allow the dlm to internally resolve conversion deadlocks by demoting + * the lock to unlocked and then reacquiring it in the requested mode. Instead, + * it should cancel the request and return LM_OUT_CONV_DEADLK. */ #define LM_MFLAG_SPECTATOR 0x00000001 +#define LM_MFLAG_CONV_NODROP 0x00000002 /* * lm_lockstruct flags @@ -110,6 +116,9 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); * * LM_OUT_ASYNC * The result of the request will be returned in an LM_CB_ASYNC callback. + * + * LM_OUT_CONV_DEADLK + * The lock request was canceled do to a conversion deadlock. */ #define LM_OUT_ST_MASK 0x00000003 @@ -117,6 +126,7 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); #define LM_OUT_CANCELED 0x00000008 #define LM_OUT_ASYNC 0x00000080 #define LM_OUT_ERROR 0x00000100 +#define LM_OUT_CONV_DEADLK 0x00000200 /* * lm_callback_t types -- cgit v1.2.3 From c0f39322c335412339dec16ebfd2a05ceba5ebcf Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 2 Apr 2008 00:10:28 -0700 Subject: [NETNS]: Do not include net/net_namespace.h from seq_file.h Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/seq_file.h | 22 ---------------------- include/linux/seq_file_net.h | 27 +++++++++++++++++++++++++++ include/net/net_namespace.h | 2 ++ 3 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 include/linux/seq_file_net.h (limited to 'include/linux') diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 5da70c3f4417..1da1e6208a0a 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -5,7 +5,6 @@ #include #include #include -#include struct seq_operations; struct file; @@ -63,26 +62,5 @@ extern struct list_head *seq_list_start_head(struct list_head *head, extern struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); -#ifdef CONFIG_NET -struct net; -struct seq_net_private { -#ifdef CONFIG_NET_NS - struct net *net; -#endif -}; - -int seq_open_net(struct inode *, struct file *, - const struct seq_operations *, int); -int seq_release_net(struct inode *, struct file *); -static inline struct net *seq_file_net(struct seq_file *seq) -{ -#ifdef CONFIG_NET_NS - return ((struct seq_net_private *)seq->private)->net; -#else - return &init_net; -#endif -} -#endif /* CONFIG_NET */ - #endif #endif diff --git a/include/linux/seq_file_net.h b/include/linux/seq_file_net.h new file mode 100644 index 000000000000..4ac52542a563 --- /dev/null +++ b/include/linux/seq_file_net.h @@ -0,0 +1,27 @@ +#ifndef __SEQ_FILE_NET_H__ +#define __SEQ_FILE_NET_H__ + +#include + +struct net; +extern struct net init_net; + +struct seq_net_private { +#ifdef CONFIG_NET_NS + struct net *net; +#endif +}; + +int seq_open_net(struct inode *, struct file *, + const struct seq_operations *, int); +int seq_release_net(struct inode *, struct file *); +static inline struct net *seq_file_net(struct seq_file *seq) +{ +#ifdef CONFIG_NET_NS + return ((struct seq_net_private *)seq->private)->net; +#else + return &init_net; +#endif +} + +#endif diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 4a37037b1d17..6c9a48a46685 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -61,6 +61,8 @@ struct net { #ifdef CONFIG_NET +#include + /* Init's network namespace */ extern struct net init_net; #define INIT_NET_NS(net_ns) .net_ns = &init_net, -- cgit v1.2.3 From fadf6bf06069138f8e97c9a963be38348ba2708b Mon Sep 17 00:00:00 2001 From: "Templin, Fred L" Date: Tue, 11 Mar 2008 18:35:59 -0400 Subject: [IPV6] SIT: Add PRL management for ISATAP. This patch updates the Linux the Intra-Site Automatic Tunnel Addressing Protocol (ISATAP) implementation. It places the ISATAP potential router list (PRL) in the kernel and adds three new private ioctls for PRL management. [Add several changes of structure name, constant names etc. - yoshfuji] Signed-off-by: Fred L. Templin Signed-off-by: YOSHIFUJI Hideaki --- include/linux/if_tunnel.h | 18 ++++- include/linux/skbuff.h | 3 +- include/net/ipip.h | 7 ++ include/net/ndisc.h | 9 +++ net/ipv6/ndisc.c | 24 ++++++ net/ipv6/route.c | 2 - net/ipv6/sit.c | 186 +++++++++++++++++++++++++++++++++++----------- 7 files changed, 199 insertions(+), 50 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 228eb4eb3129..f20c224d544c 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -7,6 +7,9 @@ #define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) #define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) #define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +#define SIOCADDPRL (SIOCDEVPRIVATE + 5) +#define SIOCDELPRL (SIOCDEVPRIVATE + 6) +#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) #define GRE_CSUM __constant_htons(0x8000) #define GRE_ROUTING __constant_htons(0x4000) @@ -17,9 +20,6 @@ #define GRE_FLAGS __constant_htons(0x00F8) #define GRE_VERSION __constant_htons(0x0007) -/* i_flags values for SIT mode */ -#define SIT_ISATAP 0x0001 - struct ip_tunnel_parm { char name[IFNAMSIZ]; @@ -31,4 +31,16 @@ struct ip_tunnel_parm struct iphdr iph; }; +/* SIT-mode i_flags */ +#define SIT_ISATAP 0x0001 + +struct ip_tunnel_prl { + __be32 addr; + __u16 flags; + __u16 __reserved; +}; + +/* PRL flags */ +#define PRL_DEFAULT 0x0001 + #endif /* _IF_TUNNEL_H_ */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ff72145d5d9e..e10e55c9b081 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -313,7 +313,8 @@ struct sk_buff { __u16 tc_verd; /* traffic control verdict */ #endif #endif - /* 2 byte hole */ + __u8 ndisc_nodetype:2; + /* 14 bit hole */ #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; diff --git a/include/net/ipip.h b/include/net/ipip.h index 549e132bca9c..205536a014e8 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -24,6 +24,13 @@ struct ip_tunnel int mlink; struct ip_tunnel_parm parms; + struct ip_tunnel_prl_entry *prl; /* potential router list */ +}; + +struct ip_tunnel_prl_entry +{ + struct ip_tunnel_prl_entry *next; + struct ip_tunnel_prl entry; }; #define IPTUNNEL_XMIT() do { \ diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 5aedf324de66..9f2bae68d28c 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -11,6 +11,15 @@ #define NDISC_NEIGHBOUR_ADVERTISEMENT 136 #define NDISC_REDIRECT 137 +/* + * Router type: cross-layer information from link-layer to + * IPv6 layer reported by certain link types (e.g., RFC4214). + */ +#define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */ +#define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */ +#define NDISC_NODETYPE_NODEFAULT 2 /* non-default router */ +#define NDISC_NODETYPE_DEFAULT 3 /* default router */ + /* * ndisc options */ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 510aa747a404..53b546019fd5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1092,6 +1092,12 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { + ND_PRINTK2(KERN_WARNING + "ICMPv6 RA: from host or unauthorized router\n"); + return; + } + /* * set the RA_RECV flag in the interface */ @@ -1115,6 +1121,10 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + /* skip link-specific parameters from interior routers */ + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + goto skip_linkparms; + if (in6_dev->if_flags & IF_RS_SENT) { /* * flag that an RA was received after an RS was sent @@ -1229,6 +1239,8 @@ skip_defrtr: } } +skip_linkparms: + /* * Process options. */ @@ -1268,6 +1280,10 @@ skip_defrtr: } #endif + /* skip link-specific ndopts from interior routers */ + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + goto out; + if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { struct nd_opt_hdr *p; for (p = ndopts.nd_opts_pi; @@ -1331,6 +1347,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) int optlen; u8 *lladdr = NULL; + switch (skb->ndisc_nodetype) { + case NDISC_NODETYPE_HOST: + case NDISC_NODETYPE_NODEFAULT: + ND_PRINTK2(KERN_WARNING + "ICMPv6 Redirect: from host or unauthorized router\n"); + return; + } + if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: source address is not link-local.\n"); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd82b6db35ff..f17b2f61891e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1699,8 +1699,6 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d return rt; } -EXPORT_SYMBOL(rt6_get_dflt_router); - struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1b8196c8d145..4786419ade0e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -16,7 +16,7 @@ * Changes: * Roger Venning : 6to4 support * Nate Thompson : 6to4 support - * Fred L. Templin : isatap support + * Fred Templin : isatap support */ #include @@ -197,6 +197,119 @@ failed: return NULL; } +static struct ip_tunnel_prl_entry * +ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) +{ + struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; + + for (p = t->prl; p; p = p->next) + if (p->entry.addr == addr) + break; + return p; + +} + +static int +ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) +{ + struct ip_tunnel_prl_entry *p; + + for (p = t->prl; p; p = p->next) { + if (p->entry.addr == a->addr) { + if (chg) { + p->entry = *a; + return 0; + } + return -EEXIST; + } + } + + if (chg) + return -ENXIO; + + p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); + if (!p) + return -ENOBUFS; + + p->entry = *a; + p->next = t->prl; + t->prl = p; + return 0; +} + +static int +ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) +{ + struct ip_tunnel_prl_entry *x, **p; + + if (a) { + for (p = &t->prl; *p; p = &(*p)->next) { + if ((*p)->entry.addr == a->addr) { + x = *p; + *p = x->next; + kfree(x); + return 0; + } + } + return -ENXIO; + } else { + while (t->prl) { + x = t->prl; + t->prl = t->prl->next; + kfree(x); + } + } + return 0; +} + +/* copied directly from anycast.c */ +static int +ipip6_onlink(struct in6_addr *addr, struct net_device *dev) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + int onlink; + + onlink = 0; + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { + onlink = ipv6_prefix_equal(addr, &ifa->addr, + ifa->prefix_len); + if (onlink) + break; + } + read_unlock_bh(&idev->lock); + } + rcu_read_unlock(); + return onlink; +} + +static int +isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) +{ + struct ip_tunnel_prl_entry *p = ipip6_tunnel_locate_prl(t, iph->saddr); + int ok = 1; + + if (p) { + if (p->entry.flags & PRL_DEFAULT) + skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; + else + skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; + } else { + struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + if (ipv6_addr_is_isatap(addr6) && + (addr6->s6_addr32[3] == iph->saddr) && + ipip6_onlink(addr6, t->dev)) + skb->ndisc_nodetype = NDISC_NODETYPE_HOST; + else + ok = 0; + } + return ok; +} + static void ipip6_tunnel_uninit(struct net_device *dev) { if (dev == ipip6_fb_tunnel_dev) { @@ -206,6 +319,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) dev_put(dev); } else { ipip6_tunnel_unlink(netdev_priv(dev)); + ipip6_tunnel_del_prl(netdev_priv(dev), 0); dev_put(dev); } } @@ -365,48 +479,6 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) IP6_ECN_set_ce(ipv6_hdr(skb)); } -/* ISATAP (RFC4214) - check source address */ -static int -isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev) -{ - struct neighbour *neigh; - struct dst_entry *dst; - struct rt6_info *rt; - struct flowi fl; - struct in6_addr *addr6; - struct in6_addr rtr; - struct ipv6hdr *iph6; - int ok = 0; - - /* from onlink default router */ - ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); - ipv6_isatap_eui64(rtr.s6_addr + 8, iph->saddr); - if ((rt = rt6_get_dflt_router(&rtr, dev))) { - dst_release(&rt->u.dst); - return 1; - } - - iph6 = ipv6_hdr(skb); - memset(&fl, 0, sizeof(fl)); - fl.proto = iph6->nexthdr; - ipv6_addr_copy(&fl.fl6_dst, &iph6->saddr); - fl.oif = dev->ifindex; - security_skb_classify_flow(skb, &fl); - - dst = ip6_route_output(&init_net, NULL, &fl); - if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) { - - addr6 = (struct in6_addr*)&neigh->primary_key; - - /* from correct previous hop */ - if (ipv6_addr_is_isatap(addr6) && - (addr6->s6_addr32[3] == iph->saddr)) - ok = 1; - } - dst_release(dst); - return ok; -} - static int ipip6_rcv(struct sk_buff *skb) { struct iphdr *iph; @@ -427,7 +499,7 @@ static int ipip6_rcv(struct sk_buff *skb) skb->pkt_type = PACKET_HOST; if ((tunnel->dev->priv_flags & IFF_ISATAP) && - !isatap_srcok(skb, iph, tunnel->dev)) { + !isatap_chksrc(skb, iph, tunnel)) { tunnel->stat.rx_errors++; read_unlock(&ipip6_lock); kfree_skb(skb); @@ -707,6 +779,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) { int err = 0; struct ip_tunnel_parm p; + struct ip_tunnel_prl prl; struct ip_tunnel *t; switch (cmd) { @@ -806,6 +879,31 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = 0; break; + case SIOCADDPRL: + case SIOCDELPRL: + case SIOCCHGPRL: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + goto done; + err = -EINVAL; + if (dev == ipip6_fb_tunnel_dev) + goto done; + err = -EFAULT; + if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) + goto done; + err = -ENOENT; + if (!(t = netdev_priv(dev))) + goto done; + + ipip6_tunnel_unlink(t); + if (cmd == SIOCDELPRL) + err = ipip6_tunnel_del_prl(t, &prl); + else + err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); + ipip6_tunnel_link(t); + netdev_state_change(dev); + break; + default: err = -EINVAL; } -- cgit v1.2.3 From 300aaeeaab5f447fcf40e911afe96df3de28f0db Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 24 Mar 2008 18:28:39 +0900 Subject: [IPV6] SIT: Add SIOCGETPRL ioctl to get/dump PRL. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/if_tunnel.h | 4 ++ include/net/ipip.h | 5 ++- net/ipv6/sit.c | 96 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 95 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index f20c224d544c..f1fbe9c930d7 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -7,6 +7,7 @@ #define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) #define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) #define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +#define SIOCGETPRL (SIOCDEVPRIVATE + 4) #define SIOCADDPRL (SIOCDEVPRIVATE + 5) #define SIOCDELPRL (SIOCDEVPRIVATE + 6) #define SIOCCHGPRL (SIOCDEVPRIVATE + 7) @@ -38,6 +39,9 @@ struct ip_tunnel_prl { __be32 addr; __u16 flags; __u16 __reserved; + __u32 datalen; + __u32 __reserved2; + void __user *data; }; /* PRL flags */ diff --git a/include/net/ipip.h b/include/net/ipip.h index 205536a014e8..633ed4def8e3 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -24,13 +24,16 @@ struct ip_tunnel int mlink; struct ip_tunnel_parm parms; + struct ip_tunnel_prl_entry *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ }; struct ip_tunnel_prl_entry { struct ip_tunnel_prl_entry *next; - struct ip_tunnel_prl entry; + __be32 addr; + u16 flags; }; #define IPTUNNEL_XMIT() do { \ diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 84c1ed246afb..08a483a8de50 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -203,12 +203,73 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; for (p = t->prl; p; p = p->next) - if (p->entry.addr == addr) + if (p->addr == addr) break; return p; } +static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) +{ + struct ip_tunnel_prl *kp; + struct ip_tunnel_prl_entry *prl; + unsigned int cmax, c = 0, ca, len; + int ret = 0; + + cmax = a->datalen / sizeof(*a); + if (cmax > 1 && a->addr != htonl(INADDR_ANY)) + cmax = 1; + + /* For simple GET or for root users, + * we try harder to allocate. + */ + kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ? + kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : + NULL; + + read_lock(&ipip6_lock); + + ca = t->prl_count < cmax ? t->prl_count : cmax; + + if (!kp) { + /* We don't try hard to allocate much memory for + * non-root users. + * For root users, retry allocating enough memory for + * the answer. + */ + kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC); + if (!kp) { + ret = -ENOMEM; + goto out; + } + } + + c = 0; + for (prl = t->prl; prl; prl = prl->next) { + if (c > cmax) + break; + if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr) + continue; + kp[c].addr = prl->addr; + kp[c].flags = prl->flags; + c++; + if (a->addr != htonl(INADDR_ANY)) + break; + } +out: + read_unlock(&ipip6_lock); + + len = sizeof(*kp) * c; + ret = len ? copy_to_user(a->data, kp, len) : 0; + + kfree(kp); + if (ret) + return -EFAULT; + + a->datalen = len; + return 0; +} + static int ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) { @@ -221,7 +282,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) write_lock(&ipip6_lock); for (p = t->prl; p; p = p->next) { - if (p->entry.addr == a->addr) { + if (p->addr == a->addr) { if (chg) goto update; err = -EEXIST; @@ -242,8 +303,10 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) p->next = t->prl; t->prl = p; + t->prl_count++; update: - p->entry = *a; + p->addr = a->addr; + p->flags = a->flags; out: write_unlock(&ipip6_lock); return err; @@ -259,10 +322,11 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if (a && a->addr != htonl(INADDR_ANY)) { for (p = &t->prl; *p; p = &(*p)->next) { - if ((*p)->entry.addr == a->addr) { + if ((*p)->addr == a->addr) { x = *p; *p = x->next; kfree(x); + t->prl_count--; goto out; } } @@ -272,6 +336,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) x = t->prl; t->prl = t->prl->next; kfree(x); + t->prl_count--; } } out: @@ -313,7 +378,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) read_lock(&ipip6_lock); p = __ipip6_tunnel_locate_prl(t, iph->saddr); if (p) { - if (p->entry.flags & PRL_DEFAULT) + if (p->flags & PRL_DEFAULT) skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; else skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; @@ -899,11 +964,12 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = 0; break; + case SIOCGETPRL: case SIOCADDPRL: case SIOCDELPRL: case SIOCCHGPRL: err = -EPERM; - if (!capable(CAP_NET_ADMIN)) + if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) goto done; err = -EINVAL; if (dev == ipip6_fb_tunnel_dev) @@ -915,11 +981,23 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!(t = netdev_priv(dev))) goto done; - if (cmd == SIOCDELPRL) + switch (cmd) { + case SIOCGETPRL: + err = ipip6_tunnel_get_prl(t, &prl); + if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, + &prl, sizeof(prl))) + err = -EFAULT; + break; + case SIOCDELPRL: err = ipip6_tunnel_del_prl(t, &prl); - else + break; + case SIOCADDPRL: + case SIOCCHGPRL: err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); - netdev_state_change(dev); + break; + } + if (cmd != SIOCGETPRL) + netdev_state_change(dev); break; default: -- cgit v1.2.3 From de357cc01334a468e4d5b7ba66a17b0d3ca9d63e Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 15 Mar 2008 23:59:18 -0400 Subject: [IPV6] NDISC: Don't rely on node-type hint from L2 unless required. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/skbuff.h | 2 ++ net/ipv6/Kconfig | 4 ++++ net/ipv6/ndisc.c | 10 ++++++++++ 3 files changed, 16 insertions(+) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e10e55c9b081..e517701c25ba 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -313,7 +313,9 @@ struct sk_buff { __u16 tc_verd; /* traffic control verdict */ #endif #endif +#ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; +#endif /* 14 bit hole */ #ifdef CONFIG_NET_DMA diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 47263e45bacb..7d2e7f0941ac 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -168,6 +168,7 @@ config IPV6_SIT tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" depends on IPV6 select INET_TUNNEL + select IPV6_NDISC_NODETYPE default y ---help--- Tunneling means encapsulating data of one protocol type within @@ -178,6 +179,9 @@ config IPV6_SIT Saying M here will produce a module called sit.ko. If unsure, say Y. +config IPV6_NDISC_NODETYPE + bool + config IPV6_TUNNEL tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)" select INET6_TUNNEL diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 16273e11e53d..c400b874097a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1092,11 +1092,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } +#ifdef CONFIG_IPV6_NDISC_NODETYPE if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: from host or unauthorized router\n"); return; } +#endif /* * set the RA_RECV flag in the interface @@ -1121,9 +1123,11 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } +#ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto skip_linkparms; +#endif if (in6_dev->if_flags & IF_RS_SENT) { /* @@ -1239,7 +1243,9 @@ skip_defrtr: } } +#ifdef CONFIG_IPV6_NDISC_NODETYPE skip_linkparms: +#endif /* * Process options. @@ -1286,9 +1292,11 @@ skip_linkparms: } #endif +#ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific ndopts from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto out; +#endif if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { struct nd_opt_hdr *p; @@ -1353,6 +1361,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) int optlen; u8 *lladdr = NULL; +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) { case NDISC_NODETYPE_HOST: case NDISC_NODETYPE_NODEFAULT: @@ -1360,6 +1369,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) "ICMPv6 Redirect: from host or unauthorized router\n"); return; } +#endif if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { ND_PRINTK2(KERN_WARNING -- cgit v1.2.3 From a4aa834a9165150252c5cd953faab4de29d51b87 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 13:04:33 -0700 Subject: [NETNS]: Declare init_net even without CONFIG_NET defined. This does not look good, but there is no other choice. The compilation without CONFIG_NET is broken and can not be fixed with ease. After that there is no need for the following commits: 1567ca7eec7664b8be3b07755ac59dc1b1ec76cb 3edf8fa5ccf10688a9280b5cbca8ed3947c42866 2d38f9a4f8d2ebdc799f03eecf82345825495711 Revert them. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ---- include/net/net_namespace.h | 3 ++- lib/kobject_uevent.c | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c36c76caf20b..8b17ed40dea2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,7 +741,6 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) -#ifdef CONFIG_NET /* * Net namespace inlines */ @@ -762,7 +761,6 @@ void dev_net_set(struct net_device *dev, struct net *net) dev->nd_net = net; #endif } -#endif /** * netdev_priv - access network device private data @@ -827,7 +825,6 @@ struct packet_type { extern rwlock_t dev_base_lock; /* Device list lock */ -#ifdef CONFIG_NET #define for_each_netdev(net, d) \ list_for_each_entry(d, &(net)->dev_base_head, dev_list) #define for_each_netdev_safe(net, d, n) \ @@ -851,7 +848,6 @@ static inline struct net_device *first_net_device(struct net *net) return list_empty(&net->dev_base_head) ? NULL : net_device_entry(net->dev_base_head.next); } -#endif extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 6c9a48a46685..0ab62ed2fdef 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -60,11 +60,12 @@ struct net { }; -#ifdef CONFIG_NET #include /* Init's network namespace */ extern struct net init_net; + +#ifdef CONFIG_NET #define INIT_NET_NS(net_ns) .net_ns = &init_net, extern struct net *copy_net_ns(unsigned long flags, struct net *net_ns); diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 0d56dad319ad..b06185ed1895 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -19,12 +19,10 @@ #include #include -#ifdef CONFIG_NET #include #include #include #include -#endif u64 uevent_seqnum; -- cgit v1.2.3 From 2e8046271f68198dd37451017c1a4a2432e4ec68 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:09 +0900 Subject: [IPV4] MROUTE: Move PIM definitions to . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/Kbuild | 1 + include/linux/mroute.h | 22 +--------------------- include/linux/pim.h | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 include/linux/pim.h (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 9cdd12a9e843..84736acb4b99 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -289,6 +289,7 @@ unifdef-y += parport.h unifdef-y += patchkey.h unifdef-y += pci.h unifdef-y += personality.h +unifdef-y += pim.h unifdef-y += pktcdvd.h unifdef-y += pmu.h unifdef-y += poll.h diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 35a8277ec1bd..c41b4217ae3b 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -3,6 +3,7 @@ #include #include +#include /* * Based on the MROUTING 3.5 defines primarily to keep @@ -210,27 +211,6 @@ struct mfc_cache #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ #ifdef __KERNEL__ - -#define PIM_V1_VERSION __constant_htonl(0x10000000) -#define PIM_V1_REGISTER 1 - -#define PIM_VERSION 2 -#define PIM_REGISTER 1 - -#define PIM_NULL_REGISTER __constant_htonl(0x40000000) - -/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ - -struct pimreghdr -{ - __u8 type; - __u8 reserved; - __be16 csum; - __be32 flags; -}; - -extern int pim_rcv_v1(struct sk_buff *); - struct rtmsg; extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); #endif diff --git a/include/linux/pim.h b/include/linux/pim.h new file mode 100644 index 000000000000..6f689dc85503 --- /dev/null +++ b/include/linux/pim.h @@ -0,0 +1,29 @@ +#ifndef __LINUX_PIM_H +#define __LINUX_PIM_H + +#include + +/* Message types - V1 */ +#define PIM_V1_VERSION __constant_htonl(0x10000000) +#define PIM_V1_REGISTER 1 + +/* Message types - V2 */ +#define PIM_VERSION 2 +#define PIM_REGISTER 1 + +#if defined(__KERNEL__) +#define PIM_NULL_REGISTER __constant_htonl(0x40000000) + +/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ +struct pimreghdr +{ + __u8 type; + __u8 reserved; + __be16 csum; + __be32 flags; +}; + +struct sk_buff; +extern int pim_rcv_v1(struct sk_buff *); +#endif +#endif -- cgit v1.2.3 From 80a9492a33dd7d852465625022d56ff76d62174d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:52 +0900 Subject: [IPV4] MROUTE: Adjust include files for user-space. needs . Avoid including in user-space, which conflicts with standard . Add basic struct and constant in . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/mroute.h | 3 +++ include/linux/pim.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mroute.h b/include/linux/mroute.h index c41b4217ae3b..de4decfa1bfc 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -2,7 +2,10 @@ #define __LINUX_MROUTE_H #include +#include +#ifdef __KERNEL__ #include +#endif #include /* diff --git a/include/linux/pim.h b/include/linux/pim.h index 6f689dc85503..236ffd317394 100644 --- a/include/linux/pim.h +++ b/include/linux/pim.h @@ -3,6 +3,22 @@ #include +#ifndef __KERNEL__ +struct pim { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 pim_type:4, /* PIM message type */ + pim_ver:4; /* PIM version */ +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 pim_ver:4; /* PIM version */ + pim_type:4; /* PIM message type */ +#endif + __u8 pim_rsv; /* Reserved */ + __be16 pim_cksum; /* Checksum */ +}; + +#define PIM_MINLEN 8 +#endif + /* Message types - V1 */ #define PIM_V1_VERSION __constant_htonl(0x10000000) #define PIM_V1_REGISTER 1 -- cgit v1.2.3 From 7bc570c8b4f75ddb3fd5dbeb38127cdc4acbcc9c Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:53 +0900 Subject: [IPV6] MROUTE: Support multicast forwarding. Based on ancient patch by Mickael Hoerdt , which is available at . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/Kbuild | 1 + include/linux/ipv6.h | 5 + include/linux/mroute6.h | 227 ++++++++ net/ipv6/Kconfig | 7 + net/ipv6/Makefile | 2 + net/ipv6/addrconf.c | 15 +- net/ipv6/af_inet6.c | 6 + net/ipv6/ip6_input.c | 87 ++- net/ipv6/ip6_output.c | 6 +- net/ipv6/ip6mr.c | 1384 ++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ipv6_sockglue.c | 7 + net/ipv6/raw.c | 7 +- net/ipv6/route.c | 30 +- 13 files changed, 1754 insertions(+), 30 deletions(-) create mode 100644 include/linux/mroute6.h create mode 100644 net/ipv6/ip6mr.c (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 84736acb4b99..29ab9b95d376 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -261,6 +261,7 @@ unifdef-y += mempolicy.h unifdef-y += mii.h unifdef-y += mman.h unifdef-y += mroute.h +unifdef-y += mroute6.h unifdef-y += msdos_fs.h unifdef-y += msg.h unifdef-y += nbd.h diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index b90d3d461d4e..f53e4764fc05 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -159,6 +159,9 @@ struct ipv6_devconf { __s32 accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; +#endif +#ifdef CONFIG_IPV6_MROUTE + __s32 mc_forwarding; #endif void *sysctl; }; @@ -190,6 +193,7 @@ enum { DEVCONF_PROXY_NDP, DEVCONF_OPTIMISTIC_DAD, DEVCONF_ACCEPT_SOURCE_ROUTE, + DEVCONF_MC_FORWARDING, DEVCONF_MAX }; @@ -230,6 +234,7 @@ struct inet6_skb_parm { #endif #define IP6SKB_XFRM_TRANSFORMED 1 +#define IP6SKB_FORWARDED 2 }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h new file mode 100644 index 000000000000..b92190304e0b --- /dev/null +++ b/include/linux/mroute6.h @@ -0,0 +1,227 @@ +#ifndef __LINUX_MROUTE6_H +#define __LINUX_MROUTE6_H + +#include +#include + +/* + * Based on the MROUTING 3.5 defines primarily to keep + * source compatibility with BSD. + * + * See the pim6sd code for the original history. + * + * Protocol Independent Multicast (PIM) data structures included + * Carlos Picoto (cap@di.fc.ul.pt) + * + */ + +#define MRT6_BASE 200 +#define MRT6_INIT (MRT6_BASE) /* Activate the kernel mroute code */ +#define MRT6_DONE (MRT6_BASE+1) /* Shutdown the kernel mroute */ +#define MRT6_ADD_MIF (MRT6_BASE+2) /* Add a virtual interface */ +#define MRT6_DEL_MIF (MRT6_BASE+3) /* Delete a virtual interface */ +#define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ +#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ +#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ + +#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ +#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) +#define SIOCGETRPF (SIOCPROTOPRIVATE+2) + +#define MAXMIFS 32 +typedef unsigned long mifbitmap_t; /* User mode code depends on this lot */ +typedef unsigned short mifi_t; +#define ALL_MIFS ((mifi_t)(-1)) + +#ifndef IF_SETSIZE +#define IF_SETSIZE 256 +#endif + +typedef __u32 if_mask; +#define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */ + +#if !defined(__KERNEL__) && !defined(DIV_ROUND_UP) +#define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y)) +#endif + +typedef struct if_set { + if_mask ifs_bits[DIV_ROUND_UP(IF_SETSIZE, NIFBITS)]; +} if_set; + +#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) +#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS))) +#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS))) +#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f))) +#define IF_ZERO(p) bzero(p, sizeof(*(p))) + +/* + * Passed by mrouted for an MRT_ADD_MIF - again we use the + * mrouted 3.6 structures for compatibility + */ + +struct mif6ctl { + mifi_t mif6c_mifi; /* Index of MIF */ + unsigned char mif6c_flags; /* MIFF_ flags */ + unsigned char vifc_threshold; /* ttl limit */ + u_short mif6c_pifi; /* the index of the physical IF */ + unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ +}; + +#define MIFF_REGISTER 0x1 /* register vif */ + +/* + * Cache manipulation structures for mrouted and PIMd + */ + +struct mf6cctl +{ + struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */ + struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */ + mifi_t mf6cc_parent; /* Where it arrived */ + struct if_set mf6cc_ifset; /* Where it is going */ +}; + +/* + * Group count retrieval for pim6sd + */ + +struct sioc_sg_req6 +{ + struct sockaddr_in6 src; + struct sockaddr_in6 grp; + unsigned long pktcnt; + unsigned long bytecnt; + unsigned long wrong_if; +}; + +/* + * To get vif packet counts + */ + +struct sioc_mif_req6 +{ + mifi_t mifi; /* Which iface */ + unsigned long icount; /* In packets */ + unsigned long ocount; /* Out packets */ + unsigned long ibytes; /* In bytes */ + unsigned long obytes; /* Out bytes */ +}; + +/* + * That's all usermode folks + */ + +#ifdef __KERNEL__ + +#include /* for struct sk_buff_head */ + +struct net_device; +struct inet6_dev *ipv6_find_idev(struct net_device *dev); + +#ifdef CONFIG_IPV6_MROUTE +static inline int ip6_mroute_opt(int opt) +{ + return (opt >= MRT6_BASE) && (opt <= MRT6_BASE + 10); +} +#else +static inline int ip6_mroute_opt(int opt) +{ + return 0; +} +#endif + +struct sock; + +extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); +extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); +extern int ip6_mr_input(struct sk_buff *skb); +extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); +extern void ip6_mr_init(void); + +struct mif_device +{ + struct net_device *dev; /* Device we are using */ + unsigned long bytes_in,bytes_out; + unsigned long pkt_in,pkt_out; /* Statistics */ + unsigned long rate_limit; /* Traffic shaping (NI) */ + unsigned char threshold; /* TTL threshold */ + unsigned short flags; /* Control flags */ + int link; /* Physical interface index */ +}; + +#define VIFF_STATIC 0x8000 + +struct mfc6_cache +{ + struct mfc6_cache *next; /* Next entry on cache line */ + struct in6_addr mf6c_mcastgrp; /* Group the entry belongs to */ + struct in6_addr mf6c_origin; /* Source of packet */ + mifi_t mf6c_parent; /* Source interface */ + int mfc_flags; /* Flags on line */ + + union { + struct { + unsigned long expires; + struct sk_buff_head unresolved; /* Unresolved buffers */ + } unres; + struct { + unsigned long last_assert; + int minvif; + int maxvif; + unsigned long bytes; + unsigned long pkt; + unsigned long wrong_if; + unsigned char ttls[MAXMIFS]; /* TTL thresholds */ + } res; + } mfc_un; +}; + +#define MFC_STATIC 1 +#define MFC_NOTIFY 2 + +#define MFC6_LINES 64 + +#define MFC6_HASH(a, g) (((__force u32)(a)->s6_addr32[0] ^ \ + (__force u32)(a)->s6_addr32[1] ^ \ + (__force u32)(a)->s6_addr32[2] ^ \ + (__force u32)(a)->s6_addr32[3] ^ \ + (__force u32)(g)->s6_addr32[0] ^ \ + (__force u32)(g)->s6_addr32[1] ^ \ + (__force u32)(g)->s6_addr32[2] ^ \ + (__force u32)(g)->s6_addr32[3]) % MFC6_LINES) + +#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ + +#endif + +#ifdef __KERNEL__ +struct rtmsg; +extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); + +#ifdef CONFIG_IPV6_MROUTE +extern struct sock *mroute6_socket; +extern int ip6mr_sk_done(struct sock *sk); +#else +#define mroute6_socket NULL +static inline int ip6mr_sk_done(struct sock *sk) { return 0; } +#endif +#endif + +/* + * Structure used to communicate from kernel to multicast router. + * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} + * used for IPv4 implementation). This is because this structure will be passed via an + * IPv6 raw socket, on wich an application will only receiver the payload i.e the data after + * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) + */ + +struct mrt6msg { +#define MRT6MSG_NOCACHE 1 + __u8 im6_mbz; /* must be zero */ + __u8 im6_msgtype; /* what type of message */ + __u16 im6_mif; /* mif rec'd on */ + __u32 im6_pad; /* padding for 64 bit arch */ + struct in6_addr im6_src, im6_dst; +}; + +#endif diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 47263e45bacb..9a2ea81e499f 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -209,3 +209,10 @@ config IPV6_SUBTREES If unsure, say N. +config IPV6_MROUTE + bool "IPv6: multicast routing (EXPERIMENTAL)" + depends on IPV6 && EXPERIMENTAL + ---help--- + Experimental support for IPv6 multicast forwarding. + If unsure, say N. + diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index ae14617e607f..686934acfac1 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -11,6 +11,8 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o +ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o + ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ xfrm6_output.o ipv6-$(CONFIG_NETFILTER) += netfilter.o diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 11037615bc73..dbc51af69017 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -412,7 +412,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) return ndev; } -static struct inet6_dev * ipv6_find_idev(struct net_device *dev) +struct inet6_dev * ipv6_find_idev(struct net_device *dev) { struct inet6_dev *idev; @@ -3547,6 +3547,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, #ifdef CONFIG_IPV6_OPTIMISTIC_DAD array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; #endif +#ifdef CONFIG_IPV6_MROUTE + array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; +#endif } static inline size_t inet6_if_nlmsg_size(void) @@ -4094,6 +4097,16 @@ static struct addrconf_sysctl_table .proc_handler = &proc_dointvec, }, +#endif +#ifdef CONFIG_IPV6_MROUTE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "mc_forwarding", + .data = &ipv6_devconf.mc_forwarding, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif { .ctl_name = 0, /* sentinel */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 1731b0abf7f5..3c6aafb02183 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -61,6 +61,9 @@ #include #include +#ifdef CONFIG_IPV6_MROUTE +#include +#endif MODULE_AUTHOR("Cast of dozens"); MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); @@ -953,6 +956,9 @@ static int __init inet6_init(void) err = icmpv6_init(); if (err) goto icmp_fail; +#ifdef CONFIG_IPV6_MROUTE + ip6_mr_init(); +#endif err = ndisc_init(); if (err) goto ndisc_fail; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 43a617e2268b..09a3201e408a 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -236,36 +237,84 @@ int ip6_mc_input(struct sk_buff *skb) hdr = ipv6_hdr(skb); deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); +#ifdef CONFIG_IPV6_MROUTE /* - * IPv6 multicast router mode isnt currently supported. + * IPv6 multicast router mode is now supported ;) */ -#if 0 - if (ipv6_config.multicast_route) { - int addr_type; - - addr_type = ipv6_addr_type(&hdr->daddr); - - if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) { - struct sk_buff *skb2; - struct dst_entry *dst; + if (ipv6_devconf.mc_forwarding && + likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { + /* + * Okay, we try to forward - split and duplicate + * packets. + */ + struct sk_buff *skb2; + struct inet6_skb_parm *opt = IP6CB(skb); + + /* Check for MLD */ + if (unlikely(opt->ra)) { + /* Check if this is a mld message */ + u8 *ptr = skb_network_header(skb) + opt->ra; + struct icmp6hdr *icmp6; + u8 nexthdr = hdr->nexthdr; + int offset; + + /* Check if the value of Router Alert + * is for MLD (0x0000). + */ + if ((ptr[2] | ptr[3]) == 0) { + if (!ipv6_ext_hdr(nexthdr)) { + /* BUG */ + goto discard; + } + offset = ipv6_skip_exthdr(skb, sizeof(*hdr), + &nexthdr); + if (offset < 0) + goto discard; + + if (nexthdr != IPPROTO_ICMPV6) + goto discard; + + if (!pskb_may_pull(skb, (skb_network_header(skb) + + offset + 1 - skb->data))) + goto discard; + + icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); + + switch (icmp6->icmp6_type) { + case ICMPV6_MGM_QUERY: + case ICMPV6_MGM_REPORT: + case ICMPV6_MGM_REDUCTION: + case ICMPV6_MLD2_REPORT: + break; + default: + /* Bogus */ + goto discard; + } + deliver = 1; + goto out; + } + /* unknown RA - process it normally */ + } - dst = skb->dst; + if (deliver) + skb2 = skb_clone(skb, GFP_ATOMIC); + else { + skb2 = skb; + skb = NULL; + } - if (deliver) { - skb2 = skb_clone(skb, GFP_ATOMIC); - dst_output(skb2); - } else { - dst_output(skb); - return 0; - } + if (skb2) { + skb2->dev = skb2->dst->dev; + ip6_mr_input(skb2); } } #endif - +out: if (likely(deliver)) { ip6_input(skb); return 0; } +discard: /* discard */ kfree_skb(skb); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a8b4da25b0a7..c0dbe549cc42 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -55,6 +55,7 @@ #include #include #include +#include static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); @@ -137,8 +138,9 @@ static int ip6_output2(struct sk_buff *skb) struct inet6_dev *idev = ip6_dst_idev(skb->dst); if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && - ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr)) { + ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || + ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, + &ipv6_hdr(skb)->saddr))) { struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); /* Do not check for IFF_ALLMULTI; multicast routing diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c new file mode 100644 index 000000000000..1bdf3c177d58 --- /dev/null +++ b/net/ipv6/ip6mr.c @@ -0,0 +1,1384 @@ +/* + * Linux IPv6 multicast routing support for BSD pim6sd + * Based on net/ipv4/ipmr.c. + * + * (c) 2004 Mickael Hoerdt, + * LSIIT Laboratory, Strasbourg, France + * (c) 2004 Jean-Philippe Andriot, + * 6WIND, Paris, France + * Copyright (C)2007,2008 USAGI/WIDE Project + * YOSHIFUJI Hideaki + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct sock *mroute6_socket; + + +/* Big lock, protecting vif table, mrt cache and mroute socket state. + Note that the changes are semaphored via rtnl_lock. + */ + +static DEFINE_RWLOCK(mrt_lock); + +/* + * Multicast router control variables + */ + +static struct mif_device vif6_table[MAXMIFS]; /* Devices */ +static int maxvif; + +#define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL) + +static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */ + +static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ +static atomic_t cache_resolve_queue_len; /* Size of unresolved */ + +/* Special spinlock for queue of unresolved entries */ +static DEFINE_SPINLOCK(mfc_unres_lock); + +/* We return to original Alan's scheme. Hash table of resolved + entries is changed only in process context and protected + with weak lock mrt_lock. Queue of unresolved entries is protected + with strong spinlock mfc_unres_lock. + + In this case data path is free of exclusive locks at all. + */ + +static struct kmem_cache *mrt_cachep __read_mostly; + +static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); +static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); +static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); + +static struct timer_list ipmr_expire_timer; + + +#ifdef CONFIG_PROC_FS + +struct ipmr_mfc_iter { + struct mfc6_cache **cache; + int ct; +}; + + +static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) +{ + struct mfc6_cache *mfc; + + it->cache = mfc6_cache_array; + read_lock(&mrt_lock); + for (it->ct = 0; it->ct < ARRAY_SIZE(mfc6_cache_array); it->ct++) + for (mfc = mfc6_cache_array[it->ct]; mfc; mfc = mfc->next) + if (pos-- == 0) + return mfc; + read_unlock(&mrt_lock); + + it->cache = &mfc_unres_queue; + spin_lock_bh(&mfc_unres_lock); + for (mfc = mfc_unres_queue; mfc; mfc = mfc->next) + if (pos-- == 0) + return mfc; + spin_unlock_bh(&mfc_unres_lock); + + it->cache = NULL; + return NULL; +} + + + + +/* + * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif + */ + +struct ipmr_vif_iter { + int ct; +}; + +static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter, + loff_t pos) +{ + for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) { + if (!MIF_EXISTS(iter->ct)) + continue; + if (pos-- == 0) + return &vif6_table[iter->ct]; + } + return NULL; +} + +static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(mrt_lock) +{ + read_lock(&mrt_lock); + return (*pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1) + : SEQ_START_TOKEN); +} + +static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct ipmr_vif_iter *iter = seq->private; + + ++*pos; + if (v == SEQ_START_TOKEN) + return ip6mr_vif_seq_idx(iter, 0); + + while (++iter->ct < maxvif) { + if (!MIF_EXISTS(iter->ct)) + continue; + return &vif6_table[iter->ct]; + } + return NULL; +} + +static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v) + __releases(mrt_lock) +{ + read_unlock(&mrt_lock); +} + +static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "Interface BytesIn PktsIn BytesOut PktsOut Flags\n"); + } else { + const struct mif_device *vif = v; + const char *name = vif->dev ? vif->dev->name : "none"; + + seq_printf(seq, + "%2Zd %-10s %8ld %7ld %8ld %7ld %05X\n", + vif - vif6_table, + name, vif->bytes_in, vif->pkt_in, + vif->bytes_out, vif->pkt_out, + vif->flags); + } + return 0; +} + +static struct seq_operations ip6mr_vif_seq_ops = { + .start = ip6mr_vif_seq_start, + .next = ip6mr_vif_seq_next, + .stop = ip6mr_vif_seq_stop, + .show = ip6mr_vif_seq_show, +}; + +static int ip6mr_vif_open(struct inode *inode, struct file *file) +{ + return seq_open_private(file, &ip6mr_vif_seq_ops, + sizeof(struct ipmr_vif_iter)); +} + +static struct file_operations ip6mr_vif_fops = { + .owner = THIS_MODULE, + .open = ip6mr_vif_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) +{ + return (*pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1) + : SEQ_START_TOKEN); +} + +static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct mfc6_cache *mfc = v; + struct ipmr_mfc_iter *it = seq->private; + + ++*pos; + + if (v == SEQ_START_TOKEN) + return ipmr_mfc_seq_idx(seq->private, 0); + + if (mfc->next) + return mfc->next; + + if (it->cache == &mfc_unres_queue) + goto end_of_list; + + BUG_ON(it->cache != mfc6_cache_array); + + while (++it->ct < ARRAY_SIZE(mfc6_cache_array)) { + mfc = mfc6_cache_array[it->ct]; + if (mfc) + return mfc; + } + + /* exhausted cache_array, show unresolved */ + read_unlock(&mrt_lock); + it->cache = &mfc_unres_queue; + it->ct = 0; + + spin_lock_bh(&mfc_unres_lock); + mfc = mfc_unres_queue; + if (mfc) + return mfc; + + end_of_list: + spin_unlock_bh(&mfc_unres_lock); + it->cache = NULL; + + return NULL; +} + +static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) +{ + struct ipmr_mfc_iter *it = seq->private; + + if (it->cache == &mfc_unres_queue) + spin_unlock_bh(&mfc_unres_lock); + else if (it->cache == mfc6_cache_array) + read_unlock(&mrt_lock); +} + +static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) +{ + int n; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "Group " + "Origin " + "Iif Pkts Bytes Wrong Oifs\n"); + } else { + const struct mfc6_cache *mfc = v; + const struct ipmr_mfc_iter *it = seq->private; + + seq_printf(seq, + NIP6_FMT " " NIP6_FMT " %-3d %8ld %8ld %8ld", + NIP6(mfc->mf6c_mcastgrp), NIP6(mfc->mf6c_origin), + mfc->mf6c_parent, + mfc->mfc_un.res.pkt, + mfc->mfc_un.res.bytes, + mfc->mfc_un.res.wrong_if); + + if (it->cache != &mfc_unres_queue) { + for (n = mfc->mfc_un.res.minvif; + n < mfc->mfc_un.res.maxvif; n++) { + if (MIF_EXISTS(n) && + mfc->mfc_un.res.ttls[n] < 255) + seq_printf(seq, + " %2d:%-3d", + n, mfc->mfc_un.res.ttls[n]); + } + } + seq_putc(seq, '\n'); + } + return 0; +} + +static struct seq_operations ipmr_mfc_seq_ops = { + .start = ipmr_mfc_seq_start, + .next = ipmr_mfc_seq_next, + .stop = ipmr_mfc_seq_stop, + .show = ipmr_mfc_seq_show, +}; + +static int ipmr_mfc_open(struct inode *inode, struct file *file) +{ + return seq_open_private(file, &ipmr_mfc_seq_ops, + sizeof(struct ipmr_mfc_iter)); +} + +static struct file_operations ip6mr_mfc_fops = { + .owner = THIS_MODULE, + .open = ipmr_mfc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif + +/* + * Delete a VIF entry + */ + +static int mif6_delete(int vifi) +{ + struct mif_device *v; + struct net_device *dev; + if (vifi < 0 || vifi >= maxvif) + return -EADDRNOTAVAIL; + + v = &vif6_table[vifi]; + + write_lock_bh(&mrt_lock); + dev = v->dev; + v->dev = NULL; + + if (!dev) { + write_unlock_bh(&mrt_lock); + return -EADDRNOTAVAIL; + } + + if (vifi + 1 == maxvif) { + int tmp; + for (tmp = vifi - 1; tmp >= 0; tmp--) { + if (MIF_EXISTS(tmp)) + break; + } + maxvif = tmp + 1; + } + + write_unlock_bh(&mrt_lock); + + dev_set_allmulti(dev, -1); + + if (v->flags & MIFF_REGISTER) + unregister_netdevice(dev); + + dev_put(dev); + return 0; +} + +/* Destroy an unresolved cache entry, killing queued skbs + and reporting error to netlink readers. + */ + +static void ip6mr_destroy_unres(struct mfc6_cache *c) +{ + struct sk_buff *skb; + + atomic_dec(&cache_resolve_queue_len); + + while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { + if (ipv6_hdr(skb)->version == 0) { + struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); + nlh->nlmsg_type = NLMSG_ERROR; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + skb_trim(skb, nlh->nlmsg_len); + ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; + rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + kfree_skb(skb); + } + + kmem_cache_free(mrt_cachep, c); +} + + +/* Single timer process for all the unresolved queue. */ + +static void ipmr_do_expire_process(unsigned long dummy) +{ + unsigned long now = jiffies; + unsigned long expires = 10 * HZ; + struct mfc6_cache *c, **cp; + + cp = &mfc_unres_queue; + + while ((c = *cp) != NULL) { + if (time_after(c->mfc_un.unres.expires, now)) { + /* not yet... */ + unsigned long interval = c->mfc_un.unres.expires - now; + if (interval < expires) + expires = interval; + cp = &c->next; + continue; + } + + *cp = c->next; + ip6mr_destroy_unres(c); + } + + if (atomic_read(&cache_resolve_queue_len)) + mod_timer(&ipmr_expire_timer, jiffies + expires); +} + +static void ipmr_expire_process(unsigned long dummy) +{ + if (!spin_trylock(&mfc_unres_lock)) { + mod_timer(&ipmr_expire_timer, jiffies + 1); + return; + } + + if (atomic_read(&cache_resolve_queue_len)) + ipmr_do_expire_process(dummy); + + spin_unlock(&mfc_unres_lock); +} + +/* Fill oifs list. It is called under write locked mrt_lock. */ + +static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls) +{ + int vifi; + + cache->mfc_un.res.minvif = MAXVIFS; + cache->mfc_un.res.maxvif = 0; + memset(cache->mfc_un.res.ttls, 255, MAXVIFS); + + for (vifi = 0; vifi < maxvif; vifi++) { + if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) { + cache->mfc_un.res.ttls[vifi] = ttls[vifi]; + if (cache->mfc_un.res.minvif > vifi) + cache->mfc_un.res.minvif = vifi; + if (cache->mfc_un.res.maxvif <= vifi) + cache->mfc_un.res.maxvif = vifi + 1; + } + } +} + +static int mif6_add(struct mif6ctl *vifc, int mrtsock) +{ + int vifi = vifc->mif6c_mifi; + struct mif_device *v = &vif6_table[vifi]; + struct net_device *dev; + + /* Is vif busy ? */ + if (MIF_EXISTS(vifi)) + return -EADDRINUSE; + + switch (vifc->mif6c_flags) { + case 0: + dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); + if (!dev) + return -EADDRNOTAVAIL; + dev_put(dev); + break; + default: + return -EINVAL; + } + + dev_set_allmulti(dev, 1); + + /* + * Fill in the VIF structures + */ + v->rate_limit = vifc->vifc_rate_limit; + v->flags = vifc->mif6c_flags; + if (!mrtsock) + v->flags |= VIFF_STATIC; + v->threshold = vifc->vifc_threshold; + v->bytes_in = 0; + v->bytes_out = 0; + v->pkt_in = 0; + v->pkt_out = 0; + v->link = dev->ifindex; + if (v->flags & MIFF_REGISTER) + v->link = dev->iflink; + + /* And finish update writing critical data */ + write_lock_bh(&mrt_lock); + dev_hold(dev); + v->dev = dev; + if (vifi + 1 > maxvif) + maxvif = vifi + 1; + write_unlock_bh(&mrt_lock); + return 0; +} + +static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_addr *mcastgrp) +{ + int line = MFC6_HASH(mcastgrp, origin); + struct mfc6_cache *c; + + for (c = mfc6_cache_array[line]; c; c = c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, origin) && + ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) + break; + } + return c; +} + +/* + * Allocate a multicast cache entry + */ +static struct mfc6_cache *ip6mr_cache_alloc(void) +{ + struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_KERNEL); + if (c == NULL) + return NULL; + memset(c, 0, sizeof(*c)); + c->mfc_un.res.minvif = MAXVIFS; + return c; +} + +static struct mfc6_cache *ip6mr_cache_alloc_unres(void) +{ + struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_ATOMIC); + if (c == NULL) + return NULL; + memset(c, 0, sizeof(*c)); + skb_queue_head_init(&c->mfc_un.unres.unresolved); + c->mfc_un.unres.expires = jiffies + 10 * HZ; + return c; +} + +/* + * A cache entry has gone into a resolved state from queued + */ + +static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) +{ + struct sk_buff *skb; + + /* + * Play the pending entries through our router + */ + + while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { + if (ipv6_hdr(skb)->version == 0) { + int err; + struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); + + if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { + nlh->nlmsg_len = skb->tail - (u8 *)nlh; + } else { + nlh->nlmsg_type = NLMSG_ERROR; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + skb_trim(skb, nlh->nlmsg_len); + ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; + } + err = rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + ip6_mr_forward(skb, c); + } +} + +/* + * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd + * expects the following bizarre scheme. + * + * Called under mrt_lock. + */ + +static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) +{ + struct sk_buff *skb; + struct mrt6msg *msg; + int ret; + + skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); + + if (!skb) + return -ENOBUFS; + + /* I suppose that internal messages + * do not require checksums */ + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* + * Copy the IP header + */ + + skb_put(skb, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb); + skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr)); + + /* + * Add our header + */ + skb_put(skb, sizeof(*msg)); + skb_reset_transport_header(skb); + msg = (struct mrt6msg *)skb_transport_header(skb); + + msg->im6_mbz = 0; + msg->im6_msgtype = assert; + msg->im6_mif = vifi; + msg->im6_pad = 0; + ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); + ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); + + skb->dst = dst_clone(pkt->dst); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb_pull(skb, sizeof(struct ipv6hdr)); + + if (mroute6_socket == NULL) { + kfree_skb(skb); + return -EINVAL; + } + + /* + * Deliver to user space multicast routing algorithms + */ + if ((ret = sock_queue_rcv_skb(mroute6_socket, skb)) < 0) { + if (net_ratelimit()) + printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n"); + kfree_skb(skb); + } + + return ret; +} + +/* + * Queue a packet for resolution. It gets locked cache entry! + */ + +static int +ip6mr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) +{ + int err; + struct mfc6_cache *c; + + spin_lock_bh(&mfc_unres_lock); + for (c = mfc_unres_queue; c; c = c->next) { + if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && + ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) + break; + } + + if (c == NULL) { + /* + * Create a new entry if allowable + */ + + if (atomic_read(&cache_resolve_queue_len) >= 10 || + (c = ip6mr_cache_alloc_unres()) == NULL) { + spin_unlock_bh(&mfc_unres_lock); + + kfree_skb(skb); + return -ENOBUFS; + } + + /* + * Fill in the new cache entry + */ + c->mf6c_parent = -1; + c->mf6c_origin = ipv6_hdr(skb)->saddr; + c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr; + + /* + * Reflect first query at pim6sd + */ + if ((err = ip6mr_cache_report(skb, vifi, MRT6MSG_NOCACHE)) < 0) { + /* If the report failed throw the cache entry + out - Brad Parker + */ + spin_unlock_bh(&mfc_unres_lock); + + kmem_cache_free(mrt_cachep, c); + kfree_skb(skb); + return err; + } + + atomic_inc(&cache_resolve_queue_len); + c->next = mfc_unres_queue; + mfc_unres_queue = c; + + ipmr_do_expire_process(1); + } + + /* + * See if we can append the packet + */ + if (c->mfc_un.unres.unresolved.qlen > 3) { + kfree_skb(skb); + err = -ENOBUFS; + } else { + skb_queue_tail(&c->mfc_un.unres.unresolved, skb); + err = 0; + } + + spin_unlock_bh(&mfc_unres_lock); + return err; +} + +/* + * MFC6 cache manipulation by user space + */ + +static int ip6mr_mfc_delete(struct mf6cctl *mfc) +{ + int line; + struct mfc6_cache *c, **cp; + + line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); + + for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && + ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + return 0; + } + } + return -ENOENT; +} + +static int ip6mr_device_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct mif_device *v; + int ct; + + if (dev_net(dev) != &init_net) + return NOTIFY_DONE; + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + + v = &vif6_table[0]; + for (ct = 0; ct < maxvif; ct++, v++) { + if (v->dev == dev) + mif6_delete(ct); + } + return NOTIFY_DONE; +} + +static struct notifier_block ip6_mr_notifier = { + .notifier_call = ip6mr_device_event +}; + +/* + * Setup for IP multicast routing + */ + +void __init ip6_mr_init(void) +{ + mrt_cachep = kmem_cache_create("ip6_mrt_cache", + sizeof(struct mfc6_cache), + 0, SLAB_HWCACHE_ALIGN, + NULL); + if (!mrt_cachep) + panic("cannot allocate ip6_mrt_cache"); + + setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); + register_netdevice_notifier(&ip6_mr_notifier); +#ifdef CONFIG_PROC_FS + proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops); + proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); +#endif +} + + +static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) +{ + int line; + struct mfc6_cache *uc, *c, **cp; + unsigned char ttls[MAXVIFS]; + int i; + + memset(ttls, 255, MAXVIFS); + for (i = 0; i < MAXVIFS; i++) { + if (IF_ISSET(i, &mfc->mf6cc_ifset)) + ttls[i] = 1; + + } + + line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); + + for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && + ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) + break; + } + + if (c != NULL) { + write_lock_bh(&mrt_lock); + c->mf6c_parent = mfc->mf6cc_parent; + ip6mr_update_thresholds(c, ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + write_unlock_bh(&mrt_lock); + return 0; + } + + if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) + return -EINVAL; + + c = ip6mr_cache_alloc(); + if (c == NULL) + return -ENOMEM; + + c->mf6c_origin = mfc->mf6cc_origin.sin6_addr; + c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr; + c->mf6c_parent = mfc->mf6cc_parent; + ip6mr_update_thresholds(c, ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + + write_lock_bh(&mrt_lock); + c->next = mfc6_cache_array[line]; + mfc6_cache_array[line] = c; + write_unlock_bh(&mrt_lock); + + /* + * Check to see if we resolved a queued list. If so we + * need to send on the frames and tidy up. + */ + spin_lock_bh(&mfc_unres_lock); + for (cp = &mfc_unres_queue; (uc = *cp) != NULL; + cp = &uc->next) { + if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && + ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { + *cp = uc->next; + if (atomic_dec_and_test(&cache_resolve_queue_len)) + del_timer(&ipmr_expire_timer); + break; + } + } + spin_unlock_bh(&mfc_unres_lock); + + if (uc) { + ip6mr_cache_resolve(uc, c); + kmem_cache_free(mrt_cachep, uc); + } + return 0; +} + +/* + * Close the multicast socket, and clear the vif tables etc + */ + +static void mroute_clean_tables(struct sock *sk) +{ + int i; + + /* + * Shut down all active vif entries + */ + for (i = 0; i < maxvif; i++) { + if (!(vif6_table[i].flags & VIFF_STATIC)) + mif6_delete(i); + } + + /* + * Wipe the cache + */ + for (i = 0; i < ARRAY_SIZE(mfc6_cache_array); i++) { + struct mfc6_cache *c, **cp; + + cp = &mfc6_cache_array[i]; + while ((c = *cp) != NULL) { + if (c->mfc_flags & MFC_STATIC) { + cp = &c->next; + continue; + } + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + } + } + + if (atomic_read(&cache_resolve_queue_len) != 0) { + struct mfc6_cache *c; + + spin_lock_bh(&mfc_unres_lock); + while (mfc_unres_queue != NULL) { + c = mfc_unres_queue; + mfc_unres_queue = c->next; + spin_unlock_bh(&mfc_unres_lock); + + ip6mr_destroy_unres(c); + + spin_lock_bh(&mfc_unres_lock); + } + spin_unlock_bh(&mfc_unres_lock); + } +} + +static int ip6mr_sk_init(struct sock *sk) +{ + int err = 0; + + rtnl_lock(); + write_lock_bh(&mrt_lock); + if (likely(mroute6_socket == NULL)) + mroute6_socket = sk; + else + err = -EADDRINUSE; + write_unlock_bh(&mrt_lock); + + rtnl_unlock(); + + return err; +} + +int ip6mr_sk_done(struct sock *sk) +{ + int err = 0; + + rtnl_lock(); + if (sk == mroute6_socket) { + write_lock_bh(&mrt_lock); + mroute6_socket = NULL; + write_unlock_bh(&mrt_lock); + + mroute_clean_tables(sk); + } else + err = -EACCES; + rtnl_unlock(); + + return err; +} + +/* + * Socket options and virtual interface manipulation. The whole + * virtual interface system is a complete heap, but unfortunately + * that's how BSD mrouted happens to think. Maybe one day with a proper + * MOSPF/PIM router set up we can clean this up. + */ + +int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +{ + int ret; + struct mif6ctl vif; + struct mf6cctl mfc; + mifi_t mifi; + + if (optname != MRT6_INIT) { + if (sk != mroute6_socket && !capable(CAP_NET_ADMIN)) + return -EACCES; + } + + switch (optname) { + case MRT6_INIT: + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + if (optlen < sizeof(int)) + return -EINVAL; + + return ip6mr_sk_init(sk); + + case MRT6_DONE: + return ip6mr_sk_done(sk); + + case MRT6_ADD_MIF: + if (optlen < sizeof(vif)) + return -EINVAL; + if (copy_from_user(&vif, optval, sizeof(vif))) + return -EFAULT; + if (vif.mif6c_mifi >= MAXVIFS) + return -ENFILE; + rtnl_lock(); + ret = mif6_add(&vif, sk == mroute6_socket); + rtnl_unlock(); + return ret; + + case MRT6_DEL_MIF: + if (optlen < sizeof(mifi_t)) + return -EINVAL; + if (copy_from_user(&mifi, optval, sizeof(mifi_t))) + return -EFAULT; + rtnl_lock(); + ret = mif6_delete(mifi); + rtnl_unlock(); + return ret; + + /* + * Manipulate the forwarding caches. These live + * in a sort of kernel/user symbiosis. + */ + case MRT6_ADD_MFC: + case MRT6_DEL_MFC: + if (optlen < sizeof(mfc)) + return -EINVAL; + if (copy_from_user(&mfc, optval, sizeof(mfc))) + return -EFAULT; + rtnl_lock(); + if (optname == MRT6_DEL_MFC) + ret = ip6mr_mfc_delete(&mfc); + else + ret = ip6mr_mfc_add(&mfc, sk == mroute6_socket); + rtnl_unlock(); + return ret; + + /* + * Spurious command, or MRT_VERSION which you cannot + * set. + */ + default: + return -ENOPROTOOPT; + } +} + +/* + * Getsock opt support for the multicast routing system. + */ + +int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, + int __user *optlen) +{ + int olr; + int val; + + switch (optname) { + case MRT6_VERSION: + val = 0x0305; + break; + default: + return -ENOPROTOOPT; + } + + if (get_user(olr, optlen)) + return -EFAULT; + + olr = min_t(int, olr, sizeof(int)); + if (olr < 0) + return -EINVAL; + + if (put_user(olr, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, olr)) + return -EFAULT; + return 0; +} + +/* + * The IP multicast ioctl support routines. + */ + +int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) +{ + struct sioc_sg_req6 sr; + struct sioc_mif_req6 vr; + struct mif_device *vif; + struct mfc6_cache *c; + + switch (cmd) { + case SIOCGETMIFCNT_IN6: + if (copy_from_user(&vr, arg, sizeof(vr))) + return -EFAULT; + if (vr.mifi >= maxvif) + return -EINVAL; + read_lock(&mrt_lock); + vif = &vif6_table[vr.mifi]; + if (MIF_EXISTS(vr.mifi)) { + vr.icount = vif->pkt_in; + vr.ocount = vif->pkt_out; + vr.ibytes = vif->bytes_in; + vr.obytes = vif->bytes_out; + read_unlock(&mrt_lock); + + if (copy_to_user(arg, &vr, sizeof(vr))) + return -EFAULT; + return 0; + } + read_unlock(&mrt_lock); + return -EADDRNOTAVAIL; + case SIOCGETSGCNT_IN6: + if (copy_from_user(&sr, arg, sizeof(sr))) + return -EFAULT; + + read_lock(&mrt_lock); + c = ip6mr_cache_find(&sr.src.sin6_addr, &sr.grp.sin6_addr); + if (c) { + sr.pktcnt = c->mfc_un.res.pkt; + sr.bytecnt = c->mfc_un.res.bytes; + sr.wrong_if = c->mfc_un.res.wrong_if; + read_unlock(&mrt_lock); + + if (copy_to_user(arg, &sr, sizeof(sr))) + return -EFAULT; + return 0; + } + read_unlock(&mrt_lock); + return -EADDRNOTAVAIL; + default: + return -ENOIOCTLCMD; + } +} + + +static inline int ip6mr_forward2_finish(struct sk_buff *skb) +{ + /* XXX stats */ + return dst_output(skb); +} + +/* + * Processing handlers for ip6mr_forward + */ + +static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) +{ + struct ipv6hdr *ipv6h; + struct mif_device *vif = &vif6_table[vifi]; + struct net_device *dev; + struct dst_entry *dst; + struct flowi fl; + + if (vif->dev == NULL) + goto out_free; + + ipv6h = ipv6_hdr(skb); + + fl = (struct flowi) { + .oif = vif->link, + .nl_u = { .ip6_u = + { .daddr = ipv6h->daddr, } + } + }; + + dst = ip6_route_output(&init_net, NULL, &fl); + if (!dst) + goto out_free; + + dst_release(skb->dst); + skb->dst = dst; + + /* + * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally + * not only before forwarding, but after forwarding on all output + * interfaces. It is clear, if mrouter runs a multicasting + * program, it should receive packets not depending to what interface + * program is joined. + * If we will not make it, the program will have to join on all + * interfaces. On the other hand, multihoming host (or router, but + * not mrouter) cannot join to more than one interface - it will + * result in receiving multiple packets. + */ + dev = vif->dev; + skb->dev = dev; + vif->pkt_out++; + vif->bytes_out += skb->len; + + /* We are about to write */ + /* XXX: extension headers? */ + if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev))) + goto out_free; + + ipv6h = ipv6_hdr(skb); + ipv6h->hop_limit--; + + IP6CB(skb)->flags |= IP6SKB_FORWARDED; + + return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev, + ip6mr_forward2_finish); + +out_free: + kfree_skb(skb); + return 0; +} + +static int ip6mr_find_vif(struct net_device *dev) +{ + int ct; + for (ct = maxvif - 1; ct >= 0; ct--) { + if (vif6_table[ct].dev == dev) + break; + } + return ct; +} + +static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) +{ + int psend = -1; + int vif, ct; + + vif = cache->mf6c_parent; + cache->mfc_un.res.pkt++; + cache->mfc_un.res.bytes += skb->len; + + vif6_table[vif].pkt_in++; + vif6_table[vif].bytes_in += skb->len; + + /* + * Forward the frame + */ + for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { + if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { + if (psend != -1) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + ip6mr_forward2(skb2, cache, psend); + } + psend = ct; + } + } + if (psend != -1) { + ip6mr_forward2(skb, cache, psend); + return 0; + } + + kfree_skb(skb); + return 0; +} + + +/* + * Multicast packets for forwarding arrive here + */ + +int ip6_mr_input(struct sk_buff *skb) +{ + struct mfc6_cache *cache; + + read_lock(&mrt_lock); + cache = ip6mr_cache_find(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); + + /* + * No usable cache entry + */ + if (cache == NULL) { + int vif; + + vif = ip6mr_find_vif(skb->dev); + if (vif >= 0) { + int err = ip6mr_cache_unresolved(vif, skb); + read_unlock(&mrt_lock); + + return err; + } + read_unlock(&mrt_lock); + kfree_skb(skb); + return -ENODEV; + } + + ip6_mr_forward(skb, cache); + + read_unlock(&mrt_lock); + + return 0; +} + + +static int +ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) +{ + int ct; + struct rtnexthop *nhp; + struct net_device *dev = vif6_table[c->mf6c_parent].dev; + u8 *b = skb->tail; + struct rtattr *mp_head; + + if (dev) + RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + + mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); + + for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { + if (c->mfc_un.res.ttls[ct] < 255) { + if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) + goto rtattr_failure; + nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); + nhp->rtnh_flags = 0; + nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; + nhp->rtnh_ifindex = vif6_table[ct].dev->ifindex; + nhp->rtnh_len = sizeof(*nhp); + } + } + mp_head->rta_type = RTA_MULTIPATH; + mp_head->rta_len = skb->tail - (u8 *)mp_head; + rtm->rtm_type = RTN_MULTICAST; + return 1; + +rtattr_failure: + nlmsg_trim(skb, b); + return -EMSGSIZE; +} + +int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) +{ + int err; + struct mfc6_cache *cache; + struct rt6_info *rt = (struct rt6_info *)skb->dst; + + read_lock(&mrt_lock); + cache = ip6mr_cache_find(&rt->rt6i_src.addr, &rt->rt6i_dst.addr); + + if (!cache) { + struct sk_buff *skb2; + struct ipv6hdr *iph; + struct net_device *dev; + int vif; + + if (nowait) { + read_unlock(&mrt_lock); + return -EAGAIN; + } + + dev = skb->dev; + if (dev == NULL || (vif = ip6mr_find_vif(dev)) < 0) { + read_unlock(&mrt_lock); + return -ENODEV; + } + + /* really correct? */ + skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); + if (!skb2) { + read_unlock(&mrt_lock); + return -ENOMEM; + } + + skb_reset_transport_header(skb2); + + skb_put(skb2, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb2); + + iph = ipv6_hdr(skb2); + iph->version = 0; + iph->priority = 0; + iph->flow_lbl[0] = 0; + iph->flow_lbl[1] = 0; + iph->flow_lbl[2] = 0; + iph->payload_len = 0; + iph->nexthdr = IPPROTO_NONE; + iph->hop_limit = 0; + ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); + ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); + + err = ip6mr_cache_unresolved(vif, skb2); + read_unlock(&mrt_lock); + + return err; + } + + if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) + cache->mfc_flags |= MFC_NOTIFY; + + err = ip6mr_fill_mroute(skb, cache, rtm); + read_unlock(&mrt_lock); + return err; +} + diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4195ac92345e..99624109c010 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, valbool = (val!=0); + if (ip6_mroute_opt(optname)) + return ip6_mroute_setsockopt(sk, optname, optval, optlen); + lock_sock(sk); switch (optname) { @@ -790,6 +794,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, int len; int val; + if (ip6_mroute_opt(optname)) + return ip6_mroute_getsockopt(sk, optname, optval, optlen); + if (get_user(len, optlen)) return -EFAULT; switch (optname) { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index aae6cedf1709..088b80b4ce74 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -53,6 +53,7 @@ #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) #include #endif +#include #include #include @@ -1135,7 +1136,11 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) } default: +#ifdef CONFIG_IPV6_MROUTE + return ip6mr_ioctl(sk, cmd, (void __user *)arg); +#else return -ENOIOCTLCMD; +#endif } } @@ -1143,7 +1148,7 @@ static void rawv6_close(struct sock *sk, long timeout) { if (inet_sk(sk)->num == IPPROTO_RAW) ip6_ra_control(sk, -1, NULL); - + ip6mr_sk_done(sk); sk_common_release(sk); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd82b6db35ff..3c314d5f46c6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -2106,7 +2107,7 @@ static inline size_t rt6_nlmsg_size(void) static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *dst, struct in6_addr *src, int iif, int type, u32 pid, u32 seq, - int prefix, unsigned int flags) + int prefix, int nowait, unsigned int flags) { struct rtmsg *rtm; struct nlmsghdr *nlh; @@ -2166,9 +2167,24 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, } else if (rtm->rtm_src_len) NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); #endif - if (iif) - NLA_PUT_U32(skb, RTA_IIF, iif); - else if (dst) { + if (iif) { +#ifdef CONFIG_IPV6_MROUTE + if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { + int err = ip6mr_get_route(skb, rtm, nowait); + if (err <= 0) { + if (!nowait) { + if (err == 0) + return 0; + goto nla_put_failure; + } else { + if (err == -EMSGSIZE) + goto nla_put_failure; + } + } + } else +#endif + NLA_PUT_U32(skb, RTA_IIF, iif); + } else if (dst) { struct in6_addr saddr_buf; if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, dst, 0, &saddr_buf) == 0) @@ -2211,7 +2227,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, - prefix, NLM_F_MULTI); + prefix, 0, NLM_F_MULTI); } static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) @@ -2277,7 +2293,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, - nlh->nlmsg_seq, 0, 0); + nlh->nlmsg_seq, 0, 0, 0); if (err < 0) { kfree_skb(skb); goto errout; @@ -2303,7 +2319,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) goto errout; err = rt6_fill_node(skb, rt, NULL, NULL, 0, - event, info->pid, seq, 0, 0); + event, info->pid, seq, 0, 0, 0); if (err < 0) { /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); -- cgit v1.2.3 From 14fb64e1f449ef6666f1c3a3fa4e13aec669b98d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:54 +0900 Subject: [IPV6] MROUTE: Support PIM-SM (SSM). Based on ancient patch by Mickael Hoerdt , which is available at . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/mroute6.h | 4 + net/ipv6/Kconfig | 7 ++ net/ipv6/ip6mr.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 285 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index b92190304e0b..f6469fb90840 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -23,6 +23,8 @@ #define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ #define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ #define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ +#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ +#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ #define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) @@ -217,6 +219,8 @@ static inline int ip6mr_sk_done(struct sock *sk) { return 0; } struct mrt6msg { #define MRT6MSG_NOCACHE 1 +#define MRT6MSG_WRONGMIF 2 +#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */ __u8 im6_mbz; /* must be zero */ __u8 im6_msgtype; /* what type of message */ __u16 im6_mif; /* mif rec'd on */ diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 9a2ea81e499f..82f987b4ef84 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -216,3 +216,10 @@ config IPV6_MROUTE Experimental support for IPv6 multicast forwarding. If unsure, say N. +config IPV6_PIMSM_V2 + bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" + depends on IPV6_MROUTE + ---help--- + Support for IPv6 PIM multicast routing protocol PIM-SMv2. + If unsure, say N. + diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 1bdf3c177d58..2b70774be61f 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,13 @@ static int maxvif; #define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL) +static int mroute_do_assert; /* Set in PIM assert */ +#ifdef CONFIG_IPV6_PIMSM_V2 +static int mroute_do_pim; +#else +#define mroute_do_pim 0 +#endif + static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */ static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ @@ -97,6 +105,10 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); +#ifdef CONFIG_IPV6_PIMSM_V2 +static struct inet6_protocol pim6_protocol; +#endif + static struct timer_list ipmr_expire_timer; @@ -339,6 +351,132 @@ static struct file_operations ip6mr_mfc_fops = { }; #endif +#ifdef CONFIG_IPV6_PIMSM_V2 +static int reg_vif_num = -1; + +static int pim6_rcv(struct sk_buff *skb) +{ + struct pimreghdr *pim; + struct ipv6hdr *encap; + struct net_device *reg_dev = NULL; + + if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) + goto drop; + + pim = (struct pimreghdr *)skb_transport_header(skb); + if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) || + (pim->flags & PIM_NULL_REGISTER) || + (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && + (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))) + goto drop; + + /* check if the inner packet is destined to mcast group */ + encap = (struct ipv6hdr *)(skb_transport_header(skb) + + sizeof(*pim)); + + if (!ipv6_addr_is_multicast(&encap->daddr) || + encap->payload_len == 0 || + ntohs(encap->payload_len) + sizeof(*pim) > skb->len) + goto drop; + + read_lock(&mrt_lock); + if (reg_vif_num >= 0) + reg_dev = vif6_table[reg_vif_num].dev; + if (reg_dev) + dev_hold(reg_dev); + read_unlock(&mrt_lock); + + if (reg_dev == NULL) + goto drop; + + skb->mac_header = skb->network_header; + skb_pull(skb, (u8 *)encap - skb->data); + skb_reset_network_header(skb); + skb->dev = reg_dev; + skb->protocol = htons(ETH_P_IP); + skb->ip_summed = 0; + skb->pkt_type = PACKET_HOST; + dst_release(skb->dst); + ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++; + skb->dst = NULL; + nf_reset(skb); + netif_rx(skb); + dev_put(reg_dev); + return 0; + drop: + kfree_skb(skb); + return 0; +} + +static struct inet6_protocol pim6_protocol = { + .handler = pim6_rcv, +}; + +/* Service routines creating virtual interfaces: PIMREG */ + +static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) +{ + read_lock(&mrt_lock); + ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(dev))->tx_packets++; + ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT); + read_unlock(&mrt_lock); + kfree_skb(skb); + return 0; +} + +static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)netdev_priv(dev); +} + +static void reg_vif_setup(struct net_device *dev) +{ + dev->type = ARPHRD_PIMREG; + dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; + dev->flags = IFF_NOARP; + dev->hard_start_xmit = reg_vif_xmit; + dev->get_stats = reg_vif_get_stats; + dev->destructor = free_netdev; +} + +static struct net_device *ip6mr_reg_vif(void) +{ + struct net_device *dev; + struct inet6_dev *in_dev; + + dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", + reg_vif_setup); + + if (dev == NULL) + return NULL; + + if (register_netdevice(dev)) { + free_netdev(dev); + return NULL; + } + dev->iflink = 0; + + in_dev = ipv6_find_idev(dev); + if (!in_dev) + goto failure; + + if (dev_open(dev)) + goto failure; + + return dev; + +failure: + /* allow the register to be completed before unregistering. */ + rtnl_unlock(); + rtnl_lock(); + + unregister_netdevice(dev); + return NULL; +} +#endif + /* * Delete a VIF entry */ @@ -361,6 +499,11 @@ static int mif6_delete(int vifi) return -EADDRNOTAVAIL; } +#ifdef CONFIG_IPV6_PIMSM_V2 + if (vifi == reg_vif_num) + reg_vif_num = -1; +#endif + if (vifi + 1 == maxvif) { int tmp; for (tmp = vifi - 1; tmp >= 0; tmp--) { @@ -480,6 +623,19 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) return -EADDRINUSE; switch (vifc->mif6c_flags) { +#ifdef CONFIG_IPV6_PIMSM_V2 + case MIFF_REGISTER: + /* + * Special Purpose VIF in PIM + * All the packets will be sent to the daemon + */ + if (reg_vif_num >= 0) + return -EADDRINUSE; + dev = ip6mr_reg_vif(); + if (!dev) + return -ENOBUFS; + break; +#endif case 0: dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); if (!dev) @@ -512,6 +668,10 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) write_lock_bh(&mrt_lock); dev_hold(dev); v->dev = dev; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (v->flags & MIFF_REGISTER) + reg_vif_num = vifi; +#endif if (vifi + 1 > maxvif) maxvif = vifi + 1; write_unlock_bh(&mrt_lock); @@ -599,7 +759,13 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) struct mrt6msg *msg; int ret; - skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); +#ifdef CONFIG_IPV6_PIMSM_V2 + if (assert == MRT6MSG_WHOLEPKT) + skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt) + +sizeof(*msg)); + else +#endif + skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); if (!skb) return -ENOBUFS; @@ -609,6 +775,29 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) skb->ip_summed = CHECKSUM_UNNECESSARY; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (assert == MRT6MSG_WHOLEPKT) { + /* Ugly, but we have no choice with this interface. + Duplicate old header, fix length etc. + And all this only to mangle msg->im6_msgtype and + to set msg->im6_mbz to "mbz" :-) + */ + skb_push(skb, -skb_network_offset(pkt)); + + skb_push(skb, sizeof(*msg)); + skb_reset_transport_header(skb); + msg = (struct mrt6msg *)skb_transport_header(skb); + msg->im6_mbz = 0; + msg->im6_msgtype = MRT6MSG_WHOLEPKT; + msg->im6_mif = reg_vif_num; + msg->im6_pad = 0; + ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); + ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); + + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else +#endif + { /* * Copy the IP header */ @@ -635,6 +824,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) skb->ip_summed = CHECKSUM_UNNECESSARY; skb_pull(skb, sizeof(struct ipv6hdr)); + } if (mroute6_socket == NULL) { kfree_skb(skb); @@ -1033,6 +1223,44 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int rtnl_unlock(); return ret; + /* + * Control PIM assert (to activate pim will activate assert) + */ + case MRT6_ASSERT: + { + int v; + if (get_user(v, (int __user *)optval)) + return -EFAULT; + mroute_do_assert = !!v; + return 0; + } + +#ifdef CONFIG_IPV6_PIMSM_V2 + case MRT6_PIM: + { + int v, ret; + if (get_user(v, (int __user *)optval)) + return -EFAULT; + v = !!v; + rtnl_lock(); + ret = 0; + if (v != mroute_do_pim) { + mroute_do_pim = v; + mroute_do_assert = v; + if (mroute_do_pim) + ret = inet6_add_protocol(&pim6_protocol, + IPPROTO_PIM); + else + ret = inet6_del_protocol(&pim6_protocol, + IPPROTO_PIM); + if (ret < 0) + ret = -EAGAIN; + } + rtnl_unlock(); + return ret; + } + +#endif /* * Spurious command, or MRT_VERSION which you cannot * set. @@ -1056,6 +1284,14 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, case MRT6_VERSION: val = 0x0305; break; +#ifdef CONFIG_IPV6_PIMSM_V2 + case MRT6_PIM: + val = mroute_do_pim; + break; +#endif + case MRT6_ASSERT: + val = mroute_do_assert; + break; default: return -ENOPROTOOPT; } @@ -1151,6 +1387,18 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) if (vif->dev == NULL) goto out_free; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (vif->flags & MIFF_REGISTER) { + vif->pkt_out++; + vif->bytes_out += skb->len; + ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++; + ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT); + kfree_skb(skb); + return 0; + } +#endif + ipv6h = ipv6_hdr(skb); fl = (struct flowi) { @@ -1220,6 +1468,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) cache->mfc_un.res.pkt++; cache->mfc_un.res.bytes += skb->len; + /* + * Wrong interface: drop packet and (maybe) send PIM assert. + */ + if (vif6_table[vif].dev != skb->dev) { + int true_vifi; + + cache->mfc_un.res.wrong_if++; + true_vifi = ip6mr_find_vif(skb->dev); + + if (true_vifi >= 0 && mroute_do_assert && + /* pimsm uses asserts, when switching from RPT to SPT, + so that we cannot check that packet arrived on an oif. + It is bad, but otherwise we would need to move pretty + large chunk of pimd to kernel. Ough... --ANK + */ + (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) && + time_after(jiffies, + cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { + cache->mfc_un.res.last_assert = jiffies; + ip6mr_cache_report(skb, true_vifi, MRT6MSG_WRONGMIF); + } + goto dont_forward; + } + vif6_table[vif].pkt_in++; vif6_table[vif].bytes_in += skb->len; @@ -1241,6 +1513,7 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) return 0; } +dont_forward: kfree_skb(skb); return 0; } -- cgit v1.2.3 From 12802d058a003048104fe405a8d283b94ac50801 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:56 +0900 Subject: [IPV6]: Comment MRT6_xxx sockopts in include/linux/in6.h. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/in6.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index f674000c6c99..e6aa8de2b939 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -260,4 +260,19 @@ struct in6_flowlabel_req #define IPV6_PREFER_SRC_CGA 0x0008 #define IPV6_PREFER_SRC_NONCGA 0x0800 +/* + * Multicast Routing: + * see include/linux/mroute6.h. + * + * MRT6_INIT 200 + * MRT6_DONE 201 + * MRT6_ADD_MIF 202 + * MRT6_DEL_MIF 203 + * MRT6_ADD_MFC 204 + * MRT6_DEL_MFC 205 + * MRT6_VERSION 206 + * MRT6_ASSERT 207 + * MRT6_PIM 208 + * (reserved) 209 + */ #endif -- cgit v1.2.3 From 40f6b36c6243462fb95d0343237331c423494b03 Mon Sep 17 00:00:00 2001 From: Kai Makisara Date: Sun, 24 Feb 2008 22:23:24 +0200 Subject: [SCSI] st: add option to use SILI in variable block reads Add new option MT_ST_SILI to enable setting the SILI bit in reads in variable block mode. If SILI is set, reading a block shorter than the byte count does not result in CHECK CONDITION. The length of the block is determined using the residual count from the HBA. Avoiding the REQUEST SENSE command for every block speeds up some real applications considerably. Signed-off-by: Kai Makisara Signed-off-by: James Bottomley --- Documentation/scsi/st.txt | 7 ++++++- drivers/scsi/st.c | 40 ++++++++++++++++++++++++++++++++++++---- drivers/scsi/st.h | 3 +++ drivers/scsi/st_options.h | 6 +++++- include/linux/mtio.h | 1 + 5 files changed, 51 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt index b7be95b5bd24..38f81188def0 100644 --- a/Documentation/scsi/st.txt +++ b/Documentation/scsi/st.txt @@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver. The driver is currently maintained by Kai Mäkisara (email Kai.Makisara@kolumbus.fi) -Last modified: Mon Mar 7 21:14:44 2005 by kai.makisara +Last modified: Thu Feb 21 21:54:16 2008 by kai.makisara BASICS @@ -372,6 +372,11 @@ MTSETDRVBUFFER MT_ST_SYSV sets the SYSV semantics (mode) MT_ST_NOWAIT enables immediate mode (i.e., don't wait for the command to finish) for some commands (e.g., rewind) + MT_ST_SILI enables setting the SILI bit in SCSI commands when + reading in variable block mode to enhance performance when + reading blocks shorter than the byte count; set this only + if you are sure that the drive supports SILI and the HBA + correctly returns transfer residuals MT_ST_DEBUGGING debugging (global; debugging must be compiled into the driver) MT_ST_SETBOOLEANS diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0a52d9d2da2c..a4361a8c6ac6 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static const char *verstr = "20080221"; +static const char *verstr = "20080224"; #include @@ -183,6 +183,7 @@ static int modes_defined; static struct st_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(struct st_buffer *, int, int); +static void clear_buffer(struct st_buffer *); static void normalize_buffer(struct st_buffer *); static int append_to_buffer(const char __user *, struct st_buffer *, int); static int from_buffer(struct st_buffer *, char __user *, int); @@ -442,6 +443,7 @@ static void st_sleep_done(void *data, char *sense, int result, int resid) memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; + (STp->buffer)->cmdstat.residual = resid; DEB( STp->write_pending = 0; ) if (SRpnt->waiting) @@ -1159,6 +1161,7 @@ static int st_open(struct inode *inode, struct file *filp) goto err_out; } + (STp->buffer)->cleared = 0; (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; @@ -1432,8 +1435,14 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, if (STp->block_size) bufsize = STp->block_size > st_fixed_buffer_size ? STp->block_size : st_fixed_buffer_size; - else + else { bufsize = count; + /* Make sure that data from previous user is not leaked even if + HBA does not return correct residual */ + if (is_read && STp->sili && !STbp->cleared) + clear_buffer(STbp); + } + if (bufsize > STbp->buffer_size && !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", @@ -1783,6 +1792,8 @@ static long read_tape(struct scsi_tape *STp, long count, memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_6; cmd[1] = (STp->block_size != 0); + if (!cmd[1] && STp->sili) + cmd[1] |= 2; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; @@ -1911,8 +1922,11 @@ static long read_tape(struct scsi_tape *STp, long count, } /* End of error handling */ - else /* Read successful */ + else { /* Read successful */ STbp->buffer_bytes = bytes; + if (STp->sili) /* In fixed block mode residual is always zero here */ + STbp->buffer_bytes -= STp->buffer->cmdstat.residual; + } if (STps->drv_block >= 0) { if (STp->block_size == 0) @@ -2090,7 +2104,8 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); + "%s: sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate, + STp->sili); printk(KERN_INFO "%s: debugging: %d\n", name, debugging); } @@ -2133,6 +2148,7 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; + STp->sili = (options & MT_ST_SILI) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; st_log_options(STp, STm, name); ) } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { @@ -2164,6 +2180,8 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->immediate = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; + if ((options & MT_ST_SILI) != 0) + STp->sili = value; DEB( if ((options & MT_ST_DEBUGGING) != 0) debugging = value; @@ -3655,6 +3673,8 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm STbuffer->frp_segs += 1; got += b_size; STbuffer->buffer_size = got; + if (STbuffer->cleared) + memset(page_address(STbuffer->frp[segs].page), 0, b_size); segs++; } STbuffer->b_data = page_address(STbuffer->frp[0].page); @@ -3663,6 +3683,17 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm } +/* Make sure that no data from previous user is in the internal buffer */ +static void clear_buffer(struct st_buffer * st_bp) +{ + int i; + + for (i=0; i < st_bp->frp_segs; i++) + memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); + st_bp->cleared = 1; +} + + /* Release the extra buffer */ static void normalize_buffer(struct st_buffer * STbuffer) { @@ -3987,6 +4018,7 @@ static int st_probe(struct device *dev) tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; tpnt->scsi2_logical = ST_SCSI2LOGICAL; + tpnt->sili = ST_SILI; tpnt->immediate = ST_NOWAIT; tpnt->default_drvbuffer = 0xff; /* No forced buffering */ tpnt->partition = 0; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 5931726fcf93..b92712f95931 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -12,6 +12,7 @@ struct st_cmdstatus { int midlevel_result; struct scsi_sense_hdr sense_hdr; int have_sense; + int residual; u64 uremainder64; u8 flags; u8 remainder_valid; @@ -34,6 +35,7 @@ struct st_request { struct st_buffer { unsigned char dma; /* DMA-able buffer */ unsigned char do_dio; /* direct i/o set up? */ + unsigned char cleared; /* internal buffer cleared after open? */ int buffer_size; int buffer_blocks; int buffer_bytes; @@ -122,6 +124,7 @@ struct scsi_tape { unsigned char try_dio_now; /* try direct i/o before next close? */ unsigned char c_algo; /* compression algorithm */ unsigned char pos_unknown; /* after reset position unknown */ + unsigned char sili; /* use SILI when reading in variable b mode */ int tape_type; int long_timeout; /* timeout for commands known to take long time */ diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h index b6b5c9c37677..d2f947935554 100644 --- a/drivers/scsi/st_options.h +++ b/drivers/scsi/st_options.h @@ -3,7 +3,7 @@ Copyright 1995-2003 Kai Makisara. - Last modified: Mon Apr 7 22:49:18 2003 by makisara + Last modified: Thu Feb 21 21:47:07 2008 by kai.makisara */ #ifndef _ST_OPTIONS_H @@ -94,6 +94,10 @@ The default is BSD semantics. */ #define ST_SYSV 0 +/* If ST_SILI is non-zero, the SILI bit is set when reading in variable block + mode and the block size is determined using the residual returned by the HBA. */ +#define ST_SILI 0 + /* Time to wait for the drive to become ready if blocking open */ #define ST_BLOCK_SECONDS 120 diff --git a/include/linux/mtio.h b/include/linux/mtio.h index 6f8d2d45a8fb..ef01d6aa5934 100644 --- a/include/linux/mtio.h +++ b/include/linux/mtio.h @@ -192,6 +192,7 @@ struct mtpos { #define MT_ST_SCSI2LOGICAL 0x800 #define MT_ST_SYSV 0x1000 #define MT_ST_NOWAIT 0x2000 +#define MT_ST_SILI 0x4000 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff -- cgit v1.2.3 From b1adaf65ba0398c9a1adc8f3a274533165a4df61 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 18 Mar 2008 00:15:03 +0900 Subject: [SCSI] block: add sg buffer copy helper functions This patch adds new three helper functions to copy data between an SG list and a linear buffer. - sg_copy_from_buffer copies data from linear buffer to an SG list - sg_copy_to_buffer copies data from an SG list to a linear buffer When the APIs copy data from a linear buffer to an SG list, flush_kernel_dcache_page is called. It's not necessary for everyone but it's a no-op on most architectures and in general the API is not used in performance critical path. Signed-off-by: FUJITA Tomonori Acked-by: Jens Axboe Signed-off-by: James Bottomley --- include/linux/scatterlist.h | 5 +++ lib/scatterlist.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) (limited to 'include/linux') diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index a3d567a974e8..71fc81360048 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -213,6 +213,11 @@ int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t, sg_alloc_fn *); int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); +size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen); +size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen); + /* * Maximum number of entries that will be allocated in one piece, if * a list larger than this is required then chaining will be utilized. diff --git a/lib/scatterlist.c b/lib/scatterlist.c index acca4901046c..b80c21100d78 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -8,6 +8,7 @@ */ #include #include +#include /** * sg_next - return the next scatterlist entry in a list @@ -292,3 +293,104 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) return ret; } EXPORT_SYMBOL(sg_alloc_table); + +/** + * sg_copy_buffer - Copy data between a linear buffer and an SG list + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy from + * @buflen: The number of bytes to copy + * @to_buffer: transfer direction (non zero == from an sg list to a + * buffer, 0 == from a buffer to an sg list + * + * Returns the number of copied bytes. + * + **/ +static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen, int to_buffer) +{ + struct scatterlist *sg; + size_t buf_off = 0; + int i; + + WARN_ON(!irqs_disabled()); + + for_each_sg(sgl, sg, nents, i) { + struct page *page; + int n = 0; + unsigned int sg_off = sg->offset; + unsigned int sg_copy = sg->length; + + if (sg_copy > buflen) + sg_copy = buflen; + buflen -= sg_copy; + + while (sg_copy > 0) { + unsigned int page_copy; + void *p; + + page_copy = PAGE_SIZE - sg_off; + if (page_copy > sg_copy) + page_copy = sg_copy; + + page = nth_page(sg_page(sg), n); + p = kmap_atomic(page, KM_BIO_SRC_IRQ); + + if (to_buffer) + memcpy(buf + buf_off, p + sg_off, page_copy); + else { + memcpy(p + sg_off, buf + buf_off, page_copy); + flush_kernel_dcache_page(page); + } + + kunmap_atomic(p, KM_BIO_SRC_IRQ); + + buf_off += page_copy; + sg_off += page_copy; + if (sg_off == PAGE_SIZE) { + sg_off = 0; + n++; + } + sg_copy -= page_copy; + } + + if (!buflen) + break; + } + + return buf_off; +} + +/** + * sg_copy_from_buffer - Copy from a linear buffer to an SG list + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy from + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, buf, buflen, 0); +} +EXPORT_SYMBOL(sg_copy_from_buffer); + +/** + * sg_copy_to_buffer - Copy from an SG list to a linear buffer + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy to + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, buf, buflen, 1); +} +EXPORT_SYMBOL(sg_copy_to_buffer); -- cgit v1.2.3 From 2f3edc6936e3f6be3f1df1e89c141ae028fa605e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 2 Apr 2008 10:05:48 -0500 Subject: [SCSI] transport_class: BUG if we can't release the attribute container Every current transport class calls transport_container_release but ignores the return value. This is catastrophic if it returns an error because the containers are part of a global list and the next action of almost every transport class is to free the memory used by the container. Fix this by making transport_container_release a void, but making it BUG if attribute_container_release returns an error ... this catches the root cause of a system panic much earlier. If we don't do this, we get an eventual BUG when the attribute container list notices the corruption caused by the freed memory it's still referencing. Also made attribute_container_release __must_check as a reminder. Cc: Greg KH Signed-off-by: James Bottomley --- drivers/base/transport_class.c | 3 ++- drivers/scsi/raid_class.c | 2 +- include/linux/attribute_container.h | 2 +- include/linux/transport_class.h | 5 +++-- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 40bca48abc12..cabd0edf2156 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -108,7 +108,8 @@ EXPORT_SYMBOL_GPL(anon_transport_class_register); */ void anon_transport_class_unregister(struct anon_transport_class *atc) { - attribute_container_unregister(&atc->container); + if (unlikely(attribute_container_unregister(&atc->container))) + BUG(); } EXPORT_SYMBOL_GPL(anon_transport_class_unregister); diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 86e13183c9ba..52182a744ba6 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -289,7 +289,7 @@ raid_class_release(struct raid_template *r) { struct raid_internal *i = to_raid_internal(r); - attribute_container_unregister(&i->r.raid_attrs.ac); + BUG_ON(attribute_container_unregister(&i->r.raid_attrs.ac)); kfree(i); } diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index f5582332af04..574b201b99d8 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -37,7 +37,7 @@ attribute_container_set_no_classdevs(struct attribute_container *atc) } int attribute_container_register(struct attribute_container *cont); -int attribute_container_unregister(struct attribute_container *cont); +int __must_check attribute_container_unregister(struct attribute_container *cont); void attribute_container_create_device(struct device *dev, int (*fn)(struct attribute_container *, struct device *, diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h index 1d6cc22e5f42..6696cf79c4f7 100644 --- a/include/linux/transport_class.h +++ b/include/linux/transport_class.h @@ -86,9 +86,10 @@ static inline int transport_container_register(struct transport_container *tc) return attribute_container_register(&tc->ac); } -static inline int transport_container_unregister(struct transport_container *tc) +static inline void transport_container_unregister(struct transport_container *tc) { - return attribute_container_unregister(&tc->ac); + if (unlikely(attribute_container_unregister(&tc->ac))) + BUG(); } int transport_class_register(struct transport_class *); -- cgit v1.2.3 From 8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Mar 2008 00:10:50 +0100 Subject: ssb: Turn suspend/resume upside down Turn the SSB bus suspend mechanism upside down. Instead of deciding by an internal reference count when to suspend/resume, let the parent bus call us in their suspend/resume routine. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/pcmcia.c | 10 ++-- drivers/ssb/driver_chipcommon.c | 2 +- drivers/ssb/main.c | 81 +++++++++++++------------------ drivers/ssb/pcihost_wrapper.c | 10 ++++ drivers/ssb/pcmcia.c | 34 +++++++++---- drivers/ssb/ssb_private.h | 5 ++ include/linux/ssb/ssb.h | 10 ++-- include/linux/ssb/ssb_driver_chipcommon.h | 3 +- 8 files changed, 88 insertions(+), 67 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 371e4a119511..b8aa16307f79 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); #ifdef CONFIG_PM static int b43_pcmcia_suspend(struct pcmcia_device *dev) { - //TODO - return 0; + struct ssb_bus *ssb = dev->priv; + + return ssb_bus_suspend(ssb); } static int b43_pcmcia_resume(struct pcmcia_device *dev) { - //TODO - return 0; + struct ssb_bus *ssb = dev->priv; + + return ssb_bus_resume(ssb); } #else /* CONFIG_PM */ # define b43_pcmcia_suspend NULL diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 45b672a69003..571f4fd55236 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -251,7 +251,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) calc_fast_powerup_delay(cc); } -void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) +void ssb_chipco_suspend(struct ssb_chipcommon *cc) { if (!cc->dev) return; diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 2fcfd73b3b6e..c0cbdba07aee 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev) put_device(dev->dev); } -static int ssb_bus_resume(struct ssb_bus *bus) -{ - int err; - - ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); - err = ssb_pcmcia_init(bus); - if (err) { - /* No need to disable XTAL, as we don't have one on PCMCIA. */ - return err; - } - ssb_chipco_resume(&bus->chipco); - - return 0; -} - static int ssb_device_resume(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); struct ssb_driver *ssb_drv; - struct ssb_bus *bus; int err = 0; - bus = ssb_dev->bus; - if (bus->suspend_cnt == bus->nr_devices) { - err = ssb_bus_resume(bus); - if (err) - return err; - } - bus->suspend_cnt--; if (dev->driver) { ssb_drv = drv_to_ssb_drv(dev->driver); if (ssb_drv && ssb_drv->resume) @@ -160,27 +137,10 @@ out: return err; } -static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) -{ - ssb_chipco_suspend(&bus->chipco, state); - ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); - - /* Reset HW state information in memory, so that HW is - * completely reinitialized on resume. */ - bus->mapped_device = NULL; -#ifdef CONFIG_SSB_DRIVER_PCICORE - bus->pcicore.setup_done = 0; -#endif -#ifdef CONFIG_SSB_DEBUG - bus->powered_up = 0; -#endif -} - static int ssb_device_suspend(struct device *dev, pm_message_t state) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); struct ssb_driver *ssb_drv; - struct ssb_bus *bus; int err = 0; if (dev->driver) { @@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) if (err) goto out; } +out: + return err; +} + +int ssb_bus_resume(struct ssb_bus *bus) +{ + int err; - bus = ssb_dev->bus; - bus->suspend_cnt++; - if (bus->suspend_cnt == bus->nr_devices) { - /* All devices suspended. Shutdown the bus. */ - ssb_bus_suspend(bus, state); + /* Reset HW state information in memory, so that HW is + * completely reinitialized. */ + bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE + bus->pcicore.setup_done = 0; +#endif + + err = ssb_bus_powerup(bus, 0); + if (err) + return err; + err = ssb_pcmcia_hardware_setup(bus); + if (err) { + ssb_bus_may_powerdown(bus); + return err; } + ssb_chipco_resume(&bus->chipco); + ssb_bus_may_powerdown(bus); -out: - return err; + return 0; +} +EXPORT_SYMBOL(ssb_bus_resume); + +int ssb_bus_suspend(struct ssb_bus *bus) +{ + ssb_chipco_suspend(&bus->chipco); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + + return 0; } +EXPORT_SYMBOL(ssb_bus_suspend); #ifdef CONFIG_SSB_PCIHOST int ssb_devices_freeze(struct ssb_bus *bus) diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index 82a10abef640..e82db4aaa050 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -18,6 +18,12 @@ #ifdef CONFIG_PM static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) { + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + + err = ssb_bus_suspend(ssb); + if (err) + return err; pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); @@ -27,6 +33,7 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) static int ssb_pcihost_resume(struct pci_dev *dev) { + struct ssb_bus *ssb = pci_get_drvdata(dev); int err; pci_set_power_state(dev, 0); @@ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev) if (err) return err; pci_restore_state(dev); + err = ssb_bus_resume(ssb); + if (err) + return err; return 0; } diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index d674cef7210d..dcaf2412bea7 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -684,6 +684,29 @@ static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor) return 0; } +/* Initialize the PCMCIA hardware. This is called on Init and Resume. */ +int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) +{ + int err; + + if (bus->bustype != SSB_BUSTYPE_PCMCIA) + return 0; + + /* Switch segment to a known state and sync + * bus->mapped_pcmcia_seg with hardware state. */ + ssb_pcmcia_switch_segment(bus, 0); + /* Init the COR register. */ + err = ssb_pcmcia_cor_setup(bus, CISREG_COR); + if (err) + return err; + /* Some cards also need this register to get poked. */ + err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); + if (err) + return err; + + return 0; +} + void ssb_pcmcia_exit(struct ssb_bus *bus) { if (bus->bustype != SSB_BUSTYPE_PCMCIA) @@ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus) if (bus->bustype != SSB_BUSTYPE_PCMCIA) return 0; - /* Switch segment to a known state and sync - * bus->mapped_pcmcia_seg with hardware state. */ - ssb_pcmcia_switch_segment(bus, 0); - - /* Init the COR register. */ - err = ssb_pcmcia_cor_setup(bus, CISREG_COR); - if (err) - goto error; - /* Some cards also need this register to get poked. */ - err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); + err = ssb_pcmcia_hardware_setup(bus); if (err) goto error; diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index a83bf7a4d80b..ebc32d8fe15f 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -81,6 +81,7 @@ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg); extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv); +extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); extern void ssb_pcmcia_exit(struct ssb_bus *bus); extern int ssb_pcmcia_init(struct ssb_bus *bus); extern const struct ssb_bus_ops ssb_pcmcia_ops; @@ -100,6 +101,10 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, { return 0; } +static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) +{ + return 0; +} static inline void ssb_pcmcia_exit(struct ssb_bus *bus) { } diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 8644e03cf588..a8ca396f810a 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -260,9 +260,6 @@ struct ssb_bus { struct ssb_device devices[SSB_MAX_NR_CORES]; u8 nr_devices; - /* Reference count. Number of suspended devices. */ - u8 suspend_cnt; - /* Software ID number for this bus. */ unsigned int busnumber; @@ -334,6 +331,13 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, extern void ssb_bus_unregister(struct ssb_bus *bus); +/* Suspend a SSB bus. + * Call this from the parent bus suspend routine. */ +extern int ssb_bus_suspend(struct ssb_bus *bus); +/* Resume a SSB bus. + * Call this from the parent bus resume routine. */ +extern int ssb_bus_resume(struct ssb_bus *bus); + extern u32 ssb_clockspeed(struct ssb_bus *bus); /* Is the device enabled in hardware? */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index b548a54ff1f5..7d7e03dcf77c 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -367,8 +367,7 @@ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); -#include -extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); +extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); extern void ssb_chipco_resume(struct ssb_chipcommon *cc); extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, -- cgit v1.2.3 From d625a29ba649a4df6027520ffc378f23c0e6883e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 2 Apr 2008 19:46:56 +0200 Subject: ssb: Add support for block-I/O This adds support for block based I/O to SSB. This is needed in order to efficiently support PIO data transfers to the card. The block-I/O support is only compiled, if it's selected by the weird driver that needs it. So there's no overhead for sane devices. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 5 ++ drivers/ssb/main.c | 102 +++++++++++++++++++++++++++++++++++++++++ drivers/ssb/pci.c | 70 ++++++++++++++++++++++++++++ drivers/ssb/pcmcia.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/ssb/ssb.h | 19 ++++++++ 5 files changed, 315 insertions(+) (limited to 'include/linux') diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 0f7cce2560d1..cd845b8acd17 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -24,6 +24,11 @@ config SSB config SSB_SPROM bool +# Support for Block-I/O. SELECT this from the driver that needs it. +config SSB_BLOCKIO + bool + depends on SSB + config SSB_PCIHOST_POSSIBLE bool depends on SSB && (PCI = y || PCI = SSB) diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 3e58db7ef608..19ddd2bd1057 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -555,6 +555,55 @@ static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) return readl(bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr; + + offset += dev->core_index * SSB_CORE_SIZE; + addr = bus->mmio + offset; + + switch (reg_width) { + case sizeof(u8): { + u8 *buf = buffer; + + while (count) { + *buf = __raw_readb(addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + __le32 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + *buf = (__force __le32)__raw_readl(addr); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) { struct ssb_bus *bus = dev->bus; @@ -579,6 +628,55 @@ static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) writel(value, bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr; + + offset += dev->core_index * SSB_CORE_SIZE; + addr = bus->mmio + offset; + + switch (reg_width) { + case sizeof(u8): { + const u8 *buf = buffer; + + while (count) { + __raw_writeb(*buf, addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + const __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + const __le32 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + __raw_writel((__force u32)(*buf), addr); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ static const struct ssb_bus_ops ssb_ssb_ops = { .read8 = ssb_ssb_read8, @@ -587,6 +685,10 @@ static const struct ssb_bus_ops ssb_ssb_ops = { .write8 = ssb_ssb_write8, .write16 = ssb_ssb_write16, .write32 = ssb_ssb_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_ssb_block_read, + .block_write = ssb_ssb_block_write, +#endif }; static int ssb_fetch_invariants(struct ssb_bus *bus, diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index f1514b33cfae..904b1a8d0885 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -613,6 +613,41 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) return ioread32(bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pci_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr = bus->mmio + offset; + + if (unlikely(ssb_pci_assert_buspower(bus))) + goto error; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + goto error; + } + switch (reg_width) { + case sizeof(u8): + ioread8_rep(addr, buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + ioread16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + ioread32_rep(addr, buffer, count >> 2); + break; + default: + SSB_WARN_ON(1); + } + + return; +error: + memset(buffer, 0xFF, count); +} +#endif /* CONFIG_SSB_BLOCKIO */ + static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) { struct ssb_bus *bus = dev->bus; @@ -652,6 +687,37 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) iowrite32(value, bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr = bus->mmio + offset; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + switch (reg_width) { + case sizeof(u8): + iowrite8_rep(addr, buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + iowrite16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + iowrite32_rep(addr, buffer, count >> 2); + break; + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + /* Not "static", as it's used in main.c */ const struct ssb_bus_ops ssb_pci_ops = { .read8 = ssb_pci_read8, @@ -660,6 +726,10 @@ const struct ssb_bus_ops ssb_pci_ops = { .write8 = ssb_pci_write8, .write16 = ssb_pci_write16, .write32 = ssb_pci_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_pci_block_read, + .block_write = ssb_pci_block_write, +#endif }; static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index dcaf2412bea7..24c2a46c1476 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -285,6 +285,64 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) return (lo | (hi << 16)); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + unsigned long flags; + void __iomem *addr = bus->mmio + offset; + int err; + + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (unlikely(err)) { + memset(buffer, 0xFF, count); + goto unlock; + } + switch (reg_width) { + case sizeof(u8): { + u8 *buf = buffer; + + while (count) { + *buf = __raw_readb(addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + __le16 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + *buf = (__force __le16)__raw_readw(addr + 2); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +unlock: + spin_unlock_irqrestore(&bus->bar_lock, flags); +} +#endif /* CONFIG_SSB_BLOCKIO */ + static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) { struct ssb_bus *bus = dev->bus; @@ -329,6 +387,63 @@ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) spin_unlock_irqrestore(&bus->bar_lock, flags); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + unsigned long flags; + void __iomem *addr = bus->mmio + offset; + int err; + + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (unlikely(err)) + goto unlock; + switch (reg_width) { + case sizeof(u8): { + const u8 *buf = buffer; + + while (count) { + __raw_writeb(*buf, addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + const __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + const __le16 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + __raw_writew((__force u16)(*buf), addr + 2); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +unlock: + mmiowb(); + spin_unlock_irqrestore(&bus->bar_lock, flags); +} +#endif /* CONFIG_SSB_BLOCKIO */ + /* Not "static", as it's used in main.c */ const struct ssb_bus_ops ssb_pcmcia_ops = { .read8 = ssb_pcmcia_read8, @@ -337,6 +452,10 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { .write8 = ssb_pcmcia_write8, .write16 = ssb_pcmcia_write16, .write32 = ssb_pcmcia_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_pcmcia_block_read, + .block_write = ssb_pcmcia_block_write, +#endif }; static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index a8ca396f810a..9f95afd0e9e3 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -78,6 +78,12 @@ struct ssb_bus_ops { void (*write8)(struct ssb_device *dev, u16 offset, u8 value); void (*write16)(struct ssb_device *dev, u16 offset, u16 value); void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +#ifdef CONFIG_SSB_BLOCKIO + void (*block_read)(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width); + void (*block_write)(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width); +#endif }; @@ -374,6 +380,19 @@ static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value) { dev->ops->write32(dev, offset, value); } +#ifdef CONFIG_SSB_BLOCKIO +static inline void ssb_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + dev->ops->block_read(dev, buffer, count, offset, reg_width); +} + +static inline void ssb_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + dev->ops->block_write(dev, buffer, count, offset, reg_width); +} +#endif /* CONFIG_SSB_BLOCKIO */ /* Translation (routing) bits that need to be ORed to DMA -- cgit v1.2.3 From b715631fad3ed320b85d386a84a6fb0b3f86b0b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:33:47 -0700 Subject: socket: sk_filter minor cleanups Some minor style cleanups: * Move __KERNEL__ definitions to one place in filter.h * Use const for sk_filter_len * Line wrapping * Put EXPORT_SYMBOL next to function definition Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 31 +++++++++++++++---------------- net/core/filter.c | 5 ++--- 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/include/linux/filter.h b/include/linux/filter.h index ddfa0372a3b7..bfc5d319b946 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -37,21 +37,6 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ struct sock_filter __user *filter; }; -#ifdef __KERNEL__ -struct sk_filter -{ - atomic_t refcnt; - unsigned int len; /* Number of filter blocks */ - struct rcu_head rcu; - struct sock_filter insns[0]; -}; - -static inline unsigned int sk_filter_len(struct sk_filter *fp) -{ - return fp->len*sizeof(struct sock_filter) + sizeof(*fp); -} -#endif - /* * Instruction classes */ @@ -141,10 +126,24 @@ static inline unsigned int sk_filter_len(struct sk_filter *fp) #define SKF_LL_OFF (-0x200000) #ifdef __KERNEL__ +struct sk_filter +{ + atomic_t refcnt; + unsigned int len; /* Number of filter blocks */ + struct rcu_head rcu; + struct sock_filter insns[0]; +}; + +static inline unsigned int sk_filter_len(const struct sk_filter *fp) +{ + return fp->len * sizeof(struct sock_filter) + sizeof(*fp); +} + struct sk_buff; struct sock; -extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); +extern unsigned int sk_run_filter(struct sk_buff *skb, + struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, int flen); diff --git a/net/core/filter.c b/net/core/filter.c index e0a06942c025..85a5febab567 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -275,6 +275,7 @@ load_b: return 0; } +EXPORT_SYMBOL(sk_run_filter); /** * sk_chk_filter - verify socket filter code @@ -385,6 +386,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL; } +EXPORT_SYMBOL(sk_chk_filter); /** * sk_filter_rcu_release: Release a socket filter by rcu_head @@ -467,6 +469,3 @@ int sk_detach_filter(struct sock *sk) rcu_read_unlock_bh(); return ret; } - -EXPORT_SYMBOL(sk_chk_filter); -EXPORT_SYMBOL(sk_run_filter); -- cgit v1.2.3 From 43db6d65e0ef943a361cb91f8baa49132009227b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:43:09 -0700 Subject: socket: sk_filter deinline The sk_filter function is too big to be inlined. This saves 2296 bytes of text on allyesconfig. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 1 + include/net/sock.h | 35 ----------------------------------- net/core/filter.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/include/linux/filter.h b/include/linux/filter.h index bfc5d319b946..673e5677ebcc 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -142,6 +142,7 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) struct sk_buff; struct sock; +extern int sk_filter(struct sock *sk, struct sk_buff *skb); extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index f4fdd101c9a2..09255eae93e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -927,41 +927,6 @@ extern void sk_common_release(struct sock *sk); /* Initialise core socket variables */ extern void sock_init_data(struct socket *sock, struct sock *sk); -/** - * sk_filter - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * @needlock: set to 1 if the sock is not locked by caller. - * - * Run the filter code and then cut skb->data to correct size returned by - * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to sk_run_filter. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ - -static inline int sk_filter(struct sock *sk, struct sk_buff *skb) -{ - int err; - struct sk_filter *filter; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock_bh(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - unsigned int pkt_len = sk_run_filter(skb, filter->insns, - filter->len); - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; - } - rcu_read_unlock_bh(); - - return err; -} - /** * sk_filter_release: Release a socket filter * @sk: socket diff --git a/net/core/filter.c b/net/core/filter.c index 85a5febab567..bbb53c69857c 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -63,6 +63,41 @@ static inline void *load_pointer(struct sk_buff *skb, int k, } } +/** + * sk_filter - run a packet through a socket filter + * @sk: sock associated with &sk_buff + * @skb: buffer to filter + * @needlock: set to 1 if the sock is not locked by caller. + * + * Run the filter code and then cut skb->data to correct size returned by + * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller + * than pkt_len we keep whole skb->data. This is the socket level + * wrapper to sk_run_filter. It returns 0 if the packet should + * be accepted or -EPERM if the packet should be tossed. + * + */ +int sk_filter(struct sock *sk, struct sk_buff *skb) +{ + int err; + struct sk_filter *filter; + + err = security_sock_rcv_skb(sk, skb); + if (err) + return err; + + rcu_read_lock_bh(); + filter = rcu_dereference(sk->sk_filter); + if (filter) { + unsigned int pkt_len = sk_run_filter(skb, filter->insns, + filter->len); + err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; + } + rcu_read_unlock_bh(); + + return err; +} +EXPORT_SYMBOL(sk_filter); + /** * sk_run_filter - run a filter on a socket * @skb: buffer to run the filter on -- cgit v1.2.3 From 4738c1db1593687713869fa69e733eebc7b0d6d8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 10 Apr 2008 02:02:28 -0700 Subject: [SKFILTER]: Add SKF_ADF_NLATTR instruction SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually parsing and walking attributes. It takes the offset at which to start searching in the 'A' register and the attribute type in the 'X' register and returns the offset in the 'A' register. When the attribute is not found it returns zero. A top-level attribute can be located using a filter like this (example for nfnetlink, using struct nfgenmsg): ... { /* A = offset of first attribute */ .code = BPF_LD | BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, { /* Exit if not found */ .code = BPF_JMP | BPF_JEQ | BPF_K, .k = 0, .jt = }, ... A nested attribute below the CTA_PROTOINFO attribute would then be parsed like this: ... { /* A += sizeof(struct nlattr) */ .code = BPF_ALU | BPF_ADD | BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, ... The data of an attribute can be loaded into 'A' like this: ... { /* X = A (attribute offset) */ .code = BPF_MISC | BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD | BPF_B | BPF_IND, .k = sizeof(struct nlattr), }, ... Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/filter.h | 3 ++- net/core/filter.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/filter.h b/include/linux/filter.h index 673e5677ebcc..b6ea9aa9e853 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -121,7 +121,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_PROTOCOL 0 #define SKF_AD_PKTTYPE 4 #define SKF_AD_IFINDEX 8 -#define SKF_AD_MAX 12 +#define SKF_AD_NLATTR 12 +#define SKF_AD_MAX 16 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index bbb53c69857c..f5f3cf603064 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -303,6 +304,22 @@ load_b: case SKF_AD_IFINDEX: A = skb->dev->ifindex; continue; + case SKF_AD_NLATTR: { + struct nlattr *nla; + + if (skb_is_nonlinear(skb)) + return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + + nla = nla_find((struct nlattr *)&skb->data[A], + skb->len - A, X); + if (nla) + A = (void *)nla - (void *)skb->data; + else + A = 0; + continue; + } default: return 0; } -- cgit v1.2.3 From f3ee4010e84452aa133e5163e6cfabc52b194e94 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:11 +0900 Subject: [IPV6]: Define constants for link-local multicast addresses. - Define link-local all-node / all-router multicast addresses. - Remove ipv6_addr_all_nodes() and ipv6_addr_all_routers(). Signed-off-by: YOSHIFUJI Hideaki --- include/linux/in6.h | 8 ++++++++ include/net/addrconf.h | 11 ----------- net/ipv6/addrconf.c | 25 +++++++------------------ net/ipv6/mcast.c | 23 ++++++++--------------- net/ipv6/ndisc.c | 5 +---- 5 files changed, 24 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index e6aa8de2b939..bc492048c349 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -48,6 +48,14 @@ extern const struct in6_addr in6addr_any; #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } extern const struct in6_addr in6addr_loopback; #define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +#ifdef __KERNEL__ +extern const struct in6_addr in6addr_linklocal_allnodes; +#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ + { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +extern const struct in6_addr in6addr_linklocal_allrouters; +#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ + { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } } +#endif struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 92af23d66eb9..0a2f0372df31 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -205,17 +205,6 @@ static inline void addrconf_addr_solict_mult(const struct in6_addr *addr, htonl(0xFF000000) | addr->s6_addr32[3]); } - -static inline void ipv6_addr_all_nodes(struct in6_addr *addr) -{ - ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x1)); -} - -static inline void ipv6_addr_all_routers(struct in6_addr *addr) -{ - ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x2)); -} - static inline int ipv6_addr_is_multicast(const struct in6_addr *addr) { return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4048c2b73b0b..7df04d294924 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -222,6 +222,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; +const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; +const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; /* Check if a valid qdisc is available */ static inline int addrconf_qdisc_ok(struct net_device *dev) @@ -321,7 +323,6 @@ EXPORT_SYMBOL(in6_dev_finish_destroy); static struct inet6_dev * ipv6_add_dev(struct net_device *dev) { struct inet6_dev *ndev; - struct in6_addr maddr; ASSERT_RTNL(); @@ -406,8 +407,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) rcu_assign_pointer(dev->ip6_ptr, ndev); /* Join all-node multicast group */ - ipv6_addr_all_nodes(&maddr); - ipv6_dev_mc_inc(dev, &maddr); + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); return ndev; } @@ -433,18 +433,15 @@ static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; struct inet6_ifaddr *ifa; - struct in6_addr addr; if (!idev) return; dev = idev->dev; if (dev && (dev->flags & IFF_MULTICAST)) { - ipv6_addr_all_routers(&addr); - if (idev->cnf.forwarding) - ipv6_dev_mc_inc(dev, &addr); + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); else - ipv6_dev_mc_dec(dev, &addr); + ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); } for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { if (ifa->flags&IFA_F_TENTATIVE) @@ -2654,8 +2651,6 @@ static void addrconf_rs_timer(unsigned long data) spin_lock(&ifp->lock); if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { - struct in6_addr all_routers; - /* The wait after the last probe can be shorter */ addrconf_mod_timer(ifp, AC_RS, (ifp->probes == ifp->idev->cnf.rtr_solicits) ? @@ -2663,9 +2658,7 @@ static void addrconf_rs_timer(unsigned long data) ifp->idev->cnf.rtr_solicit_interval); spin_unlock(&ifp->lock); - ipv6_addr_all_routers(&all_routers); - - ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); + ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); } else { spin_unlock(&ifp->lock); /* @@ -2806,16 +2799,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) ifp->idev->cnf.rtr_solicits > 0 && (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { - struct in6_addr all_routers; - - ipv6_addr_all_routers(&all_routers); - /* * If a host as already performed a random delay * [...] as part of DAD [...] there is no need * to delay again before sending the first RS */ - ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); + ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); spin_lock_bh(&ifp->lock); ifp->probes = 1; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0a0132a1c443..c2dc2e2b6c07 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1766,10 +1766,9 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) struct inet6_dev *idev; struct sk_buff *skb; struct icmp6hdr *hdr; - struct in6_addr *snd_addr; + const struct in6_addr *snd_addr; struct in6_addr *addrp; struct in6_addr addr_buf; - struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, @@ -1780,11 +1779,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) IP6_INC_STATS(__in6_dev_get(dev), IPSTATS_MIB_OUTREQUESTS); rcu_read_unlock(); - snd_addr = addr; - if (type == ICMPV6_MGM_REDUCTION) { - snd_addr = &all_routers; - ipv6_addr_all_routers(&all_routers); - } + if (type == ICMPV6_MGM_REDUCTION) + snd_addr = &in6addr_linklocal_allrouters; + else + snd_addr = addr; len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); payload_len = len + sizeof(ra); @@ -2309,24 +2307,19 @@ void ipv6_mc_init_dev(struct inet6_dev *idev) void ipv6_mc_destroy_dev(struct inet6_dev *idev) { struct ifmcaddr6 *i; - struct in6_addr maddr; /* Deactivate timers */ ipv6_mc_down(idev); /* Delete all-nodes address. */ - ipv6_addr_all_nodes(&maddr); - /* We cannot call ipv6_dev_mc_dec() directly, our caller in * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will * fail. */ - __ipv6_dev_mc_dec(idev, &maddr); + __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allnodes); - if (idev->cnf.forwarding) { - ipv6_addr_all_routers(&maddr); - __ipv6_dev_mc_dec(idev, &maddr); - } + if (idev->cnf.forwarding) + __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allrouters); write_lock_bh(&idev->lock); while ((i = idev->mc_list) != NULL) { diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5b9ad5e2f56d..2c74885f8355 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -818,10 +818,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) is_router = !!idev->cnf.forwarding; if (dad) { - struct in6_addr maddr; - - ipv6_addr_all_nodes(&maddr); - ndisc_send_na(dev, NULL, &maddr, &msg->target, + ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, is_router, 0, (ifp != NULL), 1); goto out; } -- cgit v1.2.3 From 14daa02139dcb3193b2b0250c0720a23ef610c49 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 12 Apr 2008 18:48:58 -0700 Subject: net: make struct tun_struct private to tun.c There's no reason for this to be in the header, and it just hurts recompile time. Signed-off-by: Rusty Russell Acked-by: Max Krasnyanskiy Signed-off-by: David S. Miller --- drivers/net/tun.c | 33 +++++++++++++++++++++++++++++++++ include/linux/Kbuild | 2 +- include/linux/if_tun.h | 39 --------------------------------------- 3 files changed, 34 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7b816a032957..970ec4793442 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -67,9 +67,42 @@ #include #include +/* Uncomment to enable debugging */ +/* #define TUN_DEBUG 1 */ + #ifdef TUN_DEBUG static int debug; + +#define DBG if(tun->debug)printk +#define DBG1 if(debug==2)printk +#else +#define DBG( a... ) +#define DBG1( a... ) +#endif + +struct tun_struct { + struct list_head list; + unsigned long flags; + int attached; + uid_t owner; + gid_t group; + + wait_queue_head_t read_wait; + struct sk_buff_head readq; + + struct net_device *dev; + + struct fasync_struct *fasync; + + unsigned long if_flags; + u8 dev_addr[ETH_ALEN]; + u32 chr_filter[2]; + u32 net_filter[2]; + +#ifdef TUN_DEBUG + int debug; #endif +}; /* Network device part of the driver */ diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 9cdd12a9e843..cedbbd806bf6 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -86,6 +86,7 @@ header-y += if_plip.h header-y += if_ppp.h header-y += if_slip.h header-y += if_strip.h +header-y += if_tun.h header-y += if_tunnel.h header-y += in6.h header-y += in_route.h @@ -229,7 +230,6 @@ unifdef-y += if_link.h unifdef-y += if_pppol2tp.h unifdef-y += if_pppox.h unifdef-y += if_tr.h -unifdef-y += if_tun.h unifdef-y += if_vlan.h unifdef-y += if_wanpipe.h unifdef-y += igmp.h diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 72f1c5f47be3..8c71fe2fb1f5 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -18,47 +18,8 @@ #ifndef __IF_TUN_H #define __IF_TUN_H -/* Uncomment to enable debugging */ -/* #define TUN_DEBUG 1 */ - #include -#ifdef __KERNEL__ - -#ifdef TUN_DEBUG -#define DBG if(tun->debug)printk -#define DBG1 if(debug==2)printk -#else -#define DBG( a... ) -#define DBG1( a... ) -#endif - -struct tun_struct { - struct list_head list; - unsigned long flags; - int attached; - uid_t owner; - gid_t group; - - wait_queue_head_t read_wait; - struct sk_buff_head readq; - - struct net_device *dev; - - struct fasync_struct *fasync; - - unsigned long if_flags; - u8 dev_addr[ETH_ALEN]; - u32 chr_filter[2]; - u32 net_filter[2]; - -#ifdef TUN_DEBUG - int debug; -#endif -}; - -#endif /* __KERNEL__ */ - /* Read queue size */ #define TUN_READQ_SIZE 500 -- cgit v1.2.3 From 03e1ad7b5d871d4189b1da3125c2f12d1b5f7d0b Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sat, 12 Apr 2008 19:07:52 -0700 Subject: LSM: Make the Labeled IPsec hooks more stack friendly The xfrm_get_policy() and xfrm_add_pol_expire() put some rather large structs on the stack to work around the LSM API. This patch attempts to fix that problem by changing the LSM API to require only the relevant "security" pointers instead of the entire SPD entry; we do this for all of the security_xfrm_policy*() functions to keep things consistent. Signed-off-by: Paul Moore Acked-by: James Morris Signed-off-by: David S. Miller --- include/linux/security.h | 48 ++++++++++++++++++++--------------------- net/key/af_key.c | 23 ++++++++++---------- net/xfrm/xfrm_policy.c | 24 +++++++++++++-------- net/xfrm/xfrm_user.c | 33 ++++++++++++++-------------- security/dummy.c | 14 ++++++------ security/security.c | 21 +++++++++--------- security/selinux/include/xfrm.h | 13 +++++------ security/selinux/xfrm.c | 39 ++++++++++++++------------------- 8 files changed, 109 insertions(+), 106 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index c673dfd4dffc..f5eb9ff47ac5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -910,24 +910,24 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Security hooks for XFRM operations. * * @xfrm_policy_alloc_security: - * @xp contains the xfrm_policy being added to Security Policy Database - * used by the XFRM system. + * @ctxp is a pointer to the xfrm_sec_ctx being added to Security Policy + * Database used by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level policy update program (e.g., setkey). * Allocate a security structure to the xp->security field; the security * field is initialized to NULL when the xfrm_policy is allocated. * Return 0 if operation was successful (memory to allocate, legal context) * @xfrm_policy_clone_security: - * @old contains an existing xfrm_policy in the SPD. - * @new contains a new xfrm_policy being cloned from old. - * Allocate a security structure to the new->security field - * that contains the information from the old->security field. + * @old_ctx contains an existing xfrm_sec_ctx. + * @new_ctxp contains a new xfrm_sec_ctx being cloned from old. + * Allocate a security structure in new_ctxp that contains the + * information from the old_ctx structure. * Return 0 if operation was successful (memory to allocate). * @xfrm_policy_free_security: - * @xp contains the xfrm_policy + * @ctx contains the xfrm_sec_ctx * Deallocate xp->security. * @xfrm_policy_delete_security: - * @xp contains the xfrm_policy. + * @ctx contains the xfrm_sec_ctx. * Authorize deletion of xp->security. * @xfrm_state_alloc_security: * @x contains the xfrm_state being added to the Security Association @@ -947,7 +947,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @x contains the xfrm_state. * Authorize deletion of x->security. * @xfrm_policy_lookup: - * @xp contains the xfrm_policy for which the access control is being + * @ctx contains the xfrm_sec_ctx for which the access control is being * checked. * @fl_secid contains the flow security label that is used to authorize * access to the policy xp. @@ -1454,17 +1454,17 @@ struct security_operations { #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM - int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, + int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx); - int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); - void (*xfrm_policy_free_security) (struct xfrm_policy *xp); - int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); + int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); + void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); + int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void (*xfrm_state_free_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x); - int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); + int (*xfrm_policy_lookup)(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); @@ -2562,16 +2562,16 @@ static inline void security_inet_conn_established(struct sock *sk, #ifdef CONFIG_SECURITY_NETWORK_XFRM -int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); -int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); -void security_xfrm_policy_free(struct xfrm_policy *xp); -int security_xfrm_policy_delete(struct xfrm_policy *xp); +int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx); +int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp); +void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx); +int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); int security_xfrm_state_alloc_acquire(struct xfrm_state *x, struct xfrm_sec_ctx *polsec, u32 secid); int security_xfrm_state_delete(struct xfrm_state *x); void security_xfrm_state_free(struct xfrm_state *x); -int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); +int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid); @@ -2579,21 +2579,21 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl); #else /* CONFIG_SECURITY_NETWORK_XFRM */ -static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) +static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) { return 0; } -static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +static inline int security_xfrm_policy_clone(struct xfrm_sec_ctx *old, struct xfrm_sec_ctx **new_ctxp) { return 0; } -static inline void security_xfrm_policy_free(struct xfrm_policy *xp) +static inline void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { } -static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) +static inline int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { return 0; } @@ -2619,7 +2619,7 @@ static inline int security_xfrm_state_delete(struct xfrm_state *x) return 0; } -static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +static inline int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { return 0; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 6db58924368a..1fb0fe42a72e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2292,7 +2292,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h goto out; } - err = security_xfrm_policy_alloc(xp, uctx); + err = security_xfrm_policy_alloc(&xp->security, uctx); kfree(uctx); if (err) @@ -2352,10 +2352,11 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg int err; struct sadb_address *sa; struct sadb_x_policy *pol; - struct xfrm_policy *xp, tmp; + struct xfrm_policy *xp; struct xfrm_selector sel; struct km_event c; struct sadb_x_sec_ctx *sec_ctx; + struct xfrm_sec_ctx *pol_ctx; if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || @@ -2385,25 +2386,23 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg sel.dport_mask = htons(0xffff); sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; - memset(&tmp, 0, sizeof(struct xfrm_policy)); - if (sec_ctx != NULL) { struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); if (!uctx) return -ENOMEM; - err = security_xfrm_policy_alloc(&tmp, uctx); + err = security_xfrm_policy_alloc(&pol_ctx, uctx); kfree(uctx); - if (err) return err; - } - - xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, - &sel, tmp.security, 1, &err); - security_xfrm_policy_free(&tmp); + } else + pol_ctx = NULL; + xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, + pol->sadb_x_policy_dir - 1, &sel, pol_ctx, + 1, &err); + security_xfrm_policy_free(pol_ctx); if (xp == NULL) return -ENOENT; @@ -3298,7 +3297,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, if ((*dir = verify_sec_ctx_len(p))) goto out; uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); - *dir = security_xfrm_policy_alloc(xp, uctx); + *dir = security_xfrm_policy_alloc(&xp->security, uctx); kfree(uctx); if (*dir) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 15d73e47cc2c..ab4d0e598a2c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -263,7 +263,7 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) list_del(&policy->bytype); write_unlock_bh(&xfrm_policy_lock); - security_xfrm_policy_free(policy); + security_xfrm_policy_free(policy->security); kfree(policy); } EXPORT_SYMBOL(xfrm_policy_destroy); @@ -676,7 +676,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, xfrm_sec_ctx_match(ctx, pol->security)) { xfrm_pol_hold(pol); if (delete) { - *err = security_xfrm_policy_delete(pol); + *err = security_xfrm_policy_delete( + pol->security); if (*err) { write_unlock_bh(&xfrm_policy_lock); return pol; @@ -718,7 +719,8 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, if (pol->type == type && pol->index == id) { xfrm_pol_hold(pol); if (delete) { - *err = security_xfrm_policy_delete(pol); + *err = security_xfrm_policy_delete( + pol->security); if (*err) { write_unlock_bh(&xfrm_policy_lock); return pol; @@ -756,7 +758,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) &xfrm_policy_inexact[dir], bydst) { if (pol->type != type) continue; - err = security_xfrm_policy_delete(pol); + err = security_xfrm_policy_delete(pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, audit_info->loginuid, @@ -770,7 +772,8 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) bydst) { if (pol->type != type) continue; - err = security_xfrm_policy_delete(pol); + err = security_xfrm_policy_delete( + pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, audit_info->loginuid, @@ -931,7 +934,8 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, match = xfrm_selector_match(sel, fl, family); if (match) - ret = security_xfrm_policy_lookup(pol, fl->secid, dir); + ret = security_xfrm_policy_lookup(pol->security, fl->secid, + dir); return ret; } @@ -1048,8 +1052,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc int err = 0; if (match) { - err = security_xfrm_policy_lookup(pol, fl->secid, - policy_to_flow_dir(dir)); + err = security_xfrm_policy_lookup(pol->security, + fl->secid, + policy_to_flow_dir(dir)); if (!err) xfrm_pol_hold(pol); else if (err == -ESRCH) @@ -1138,7 +1143,8 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) if (newp) { newp->selector = old->selector; - if (security_xfrm_policy_clone(old, newp)) { + if (security_xfrm_policy_clone(old->security, + &newp->security)) { kfree(newp); return NULL; /* ENOMEM */ } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5578c909fcf6..ecf9d67daef5 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -959,7 +959,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs return 0; uctx = nla_data(rt); - return security_xfrm_policy_alloc(pol, uctx); + return security_xfrm_policy_alloc(&pol->security, uctx); } static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, @@ -1143,7 +1143,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, NETLINK_CB(skb).sid); if (err) { - security_xfrm_policy_free(xp); + security_xfrm_policy_free(xp->security); kfree(xp); return err; } @@ -1337,22 +1337,23 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; - struct xfrm_policy tmp; + struct xfrm_sec_ctx *ctx; err = verify_sec_ctx_len(attrs); if (err) return err; - memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); - if ((err = security_xfrm_policy_alloc(&tmp, uctx))) + err = security_xfrm_policy_alloc(&ctx, uctx); + if (err) return err; - } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, + } else + ctx = NULL; + xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, delete, &err); - security_xfrm_policy_free(&tmp); + security_xfrm_policy_free(ctx); } if (xp == NULL) return -ENOENT; @@ -1572,26 +1573,26 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; - struct xfrm_policy tmp; + struct xfrm_sec_ctx *ctx; err = verify_sec_ctx_len(attrs); if (err) return err; - memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); - if ((err = security_xfrm_policy_alloc(&tmp, uctx))) + err = security_xfrm_policy_alloc(&ctx, uctx); + if (err) return err; - } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, - 0, &err); - security_xfrm_policy_free(&tmp); + } else + ctx = NULL; + xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err); + security_xfrm_policy_free(ctx); } - if (xp == NULL) return -ENOENT; + read_lock(&xp->lock); if (xp->dead) { read_unlock(&xp->lock); diff --git a/security/dummy.c b/security/dummy.c index 78d8f92310a4..480366f9c41d 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -876,22 +876,23 @@ static inline void dummy_req_classify_flow(const struct request_sock *req, #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM -static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx) +static int dummy_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx) { return 0; } -static inline int dummy_xfrm_policy_clone_security(struct xfrm_policy *old, struct xfrm_policy *new) +static inline int dummy_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { return 0; } -static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp) +static void dummy_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx) { } -static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) +static int dummy_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) { return 0; } @@ -911,7 +912,8 @@ static int dummy_xfrm_state_delete_security(struct xfrm_state *x) return 0; } -static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) +static int dummy_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, + u32 sk_sid, u8 dir) { return 0; } diff --git a/security/security.c b/security/security.c index b1387a6b416d..c9ff7d18c2f4 100644 --- a/security/security.c +++ b/security/security.c @@ -1014,26 +1014,27 @@ void security_inet_conn_established(struct sock *sk, #ifdef CONFIG_SECURITY_NETWORK_XFRM -int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) +int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); + return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx); } EXPORT_SYMBOL(security_xfrm_policy_alloc); -int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - return security_ops->xfrm_policy_clone_security(old, new); + return security_ops->xfrm_policy_clone_security(old_ctx, new_ctxp); } -void security_xfrm_policy_free(struct xfrm_policy *xp) +void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - security_ops->xfrm_policy_free_security(xp); + security_ops->xfrm_policy_free_security(ctx); } EXPORT_SYMBOL(security_xfrm_policy_free); -int security_xfrm_policy_delete(struct xfrm_policy *xp) +int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { - return security_ops->xfrm_policy_delete_security(xp); + return security_ops->xfrm_policy_delete_security(ctx); } int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) @@ -1065,9 +1066,9 @@ void security_xfrm_state_free(struct xfrm_state *x) security_ops->xfrm_state_free_security(x); } -int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { - return security_ops->xfrm_policy_lookup(xp, fl_secid, dir); + return security_ops->xfrm_policy_lookup(ctx, fl_secid, dir); } int security_xfrm_state_pol_flow_match(struct xfrm_state *x, diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 36b0510efa7b..289e24b39e3e 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -7,16 +7,17 @@ #ifndef _SELINUX_XFRM_H_ #define _SELINUX_XFRM_H_ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx); -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); -void selinux_xfrm_policy_free(struct xfrm_policy *xp); -int selinux_xfrm_policy_delete(struct xfrm_policy *xp); +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx); +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp); +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void selinux_xfrm_state_free(struct xfrm_state *x); int selinux_xfrm_state_delete(struct xfrm_state *x); -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 7e158205d081..874d17c83c61 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -77,20 +77,18 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) * LSM hook implementation that authorizes that a flow can use * a xfrm policy rule. */ -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { int rc; u32 sel_sid; - struct xfrm_sec_ctx *ctx; /* Context sid is either set to label or ANY_ASSOC */ - if ((ctx = xp->security)) { + if (ctx) { if (!selinux_authorizable_ctx(ctx)) return -EINVAL; sel_sid = ctx->ctx_sid; - } - else + } else /* * All flows should be treated as polmatch'ing an * otherwise applicable "non-labeled" policy. This @@ -103,7 +101,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) NULL); if (rc == -EACCES) - rc = -ESRCH; + return -ESRCH; return rc; } @@ -287,15 +285,14 @@ out2: * LSM hook implementation that allocs and transfers uctx spec to * xfrm_policy. */ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *uctx) +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *uctx) { int err; - BUG_ON(!xp); BUG_ON(!uctx); - err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); + err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); if (err == 0) atomic_inc(&selinux_xfrm_refcount); @@ -307,32 +304,29 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, * LSM hook implementation that copies security data structure from old to * new for policy cloning. */ -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - struct xfrm_sec_ctx *old_ctx, *new_ctx; - - old_ctx = old->security; + struct xfrm_sec_ctx *new_ctx; if (old_ctx) { - new_ctx = new->security = kmalloc(sizeof(*new_ctx) + - old_ctx->ctx_len, - GFP_KERNEL); - + new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, + GFP_KERNEL); if (!new_ctx) return -ENOMEM; memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); + *new_ctxp = new_ctx; } return 0; } /* - * LSM hook implementation that frees xfrm_policy security information. + * LSM hook implementation that frees xfrm_sec_ctx security information. */ -void selinux_xfrm_policy_free(struct xfrm_policy *xp) +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - struct xfrm_sec_ctx *ctx = xp->security; if (ctx) kfree(ctx); } @@ -340,10 +334,9 @@ void selinux_xfrm_policy_free(struct xfrm_policy *xp) /* * LSM hook implementation that authorizes deletion of labeled policies. */ -int selinux_xfrm_policy_delete(struct xfrm_policy *xp) +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { struct task_security_struct *tsec = current->security; - struct xfrm_sec_ctx *ctx = xp->security; int rc = 0; if (ctx) { -- cgit v1.2.3 From cee8947338d46bccece54c752bf6cd4043035f05 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sun, 13 Apr 2008 23:21:16 -0700 Subject: [IPV6] MROUTE: Do not call ipv6_find_idev() directly. Since NETDEV_REGISTER notifier chain is responsible for creating inet6_dev{}, we do not need to call ipv6_find_idev() directly here. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/mroute6.h | 3 --- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6mr.c | 5 ----- 3 files changed, 1 insertion(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index f6469fb90840..e7989593142b 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -117,9 +117,6 @@ struct sioc_mif_req6 #include /* for struct sk_buff_head */ -struct net_device; -struct inet6_dev *ipv6_find_idev(struct net_device *dev); - #ifdef CONFIG_IPV6_MROUTE static inline int ip6_mroute_opt(int opt) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e93fa62089f8..9d49ed2578d7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -412,7 +412,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) return ndev; } -struct inet6_dev * ipv6_find_idev(struct net_device *dev) +static struct inet6_dev * ipv6_find_idev(struct net_device *dev) { struct inet6_dev *idev; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 94ede696da2a..6e2e3c957a31 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -435,7 +435,6 @@ static void reg_vif_setup(struct net_device *dev) static struct net_device *ip6mr_reg_vif(void) { struct net_device *dev; - struct inet6_dev *in_dev; dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", reg_vif_setup); @@ -449,10 +448,6 @@ static struct net_device *ip6mr_reg_vif(void) } dev->iflink = 0; - in_dev = ipv6_find_idev(dev); - if (!in_dev) - goto failure; - if (dev_open(dev)) goto failure; -- cgit v1.2.3 From 7cd636fe9ce5de0051c11283911baca4291868c8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sun, 13 Apr 2008 23:33:52 -0700 Subject: [IPV6]: IPv6 extension header structures need to be packed. struct ipv6_opt_hdr is the common structure for IPv6 extension headers, and it is common to increment the pointer to get the real content. On the other hand, since the structure consists only of 1-byte next-header field and 1-byte length field, size of that structure depends on architecture; 2 or 4. Add "packed" attribute to get 2. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/ipv6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4aaefc349a4b..134c8e5cf07c 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -53,7 +53,7 @@ struct ipv6_opt_hdr { /* * TLV encoded option data follows. */ -}; +} __attribute__ ((packed)); /* required for some archs */ #define ipv6_destopt_hdr ipv6_opt_hdr #define ipv6_hopopt_hdr ipv6_opt_hdr -- cgit v1.2.3 From f525c06d12b72cddb085df7f6f348c3c5a39b3ce Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 14 Apr 2008 00:04:12 -0700 Subject: [SKB]: __skb_dequeue = skb_peek + __skb_unlink By rearranging the order of declarations, __skb_dequeue() is expressed in terms of * skb_peek() and * __skb_unlink(), thus in effect mirroring the analogue implementation of __skb_dequeue_tail(). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/skbuff.h | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e517701c25ba..c2116200580a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -734,35 +734,6 @@ static inline void __skb_queue_tail(struct sk_buff_head *list, next->prev = prev->next = newsk; } - -/** - * __skb_dequeue - remove from the head of the queue - * @list: list to dequeue from - * - * Remove the head of the list. This function does not take any locks - * so must be used with appropriate locks held only. The head item is - * returned or %NULL if the list is empty. - */ -extern struct sk_buff *skb_dequeue(struct sk_buff_head *list); -static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list) -{ - struct sk_buff *next, *prev, *result; - - prev = (struct sk_buff *) list; - next = prev->next; - result = NULL; - if (next != prev) { - result = next; - next = next->next; - list->qlen--; - next->prev = prev; - prev->next = next; - result->next = result->prev = NULL; - } - return result; -} - - /* * Insert a packet on a list. */ @@ -803,8 +774,22 @@ static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) prev->next = next; } - -/* XXX: more streamlined implementation */ +/** + * __skb_dequeue - remove from the head of the queue + * @list: list to dequeue from + * + * Remove the head of the list. This function does not take any locks + * so must be used with appropriate locks held only. The head item is + * returned or %NULL if the list is empty. + */ +extern struct sk_buff *skb_dequeue(struct sk_buff_head *list); +static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list) +{ + struct sk_buff *skb = skb_peek(list); + if (skb) + __skb_unlink(skb, list); + return skb; +} /** * __skb_dequeue_tail - remove from the tail of the queue -- cgit v1.2.3 From bf299275882624b1908521ee8074df85160e9679 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 14 Apr 2008 00:04:51 -0700 Subject: [SKB]: __skb_queue_after(prev) = __skb_insert(prev, prev->next) By reordering, __skb_queue_after() is expressed in terms of __skb_insert(). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/skbuff.h | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c2116200580a..bb107ab675fc 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -663,11 +663,21 @@ static inline void skb_queue_head_init_class(struct sk_buff_head *list, } /* - * Insert an sk_buff at the start of a list. + * Insert an sk_buff on a list. * * The "__skb_xxxx()" functions are the non-atomic ones that * can only be called with interrupts disabled. */ +extern void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); +static inline void __skb_insert(struct sk_buff *newsk, + struct sk_buff *prev, struct sk_buff *next, + struct sk_buff_head *list) +{ + newsk->next = next; + newsk->prev = prev; + next->prev = prev->next = newsk; + list->qlen++; +} /** * __skb_queue_after - queue a buffer at the list head @@ -684,13 +694,7 @@ static inline void __skb_queue_after(struct sk_buff_head *list, struct sk_buff *prev, struct sk_buff *newsk) { - struct sk_buff *next; - list->qlen++; - - next = prev->next; - newsk->next = next; - newsk->prev = prev; - next->prev = prev->next = newsk; + __skb_insert(newsk, prev, prev->next, list); } /** @@ -734,20 +738,6 @@ static inline void __skb_queue_tail(struct sk_buff_head *list, next->prev = prev->next = newsk; } -/* - * Insert a packet on a list. - */ -extern void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); -static inline void __skb_insert(struct sk_buff *newsk, - struct sk_buff *prev, struct sk_buff *next, - struct sk_buff_head *list) -{ - newsk->next = next; - newsk->prev = prev; - next->prev = prev->next = newsk; - list->qlen++; -} - /* * Place a packet after a given packet in a list. */ -- cgit v1.2.3 From 7de6c033367ab86f39c7723392caf73325cbf286 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 14 Apr 2008 00:05:09 -0700 Subject: [SKB]: __skb_append = __skb_queue_after This expresses __skb_append in terms of __skb_queue_after, exploiting that __skb_append(old, new, list) = __skb_queue_after(list, old, new). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/skbuff.h | 12 +++--------- include/net/tcp.h | 2 +- net/core/skbuff.c | 2 +- net/ipv4/tcp_input.c | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bb107ab675fc..83c851846829 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -697,6 +697,9 @@ static inline void __skb_queue_after(struct sk_buff_head *list, __skb_insert(newsk, prev, prev->next, list); } +extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, + struct sk_buff_head *list); + /** * __skb_queue_head - queue a buffer at the list head * @list: list to use @@ -738,15 +741,6 @@ static inline void __skb_queue_tail(struct sk_buff_head *list, next->prev = prev->next = newsk; } -/* - * Place a packet after a given packet in a list. - */ -extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); -static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list) -{ - __skb_insert(newsk, old, old->next, list); -} - /* * remove sk_buff from list. _Must_ be called atomically, and with * the list known.. diff --git a/include/net/tcp.h b/include/net/tcp.h index 58d82822414d..2ab350eca02e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1247,7 +1247,7 @@ static inline void tcp_insert_write_queue_after(struct sk_buff *skb, struct sk_buff *buff, struct sock *sk) { - __skb_append(skb, buff, &sk->sk_write_queue); + __skb_queue_after(&sk->sk_write_queue, skb, buff); } /* Insert skb between prev and next on the write queue of sk. */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e4259215607f..4cd12d99b12e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1860,7 +1860,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head unsigned long flags; spin_lock_irqsave(&list->lock, flags); - __skb_append(old, newsk, list); + __skb_queue_after(list, old, newsk); spin_unlock_irqrestore(&list->lock, flags); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6e46b4c0f28c..743611956045 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3968,7 +3968,7 @@ drop: u32 end_seq = TCP_SKB_CB(skb)->end_seq; if (seq == TCP_SKB_CB(skb1)->end_seq) { - __skb_append(skb1, skb, &tp->out_of_order_queue); + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); if (!tp->rx_opt.num_sacks || tp->selective_acks[0].end_seq != seq) -- cgit v1.2.3 From f5572855ec492334d8c3ec0e0e86c31865d5cf07 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 14 Apr 2008 00:05:28 -0700 Subject: [SKB]: __skb_queue_tail = __skb_insert before This expresses __skb_queue_tail() in terms of __skb_insert(), using __skb_insert_before() as auxiliary function. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 83c851846829..11fd9f2c4093 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -700,6 +700,13 @@ static inline void __skb_queue_after(struct sk_buff_head *list, extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); +static inline void __skb_queue_before(struct sk_buff_head *list, + struct sk_buff *next, + struct sk_buff *newsk) +{ + __skb_insert(newsk, next->prev, next, list); +} + /** * __skb_queue_head - queue a buffer at the list head * @list: list to use @@ -731,14 +738,7 @@ extern void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk); static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) { - struct sk_buff *prev, *next; - - list->qlen++; - next = (struct sk_buff *)list; - prev = next->prev; - newsk->next = next; - newsk->prev = prev; - next->prev = prev->next = newsk; + __skb_queue_before(list, (struct sk_buff *)list, newsk); } /* -- cgit v1.2.3 From 666953df353194bef76086fa3f126241cbac3e3a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 14 Apr 2008 09:56:02 +0200 Subject: [NETFILTER]: ip_tables: per-netns FILTER/MANGLE/RAW tables for real Commit 9335f047fe61587ec82ff12fbb1220bcfdd32006 aka "[NETFILTER]: ip_tables: per-netns FILTER, MANGLE, RAW" added per-netns _view_ of iptables rules. They were shown to user, but ignored by filtering code. Now that it's possible to at least ping loopback, per-netns tables can affect filtering decisions. netns is taken in case of PRE_ROUTING, LOCAL_IN -- from in device, POST_ROUTING, LOCAL_OUT -- from out device, FORWARD -- from in device which should be equal to out device's netns. This code is relatively new, so BUG_ON was plugged. Wrappers were added to a) keep code the same from CONFIG_NET_NS=n users (overwhelming majority), b) consolidate code in one place -- similar changes will be done in ipv6 and arp netfilter code. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 54 ++++++++++++++++++++++++++++++++++++- net/ipv4/netfilter/iptable_filter.c | 19 ++++++++++--- net/ipv4/netfilter/iptable_mangle.c | 49 ++++++++++++++++++++++++++++----- net/ipv4/netfilter/iptable_raw.c | 6 +++-- 4 files changed, 115 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 89e6c72ad295..66bc52060fd6 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include #endif #include @@ -76,7 +78,6 @@ extern void netfilter_init(void); #define NF_MAX_HOOKS 8 struct sk_buff; -struct net_device; typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff *skb, @@ -320,5 +321,56 @@ extern void (*nf_ct_destroy)(struct nf_conntrack *); static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} #endif +static inline struct net *nf_pre_routing_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_local_in_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_forward_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + BUG_ON(in->nd_net != out->nd_net); + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_local_out_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return out->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_post_routing_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return out->nd_net; +#else + return &init_net; +#endif +} + #endif /*__KERNEL__*/ #endif /*__LINUX_NETFILTER_H*/ diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 69f3d7e6e96f..7fcf60adbbed 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -62,6 +62,17 @@ static struct xt_table packet_filter = { }; /* The work comes in here from netfilter.c. */ +static unsigned int +ipt_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv4.iptable_filter); +} + static unsigned int ipt_hook(unsigned int hook, struct sk_buff *skb, @@ -69,7 +80,8 @@ ipt_hook(unsigned int hook, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); + return ipt_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv4.iptable_filter); } static unsigned int @@ -88,12 +100,13 @@ ipt_local_out_hook(unsigned int hook, return NF_ACCEPT; } - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); + return ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_filter); } static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_hook, + .hook = ipt_local_in_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index c55a210853a7..ba827035b691 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -74,13 +74,47 @@ static struct xt_table packet_mangler = { /* The work comes in here from netfilter.c. */ static unsigned int -ipt_route_hook(unsigned int hook, +ipt_pre_routing_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_pre_routing_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_post_routing_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_post_routing_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_forward_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); + return ipt_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv4.iptable_mangle); } static unsigned int @@ -112,7 +146,8 @@ ipt_local_hook(unsigned int hook, daddr = iph->daddr; tos = iph->tos; - ret = ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); + ret = ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { iph = ip_hdr(skb); @@ -130,21 +165,21 @@ ipt_local_hook(unsigned int hook, static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_route_hook, + .hook = ipt_pre_routing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_local_in_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_forward_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_FORWARD, @@ -158,7 +193,7 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = { .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_post_routing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_POST_ROUTING, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index e41fe8ca4e1c..4b689742d58b 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -52,7 +52,8 @@ ipt_hook(unsigned int hook, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); + return ipt_do_table(skb, hook, in, out, + nf_pre_routing_net(in, out)->ipv4.iptable_raw); } static unsigned int @@ -70,7 +71,8 @@ ipt_local_hook(unsigned int hook, "packet.\n"); return NF_ACCEPT; } - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); + return ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_raw); } /* 'raw' is the very first table. */ -- cgit v1.2.3 From b9f61b160336da5eaaacb0cb41ebe32169e3bde5 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 09:56:04 +0200 Subject: [NETFILTER]: xt_sctp: simplify xt_sctp.h The use of xt_sctp.h flagged up -Wshadow warnings in userspace, which prompted me to look at it and clean it up. Basic operations have been directly replaced by library calls (memcpy, memset is both available in the kernel and userspace, and usually faster than a self-made loop). The is_set and is_clear functions now use a processing time shortcut, too. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter/xt_sctp.h | 84 ++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h index dd5a4fd4cfd3..32000ba6ecef 100644 --- a/include/linux/netfilter/xt_sctp.h +++ b/include/linux/netfilter/xt_sctp.h @@ -37,68 +37,54 @@ struct xt_sctp_info { #define SCTP_CHUNKMAP_SET(chunkmap, type) \ do { \ - chunkmap[type / bytes(u_int32_t)] |= \ + (chunkmap)[type / bytes(u_int32_t)] |= \ 1 << (type % bytes(u_int32_t)); \ } while (0) #define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ do { \ - chunkmap[type / bytes(u_int32_t)] &= \ + (chunkmap)[type / bytes(u_int32_t)] &= \ ~(1 << (type % bytes(u_int32_t))); \ } while (0) #define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ ({ \ - (chunkmap[type / bytes (u_int32_t)] & \ + ((chunkmap)[type / bytes (u_int32_t)] & \ (1 << (type % bytes (u_int32_t)))) ? 1: 0; \ }) -#define SCTP_CHUNKMAP_RESET(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \ - chunkmap[i] = 0; \ - } while (0) - -#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \ - chunkmap[i] = ~0; \ - } while (0) - -#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(srcmap); i++) \ - destmap[i] = srcmap[i]; \ - } while (0) - -#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \ - if (chunkmap[i]) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) - -#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \ - if (chunkmap[i] != ~0) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) +#define SCTP_CHUNKMAP_RESET(chunkmap) \ + memset((chunkmap), 0, sizeof(chunkmap)) + +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ + memset((chunkmap), ~0U, sizeof(chunkmap)) + +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ + memcpy((destmap), (srcmap), sizeof(srcmap)) + +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ + __sctp_chunkmap_is_clear((chunkmap), ARRAY_SIZE(chunkmap)) +static inline bool +__sctp_chunkmap_is_clear(const u_int32_t *chunkmap, unsigned int n) +{ + unsigned int i; + for (i = 0; i < n; ++i) + if (chunkmap[i]) + return false; + return true; +} + +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ + __sctp_chunkmap_is_all_set((chunkmap), ARRAY_SIZE(chunkmap)) +static inline bool +__sctp_chunkmap_is_all_set(const u_int32_t *chunkmap, unsigned int n) +{ + unsigned int i; + for (i = 0; i < n; ++i) + if (chunkmap[i] != ~0U) + return false; + return true; +} #endif /* _XT_SCTP_H_ */ -- cgit v1.2.3 From 5452e425adfdfc4647b618e303f73d48f2405b0e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:35 +0200 Subject: [NETFILTER]: annotate {arp,ip,ip6,x}tables with const Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 4 ++-- net/ipv4/netfilter/arp_tables.c | 31 ++++++++++++++++--------------- net/ipv4/netfilter/arpt_mangle.c | 2 +- net/ipv4/netfilter/ip_tables.c | 31 ++++++++++++++++--------------- net/ipv6/netfilter/ip6_tables.c | 29 +++++++++++++++-------------- net/netfilter/x_tables.c | 18 +++++++++--------- 6 files changed, 59 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index b2c62cc618f5..2326296b6f25 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -430,13 +430,13 @@ extern int xt_compat_add_offset(int af, unsigned int offset, short delta); extern void xt_compat_flush_offsets(int af); extern short xt_compat_calc_jump(int af, unsigned int offset); -extern int xt_compat_match_offset(struct xt_match *match); +extern int xt_compat_match_offset(const struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size); extern int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, unsigned int *size); -extern int xt_compat_target_offset(struct xt_target *target); +extern int xt_compat_target_offset(const struct xt_target *target); extern void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size); extern int xt_compat_target_to_user(struct xt_entry_target *t, diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 1563f29b5117..10cc442330c3 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -59,7 +59,7 @@ do { \ #endif static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, - char *hdr_addr, int len) + const char *hdr_addr, int len) { int i, ret; @@ -80,8 +80,8 @@ static inline int arp_packet_match(const struct arphdr *arphdr, const char *outdev, const struct arpt_arp *arpinfo) { - char *arpptr = (char *)(arphdr + 1); - char *src_devaddr, *tgt_devaddr; + const char *arpptr = (char *)(arphdr + 1); + const char *src_devaddr, *tgt_devaddr; __be32 src_ipaddr, tgt_ipaddr; int i, ret; @@ -226,12 +226,12 @@ unsigned int arpt_do_table(struct sk_buff *skb, { static const char nulldevname[IFNAMSIZ]; unsigned int verdict = NF_DROP; - struct arphdr *arp; + const struct arphdr *arp; bool hotdrop = false; struct arpt_entry *e, *back; const char *indev, *outdev; void *table_base; - struct xt_table_info *private; + const struct xt_table_info *private; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; @@ -352,7 +352,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, e->counters.pcnt = pos; for (;;) { - struct arpt_standard_target *t + const struct arpt_standard_target *t = (void *)arpt_get_target(e); int visited = e->comefrom & (1 << hook); @@ -437,7 +437,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, static inline int check_entry(struct arpt_entry *e, const char *name) { - struct arpt_entry_target *t; + const struct arpt_entry_target *t; if (!arp_checkentry(&e->arp)) { duprintf("arp_tables: arp check failed %p %s.\n", e, name); @@ -710,7 +710,7 @@ static inline struct xt_counters *alloc_counters(struct arpt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change * (other than comefrom, which userspace doesn't care @@ -737,7 +737,7 @@ static int copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct arpt_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; void *loc_cpu_entry; @@ -872,7 +872,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "arptable_%s", name); if (t && !IS_ERR(t)) { struct arpt_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -927,7 +927,8 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, t = xt_find_table_lock(net, NF_ARP, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; + duprintf("t->private->number = %u\n", private->number); if (get.size == private->size) @@ -1087,11 +1088,11 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, struct xt_counters_info tmp; struct xt_counters *paddc; unsigned int num_counters; - char *name; + const char *name; int size; void *ptmp; struct arpt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; #ifdef CONFIG_COMPAT @@ -1558,7 +1559,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; @@ -1609,7 +1610,7 @@ static int compat_get_entries(struct net *net, xt_compat_lock(NF_ARP); t = xt_find_table_lock(net, NF_ARP, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index 3f4222b0a803..3e732c827fc2 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -15,7 +15,7 @@ target(struct sk_buff *skb, const void *targinfo) { const struct arpt_mangle *mangle = targinfo; - struct arphdr *arp; + const struct arphdr *arp; unsigned char *arpptr; int pln, hln; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a819d191e1aa..aa124b50cb4a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -296,7 +296,7 @@ static void trace_packet(struct sk_buff *skb, struct ipt_entry *e) { void *table_base; - struct ipt_entry *root; + const struct ipt_entry *root; char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -327,7 +327,7 @@ ipt_do_table(struct sk_buff *skb, { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); u_int16_t offset; - struct iphdr *ip; + const struct iphdr *ip; u_int16_t datalen; bool hotdrop = false; /* Initializing verdict to NF_DROP keeps gcc happy. */ @@ -926,7 +926,7 @@ static struct xt_counters * alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -953,9 +953,9 @@ copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct ipt_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; counters = alloc_counters(table); if (IS_ERR(counters)) @@ -975,8 +975,8 @@ copy_entries_to_user(unsigned int total_size, /* ... then go back and fix counters and names */ for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ unsigned int i; - struct ipt_entry_match *m; - struct ipt_entry_target *t; + const struct ipt_entry_match *m; + const struct ipt_entry_target *t; e = (struct ipt_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off @@ -1116,7 +1116,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "iptable_%s", name); if (t && !IS_ERR(t)) { struct ipt_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -1172,7 +1172,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len) t = xt_find_table_lock(net, AF_INET, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; duprintf("t->private->number = %u\n", private->number); if (get.size == private->size) ret = copy_entries_to_user(private->size, @@ -1337,11 +1337,11 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat struct xt_counters_info tmp; struct xt_counters *paddc; unsigned int num_counters; - char *name; + const char *name; int size; void *ptmp; struct xt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; #ifdef CONFIG_COMPAT @@ -1878,11 +1878,11 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; unsigned int i = 0; counters = alloc_counters(table); @@ -1929,7 +1929,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, xt_compat_lock(AF_INET); t = xt_find_table_lock(net, AF_INET, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); ret = compat_table_info(private, &info); @@ -2130,7 +2130,8 @@ icmp_match(const struct sk_buff *skb, unsigned int protoff, bool *hotdrop) { - struct icmphdr _icmph, *ic; + const struct icmphdr *ic; + struct icmphdr _icmph; const struct ipt_icmp *icmpinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 70ef0d276cc0..782183f63366 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -325,7 +325,7 @@ static void trace_packet(struct sk_buff *skb, struct ip6t_entry *e) { void *table_base; - struct ip6t_entry *root; + const struct ip6t_entry *root; char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -952,7 +952,7 @@ static struct xt_counters *alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -979,9 +979,9 @@ copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct ip6t_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; counters = alloc_counters(table); if (IS_ERR(counters)) @@ -1001,8 +1001,8 @@ copy_entries_to_user(unsigned int total_size, /* ... then go back and fix counters and names */ for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ unsigned int i; - struct ip6t_entry_match *m; - struct ip6t_entry_target *t; + const struct ip6t_entry_match *m; + const struct ip6t_entry_target *t; e = (struct ip6t_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off @@ -1142,7 +1142,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "ip6table_%s", name); if (t && !IS_ERR(t)) { struct ip6t_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -1225,7 +1225,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct xt_table *t; struct xt_table_info *oldinfo; struct xt_counters *counters; - void *loc_cpu_old_entry; + const void *loc_cpu_old_entry; ret = 0; counters = vmalloc_node(num_counters * sizeof(struct xt_counters), @@ -1369,9 +1369,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int size; void *ptmp; struct xt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; @@ -1905,11 +1905,11 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; unsigned int i = 0; counters = alloc_counters(table); @@ -1956,7 +1956,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, xt_compat_lock(AF_INET6); t = xt_find_table_lock(net, AF_INET6, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); ret = compat_table_info(private, &info); @@ -2155,7 +2155,8 @@ icmp6_match(const struct sk_buff *skb, unsigned int protoff, bool *hotdrop) { - struct icmp6hdr _icmph, *ic; + const struct icmp6hdr *ic; + struct icmp6hdr _icmph; const struct ip6t_icmp *icmpinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 0bd95680a494..f52f7f810ac4 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -58,7 +58,7 @@ static struct xt_af *xt; #define duprintf(format, args...) #endif -static const char *xt_prefix[NPROTO] = { +static const char *const xt_prefix[NPROTO] = { [AF_INET] = "ip", [AF_INET6] = "ip6", [NF_ARP] = "arp", @@ -248,7 +248,7 @@ EXPORT_SYMBOL_GPL(xt_request_find_target); static int match_revfn(int af, const char *name, u8 revision, int *bestp) { - struct xt_match *m; + const struct xt_match *m; int have_rev = 0; list_for_each_entry(m, &xt[af].match, list) { @@ -264,7 +264,7 @@ static int match_revfn(int af, const char *name, u8 revision, int *bestp) static int target_revfn(int af, const char *name, u8 revision, int *bestp) { - struct xt_target *t; + const struct xt_target *t; int have_rev = 0; list_for_each_entry(t, &xt[af].target, list) { @@ -385,7 +385,7 @@ short xt_compat_calc_jump(int af, unsigned int offset) } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -int xt_compat_match_offset(struct xt_match *match) +int xt_compat_match_offset(const struct xt_match *match) { u_int16_t csize = match->compatsize ? : match->matchsize; return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); @@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_offset); int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size) { - struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; int pad, off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; @@ -422,7 +422,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_from_user); int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, unsigned int *size) { - struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match __user *cm = *dstptr; int off = xt_compat_match_offset(match); u_int16_t msize = m->u.user.match_size - off; @@ -479,7 +479,7 @@ int xt_check_target(const struct xt_target *target, unsigned short family, EXPORT_SYMBOL_GPL(xt_check_target); #ifdef CONFIG_COMPAT -int xt_compat_target_offset(struct xt_target *target) +int xt_compat_target_offset(const struct xt_target *target) { u_int16_t csize = target->compatsize ? : target->targetsize; return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); @@ -489,7 +489,7 @@ EXPORT_SYMBOL_GPL(xt_compat_target_offset); void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size) { - struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; int pad, off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; @@ -515,7 +515,7 @@ EXPORT_SYMBOL_GPL(xt_compat_target_from_user); int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr, unsigned int *size) { - struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target __user *ct = *dstptr; int off = xt_compat_target_offset(target); u_int16_t tsize = t->u.user.target_size - off; -- cgit v1.2.3 From 4abff0775d5e4feb20b21371e1c63a1b30fc2140 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:43 +0200 Subject: [NETFILTER]: remove arpt_table indirection macro Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 11 +++++------ net/ipv4/netfilter/arp_tables.c | 27 +++++++++++++-------------- net/ipv4/netfilter/arptable_filter.c | 2 +- 3 files changed, 19 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index db223ca92c8b..102c4134a713 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -24,7 +24,6 @@ #define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN #define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN #define arpt_target xt_target -#define arpt_table xt_table #define ARPT_DEV_ADDR_LEN_MAX 16 @@ -271,15 +270,15 @@ struct arpt_error xt_register_target(tgt); }) #define arpt_unregister_target(tgt) xt_unregister_target(tgt) -extern struct arpt_table *arpt_register_table(struct net *net, - struct arpt_table *table, - const struct arpt_replace *repl); -extern void arpt_unregister_table(struct arpt_table *table); +extern struct xt_table *arpt_register_table(struct net *net, + struct xt_table *table, + const struct arpt_replace *repl); +extern void arpt_unregister_table(struct xt_table *table); extern unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct arpt_table *table); + struct xt_table *table); #define ARPT_ALIGN(s) XT_ALIGN(s) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 10cc442330c3..34c42c831b18 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -222,7 +222,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct arpt_table *table) + struct xt_table *table) { static const char nulldevname[IFNAMSIZ]; unsigned int verdict = NF_DROP; @@ -706,7 +706,7 @@ static void get_counters(const struct xt_table_info *t, } } -static inline struct xt_counters *alloc_counters(struct arpt_table *table) +static inline struct xt_counters *alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; @@ -731,13 +731,13 @@ static inline struct xt_counters *alloc_counters(struct arpt_table *table) } static int copy_entries_to_user(unsigned int total_size, - struct arpt_table *table, + struct xt_table *table, void __user *userptr) { unsigned int off, num; struct arpt_entry *e; struct xt_counters *counters; - const struct xt_table_info *private = table->private; + struct xt_table_info *private = table->private; int ret = 0; void *loc_cpu_entry; @@ -851,7 +851,7 @@ static int compat_table_info(const struct xt_table_info *info, static int get_info(struct net *net, void __user *user, int *len, int compat) { char name[ARPT_TABLE_MAXNAMELEN]; - struct arpt_table *t; + struct xt_table *t; int ret; if (*len != sizeof(struct arpt_getinfo)) { @@ -911,7 +911,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, { int ret; struct arpt_get_entries get; - struct arpt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { duprintf("get_entries: %u < %Zu\n", *len, sizeof(get)); @@ -954,7 +954,7 @@ static int __do_replace(struct net *net, const char *name, void __user *counters_ptr) { int ret; - struct arpt_table *t; + struct xt_table *t; struct xt_table_info *oldinfo; struct xt_counters *counters; void *loc_cpu_old_entry; @@ -1091,7 +1091,7 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, const char *name; int size; void *ptmp; - struct arpt_table *t; + struct xt_table *t; const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; @@ -1555,7 +1555,7 @@ out: } static int compat_copy_entries_to_user(unsigned int total_size, - struct arpt_table *table, + struct xt_table *table, void __user *userptr) { struct xt_counters *counters; @@ -1593,7 +1593,7 @@ static int compat_get_entries(struct net *net, { int ret; struct compat_arpt_get_entries get; - struct arpt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get)); @@ -1723,9 +1723,8 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len return ret; } -struct arpt_table *arpt_register_table(struct net *net, - struct arpt_table *table, - const struct arpt_replace *repl) +struct xt_table *arpt_register_table(struct net *net, struct xt_table *table, + const struct arpt_replace *repl) { int ret; struct xt_table_info *newinfo; @@ -1767,7 +1766,7 @@ out: return ERR_PTR(ret); } -void arpt_unregister_table(struct arpt_table *table) +void arpt_unregister_table(struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 629e4951a9b1..9f6526c87757 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -45,7 +45,7 @@ static struct .term = ARPT_ERROR_INIT, }; -static struct arpt_table packet_filter = { +static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), -- cgit v1.2.3 From 95eea855af69bfd54a7b73546190e76046ca2e07 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:43 +0200 Subject: [NETFILTER]: remove arpt_target indirection macro Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 1 - net/ipv4/netfilter/arp_tables.c | 8 ++++---- net/ipv4/netfilter/arpt_mangle.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 102c4134a713..782b83e5bdb9 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -23,7 +23,6 @@ #define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN #define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN -#define arpt_target xt_target #define ARPT_DEV_ADDR_LEN_MAX 16 diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 34c42c831b18..d55f3b42eba5 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -457,7 +457,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name) static inline int check_target(struct arpt_entry *e, const char *name) { struct arpt_entry_target *t; - struct arpt_target *target; + struct xt_target *target; int ret; t = arpt_get_target(e); @@ -480,7 +480,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, unsigned int *i) { struct arpt_entry_target *t; - struct arpt_target *target; + struct xt_target *target; int ret; ret = check_entry(e, name); @@ -1784,7 +1784,7 @@ void arpt_unregister_table(struct xt_table *table) } /* The built-in targets: standard (NULL) and error. */ -static struct arpt_target arpt_standard_target __read_mostly = { +static struct xt_target arpt_standard_target __read_mostly = { .name = ARPT_STANDARD_TARGET, .targetsize = sizeof(int), .family = NF_ARP, @@ -1795,7 +1795,7 @@ static struct arpt_target arpt_standard_target __read_mostly = { #endif }; -static struct arpt_target arpt_error_target __read_mostly = { +static struct xt_target arpt_error_target __read_mostly = { .name = ARPT_ERROR_TARGET, .target = arpt_error, .targetsize = ARPT_FUNCTION_MAXNAMELEN, diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index 3e732c827fc2..f9c102ab891b 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -73,7 +73,7 @@ checkentry(const char *tablename, const void *e, const struct xt_target *target, return true; } -static struct arpt_target arpt_mangle_reg __read_mostly = { +static struct xt_target arpt_mangle_reg __read_mostly = { .name = "mangle", .target = target, .targetsize = sizeof(struct arpt_mangle), -- cgit v1.2.3 From 3bb0362d2f53fa54a17b88c96b43fc093e47699b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:44 +0200 Subject: [NETFILTER]: remove arpt_(un)register_target indirection macros Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 5 ----- net/ipv4/netfilter/arpt_mangle.c | 8 +++----- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 782b83e5bdb9..dd9c97f2d436 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -264,11 +264,6 @@ struct arpt_error .target.errorname = "ERROR", \ } -#define arpt_register_target(tgt) \ -({ (tgt)->family = NF_ARP; \ - xt_register_target(tgt); }) -#define arpt_unregister_target(tgt) xt_unregister_target(tgt) - extern struct xt_table *arpt_register_table(struct net *net, struct xt_table *table, const struct arpt_replace *repl); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index f9c102ab891b..a385959d2655 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -75,6 +75,7 @@ checkentry(const char *tablename, const void *e, const struct xt_target *target, static struct xt_target arpt_mangle_reg __read_mostly = { .name = "mangle", + .family = NF_ARP, .target = target, .targetsize = sizeof(struct arpt_mangle), .checkentry = checkentry, @@ -83,15 +84,12 @@ static struct xt_target arpt_mangle_reg __read_mostly = { static int __init arpt_mangle_init(void) { - if (arpt_register_target(&arpt_mangle_reg)) - return -EINVAL; - - return 0; + return xt_register_target(&arpt_mangle_reg); } static void __exit arpt_mangle_fini(void) { - arpt_unregister_target(&arpt_mangle_reg); + xt_unregister_target(&arpt_mangle_reg); } module_init(arpt_mangle_init); -- cgit v1.2.3 From d63a650736f566a1f9e9434725d2089597c0d2cc Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:53 +0100 Subject: [NETFILTER]: Add partial checksum validation helper Move the UDP-Lite conntrack checksum validation to a generic helper similar to nf_checksum() and make it fall back to nf_checksum() in case the full packet is to be checksummed and hardware checksums are available. This is to be used by DCCP conntrack, which also needs to verify partial checksums. Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 22 ++++++++++++++++ net/ipv4/netfilter.c | 37 +++++++++++++++++++++----- net/ipv6/netfilter.c | 42 +++++++++++++++++++++++++----- net/netfilter/nf_conntrack_proto_udplite.c | 33 +++++------------------ 4 files changed, 94 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 66bc52060fd6..e4c66593b5c6 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -234,6 +234,11 @@ struct nf_afinfo { unsigned short family; __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); + __sum16 (*checksum_partial)(struct sk_buff *skb, + unsigned int hook, + unsigned int dataoff, + unsigned int len, + u_int8_t protocol); int (*route)(struct dst_entry **dst, struct flowi *fl); void (*saveroute)(const struct sk_buff *skb, struct nf_queue_entry *entry); @@ -263,6 +268,23 @@ nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, return csum; } +static inline __sum16 +nf_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol, unsigned short family) +{ + const struct nf_afinfo *afinfo; + __sum16 csum = 0; + + rcu_read_lock(); + afinfo = nf_get_afinfo(family); + if (afinfo) + csum = afinfo->checksum_partial(skb, hook, dataoff, len, + protocol); + rcu_read_unlock(); + return csum; +} + extern int nf_register_afinfo(const struct nf_afinfo *afinfo); extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 9a904c6c0dc8..f8edacdf991d 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -182,21 +182,44 @@ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, } return csum; } - EXPORT_SYMBOL(nf_ip_checksum); +static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol) +{ + const struct iphdr *iph = ip_hdr(skb); + __sum16 csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (len == skb->len - dataoff) + return nf_ip_checksum(skb, hook, dataoff, protocol); + /* fall through */ + case CHECKSUM_NONE: + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol, + skb->len - dataoff, 0); + skb->ip_summed = CHECKSUM_NONE; + csum = __skb_checksum_complete_head(skb, dataoff + len); + if (!csum) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return csum; +} + static int nf_ip_route(struct dst_entry **dst, struct flowi *fl) { return ip_route_output_key(&init_net, (struct rtable **)dst, fl); } static const struct nf_afinfo nf_ip_afinfo = { - .family = AF_INET, - .checksum = nf_ip_checksum, - .route = nf_ip_route, - .saveroute = nf_ip_saveroute, - .reroute = nf_ip_reroute, - .route_key_size = sizeof(struct ip_rt_info), + .family = AF_INET, + .checksum = nf_ip_checksum, + .checksum_partial = nf_ip_checksum_partial, + .route = nf_ip_route, + .saveroute = nf_ip_saveroute, + .reroute = nf_ip_reroute, + .route_key_size = sizeof(struct ip_rt_info), }; static int ipv4_netfilter_init(void) diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index aed51bcc66b4..8c6c5e71f210 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -121,16 +121,44 @@ __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, } return csum; } - EXPORT_SYMBOL(nf_ip6_checksum); +static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol) +{ + struct ipv6hdr *ip6h = ipv6_hdr(skb); + __wsum hsum; + __sum16 csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (len == skb->len - dataoff) + return nf_ip6_checksum(skb, hook, dataoff, protocol); + /* fall through */ + case CHECKSUM_NONE: + hsum = skb_checksum(skb, 0, dataoff, 0); + skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, + &ip6h->daddr, + skb->len - dataoff, + protocol, + csum_sub(0, hsum))); + skb->ip_summed = CHECKSUM_NONE; + csum = __skb_checksum_complete_head(skb, dataoff + len); + if (!csum) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return csum; +}; + static const struct nf_afinfo nf_ip6_afinfo = { - .family = AF_INET6, - .checksum = nf_ip6_checksum, - .route = nf_ip6_route, - .saveroute = nf_ip6_saveroute, - .reroute = nf_ip6_reroute, - .route_key_size = sizeof(struct ip6_rt_info), + .family = AF_INET6, + .checksum = nf_ip6_checksum, + .checksum_partial = nf_ip6_checksum_partial, + .route = nf_ip6_route, + .saveroute = nf_ip6_saveroute, + .reroute = nf_ip6_reroute, + .route_key_size = sizeof(struct ip6_rt_info), }; int __init ipv6_netfilter_init(void) diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 9dd03c7aeac6..c3eaee6afffd 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -127,32 +127,13 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff, } /* Checksum invalid? Ignore. */ - if (nf_conntrack_checksum && !skb_csum_unnecessary(skb) && - hooknum == NF_INET_PRE_ROUTING) { - if (pf == PF_INET) { - struct iphdr *iph = ip_hdr(skb); - - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - udplen, IPPROTO_UDPLITE, 0); - } else { - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - __wsum hsum = skb_checksum(skb, 0, dataoff, 0); - - skb->csum = ~csum_unfold( - csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, - udplen, IPPROTO_UDPLITE, - csum_sub(0, hsum))); - } - - skb->ip_summed = CHECKSUM_NONE; - if (__skb_checksum_complete_head(skb, dataoff + cscov)) { - if (LOG_INVALID(IPPROTO_UDPLITE)) - nf_log_packet(pf, 0, skb, NULL, NULL, NULL, - "nf_ct_udplite: bad UDPLite " - "checksum "); - return -NF_ACCEPT; - } - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING && + nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP, + pf)) { + if (LOG_INVALID(IPPROTO_UDPLITE)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_udplite: bad UDPLite checksum "); + return -NF_ACCEPT; } return NF_ACCEPT; -- cgit v1.2.3 From 2bc780499aa33311ec0f3e42624dfaa7be0ade5e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:55 +0100 Subject: [NETFILTER]: nf_conntrack: add DCCP protocol support Add DCCP conntrack helper. Thanks to Gerrit Renker for review and testing. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_dccp.h | 40 ++ include/linux/netfilter/nfnetlink_conntrack.h | 8 + include/net/netfilter/nf_conntrack.h | 2 + include/net/netfilter/nf_conntrack_tuple.h | 6 + net/netfilter/Kconfig | 10 + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_proto_dccp.c | 816 ++++++++++++++++++++++++++ 7 files changed, 883 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_dccp.h create mode 100644 net/netfilter/nf_conntrack_proto_dccp.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_dccp.h b/include/linux/netfilter/nf_conntrack_dccp.h new file mode 100644 index 000000000000..40dcc82058d1 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_dccp.h @@ -0,0 +1,40 @@ +#ifndef _NF_CONNTRACK_DCCP_H +#define _NF_CONNTRACK_DCCP_H + +/* Exposed to userspace over nfnetlink */ +enum ct_dccp_states { + CT_DCCP_NONE, + CT_DCCP_REQUEST, + CT_DCCP_RESPOND, + CT_DCCP_PARTOPEN, + CT_DCCP_OPEN, + CT_DCCP_CLOSEREQ, + CT_DCCP_CLOSING, + CT_DCCP_TIMEWAIT, + CT_DCCP_IGNORE, + CT_DCCP_INVALID, + __CT_DCCP_MAX +}; +#define CT_DCCP_MAX (__CT_DCCP_MAX - 1) + +enum ct_dccp_roles { + CT_DCCP_ROLE_CLIENT, + CT_DCCP_ROLE_SERVER, + __CT_DCCP_ROLE_MAX +}; +#define CT_DCCP_ROLE_MAX (__CT_DCCP_ROLE_MAX - 1) + +#ifdef __KERNEL__ +#include + +struct nf_ct_dccp { + u_int8_t role[IP_CT_DIR_MAX]; + u_int8_t state; + u_int8_t last_pkt; + u_int8_t last_dir; + u_int64_t handshake_seq; +}; + +#endif /* __KERNEL__ */ + +#endif /* _NF_CONNTRACK_DCCP_H */ diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index e3e1533aba2d..0a383ac083cb 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -80,6 +80,7 @@ enum ctattr_l4proto { enum ctattr_protoinfo { CTA_PROTOINFO_UNSPEC, CTA_PROTOINFO_TCP, + CTA_PROTOINFO_DCCP, __CTA_PROTOINFO_MAX }; #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1) @@ -95,6 +96,13 @@ enum ctattr_protoinfo_tcp { }; #define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1) +enum ctattr_protoinfo_dccp { + CTA_PROTOINFO_DCCP_UNSPEC, + CTA_PROTOINFO_DCCP_STATE, + __CTA_PROTOINFO_DCCP_MAX, +}; +#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1) + enum ctattr_counters { CTA_COUNTERS_UNSPEC, CTA_COUNTERS_PACKETS, /* old 64bit counters */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index a3567a7a6d67..bb9fc852e973 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ /* per conntrack: protocol private data */ union nf_conntrack_proto { /* insert conntrack proto private data here */ + struct nf_ct_dccp dccp; struct ip_ct_sctp sctp; struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index 168c91754d89..bdeec3461384 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -39,6 +39,9 @@ union nf_conntrack_man_proto struct { __be16 id; } icmp; + struct { + __be16 port; + } dccp; struct { __be16 port; } sctp; @@ -77,6 +80,9 @@ struct nf_conntrack_tuple struct { u_int8_t type, code; } icmp; + struct { + __be16 port; + } dccp; struct { __be16 port; } sctp; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index daf5b881064d..c1fc0f1a641c 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -86,6 +86,16 @@ config NF_CONNTRACK_EVENTS If unsure, say `N'. +config NF_CT_PROTO_DCCP + tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)' + depends on EXPERIMENTAL && NF_CONNTRACK + depends on NETFILTER_ADVANCED + help + With this option enabled, the layer 3 independent connection + tracking code will be able to do state tracking on DCCP connections. + + If unsure, say 'N'. + config NF_CT_PROTO_GRE tristate depends on NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index ea7508387f95..5c4b183f6422 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o # SCTP protocol connection tracking +obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c new file mode 100644 index 000000000000..db88c5bcc5fd --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -0,0 +1,816 @@ +/* + * DCCP connection tracking protocol helper + * + * Copyright (c) 2005, 2006, 2008 Patrick McHardy + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static DEFINE_RWLOCK(dccp_lock); + +static int nf_ct_dccp_loose __read_mostly = 1; + +/* Timeouts are based on values from RFC4340: + * + * - REQUEST: + * + * 8.1.2. Client Request + * + * A client MAY give up on its DCCP-Requests after some time + * (3 minutes, for example). + * + * - RESPOND: + * + * 8.1.3. Server Response + * + * It MAY also leave the RESPOND state for CLOSED after a timeout of + * not less than 4MSL (8 minutes); + * + * - PARTOPEN: + * + * 8.1.5. Handshake Completion + * + * If the client remains in PARTOPEN for more than 4MSL (8 minutes), + * it SHOULD reset the connection with Reset Code 2, "Aborted". + * + * - OPEN: + * + * The DCCP timestamp overflows after 11.9 hours. If the connection + * stays idle this long the sequence number won't be recognized + * as valid anymore. + * + * - CLOSEREQ/CLOSING: + * + * 8.3. Termination + * + * The retransmission timer should initially be set to go off in two + * round-trip times and should back off to not less than once every + * 64 seconds ... + * + * - TIMEWAIT: + * + * 4.3. States + * + * A server or client socket remains in this state for 2MSL (4 minutes) + * after the connection has been town down, ... + */ + +#define DCCP_MSL (2 * 60 * HZ) + +static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = { + [CT_DCCP_REQUEST] = 2 * DCCP_MSL, + [CT_DCCP_RESPOND] = 4 * DCCP_MSL, + [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL, + [CT_DCCP_OPEN] = 12 * 3600 * HZ, + [CT_DCCP_CLOSEREQ] = 64 * HZ, + [CT_DCCP_CLOSING] = 64 * HZ, + [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL, +}; + +static const char * const dccp_state_names[] = { + [CT_DCCP_NONE] = "NONE", + [CT_DCCP_REQUEST] = "REQUEST", + [CT_DCCP_RESPOND] = "RESPOND", + [CT_DCCP_PARTOPEN] = "PARTOPEN", + [CT_DCCP_OPEN] = "OPEN", + [CT_DCCP_CLOSEREQ] = "CLOSEREQ", + [CT_DCCP_CLOSING] = "CLOSING", + [CT_DCCP_TIMEWAIT] = "TIMEWAIT", + [CT_DCCP_IGNORE] = "IGNORE", + [CT_DCCP_INVALID] = "INVALID", +}; + +#define sNO CT_DCCP_NONE +#define sRQ CT_DCCP_REQUEST +#define sRS CT_DCCP_RESPOND +#define sPO CT_DCCP_PARTOPEN +#define sOP CT_DCCP_OPEN +#define sCR CT_DCCP_CLOSEREQ +#define sCG CT_DCCP_CLOSING +#define sTW CT_DCCP_TIMEWAIT +#define sIG CT_DCCP_IGNORE +#define sIV CT_DCCP_INVALID + +/* + * DCCP state transistion table + * + * The assumption is the same as for TCP tracking: + * + * We are the man in the middle. All the packets go through us but might + * get lost in transit to the destination. It is assumed that the destination + * can't receive segments we haven't seen. + * + * The following states exist: + * + * NONE: Initial state, expecting Request + * REQUEST: Request seen, waiting for Response from server + * RESPOND: Response from server seen, waiting for Ack from client + * PARTOPEN: Ack after Response seen, waiting for packet other than Response, + * Reset or Sync from server + * OPEN: Packet other than Response, Reset or Sync seen + * CLOSEREQ: CloseReq from server seen, expecting Close from client + * CLOSING: Close seen, expecting Reset + * TIMEWAIT: Reset seen + * IGNORE: Not determinable whether packet is valid + * + * Some states exist only on one side of the connection: REQUEST, RESPOND, + * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to + * the one it was in before. + * + * Packets are marked as ignored (sIG) if we don't know if they're valid + * (for example a reincarnation of a connection we didn't notice is dead + * already) and the server may send back a connection closing Reset or a + * Response. They're also used for Sync/SyncAck packets, which we don't + * care about. + */ +static const u_int8_t +dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { + [CT_DCCP_ROLE_CLIENT] = { + [DCCP_PKT_REQUEST] = { + /* + * sNO -> sRQ Regular Request + * sRQ -> sRQ Retransmitted Request or reincarnation + * sRS -> sRS Retransmitted Request (apparently Response + * got lost after we saw it) or reincarnation + * sPO -> sIG Ignore, conntrack might be out of sync + * sOP -> sIG Ignore, conntrack might be out of sync + * sCR -> sIG Ignore, conntrack might be out of sync + * sCG -> sIG Ignore, conntrack might be out of sync + * sTW -> sRQ Reincarnation + * + * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ + sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, + }, + [DCCP_PKT_RESPONSE] = { + /* + * sNO -> sIV Invalid + * sRQ -> sIG Ignore, might be response to ignored Request + * sRS -> sIG Ignore, might be response to ignored Request + * sPO -> sIG Ignore, might be response to ignored Request + * sOP -> sIG Ignore, might be response to ignored Request + * sCR -> sIG Ignore, might be response to ignored Request + * sCG -> sIG Ignore, might be response to ignored Request + * sTW -> sIV Invalid, reincarnation in reverse direction + * goes through sRQ + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, + }, + [DCCP_PKT_ACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) + * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN + * sOP -> sOP Regular ACK, remain in OPEN + * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV + }, + [DCCP_PKT_DATA] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) + * sOP -> sOP Regular Data packet + * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, + }, + [DCCP_PKT_DATAACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) + * sPO -> sPO Remain in PARTOPEN state + * sOP -> sOP Regular DataAck packet in OPEN state + * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV + }, + [DCCP_PKT_CLOSEREQ] = { + /* + * CLOSEREQ may only be sent by the server. + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV + }, + [DCCP_PKT_CLOSE] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sCG Client-initiated close + * sOP -> sCG Client-initiated close + * sCR -> sCG Close in response to CloseReq (8.3.) + * sCG -> sCG Retransmit + * sTW -> sIV Late retransmit, already in TIME_WAIT + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV + }, + [DCCP_PKT_RESET] = { + /* + * sNO -> sIV No connection + * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) + * sRS -> sTW Response received without Request + * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) + * sOP -> sTW Connection reset + * sCR -> sTW Connection reset + * sCG -> sTW Connection reset + * sTW -> sIG Ignore (don't refresh timer) + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG + }, + [DCCP_PKT_SYNC] = { + /* + * We currently ignore Sync packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + [DCCP_PKT_SYNCACK] = { + /* + * We currently ignore SyncAck packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + }, + [CT_DCCP_ROLE_SERVER] = { + [DCCP_PKT_REQUEST] = { + /* + * sNO -> sIV Invalid + * sRQ -> sIG Ignore, conntrack might be out of sync + * sRS -> sIG Ignore, conntrack might be out of sync + * sPO -> sIG Ignore, conntrack might be out of sync + * sOP -> sIG Ignore, conntrack might be out of sync + * sCR -> sIG Ignore, conntrack might be out of sync + * sCG -> sIG Ignore, conntrack might be out of sync + * sTW -> sRQ Reincarnation, must reverse roles + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ + }, + [DCCP_PKT_RESPONSE] = { + /* + * sNO -> sIV Response without Request + * sRQ -> sRS Response to clients Request + * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) + * sPO -> sIG Response to an ignored Request or late retransmit + * sOP -> sIG Ignore, might be response to ignored Request + * sCR -> sIG Ignore, might be response to ignored Request + * sCG -> sIG Ignore, might be response to ignored Request + * sTW -> sIV Invalid, Request from client in sTW moves to sRQ + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV + }, + [DCCP_PKT_ACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular Ack in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_DATA] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular Data packet in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_DATAACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular DataAck in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_CLOSEREQ] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) + * sOP -> sCR CloseReq in OPEN state + * sCR -> sCR Retransmit + * sCG -> sCR Simultaneous close, client sends another Close + * sTW -> sIV Already closed + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV + }, + [DCCP_PKT_CLOSE] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP -> sCG Move direcly to CLOSING + * sOP -> sCG Move to CLOSING + * sCR -> sIV Close after CloseReq is invalid + * sCG -> sCG Retransmit + * sTW -> sIV Already closed + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV + }, + [DCCP_PKT_RESET] = { + /* + * sNO -> sIV No connection + * sRQ -> sTW Reset in response to Request + * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) + * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) + * sOP -> sTW + * sCR -> sTW + * sCG -> sTW + * sTW -> sIG Ignore (don't refresh timer) + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG + }, + [DCCP_PKT_SYNC] = { + /* + * We currently ignore Sync packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + [DCCP_PKT_SYNCACK] = { + /* + * We currently ignore SyncAck packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + }, +}; + +static int dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) +{ + struct dccp_hdr _hdr, *dh; + + dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); + if (dh == NULL) + return 0; + + tuple->src.u.dccp.port = dh->dccph_sport; + tuple->dst.u.dccp.port = dh->dccph_dport; + return 1; +} + +static int dccp_invert_tuple(struct nf_conntrack_tuple *inv, + const struct nf_conntrack_tuple *tuple) +{ + inv->src.u.dccp.port = tuple->dst.u.dccp.port; + inv->dst.u.dccp.port = tuple->src.u.dccp.port; + return 1; +} + +static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) +{ + int pf = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + struct dccp_hdr _dh, *dh; + const char *msg; + u_int8_t state; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + BUG_ON(dh == NULL); + + state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; + switch (state) { + default: + if (nf_ct_dccp_loose == 0) { + msg = "nf_ct_dccp: not picking up existing connection "; + goto out_invalid; + } + case CT_DCCP_REQUEST: + break; + case CT_DCCP_INVALID: + msg = "nf_ct_dccp: invalid state transition "; + goto out_invalid; + } + + ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; + ct->proto.dccp.state = CT_DCCP_NONE; + return 1; + +out_invalid: + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); + return 0; +} + +static u64 dccp_ack_seq(const struct dccp_hdr *dh) +{ + const struct dccp_hdr_ack_bits *dhack; + + dhack = (void *)dh + __dccp_basic_hdr_len(dh); + return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + + ntohl(dhack->dccph_ack_nr_low); +} + +static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info ctinfo, + int pf, unsigned int hooknum) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + struct dccp_hdr _dh, *dh; + u_int8_t type, old_state, new_state; + enum ct_dccp_roles role; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + BUG_ON(dh == NULL); + type = dh->dccph_type; + + if (type == DCCP_PKT_RESET && + !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { + /* Tear down connection immediately if only reply is a RESET */ + if (del_timer(&ct->timeout)) + ct->timeout.function((unsigned long)ct); + return NF_ACCEPT; + } + + write_lock_bh(&dccp_lock); + + role = ct->proto.dccp.role[dir]; + old_state = ct->proto.dccp.state; + new_state = dccp_state_table[role][type][old_state]; + + switch (new_state) { + case CT_DCCP_REQUEST: + if (old_state == CT_DCCP_TIMEWAIT && + role == CT_DCCP_ROLE_SERVER) { + /* Reincarnation in the reverse direction: reopen and + * reverse client/server roles. */ + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; + } + break; + case CT_DCCP_RESPOND: + if (old_state == CT_DCCP_REQUEST) + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); + break; + case CT_DCCP_PARTOPEN: + if (old_state == CT_DCCP_RESPOND && + type == DCCP_PKT_ACK && + dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) + set_bit(IPS_ASSURED_BIT, &ct->status); + break; + case CT_DCCP_IGNORE: + /* + * Connection tracking might be out of sync, so we ignore + * packets that might establish a new connection and resync + * if the server responds with a valid Response. + */ + if (ct->proto.dccp.last_dir == !dir && + ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && + type == DCCP_PKT_RESPONSE) { + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); + new_state = CT_DCCP_RESPOND; + break; + } + ct->proto.dccp.last_dir = dir; + ct->proto.dccp.last_pkt = type; + + write_unlock_bh(&dccp_lock); + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_dccp: invalid packet ignored "); + return NF_ACCEPT; + case CT_DCCP_INVALID: + write_unlock_bh(&dccp_lock); + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_dccp: invalid state transition "); + return -NF_ACCEPT; + } + + ct->proto.dccp.last_dir = dir; + ct->proto.dccp.last_pkt = type; + ct->proto.dccp.state = new_state; + write_unlock_bh(&dccp_lock); + nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); + + return NF_ACCEPT; +} + +static int dccp_error(struct sk_buff *skb, unsigned int dataoff, + enum ip_conntrack_info *ctinfo, int pf, + unsigned int hooknum) +{ + struct dccp_hdr _dh, *dh; + unsigned int dccp_len = skb->len - dataoff; + unsigned int cscov; + const char *msg; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + if (dh == NULL) { + msg = "nf_ct_dccp: short packet "; + goto out_invalid; + } + + if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || + dh->dccph_doff * 4 > dccp_len) { + msg = "nf_ct_dccp: truncated/malformed packet "; + goto out_invalid; + } + + cscov = dccp_len; + if (dh->dccph_cscov) { + cscov = (dh->dccph_cscov - 1) * 4; + if (cscov > dccp_len) { + msg = "nf_ct_dccp: bad checksum coverage "; + goto out_invalid; + } + } + + if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING && + nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, + pf)) { + msg = "nf_ct_dccp: bad checksum "; + goto out_invalid; + } + + if (dh->dccph_type >= DCCP_PKT_INVALID) { + msg = "nf_ct_dccp: reserved packet type "; + goto out_invalid; + } + + return NF_ACCEPT; + +out_invalid: + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); + return -NF_ACCEPT; +} + +static int dccp_print_tuple(struct seq_file *s, + const struct nf_conntrack_tuple *tuple) +{ + return seq_printf(s, "sport=%hu dport=%hu ", + ntohs(tuple->src.u.dccp.port), + ntohs(tuple->dst.u.dccp.port)); +} + +static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +{ + return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); +} + +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, + const struct nf_conn *ct) +{ + struct nlattr *nest_parms; + + read_lock_bh(&dccp_lock); + nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); + nla_nest_end(skb, nest_parms); + read_unlock_bh(&dccp_lock); + return 0; + +nla_put_failure: + read_unlock_bh(&dccp_lock); + return -1; +} + +static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { + [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, +}; + +static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) +{ + struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; + struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; + int err; + + if (!attr) + return 0; + + err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, + dccp_nla_policy); + if (err < 0) + return err; + + if (!tb[CTA_PROTOINFO_DCCP_STATE] || + nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) + return -EINVAL; + + write_lock_bh(&dccp_lock); + ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); + write_unlock_bh(&dccp_lock); + return 0; +} +#endif + +#ifdef CONFIG_SYSCTL +static unsigned int dccp_sysctl_table_users; +static struct ctl_table_header *dccp_sysctl_header; +static ctl_table dccp_sysctl_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_request", + .data = &dccp_timeout[CT_DCCP_REQUEST], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_respond", + .data = &dccp_timeout[CT_DCCP_RESPOND], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_partopen", + .data = &dccp_timeout[CT_DCCP_PARTOPEN], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_open", + .data = &dccp_timeout[CT_DCCP_OPEN], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_closereq", + .data = &dccp_timeout[CT_DCCP_CLOSEREQ], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_closing", + .data = &dccp_timeout[CT_DCCP_CLOSING], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_timewait", + .data = &dccp_timeout[CT_DCCP_TIMEWAIT], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_loose", + .data = &nf_ct_dccp_loose, + .maxlen = sizeof(nf_ct_dccp_loose), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = 0, + } +}; +#endif /* CONFIG_SYSCTL */ + +static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { + .l3proto = AF_INET, + .l4proto = IPPROTO_DCCP, + .name = "dccp", + .pkt_to_tuple = dccp_pkt_to_tuple, + .invert_tuple = dccp_invert_tuple, + .new = dccp_new, + .packet = dccp_packet, + .error = dccp_error, + .print_tuple = dccp_print_tuple, + .print_conntrack = dccp_print_conntrack, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = dccp_to_nlattr, + .from_nlattr = nlattr_to_dccp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, +#endif +#ifdef CONFIG_SYSCTL + .ctl_table_users = &dccp_sysctl_table_users, + .ctl_table_header = &dccp_sysctl_header, + .ctl_table = dccp_sysctl_table, +#endif +}; + +static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { + .l3proto = AF_INET6, + .l4proto = IPPROTO_DCCP, + .name = "dccp", + .pkt_to_tuple = dccp_pkt_to_tuple, + .invert_tuple = dccp_invert_tuple, + .new = dccp_new, + .packet = dccp_packet, + .error = dccp_error, + .print_tuple = dccp_print_tuple, + .print_conntrack = dccp_print_conntrack, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = dccp_to_nlattr, + .from_nlattr = nlattr_to_dccp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, +#endif +#ifdef CONFIG_SYSCTL + .ctl_table_users = &dccp_sysctl_table_users, + .ctl_table_header = &dccp_sysctl_header, + .ctl_table = dccp_sysctl_table, +#endif +}; + +static int __init nf_conntrack_proto_dccp_init(void) +{ + int err; + + err = nf_conntrack_l4proto_register(&dccp_proto4); + if (err < 0) + goto err1; + + err = nf_conntrack_l4proto_register(&dccp_proto6); + if (err < 0) + goto err2; + return 0; + +err2: + nf_conntrack_l4proto_unregister(&dccp_proto4); +err1: + return err; +} + +static void __exit nf_conntrack_proto_dccp_fini(void) +{ + nf_conntrack_l4proto_unregister(&dccp_proto6); + nf_conntrack_l4proto_unregister(&dccp_proto4); +} + +module_init(nf_conntrack_proto_dccp_init); +module_exit(nf_conntrack_proto_dccp_fini); + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("DCCP connection tracking protocol helper"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dd13b010368f85dfa59364ba87bfe8ae930b2832 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:52 +0200 Subject: [NETFILTER]: nf_nat: kill helper and seq_adjust hooks Connection tracking helpers (specifically FTP) need to be called before NAT sequence numbers adjustments are performed to be able to compare them against previously seen ones. We've introduced two new hooks around 2.6.11 to maintain this ordering when NAT modules were changed to get called from conntrack helpers directly. The cost of netfilter hooks is quite high and sequence number adjustments are only rarely needed however. Add a RCU-protected sequence number adjustment function pointer and call it from IPv4 conntrack after calling the helper. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4.h | 2 - include/net/netfilter/nf_nat_helper.h | 3 ++ net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 56 +++++++++++++------------- net/ipv4/netfilter/nf_nat_core.c | 5 +++ net/ipv4/netfilter/nf_nat_helper.c | 1 - net/ipv4/netfilter/nf_nat_standalone.c | 35 ---------------- 6 files changed, 35 insertions(+), 67 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 9a10092e358c..650318b0c405 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -62,8 +62,6 @@ enum nf_ip_hook_priorities { NF_IP_PRI_FILTER = 0, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, - NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2, - NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1, NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, NF_IP_PRI_LAST = INT_MAX, }; diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h index 58dd22687949..237a961f40e1 100644 --- a/include/net/netfilter/nf_nat_helper.h +++ b/include/net/netfilter/nf_nat_helper.h @@ -24,6 +24,9 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, extern int nf_nat_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo); +extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); /* Setup NAT on this expected conntrack so it follows master, but goes * to port ct->master->saved_proto. */ diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index a65b845c5f15..41e79613eb0a 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -23,6 +23,12 @@ #include #include #include +#include + +int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); +EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple) @@ -100,36 +106,42 @@ static unsigned int ipv4_confirm(unsigned int hooknum, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) -{ - /* We've seen it coming out the other side: confirm it */ - return nf_conntrack_confirm(skb); -} - -static unsigned int ipv4_conntrack_help(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; + unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) - return NF_ACCEPT; + goto out; help = nfct_help(ct); if (!help) - return NF_ACCEPT; + goto out; + /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) - return NF_ACCEPT; - return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), - ct, ctinfo); + goto out; + + ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), + ct, ctinfo); + if (ret != NF_ACCEPT) + return ret; + + if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + typeof(nf_nat_seq_adjust_hook) seq_adjust; + + seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); + if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) + return NF_DROP; + } +out: + /* We've seen it coming out the other side: confirm it */ + return nf_conntrack_confirm(skb); } static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, @@ -210,20 +222,6 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = { .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK, }, - { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_HELPER, - }, - { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_HELPER, - }, { .hook = ipv4_confirm, .owner = THIS_MODULE, diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 9320c7ac5729..25c3efe4207e 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -618,6 +618,9 @@ static int __init nf_nat_init(void) nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + + BUG_ON(nf_nat_seq_adjust_hook != NULL); + rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); return 0; cleanup_extend: @@ -644,6 +647,8 @@ static void __exit nf_nat_cleanup(void) nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); nf_ct_l3proto_put(l3proto); nf_ct_extend_unregister(&nat_extend); + rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); + synchronize_net(); } MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 2fca727aa8ba..11976ea29884 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -416,7 +416,6 @@ nf_nat_seq_adjust(struct sk_buff *skb, return 1; } -EXPORT_SYMBOL(nf_nat_seq_adjust); /* Setup NAT on this expected conntrack so it follows master. */ /* If we fail to get a free NAT slot, we'll get dropped on confirm */ diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index a366b5865b9c..b7dd695691a0 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -245,25 +245,6 @@ nf_nat_local_fn(unsigned int hooknum, return ret; } -static unsigned int -nf_nat_adjust(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - - ct = nf_ct_get(skb, &ctinfo); - if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { - pr_debug("nf_nat_standalone: adjusting sequence number\n"); - if (!nf_nat_seq_adjust(skb, ct, ctinfo)) - return NF_DROP; - } - return NF_ACCEPT; -} - /* We must be after connection tracking and before packet filtering. */ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { @@ -283,14 +264,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, /* Before packet filtering, change destination */ { .hook = nf_nat_local_fn, @@ -307,14 +280,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, }; static int __init nf_nat_standalone_init(void) -- cgit v1.2.3 From e7bfd0a1a6c8f82977253dab19be9d9979c1ec1b Mon Sep 17 00:00:00 2001 From: Peter Warasin Date: Mon, 14 Apr 2008 11:15:54 +0200 Subject: [NETFILTER]: bridge: add ebt_nflog watcher This patch adds the ebtables nflog watcher to the kernel in order to allow ebtables log through the nfnetlink_log backend. Signed-off-by: Peter Warasin Signed-off-by: Patrick McHardy --- include/linux/netfilter_bridge/ebt_nflog.h | 21 +++++++++ net/bridge/netfilter/Kconfig | 14 ++++++ net/bridge/netfilter/Makefile | 1 + net/bridge/netfilter/ebt_nflog.c | 74 ++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 include/linux/netfilter_bridge/ebt_nflog.h create mode 100644 net/bridge/netfilter/ebt_nflog.c (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebt_nflog.h b/include/linux/netfilter_bridge/ebt_nflog.h new file mode 100644 index 000000000000..052817849b83 --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_nflog.h @@ -0,0 +1,21 @@ +#ifndef __LINUX_BRIDGE_EBT_NFLOG_H +#define __LINUX_BRIDGE_EBT_NFLOG_H + +#define EBT_NFLOG_MASK 0x0 + +#define EBT_NFLOG_PREFIX_SIZE 64 +#define EBT_NFLOG_WATCHER "nflog" + +#define EBT_NFLOG_DEFAULT_GROUP 0x1 +#define EBT_NFLOG_DEFAULT_THRESHOLD 1 + +struct ebt_nflog_info { + u_int32_t len; + u_int16_t group; + u_int16_t threshold; + u_int16_t flags; + u_int16_t pad; + char prefix[EBT_NFLOG_PREFIX_SIZE]; +}; + +#endif /* __LINUX_BRIDGE_EBT_NFLOG_H */ diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 4a3e2bf892c7..7beeefa0f9c0 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -212,4 +212,18 @@ config BRIDGE_EBT_ULOG To compile it as a module, choose M here. If unsure, say N. +config BRIDGE_EBT_NFLOG + tristate "ebt: nflog support" + depends on BRIDGE_NF_EBTABLES + help + This option enables the nflog watcher, which allows to LOG + messages through the netfilter logging API, which can use + either the old LOG target, the old ULOG target or nfnetlink_log + as backend. + + This option adds the ulog watcher, that you can use in any rule + in any ebtables table. + + To compile it as a module, choose M here. If unsure, say N. + endmenu diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 905087e0d485..83715d73a503 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o # watchers obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o obj-$(CONFIG_BRIDGE_EBT_ULOG) += ebt_ulog.o +obj-$(CONFIG_BRIDGE_EBT_NFLOG) += ebt_nflog.o diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c new file mode 100644 index 000000000000..8e799aa9e560 --- /dev/null +++ b/net/bridge/netfilter/ebt_nflog.c @@ -0,0 +1,74 @@ +/* + * ebt_nflog + * + * Author: + * Peter Warasin + * + * February, 2008 + * + * Based on: + * xt_NFLOG.c, (C) 2006 by Patrick McHardy + * ebt_ulog.c, (C) 2004 by Bart De Schuymer + * + */ + +#include +#include +#include +#include +#include + +static void ebt_nflog(const struct sk_buff *skb, + unsigned int hooknr, + const struct net_device *in, + const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; + struct nf_loginfo li; + + li.type = NF_LOG_TYPE_ULOG; + li.u.ulog.copy_len = info->len; + li.u.ulog.group = info->group; + li.u.ulog.qthreshold = info->threshold; + + nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, "%s", info->prefix); +} + +static int ebt_nflog_check(const char *tablename, + unsigned int hookmask, + const struct ebt_entry *e, + void *data, unsigned int datalen) +{ + struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; + + if (datalen != EBT_ALIGN(sizeof(struct ebt_nflog_info))) + return -EINVAL; + if (info->flags & ~EBT_NFLOG_MASK) + return -EINVAL; + info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0'; + return 0; +} + +static struct ebt_watcher nflog __read_mostly = { + .name = EBT_NFLOG_WATCHER, + .watcher = ebt_nflog, + .check = ebt_nflog_check, + .me = THIS_MODULE, +}; + +static int __init ebt_nflog_init(void) +{ + return ebt_register_watcher(&nflog); +} + +static void __exit ebt_nflog_fini(void) +{ + ebt_unregister_watcher(&nflog); +} + +module_init(ebt_nflog_init); +module_exit(ebt_nflog_fini); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter Warasin "); +MODULE_DESCRIPTION("ebtables NFLOG netfilter logging module"); -- cgit v1.2.3 From 0f389ec63077521166f071e1e970aed36147fd45 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Mon, 14 Apr 2008 18:53:02 +0300 Subject: slub: No need for per node slab counters if !SLUB_DEBUG The per node counters are used mainly for showing data through the sysfs API. If that API is not compiled in then there is no point in keeping track of this data. Disable counters for the number of slabs and the number of total slabs if !SLUB_DEBUG. Incrementing the per node counters is also accessing a potentially contended cacheline so this could actually be a performance benefit to embedded systems. SLABINFO support is also affected. It now must depends on SLUB_DEBUG (which is on by default). Patch also avoids a check for a NULL kmem_cache_node pointer in new_slab() if the system is not compiled with NUMA support. [penberg@cs.helsinki.fi: fix oops and move ->nr_slabs into CONFIG_SLUB_DEBUG] Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg --- include/linux/slub_def.h | 2 +- init/Kconfig | 2 +- mm/slub.c | 51 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index b00c1c73eb0a..79d59c937fac 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -45,9 +45,9 @@ struct kmem_cache_cpu { struct kmem_cache_node { spinlock_t list_lock; /* Protect partial list and nr_partial */ unsigned long nr_partial; - atomic_long_t nr_slabs; struct list_head partial; #ifdef CONFIG_SLUB_DEBUG + atomic_long_t nr_slabs; struct list_head full; #endif }; diff --git a/init/Kconfig b/init/Kconfig index a97924bc5b8d..7fccf09bb95a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -763,7 +763,7 @@ endmenu # General setup config SLABINFO bool depends on PROC_FS - depends on SLAB || SLUB + depends on SLAB || SLUB_DEBUG default y config RT_MUTEXES diff --git a/mm/slub.c b/mm/slub.c index f924cffb29e7..7f8aaa291a4e 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -837,6 +837,35 @@ static void remove_full(struct kmem_cache *s, struct page *page) spin_unlock(&n->list_lock); } +/* Tracking of the number of slabs for debugging purposes */ +static inline unsigned long slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + return atomic_long_read(&n->nr_slabs); +} + +static inline void inc_slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + /* + * May be called early in order to allocate a slab for the + * kmem_cache_node structure. Solve the chicken-egg + * dilemma by deferring the increment of the count during + * bootstrap (see early_kmem_cache_node_alloc). + */ + if (!NUMA_BUILD || n) + atomic_long_inc(&n->nr_slabs); +} +static inline void dec_slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + atomic_long_dec(&n->nr_slabs); +} + +/* Object debug checks for alloc/free paths */ static void setup_object_debug(struct kmem_cache *s, struct page *page, void *object) { @@ -1028,6 +1057,11 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize, return flags; } #define slub_debug 0 + +static inline unsigned long slabs_node(struct kmem_cache *s, int node) + { return 0; } +static inline void inc_slabs_node(struct kmem_cache *s, int node) {} +static inline void dec_slabs_node(struct kmem_cache *s, int node) {} #endif /* * Slab allocation and freeing @@ -1066,7 +1100,6 @@ static void setup_object(struct kmem_cache *s, struct page *page, static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) { struct page *page; - struct kmem_cache_node *n; void *start; void *last; void *p; @@ -1078,9 +1111,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) if (!page) goto out; - n = get_node(s, page_to_nid(page)); - if (n) - atomic_long_inc(&n->nr_slabs); + inc_slabs_node(s, page_to_nid(page)); page->slab = s; page->flags |= 1 << PG_slab; if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON | @@ -1153,9 +1184,7 @@ static void free_slab(struct kmem_cache *s, struct page *page) static void discard_slab(struct kmem_cache *s, struct page *page) { - struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - - atomic_long_dec(&n->nr_slabs); + dec_slabs_node(s, page_to_nid(page)); free_slab(s, page); } @@ -1894,10 +1923,10 @@ static void init_kmem_cache_cpu(struct kmem_cache *s, static void init_kmem_cache_node(struct kmem_cache_node *n) { n->nr_partial = 0; - atomic_long_set(&n->nr_slabs, 0); spin_lock_init(&n->list_lock); INIT_LIST_HEAD(&n->partial); #ifdef CONFIG_SLUB_DEBUG + atomic_long_set(&n->nr_slabs, 0); INIT_LIST_HEAD(&n->full); #endif } @@ -2066,7 +2095,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags, init_tracking(kmalloc_caches, n); #endif init_kmem_cache_node(n); - atomic_long_inc(&n->nr_slabs); + inc_slabs_node(kmalloc_caches, node); /* * lockdep requires consistent irq usage for each lock @@ -2379,7 +2408,7 @@ static inline int kmem_cache_close(struct kmem_cache *s) struct kmem_cache_node *n = get_node(s, node); n->nr_partial -= free_list(s, n, &n->partial); - if (atomic_long_read(&n->nr_slabs)) + if (slabs_node(s, node)) return 1; } free_kmem_cache_nodes(s); @@ -2801,7 +2830,7 @@ static void slab_mem_offline_callback(void *arg) * and offline_pages() function shoudn't call this * callback. So, we must fail. */ - BUG_ON(atomic_long_read(&n->nr_slabs)); + BUG_ON(slabs_node(s, offline_node)); s->node[offline_node] = NULL; kmem_cache_free(kmalloc_caches, n); -- cgit v1.2.3 From d237e5c7ce82b6c7e1aa50348520a0c5a47274fa Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 15 Apr 2008 09:25:33 +0200 Subject: io context: increment task attachment count in ioc_task_link() Thanks to Nikanth Karthikesan for reporting this. Signed-off-by: Jens Axboe --- include/linux/iocontext.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index cac4b364cd40..2b7a1187cb29 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -91,8 +91,10 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) * if ref count is zero, don't allow sharing (ioc is going away, it's * a race). */ - if (ioc && atomic_inc_not_zero(&ioc->refcount)) + if (ioc && atomic_inc_not_zero(&ioc->refcount)) { + atomic_inc(&ioc->nr_tasks); return ioc; + } return NULL; } -- cgit v1.2.3 From 99971e70fdc1862e120f3319fc0a4dba8c728acf Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 15 Apr 2008 00:27:58 -0700 Subject: [WANPIPE]: Forgotten bits of Sangoma drivers removal. Robert P. J. Day spotted that my removal of the Sangoma drivers missed a few bits. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- Documentation/networking/00-INDEX | 2 - Documentation/networking/wan-router.txt | 621 -------------------------------- include/linux/Kbuild | 1 - include/linux/if_wanpipe.h | 124 ------- 4 files changed, 748 deletions(-) delete mode 100644 Documentation/networking/wan-router.txt delete mode 100644 include/linux/if_wanpipe.h (limited to 'include/linux') diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index c485ee028bd9..1634c6dcecae 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -100,8 +100,6 @@ tuntap.txt - TUN/TAP device driver, allowing user space Rx/Tx of packets. vortex.txt - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. -wan-router.txt - - WAN router documentation wavelan.txt - AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver x25.txt diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt deleted file mode 100644 index bc2ab419a74a..000000000000 --- a/Documentation/networking/wan-router.txt +++ /dev/null @@ -1,621 +0,0 @@ ------------------------------------------------------------------------------- -Linux WAN Router Utilities Package ------------------------------------------------------------------------------- -Version 2.2.1 -Mar 28, 2001 -Author: Nenad Corbic -Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------- - -INTRODUCTION - -Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) -and/or stand-alone hosts over vast distances with data transfer rates -significantly higher than those achievable with commonly used dial-up -connections. - -Usually an external device called `WAN router' sitting on your local network -or connected to your machine's serial port provides physical connection to -WAN. Although router's job may be as simple as taking your local network -traffic, converting it to WAN format and piping it through the WAN link, these -devices are notoriously expensive, with prices as much as 2 - 5 times higher -then the price of a typical PC box. - -Alternatively, considering robustness and multitasking capabilities of Linux, -an internal router can be built (most routers use some sort of stripped down -Unix-like operating system anyway). With a number of relatively inexpensive WAN -interface cards available on the market, a perfectly usable router can be -built for less than half a price of an external router. Yet a Linux box -acting as a router can still be used for other purposes, such as fire-walling, -running FTP, WWW or DNS server, etc. - -This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux -operating system and provides generic hardware-independent services for such -drivers. Why can existing Linux network device interface not be used for -this purpose? Well, it can. However, there are a few key differences between -a typical network interface (e.g. Ethernet) and a WAN link. - -Many WAN protocols, such as X.25 and frame relay, allow for multiple logical -connections (known as `virtual circuits' in X.25 terminology) over a single -physical link. Each such virtual circuit may (and almost always does) lead -to a different geographical location and, therefore, different network. As a -result, it is the virtual circuit, not the physical link, that represents a -route and, therefore, a network interface in Linux terms. - -To further complicate things, virtual circuits are usually volatile in nature -(excluding so called `permanent' virtual circuits or PVCs). With almost no -time required to set up and tear down a virtual circuit, it is highly desirable -to implement on-demand connections in order to minimize network charges. So -unlike a typical network driver, the WAN driver must be able to handle multiple -network interfaces and cope as multiple virtual circuits come into existence -and go away dynamically. - -Last, but not least, WAN configuration is much more complex than that of say -Ethernet and may well amount to several dozens of parameters. Some of them -are "link-wide" while others are virtual circuit-specific. The same holds -true for WAN statistics which is by far more extensive and extremely useful -when troubleshooting WAN connections. Extending the ifconfig utility to suit -these needs may be possible, but does not seem quite reasonable. Therefore, a -WAN configuration utility and corresponding application programmer's interface -is needed for this purpose. - -Most of these problems are taken care of by this module. Its goal is to -provide a user with more-or-less standard look and feel for all WAN devices and -assist a WAN device driver writer by providing common services, such as: - - o User-level interface via /proc file system - o Centralized configuration - o Device management (setup, shutdown, etc.) - o Network interface management (dynamic creation/destruction) - o Protocol encapsulation/decapsulation - -To ba able to use the Linux WAN Router you will also need a WAN Tools package -available from - - ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz - -where vX.Y.Z represent the wanpipe version number. - -For technical questions and/or comments please e-mail to ncorbic@sangoma.com. -For general inquiries please contact Sangoma Technologies Inc. by - - Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 ext: 106 - Fax: (905) 474-9223 - E-mail: dm@sangoma.com (David Mandelstam) - WWW: http://www.sangoma.com - - -INSTALLATION - -Please read the WanpipeForLinux.pdf manual on how to -install the WANPIPE tools and drivers properly. - - -After installing wanpipe package: /usr/local/wanrouter/doc. -On the ftp.sangoma.com : /linux/current_wanpipe/doc - - -COPYRIGHT AND LICENSING INFORMATION - -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; if not, write to the Free Software Foundation, Inc., 675 Mass -Ave, Cambridge, MA 02139, USA. - - - -ACKNOWLEDGEMENTS - -This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE -together with the next major release of Linux kernel in summer 1996 commanded -adequate changes to the WANPIPE code to take full advantage of new Linux -features. - -Instead of continuing developing proprietary interface tied to Sangoma WAN -cards, we decided to separate all hardware-independent code into a separate -module and defined two levels of interfaces - one for user-level applications -and another for kernel-level WAN drivers. WANPIPE is now implemented as a -WAN driver compliant with the WAN Link Driver interface. Also a general -purpose WAN configuration utility and a set of shell scripts was developed to -support WAN router at the user level. - -Many useful ideas concerning hardware-independent interface implementation -were given by Mike McLagan and his implementation -of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). - -With the new implementation of the APIs being incorporated into the WANPIPE, -a special thank goes to Alan Cox in providing insight into BSD sockets. - -Special thanks to all the WANPIPE users who performed field-testing, reported -bugs and made valuable comments and suggestions that help us to improve this -product. - - - -NEW IN THIS RELEASE - - o Updated the WANCFG utility - Calls the pppconfig to configure the PPPD - for async connections. - - o Added the PPPCONFIG utility - Used to configure the PPPD daemon for the - WANPIPE Async PPP and standard serial port. - The wancfg calls the pppconfig to configure - the pppd. - - o Fixed the PCI autodetect feature. - The SLOT 0 was used as an autodetect option - however, some high end PC's slot numbers start - from 0. - - o This release has been tested with the new backupd - daemon release. - - -PRODUCT COMPONENTS AND RELATED FILES - -/etc: (or user defined) - wanpipe1.conf default router configuration file - -/lib/modules/X.Y.Z/misc: - wanrouter.o router kernel loadable module - af_wanpipe.o wanpipe api socket module - -/lib/modules/X.Y.Z/net: - sdladrv.o Sangoma SDLA support module - wanpipe.o Sangoma WANPIPE(tm) driver module - -/proc/net/wanrouter - Config reads current router configuration - Status reads current router status - {name} reads WAN driver statistics - -/usr/sbin: - wanrouter wanrouter start-up script - wanconfig wanrouter configuration utility - sdladump WANPIPE adapter memory dump utility - fpipemon Monitor for Frame Relay - cpipemon Monitor for Cisco HDLC - ppipemon Monitor for PPP - xpipemon Monitor for X25 - wpkbdmon WANPIPE keyboard led monitor/debugger - -/usr/local/wanrouter: - README this file - COPYING GNU General Public License - Setup installation script - Filelist distribution definition file - wanrouter.rc meta-configuration file - (used by the Setup and wanrouter script) - -/usr/local/wanrouter/doc: - wanpipeForLinux.pdf WAN Router User's Manual - -/usr/local/wanrouter/patches: - wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. - wanrouter-v2214.gz patch for Linux kernel 2.2.14. - wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. - wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. - wanrouter-v240.gz patch for Linux kernel 2.4.0. - wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. - wanrouter-v2034.gz patch for Linux kernel 2.0.34 - wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. - -/usr/local/wanrouter/patches/kdrivers: - Sources of the latest WANPIPE device drivers. - These are used to UPGRADE the linux kernel to the newest - version if the kernel source has already been patched with - WANPIPE drivers. - -/usr/local/wanrouter/samples: - interface sample interface configuration file - wanpipe1.cpri CHDLC primary port - wanpipe2.csec CHDLC secondary port - wanpipe1.fr Frame Relay protocol - wanpipe1.ppp PPP protocol ) - wanpipe1.asy CHDLC ASYNC protocol - wanpipe1.x25 X25 protocol - wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) - wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) - wanrouter.rc sample meta-configuration file - -/usr/local/wanrouter/util: - * wan-tools utilities source code - -/usr/local/wanrouter/api/x25: - * x25 api sample programs. -/usr/local/wanrouter/api/chdlc: - * chdlc api sample programs. -/usr/local/wanrouter/api/fr: - * fr api sample programs. -/usr/local/wanrouter/config/wancfg: - wancfg WANPIPE GUI configuration program. - Creates wanpipe#.conf files. -/usr/local/wanrouter/config/cfgft1: - cfgft1 GUI CSU/DSU configuration program. - -/usr/include/linux: - wanrouter.h router API definitions - wanpipe.h WANPIPE API definitions - sdladrv.h SDLA support module API definitions - sdlasfm.h SDLA firmware module definitions - if_wanpipe.h WANPIPE Socket definitions - sdlapci.h WANPIPE PCI definitions - - -/usr/src/linux/net/wanrouter: - * wanrouter source code - -/var/log: - wanrouter wanrouter start-up log (created by the Setup script) - -/var/lock: (or /var/lock/subsys for RedHat) - wanrouter wanrouter lock file (created by the Setup script) - -/usr/local/wanrouter/firmware: - fr514.sfm Frame relay firmware for Sangoma S508/S514 card - cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card - ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards - x25_508.sfm X25 Firmware for Sangoma S508 card. - - -REVISION HISTORY - -1.0.0 December 31, 1996 Initial version - -1.0.1 January 30, 1997 Status and statistics can be read via /proc - filesystem entries. - -1.0.2 April 30, 1997 Added UDP management via monitors. - -1.0.3 June 3, 1997 UDP management for multiple boards using Frame - Relay and PPP - Enabled continuous transmission of Configure - Request Packet for PPP (for 508 only) - Connection Timeout for PPP changed from 900 to 0 - Flow Control Problem fixed for Frame Relay - -1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and - ppipemon utilities. - Configurable TTL for UDP packets. - Multicast and Broadcast IP source addresses are - silently discarded. - -1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame - Relay in router.conf. - Configurable Memory Address through router.conf - for Frame Relay, PPP and X.25. (commenting this - out enables auto-detection). - Fixed freeing up received buffers using kfree() - for Frame Relay and X.25. - Protect sdla_peek() by calling save_flags(), - cli() and restore_flags(). - Changed number of Trace elements from 32 to 20 - Added DLCI specific data monitoring in FPIPEMON. -2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by - critical flags for FRAME RELAY and PPP. - DLCI List interrupt mode implemented. - IPX support in FRAME RELAY and PPP. - IPX Server Support (MARS) - More driver specific stats included in FPIPEMON - and PIPEMON. - -2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0. - Protection of "enable_irq()" while - "disable_irq()" has been enabled from any other - routine (for Frame Relay, PPP and X25). - Added additional Stats for Fpipemon and Ppipemon - Improved Load Sharing for multiple boards - -2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been - implemented. - -2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame - relay, Dynamic IP assignment for PPP and Inverse - Arp support for Frame-relay. Man Pages are - included for better support and a new utility - for configuring FT1 cards. - -2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC. - Support for HDLC (LAPB) API. - Supports BiSync Streaming code for S502E - and S503 cards. - Support for Streaming HDLC API. - Provides a BSD socket interface for - creating applications using BiSync - streaming. - -2.0.5 Aug 04, 1999 CHDLC initialization bug fix. - PPP interrupt driven driver: - Fix to the PPP line hangup problem. - New PPP firmware - Added comments to the startup SYSTEM ERROR messages - Xpipemon debugging application for the X25 protocol - New USER_MANUAL.txt - Fixed the odd boundary 4byte writes to the board. - BiSync Streaming code has been taken out. - Available as a patch. - Streaming HDLC API has been taken out. - Available as a patch. - -2.0.6 Aug 17, 1999 Increased debugging in statup scripts - Fixed installation bugs from 2.0.5 - Kernel patch works for both 2.2.10 and 2.2.11 kernels. - There is no functional difference between the two packages - -2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memory leak for X25API - o Updated the X25API code for 2.2.X kernels. - o Improved NEM handling. - -2.1.0 Oct 25, 1999 o New code for S514 PCI Card - o New CHDLC and Frame Relay drivers - o PPP and X25 are not supported in this release - -2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards - -2.1.3 Apr 06, 2000 o Socket based x25api - o Socket based chdlc api - o Socket based fr api - o Dual Port Receive only CHDLC support. - o Asynchronous CHDLC support (Secondary Port) - o cfgft1 GUI csu/dsu configurator - o wancfg GUI configuration file - configurator. - o Architectural directory changes. - -beta-2.1.4 Jul 2000 o Dynamic interface configuration: - Network interfaces reflect the state - of protocol layer. If the protocol becomes - disconnected, driver will bring down - the interface. Once the protocol reconnects - the interface will be brought up. - - Note: This option is turned off by default. - - o Dynamic wanrouter setup using 'wanconfig': - wanconfig utility can be used to - shutdown,restart,start or reconfigure - a virtual circuit dynamically. - - Frame Relay: Each DLCI can be: - created,stopped,restarted and reconfigured - dynamically using wanconfig. - - ex: wanconfig card wanpipe1 dev wp1_fr16 up - - o Wanrouter startup via command line arguments: - wanconfig also supports wanrouter startup via command line - arguments. Thus, there is no need to create a wanpipe#.conf - configuration file. - - o Socket based x25api update/bug fixes. - Added support for LCN numbers greater than 255. - Option to pass up modem messages. - Provided a PCI IRQ check, so a single S514 - card is guaranteed to have a non-sharing interrupt. - - o Fixes to the wancfg utility. - o New FT1 debugging support via *pipemon utilities. - o Frame Relay ARP support Enabled. - -beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. - o Added the Multi-Port PPP - Updated utilities for the Multi-Port PPP. - -2.1.4 Aut 2000 - o In X25API: - Maximum packet an application can send - to the driver has been extended to 4096 bytes. - - Fixed the x25 startup bug. Enable - communications only after all interfaces - come up. HIGH SVC/PVC is used to calculate - the number of channels. - Enable protocol only after all interfaces - are enabled. - - o Added an extra state to the FT1 config, kernel module. - o Updated the pipemon debuggers. - - o Blocked the Multi-Port PPP from running on kernels - 2.2.16 or greater, due to syncppp kernel module - change. - -beta1-2.1.5 Nov 15 2000 - o Fixed the MultiPort PPP Support for kernels 2.2.16 and above. - 2.2.X kernels only - - o Secured the driver UDP debugging calls - - All illegal network debugging calls are reported to - the log. - - Defined a set of allowed commands, all other denied. - - o Cpipemon - - Added set FT1 commands to the cpipemon. Thus CSU/DSU - configuration can be performed using cpipemon. - All systems that cannot run cfgft1 GUI utility should - use cpipemon to configure the on board CSU/DSU. - - - o Keyboard Led Monitor/Debugger - - A new utility /usr/sbin/wpkbdmon uses keyboard leds - to convey operational statistic information of the - Sangoma WANPIPE cards. - NUM_LOCK = Line State (On=connected, Off=disconnected) - CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) - SCROLL_LOCK = Rx data (On=receiving, Off=no rx data - - o Hardware probe on module load and dynamic device allocation - - During WANPIPE module load, all Sangoma cards are probed - and found information is printed in the /var/log/messages. - - If no cards are found, the module load fails. - - Appropriate number of devices are dynamically loaded - based on the number of Sangoma cards found. - - Note: The kernel configuration option - CONFIG_WANPIPE_CARDS has been taken out. - - o Fixed the Frame Relay and Chdlc network interfaces so they are - compatible with libpcap libraries. Meaning, tcpdump, snort, - ethereal, and all other packet sniffers and debuggers work on - all WANPIPE network interfaces. - - Set the network interface encoding type to ARPHRD_PPP. - This tell the sniffers that data obtained from the - network interface is in pure IP format. - Fix for 2.2.X kernels only. - - o True interface encoding option for Frame Relay and CHDLC - - The above fix sets the network interface encoding - type to ARPHRD_PPP, however some customers use - the encoding interface type to determine the - protocol running. Therefore, the TURE ENCODING - option will set the interface type back to the - original value. - - NOTE: If this option is used with Frame Relay and CHDLC - libpcap library support will be broken. - i.e. tcpdump will not work. - Fix for 2.2.x Kernels only. - - o Ethernet Bridgind over Frame Relay - - The Frame Relay bridging has been developed by - Kristian Hoffmann and Mark Wells. - - The Linux kernel bridge is used to send ethernet - data over the frame relay links. - For 2.2.X Kernels only. - - o Added extensive 2.0.X support. Most new features of - 2.1.5 for protocols Frame Relay, PPP and CHDLC are - supported under 2.0.X kernels. - -beta1-2.2.0 Dec 30 2000 - o Updated drivers for 2.4.X kernels. - o Updated drivers for SMP support. - o X25API is now able to share PCI interrupts. - o Took out a general polling routine that was used - only by X25API. - o Added appropriate locks to the dynamic reconfiguration - code. - o Fixed a bug in the keyboard debug monitor. - -beta2-2.2.0 Jan 8 2001 - o Patches for 2.4.0 kernel - o Patches for 2.2.18 kernel - o Minor updates to PPP and CHLDC drivers. - Note: No functional difference. - -beta3-2.2.9 Jan 10 2001 - o I missed the 2.2.18 kernel patches in beta2-2.2.0 - release. They are included in this release. - -Stable Release -2.2.0 Feb 01 2001 - o Bug fix in wancfg GUI configurator. - The edit function didn't work properly. - - -bata1-2.2.1 Feb 09 2001 - o WANPIPE TTY Driver emulation. - Two modes of operation Sync and Async. - Sync: Using the PPPD daemon, kernel SyncPPP layer - and the Wanpipe sync TTY driver: a PPP protocol - connection can be established via Sangoma adapter, over - a T1 leased line. - - The 2.4.0 kernel PPP layer supports MULTILINK - protocol, that can be used to bundle any number of Sangoma - adapters (T1 lines) into one, under a single IP address. - Thus, efficiently obtaining multiple T1 throughput. - - NOTE: The remote side must also implement MULTILINK PPP - protocol. - - Async:Using the PPPD daemon, kernel AsyncPPP layer - and the WANPIPE async TTY driver: a PPP protocol - connection can be established via Sangoma adapter and - a modem, over a telephone line. - - Thus, the WANPIPE async TTY driver simulates a serial - TTY driver that would normally be used to interface the - MODEM to the linux kernel. - - o WANPIPE PPP Backup Utility - This utility will monitor the state of the PPP T1 line. - In case of failure, a dial up connection will be established - via pppd daemon, ether via a serial tty driver (serial port), - or a WANPIPE async TTY driver (in case serial port is unavailable). - - Furthermore, while in dial up mode, the primary PPP T1 link - will be monitored for signs of life. - - If the PPP T1 link comes back to life, the dial up connection - will be shutdown and T1 line re-established. - - - o New Setup installation script. - Option to UPGRADE device drivers if the kernel source has - already been patched with WANPIPE. - - Option to COMPILE WANPIPE modules against the currently - running kernel, thus no need for manual kernel and module - re-compilation. - - o Updates and Bug Fixes to wancfg utility. - -bata2-2.2.1 Feb 20 2001 - - o Bug fixes to the CHDLC device drivers. - The driver had compilation problems under kernels - 2.2.14 or lower. - - o Bug fixes to the Setup installation script. - The device drivers compilation options didn't work - properly. - - o Update to the wpbackupd daemon. - Optimized the cross-over times, between the primary - link and the backup dialup. - -beta3-2.2.1 Mar 02 2001 - o Patches for 2.4.2 kernel. - - o Bug fixes to util/ make files. - o Bug fixes to the Setup installation script. - - o Took out the backupd support and made it into - as separate package. - -beta4-2.2.1 Mar 12 2001 - - o Fix to the Frame Relay Device driver. - IPSAC sends a packet of zero length - header to the frame relay driver. The - driver tries to push its own 2 byte header - into the packet, which causes the driver to - crash. - - o Fix the WANPIPE re-configuration code. - Bug was found by trying to run the cfgft1 while the - interface was already running. - - o Updates to cfgft1. - Writes a wanpipe#.cfgft1 configuration file - once the CSU/DSU is configured. This file can - holds the current CSU/DSU configuration. - - - ->>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - diff --git a/include/linux/Kbuild b/include/linux/Kbuild index e56b739d8e23..b3d9ccde0c27 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -231,7 +231,6 @@ unifdef-y += if_pppol2tp.h unifdef-y += if_pppox.h unifdef-y += if_tr.h unifdef-y += if_vlan.h -unifdef-y += if_wanpipe.h unifdef-y += igmp.h unifdef-y += inet_diag.h unifdef-y += in.h diff --git a/include/linux/if_wanpipe.h b/include/linux/if_wanpipe.h deleted file mode 100644 index e594ca6069e5..000000000000 --- a/include/linux/if_wanpipe.h +++ /dev/null @@ -1,124 +0,0 @@ -/***************************************************************************** -* if_wanpipe.h Header file for the Sangoma AF_WANPIPE Socket -* -* Author: Nenad Corbic -* -* Copyright: (c) 2000 Sangoma Technologies 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. -* ============================================================================ -* -* Jan 28, 2000 Nenad Corbic Initial Version -* -*****************************************************************************/ - -#ifndef __LINUX_IF_WAN_PACKET_H -#define __LINUX_IF_WAN_PACKET_H - -struct wan_sockaddr_ll -{ - unsigned short sll_family; - unsigned short sll_protocol; - int sll_ifindex; - unsigned short sll_hatype; - unsigned char sll_pkttype; - unsigned char sll_halen; - unsigned char sll_addr[8]; - unsigned char sll_device[14]; - unsigned char sll_card[14]; -}; - -typedef struct -{ - unsigned char free; - unsigned char state_sk; - int rcvbuf; - int sndbuf; - int rmem; - int wmem; - int sk_count; - unsigned char bound; - char name[14]; - unsigned char d_state; - unsigned char svc; - unsigned short lcn; - unsigned char mbox; - unsigned char cmd_busy; - unsigned char command; - unsigned poll; - unsigned poll_cnt; - int rblock; -} wan_debug_hdr_t; - -#define MAX_NUM_DEBUG 10 -#define X25_PROT 0x16 -#define PVC_PROT 0x17 - -typedef struct -{ - wan_debug_hdr_t debug[MAX_NUM_DEBUG]; -}wan_debug_t; - -#define SIOC_WANPIPE_GET_CALL_DATA (SIOCPROTOPRIVATE + 0) -#define SIOC_WANPIPE_SET_CALL_DATA (SIOCPROTOPRIVATE + 1) -#define SIOC_WANPIPE_ACCEPT_CALL (SIOCPROTOPRIVATE + 2) -#define SIOC_WANPIPE_CLEAR_CALL (SIOCPROTOPRIVATE + 3) -#define SIOC_WANPIPE_RESET_CALL (SIOCPROTOPRIVATE + 4) -#define SIOC_WANPIPE_DEBUG (SIOCPROTOPRIVATE + 5) -#define SIOC_WANPIPE_SET_NONBLOCK (SIOCPROTOPRIVATE + 6) -#define SIOC_WANPIPE_CHECK_TX (SIOCPROTOPRIVATE + 7) -#define SIOC_WANPIPE_SOCK_STATE (SIOCPROTOPRIVATE + 8) - -/* Packet types */ - -#define WAN_PACKET_HOST 0 /* To us */ -#define WAN_PACKET_BROADCAST 1 /* To all */ -#define WAN_PACKET_MULTICAST 2 /* To group */ -#define WAN_PACKET_OTHERHOST 3 /* To someone else */ -#define WAN_PACKET_OUTGOING 4 /* Outgoing of any type */ -/* These ones are invisible by user level */ -#define WAN_PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ -#define WAN_PACKET_FASTROUTE 6 /* Fastrouted frame */ - - -/* X25 specific */ -#define WAN_PACKET_DATA 7 -#define WAN_PACKET_CMD 8 -#define WAN_PACKET_ASYNC 9 -#define WAN_PACKET_ERR 10 - -/* Packet socket options */ - -#define WAN_PACKET_ADD_MEMBERSHIP 1 -#define WAN_PACKET_DROP_MEMBERSHIP 2 - -#define WAN_PACKET_MR_MULTICAST 0 -#define WAN_PACKET_MR_PROMISC 1 -#define WAN_PACKET_MR_ALLMULTI 2 - -#ifdef __KERNEL__ - -/* Private wanpipe socket structures. */ -struct wanpipe_opt -{ - void *mbox; /* Mail box */ - void *card; /* Card bouded to */ - struct net_device *dev; /* Bounded device */ - unsigned short lcn; /* Binded LCN */ - unsigned char svc; /* 0=pvc, 1=svc */ - unsigned char timer; /* flag for delayed transmit*/ - struct timer_list tx_timer; - unsigned poll_cnt; - unsigned char force; /* Used to force sock release */ - atomic_t packet_sent; - unsigned short num; -}; - -#define wp_sk(__sk) ((struct wanpipe_opt *)(__sk)->sk_protinfo) - -#endif - -#endif -- cgit v1.2.3 From 31efdf0530b6351b0658d35a602a0f2d6bc2ed6f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 15 Apr 2008 00:30:16 -0700 Subject: [ISDN] include/linux/isdn.h: remove dead code This patch remove the usage of a nonexisting kconfig variable. Reported-by: Robert P. J. Day Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/linux/isdn.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 9cb2855bb170..44cd663c53b6 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -16,14 +16,8 @@ #include -#ifdef CONFIG_COBALT_MICRO_SERVER -/* Save memory */ -#define ISDN_MAX_DRIVERS 2 -#define ISDN_MAX_CHANNELS 8 -#else #define ISDN_MAX_DRIVERS 32 #define ISDN_MAX_CHANNELS 64 -#endif /* New ioctl-codes */ #define IIOCNETAIF _IO('I',1) -- cgit v1.2.3 From 4ac58469f13028e1eb97f8bc7b0fca5072591d8d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Apr 2008 11:59:00 +0200 Subject: ssb: Fix usage of struct device used for DMAing This fixes DMA on architectures where DMA is nontrivial, like PPC64. We must use the host-device's (PCI) struct device for any DMA operation instead of the SSB device. For this we add a new struct device pointer to the SSB device structure that will always point to the right device for DMAing. Without this patch b43 and b44 drivers won't work on complex-DMA architectures, that for example need dev->archdata for DMA operations. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/b44.c | 52 +++++++++++++++++++++--------------------- drivers/net/wireless/b43/dma.c | 27 +++++++++++----------- drivers/ssb/main.c | 14 +++++++----- include/linux/ssb/ssb.h | 4 ++++ 4 files changed, 52 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 25f1337cd02c..59dce6aa0865 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -148,7 +148,7 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, unsigned long offset, enum dma_data_direction dir) { - dma_sync_single_range_for_device(sdev->dev, dma_base, + dma_sync_single_range_for_device(sdev->dma_dev, dma_base, offset & dma_desc_align_mask, dma_desc_sync_size, dir); } @@ -158,7 +158,7 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, unsigned long offset, enum dma_data_direction dir) { - dma_sync_single_range_for_cpu(sdev->dev, dma_base, + dma_sync_single_range_for_cpu(sdev->dma_dev, dma_base, offset & dma_desc_align_mask, dma_desc_sync_size, dir); } @@ -613,7 +613,7 @@ static void b44_tx(struct b44 *bp) BUG_ON(skb == NULL); - dma_unmap_single(bp->sdev->dev, + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, skb->len, DMA_TO_DEVICE); @@ -653,7 +653,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) if (skb == NULL) return -ENOMEM; - mapping = dma_map_single(bp->sdev->dev, skb->data, + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); @@ -663,19 +663,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dev, mapping, + dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); if (skb == NULL) return -ENOMEM; - mapping = dma_map_single(bp->sdev->dev, skb->data, + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); if (dma_mapping_error(mapping) || mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); dev_kfree_skb_any(skb); return -ENOMEM; } @@ -750,7 +750,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_idx * sizeof(dest_desc), DMA_BIDIRECTIONAL); - dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + dma_sync_single_for_device(bp->sdev->dma_dev, le32_to_cpu(src_desc->addr), RX_PKT_BUF_SZ, DMA_FROM_DEVICE); } @@ -772,7 +772,7 @@ static int b44_rx(struct b44 *bp, int budget) struct rx_header *rh; u16 len; - dma_sync_single_for_cpu(bp->sdev->dev, map, + dma_sync_single_for_cpu(bp->sdev->dma_dev, map, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); rh = (struct rx_header *) skb->data; @@ -806,7 +806,7 @@ static int b44_rx(struct b44 *bp, int budget) skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); if (skb_size < 0) goto drop_it; - dma_unmap_single(bp->sdev->dev, map, + dma_unmap_single(bp->sdev->dma_dev, map, skb_size, DMA_FROM_DEVICE); /* Leave out rx_header */ skb_put(skb, len + RX_PKT_OFFSET); @@ -966,24 +966,24 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_out; } - mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { struct sk_buff *bounce_skb; /* Chip can't handle DMA to/from >1GB, use bounce buffer */ if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dev, mapping, len, + dma_unmap_single(bp->sdev->dma_dev, mapping, len, DMA_TO_DEVICE); bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) goto err_out; - mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, + mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data, len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - dma_unmap_single(bp->sdev->dev, mapping, + dma_unmap_single(bp->sdev->dma_dev, mapping, len, DMA_TO_DEVICE); dev_kfree_skb_any(bounce_skb); goto err_out; @@ -1082,7 +1082,7 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ, + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; @@ -1094,7 +1094,7 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len, + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; @@ -1117,12 +1117,12 @@ static void b44_init_rings(struct b44 *bp) memset(bp->tx_ring, 0, B44_TX_RING_BYTES); if (bp->flags & B44_FLAG_RX_RING_HACK) - dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, + dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma, DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); if (bp->flags & B44_FLAG_TX_RING_HACK) - dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma, DMA_TABLE_BYTES, DMA_TO_DEVICE); @@ -1144,24 +1144,24 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { - dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma, DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); kfree(bp->rx_ring); } else - dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dma_dev, 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) { if (bp->flags & B44_FLAG_TX_RING_HACK) { - dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma, DMA_TABLE_BYTES, DMA_TO_DEVICE); kfree(bp->tx_ring); } else - dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; bp->flags &= ~B44_FLAG_TX_RING_HACK; @@ -1187,7 +1187,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) goto out_err; size = DMA_TABLE_BYTES; - bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp); + bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->rx_ring_dma, gfp); if (!bp->rx_ring) { /* Allocation may have failed due to pci_alloc_consistent insisting on use of GFP_DMA, which is more restrictive @@ -1199,7 +1199,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) if (!rx_ring) goto out_err; - rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring, DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); @@ -1214,7 +1214,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) bp->flags |= B44_FLAG_RX_RING_HACK; } - bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp); + bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, &bp->tx_ring_dma, gfp); if (!bp->tx_ring) { /* Allocation may have failed due to dma_alloc_coherent insisting on use of GFP_DMA, which is more restrictive @@ -1226,7 +1226,7 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) if (!tx_ring) goto out_err; - tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring, DMA_TABLE_BYTES, DMA_TO_DEVICE); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 948eb1fe916b..48e912487b16 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -373,10 +373,10 @@ static inline dma_addr_t dmaaddr; if (tx) { - dmaaddr = dma_map_single(ring->dev->dev->dev, + dmaaddr = dma_map_single(ring->dev->dev->dma_dev, buf, len, DMA_TO_DEVICE); } else { - dmaaddr = dma_map_single(ring->dev->dev->dev, + dmaaddr = dma_map_single(ring->dev->dev->dma_dev, buf, len, DMA_FROM_DEVICE); } @@ -388,9 +388,10 @@ static inline dma_addr_t addr, size_t len, int tx) { if (tx) { - dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE); + dma_unmap_single(ring->dev->dev->dma_dev, + addr, len, DMA_TO_DEVICE); } else { - dma_unmap_single(ring->dev->dev->dev, + dma_unmap_single(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } } @@ -400,7 +401,7 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_cpu(ring->dev->dev->dev, + dma_sync_single_for_cpu(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } @@ -409,7 +410,7 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_device(ring->dev->dev->dev, + dma_sync_single_for_device(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } @@ -425,7 +426,7 @@ static inline static int alloc_ringmemory(struct b43_dmaring *ring) { - struct device *dev = ring->dev->dev->dev; + struct device *dma_dev = ring->dev->dev->dma_dev; gfp_t flags = GFP_KERNEL; /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K @@ -439,7 +440,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring) */ if (ring->type == B43_DMA_64BIT) flags |= GFP_DMA; - ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, + ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE, &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); @@ -452,9 +453,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring) static void free_ringmemory(struct b43_dmaring *ring) { - struct device *dev = ring->dev->dev->dev; + struct device *dma_dev = ring->dev->dev->dma_dev; - dma_free_coherent(dev, B43_DMA_RINGMEMSIZE, + dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE, ring->descbase, ring->dmabase); } @@ -854,7 +855,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->dev->dev, + dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); @@ -869,7 +870,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = dma_map_single(dev->dev->dev, + dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); @@ -883,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } } - dma_unmap_single(dev->dev->dev, + dma_unmap_single(dev->dev->dma_dev, dma_test, b43_txhdr_size(dev), DMA_TO_DEVICE); } diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 72017bf2e577..8003a9e55ac4 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -436,15 +436,18 @@ static int ssb_devices_register(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCIHOST sdev->irq = bus->host_pci->irq; dev->parent = &bus->host_pci->dev; + sdev->dma_dev = &bus->host_pci->dev; #endif break; case SSB_BUSTYPE_PCMCIA: #ifdef CONFIG_SSB_PCMCIAHOST sdev->irq = bus->host_pcmcia->irq.AssignedIRQ; dev->parent = &bus->host_pcmcia->dev; + sdev->dma_dev = &bus->host_pcmcia->dev; #endif break; case SSB_BUSTYPE_SSB: + sdev->dma_dev = dev; break; } @@ -1018,15 +1021,14 @@ EXPORT_SYMBOL(ssb_dma_translation); int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) { - struct device *dev = ssb_dev->dev; + struct device *dma_dev = ssb_dev->dma_dev; #ifdef CONFIG_SSB_PCIHOST - if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && - !dma_supported(dev, mask)) - return -EIO; + if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) + return dma_set_mask(dma_dev, mask); #endif - dev->coherent_dma_mask = mask; - dev->dma_mask = &dev->coherent_dma_mask; + dma_dev->coherent_dma_mask = mask; + dma_dev->dma_mask = &dma_dev->coherent_dma_mask; return 0; } diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 20add65215af..db53defde5ee 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -129,6 +129,10 @@ struct ssb_device { const struct ssb_bus_ops *ops; struct device *dev; + /* Pointer to the device that has to be used for + * any DMA related operation. */ + struct device *dma_dev; + struct ssb_bus *bus; struct ssb_device_id id; -- cgit v1.2.3 From 335e92e8a515420bd47a6b0f01cb9a206c0ed6e4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 15 Apr 2008 14:34:43 -0700 Subject: vfs: fix possible deadlock in ext2, ext3, ext4 when using xattrs mb_cache_entry_alloc() was allocating cache entries with GFP_KERNEL. But filesystems are calling this function while holding xattr_sem so possible recursion into the fs violates locking ordering of xattr_sem and transaction start / i_mutex for ext2-4. Change mb_cache_entry_alloc() so that filesystems can specify desired gfp mask and use GFP_NOFS from all of them. Signed-off-by: Jan Kara Reported-by: Dave Jones Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext2/xattr.c | 2 +- fs/ext3/xattr.c | 2 +- fs/ext4/xattr.c | 2 +- fs/mbcache.c | 4 ++-- include/linux/mbcache.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 3e8683dbb13f..a99d46f3b26e 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -835,7 +835,7 @@ ext2_xattr_cache_insert(struct buffer_head *bh) struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext2_xattr_cache); + ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); if (!ce) return -ENOMEM; error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index a6ea4d6a8bb2..42856541e9a5 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -1126,7 +1126,7 @@ ext3_xattr_cache_insert(struct buffer_head *bh) struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext3_xattr_cache); + ce = mb_cache_entry_alloc(ext3_xattr_cache, GFP_NOFS); if (!ce) { ea_bdebug(bh, "out of memory"); return; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index d7962139c010..e9054c1c7d93 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1386,7 +1386,7 @@ ext4_xattr_cache_insert(struct buffer_head *bh) struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext4_xattr_cache); + ce = mb_cache_entry_alloc(ext4_xattr_cache, GFP_NOFS); if (!ce) { ea_bdebug(bh, "out of memory"); return; diff --git a/fs/mbcache.c b/fs/mbcache.c index eb31b73e7d69..ec88ff3d04a9 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -399,11 +399,11 @@ mb_cache_destroy(struct mb_cache *cache) * if no more memory was available. */ struct mb_cache_entry * -mb_cache_entry_alloc(struct mb_cache *cache) +mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) { struct mb_cache_entry *ce; - ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL); + ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); if (ce) { atomic_inc(&cache->c_entry_count); INIT_LIST_HEAD(&ce->e_lru_list); diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h index 99e044b4efc6..a09b84e4fdb4 100644 --- a/include/linux/mbcache.h +++ b/include/linux/mbcache.h @@ -34,7 +34,7 @@ void mb_cache_destroy(struct mb_cache *); /* Functions on cache entries */ -struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *); +struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *, gfp_t); int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *, sector_t, unsigned int[]); void mb_cache_entry_release(struct mb_cache_entry *); -- cgit v1.2.3 From 5f1a3f2ac4ddf966cd0555dc445c6df65709c580 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 15 Apr 2008 14:34:47 -0700 Subject: acpi thermal trip points increased to 12 The THERMAL_MAX_TRIPS value is set to 10. It is too few for the Compaq AP550 machine which has 12 trip points. Signed-off-by: Krzysztof Helt Cc: Len Brown Cc: Zhang Rui Cc: "Rafael J. Wysocki" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/thermal/thermal.c | 4 ++++ include/linux/thermal.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index 8b86e53ccf7a..7f79bbf652d7 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c @@ -196,6 +196,10 @@ static struct device_attribute trip_point_attrs[] = { __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), + __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL), + __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL), + __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL), + __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL), }; #define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 818ca1cf0b6d..90c1c191ea69 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -50,7 +50,7 @@ struct thermal_cooling_device_ops { }; #define THERMAL_TRIPS_NONE -1 -#define THERMAL_MAX_TRIPS 10 +#define THERMAL_MAX_TRIPS 12 #define THERMAL_NAME_LENGTH 20 struct thermal_cooling_device { int id; -- cgit v1.2.3 From a9fde2607895667823e9d1172fc193087125ef68 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:48:04 -0700 Subject: [VLAN]: Tag vlan_group_device with net device, not ifindex. Currently vlan group is searched using one key - the ifindex. We'll have to lookup the vlan_group by two keys - ifindex and net. Turning the vlan_group lookup key to struct net_device pointer will make this process easier. Besides, this will eliminate one more place in the networking, that assumes that indexes are unique in the kernel. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 4 +++- net/8021q/vlan.c | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index edd55af7ebd6..15ace02b7b24 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -81,7 +81,9 @@ extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS) struct vlan_group { - int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */ + struct net_device *real_dev; /* The ethernet(like) device + * the vlan is attached to. + */ unsigned int nr_vlans; struct hlist_node hlist; /* linked list */ struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 5975ec3be7f3..cf8d810a130d 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -65,14 +65,14 @@ static inline unsigned int vlan_grp_hashfn(unsigned int idx) } /* Must be invoked with RCU read lock (no preempt) */ -static struct vlan_group *__vlan_find_group(int real_dev_ifindex) +static struct vlan_group *__vlan_find_group(struct net_device *real_dev) { struct vlan_group *grp; struct hlist_node *n; - int hash = vlan_grp_hashfn(real_dev_ifindex); + int hash = vlan_grp_hashfn(real_dev->ifindex); hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) { - if (grp->real_dev_ifindex == real_dev_ifindex) + if (grp->real_dev == real_dev) return grp; } @@ -86,7 +86,7 @@ static struct vlan_group *__vlan_find_group(int real_dev_ifindex) struct net_device *__find_vlan_dev(struct net_device *real_dev, unsigned short VID) { - struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); + struct vlan_group *grp = __vlan_find_group(real_dev); if (grp) return vlan_group_get_device(grp, VID); @@ -103,7 +103,7 @@ static void vlan_group_free(struct vlan_group *grp) kfree(grp); } -static struct vlan_group *vlan_group_alloc(int ifindex) +static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) { struct vlan_group *grp; @@ -111,9 +111,9 @@ static struct vlan_group *vlan_group_alloc(int ifindex) if (!grp) return NULL; - grp->real_dev_ifindex = ifindex; + grp->real_dev = real_dev; hlist_add_head_rcu(&grp->hlist, - &vlan_group_hash[vlan_grp_hashfn(ifindex)]); + &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]); return grp; } @@ -151,7 +151,7 @@ void unregister_vlan_dev(struct net_device *dev) ASSERT_RTNL(); - grp = __vlan_find_group(real_dev->ifindex); + grp = __vlan_find_group(real_dev); BUG_ON(!grp); vlan_proc_rem_dev(dev); @@ -246,9 +246,9 @@ int register_vlan_dev(struct net_device *dev) struct vlan_group *grp, *ngrp = NULL; int err; - grp = __vlan_find_group(real_dev->ifindex); + grp = __vlan_find_group(real_dev); if (!grp) { - ngrp = grp = vlan_group_alloc(real_dev->ifindex); + ngrp = grp = vlan_group_alloc(real_dev); if (!grp) return -ENOBUFS; } @@ -412,7 +412,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, goto out; } - grp = __vlan_find_group(dev->ifindex); + grp = __vlan_find_group(dev); if (!grp) goto out; -- cgit v1.2.3 From f3005d7f4abe03ad41af33b1548602cd086d86a2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:02:18 -0700 Subject: [NETNS]: Add netns refcnt debug for network devices. dev_set_net is called for - just allocated devices - devices moving from one namespace to another release_net has proper check inside to distinguish these cases. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 ++- net/core/dev.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8b17ed40dea2..7c1d4466583b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -758,7 +758,8 @@ static inline void dev_net_set(struct net_device *dev, struct net *net) { #ifdef CONFIG_NET_NS - dev->nd_net = net; + release_net(dev->nd_net); + dev->nd_net = hold_net(net); #endif } diff --git a/net/core/dev.c b/net/core/dev.c index 7aa01125287e..77530e9a34fc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4042,6 +4042,8 @@ EXPORT_SYMBOL(alloc_netdev_mq); */ void free_netdev(struct net_device *dev) { + release_net(dev_net(dev)); + /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); -- cgit v1.2.3 From 9d9326d3bc0ea9a8bbe40bf3e5e66c7b9858caa0 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Wed, 9 Apr 2008 19:38:13 -0500 Subject: phy: Change mii_bus id field to a string Having the id field be an int was making more complex bus topologies excessively difficult. For now, just convert it to a string, and change all instances of "bus->id = val" to snprintf(id, MII_BUS_ID_LEN, "%x", val). Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- arch/powerpc/platforms/82xx/ep8248e.c | 2 +- arch/powerpc/platforms/pasemi/gpio_mdio.c | 2 +- arch/powerpc/sysdev/fsl_soc.c | 5 +++-- drivers/net/au1000_eth.c | 6 +++--- drivers/net/bfin_mac.c | 2 +- drivers/net/cpmac.c | 5 ++--- drivers/net/fec_mpc52xx.c | 2 +- drivers/net/fec_mpc52xx_phy.c | 2 +- drivers/net/fs_enet/fs_enet-main.c | 4 ++-- drivers/net/fs_enet/mii-bitbang.c | 4 ++-- drivers/net/fs_enet/mii-fec.c | 4 ++-- drivers/net/gianfar_mii.c | 2 +- drivers/net/macb.c | 2 +- drivers/net/pasemi_mac.c | 2 +- drivers/net/phy/fixed.c | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/net/ucc_geth.c | 2 +- drivers/net/ucc_geth.h | 2 +- drivers/net/ucc_geth_mii.c | 2 +- include/linux/fsl_devices.h | 2 +- include/linux/phy.h | 12 ++++++++---- 21 files changed, 36 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index ba93d8ae9b0c..d5770fdf7f09 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -138,7 +138,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, bus->name = "ep8248e-mdio-bitbang"; bus->dev = &ofdev->dev; - bus->id = res.start; + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); return mdiobus_register(bus); } diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index b46542990cf8..ab6955412ba4 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -241,7 +241,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->reset = &gpio_mdio_reset; prop = of_get_property(np, "reg", NULL); - new_bus->id = *prop; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop); new_bus->priv = priv; new_bus->phy_mask = 0; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 2c5388ce902a..3581416905ea 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -341,7 +341,7 @@ static int __init gfar_of_init(void) goto unreg; } - gfar_data.bus_id = 0; + snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); gfar_data.phy_id = fixed_link[0]; } else { phy = of_find_node_by_phandle(*ph); @@ -362,7 +362,8 @@ static int __init gfar_of_init(void) } gfar_data.phy_id = *id; - gfar_data.bus_id = res.start; + snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%x", + res.start); of_node_put(phy); of_node_put(mdio); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 504b7ce2747d..3634b5fd7919 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -701,7 +701,7 @@ static struct net_device * au1000_probe(int port_num) aup->mii_bus.write = mdiobus_write; aup->mii_bus.reset = mdiobus_reset; aup->mii_bus.name = "au1000_eth_mii"; - aup->mii_bus.id = aup->mac_id; + snprintf(aup->mii_bus.id, MII_BUS_ID_SIZE, "%x", aup->mac_id); aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for(i = 0; i < PHY_MAX_ADDR; ++i) aup->mii_bus.irq[i] = PHY_POLL; @@ -709,11 +709,11 @@ static struct net_device * au1000_probe(int port_num) /* if known, set corresponding PHY IRQs */ #if defined(AU1XXX_PHY_STATIC_CONFIG) # if defined(AU1XXX_PHY0_IRQ) - if (AU1XXX_PHY0_BUSID == aup->mii_bus.id) + if (AU1XXX_PHY0_BUSID == aup->mac_id) aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ; # endif # if defined(AU1XXX_PHY1_IRQ) - if (AU1XXX_PHY1_BUSID == aup->mii_bus.id) + if (AU1XXX_PHY1_BUSID == aup->mac_id) aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ; # endif #endif diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 26b2dd5016cd..717dcc1aa1e9 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -969,7 +969,7 @@ static int __init bf537mac_probe(struct net_device *dev) lp->mii_bus.write = mdiobus_write; lp->mii_bus.reset = mdiobus_reset; lp->mii_bus.name = "bfin_mac_mdio"; - lp->mii_bus.id = 0; + snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "0"); lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for (i = 0; i < PHY_MAX_ADDR; ++i) lp->mii_bus.irq[i] = PHY_POLL; diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index c85194f2cd2d..9da7ff437031 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -987,7 +987,7 @@ static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { int rc, phy_id, i; - int mdio_bus_id = cpmac_mii.id; + char *mdio_bus_id = "0"; struct resource *mem; struct cpmac_priv *priv; struct net_device *dev; @@ -1008,8 +1008,6 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (external_switch || dumb_switch) { struct fixed_phy_status status = {}; - mdio_bus_id = 0; - /* * FIXME: this should be in the platform code! * Since there is not platform code at all (that is, @@ -1143,6 +1141,7 @@ int __devinit cpmac_init(void) } cpmac_mii.phy_mask = ~(mask | 0x80000000); + snprintf(cpmac_mii.id, MII_BUS_ID_SIZE, "0"); res = mdiobus_register(&cpmac_mii); if (res) diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 58b71e60204e..43b5f30743c2 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -198,7 +198,7 @@ static int mpc52xx_fec_init_phy(struct net_device *dev) struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, + snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", (unsigned int)dev->base_addr, priv->phy_addr); priv->link = PHY_DOWN; diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index 6a3ac4ea97e9..956836fc5ec0 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -124,7 +124,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i goto out_free; } - bus->id = res.start; + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); bus->priv = priv; bus->dev = dev; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 940e2041ba38..67b4b0728fce 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -1178,7 +1178,7 @@ static int __devinit find_phy(struct device_node *np, data = of_get_property(np, "fixed-link", NULL); if (data) { - snprintf(fpi->bus_id, 16, PHY_ID_FMT, 0, *data); + snprintf(fpi->bus_id, 16, "%x:%02x", 0, *data); return 0; } @@ -1202,7 +1202,7 @@ static int __devinit find_phy(struct device_node *np, if (!data || len != 4) goto out_put_mdio; - snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data); + snprintf(fpi->bus_id, 16, "%x:%02x", res.start, *data); out_put_mdio: of_node_put(mdionode); diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index b8e4a736a130..1620030cd33c 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -130,7 +130,7 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, * we get is an int, and the odds of multiple bitbang mdio buses * is low enough that it's not worth going too crazy. */ - bus->id = res.start; + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); data = of_get_property(np, "fsl,mdio-pin", &len); if (!data || len != 4) @@ -307,7 +307,7 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) return -ENOMEM; new_bus->name = "BB MII Bus", - new_bus->id = pdev->id; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); new_bus->phy_mask = ~0x9; pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data; diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index a89cf15090b8..ba75efc9f5b5 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -196,7 +196,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (ret) return ret; - new_bus->id = res.start; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); fec->fecp = ioremap(res.start, res.end - res.start + 1); if (!fec->fecp) @@ -309,7 +309,7 @@ static int __devinit fs_enet_fec_mdio_probe(struct device *dev) new_bus->read = &fs_enet_fec_mii_read, new_bus->write = &fs_enet_fec_mii_write, new_bus->reset = &fs_enet_fec_mii_reset, - new_bus->id = pdev->id; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data; diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 24327629bf03..b8898927236a 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -173,7 +173,7 @@ int gfar_mdio_probe(struct device *dev) new_bus->read = &gfar_mdio_read, new_bus->write = &gfar_mdio_write, new_bus->reset = &gfar_mdio_reset, - new_bus->id = pdev->id; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 489c7c3b90d9..d513bb8a4902 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -246,7 +246,7 @@ static int macb_mii_init(struct macb *bp) bp->mii_bus.read = &macb_mdio_read; bp->mii_bus.write = &macb_mdio_write; bp->mii_bus.reset = &macb_mdio_reset; - bp->mii_bus.id = bp->pdev->id; + snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); bp->mii_bus.priv = bp; bp->mii_bus.dev = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 2e39e0285d8f..bcd7f9814ed8 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1012,7 +1012,7 @@ static int pasemi_mac_phy_init(struct net_device *dev) goto err; phy_id = *prop; - snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id); + snprintf(mac->phy_id, BUS_ID_SIZE, "%x:%02x", (int)r.start, phy_id); of_node_put(phy_dn); diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index ca9b040f9ad9..4e07956a483b 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -213,7 +213,7 @@ static int __init fixed_mdio_bus_init(void) goto err_pdev; } - fmb->mii_bus.id = 0; + snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0"); fmb->mii_bus.name = "Fixed MDIO Bus"; fmb->mii_bus.dev = &pdev->dev; fmb->mii_bus.read = &fixed_mdio_read; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7b53d658e337..888b7dec9866 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2374,7 +2374,7 @@ static int sbmac_init(struct platform_device *pldev, long long base) dev->name, base, print_mac(mac, eaddr)); sc->mii_bus.name = sbmac_mdio_string; - sc->mii_bus.id = idx; + snprintf(sc->mii_bus.id, MII_BUS_ID_SIZE, "%x", idx); sc->mii_bus.priv = sc; sc->mii_bus.read = sbmac_mii_read; sc->mii_bus.write = sbmac_mii_write; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 0ee4c168e4c0..29a4d650e8a8 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3954,7 +3954,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma if (err) return -1; - ug_info->mdio_bus = res.start; + snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", res.start); } /* get the phy interface type, or default to MII */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 4fb95b3af948..9f8b7580a3a4 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1156,7 +1156,7 @@ struct ucc_geth_info { u16 pausePeriod; u16 extensionField; u8 phy_address; - u32 mdio_bus; + char mdio_bus[MII_BUS_ID_SIZE]; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index c69e654d539f..e4d3f330bac3 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -157,7 +157,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma if (err) goto reg_map_fail; - new_bus->id = res.start; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 1831b196c70a..2cad5c67397e 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -50,7 +50,7 @@ struct gianfar_platform_data { u32 device_flags; /* board specific information */ u32 board_flags; - u32 bus_id; + char bus_id[MII_BUS_ID_SIZE]; u32 phy_id; u8 mac_addr[6]; phy_interface_t interface; diff --git a/include/linux/phy.h b/include/linux/phy.h index 5e43ae751412..6509f377bb10 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -63,8 +63,6 @@ typedef enum { PHY_INTERFACE_MODE_RTBI } phy_interface_t; -#define MII_BUS_MAX 4 - #define PHY_INIT_TIMEOUT 100000 #define PHY_STATE_TIME 1 @@ -74,13 +72,19 @@ typedef enum { #define PHY_MAX_ADDR 32 /* Used when trying to connect to a specific phy (mii bus id:phy device id) */ -#define PHY_ID_FMT "%x:%02x" +#define PHY_ID_FMT "%s:%02x" + +/* + * Need to be a little smaller than phydev->dev.bus_id to leave room + * for the ":%02x" + */ +#define MII_BUS_ID_SIZE (BUS_ID_SIZE - 3) /* The Bus class for PHYs. Devices which provide access to * PHYs should register using this structure */ struct mii_bus { const char *name; - int id; + char id[MII_BUS_ID_SIZE]; void *priv; int (*read)(struct mii_bus *bus, int phy_id, int regnum); int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val); -- cgit v1.2.3 From c5e38a949bfa11d10f73927fbf4fe66b73bc3001 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Wed, 9 Apr 2008 19:38:27 -0500 Subject: phy: Clean up header style Multi-line comments weren't all CodingStyle compliant Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- include/linux/phy.h | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/phy.h b/include/linux/phy.h index 6509f377bb10..2d838448415c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -39,7 +39,8 @@ SUPPORTED_1000baseT_Half | \ SUPPORTED_1000baseT_Full) -/* Set phydev->irq to PHY_POLL if interrupts are not supported, +/* + * Set phydev->irq to PHY_POLL if interrupts are not supported, * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if * the attached driver handles the interrupt */ @@ -80,8 +81,10 @@ typedef enum { */ #define MII_BUS_ID_SIZE (BUS_ID_SIZE - 3) -/* The Bus class for PHYs. Devices which provide access to - * PHYs should register using this structure */ +/* + * The Bus class for PHYs. Devices which provide access to + * PHYs should register using this structure + */ struct mii_bus { const char *name; char id[MII_BUS_ID_SIZE]; @@ -90,8 +93,10 @@ struct mii_bus { int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val); int (*reset)(struct mii_bus *bus); - /* A lock to ensure that only one thing can read/write - * the MDIO bus at a time */ + /* + * A lock to ensure that only one thing can read/write + * the MDIO bus at a time + */ struct mutex mdio_lock; struct device *dev; @@ -102,8 +107,10 @@ struct mii_bus { /* Phy addresses to be ignored when probing */ u32 phy_mask; - /* Pointer to an array of interrupts, each PHY's - * interrupt at the index matching its address */ + /* + * Pointer to an array of interrupts, each PHY's + * interrupt at the index matching its address + */ int *irq; }; @@ -255,7 +262,8 @@ struct phy_device { /* Bus address of the PHY (0-32) */ int addr; - /* forced speed & duplex (no autoneg) + /* + * forced speed & duplex (no autoneg) * partner speed & duplex & pause (autoneg) */ int speed; @@ -278,8 +286,10 @@ struct phy_device { int link_timeout; - /* Interrupt number for this PHY - * -1 means no interrupt */ + /* + * Interrupt number for this PHY + * -1 means no interrupt + */ int irq; /* private data pointer */ @@ -329,22 +339,28 @@ struct phy_driver { u32 features; u32 flags; - /* Called to initialize the PHY, - * including after a reset */ + /* + * Called to initialize the PHY, + * including after a reset + */ int (*config_init)(struct phy_device *phydev); - /* Called during discovery. Used to set - * up device-specific structures, if any */ + /* + * Called during discovery. Used to set + * up device-specific structures, if any + */ int (*probe)(struct phy_device *phydev); /* PHY Power Management */ int (*suspend)(struct phy_device *phydev); int (*resume)(struct phy_device *phydev); - /* Configures the advertisement and resets + /* + * Configures the advertisement and resets * autonegotiation if phydev->autoneg is on, * forces the speed to the current settings in phydev - * if phydev->autoneg is off */ + * if phydev->autoneg is off + */ int (*config_aneg)(struct phy_device *phydev); /* Determines the negotiated speed and duplex */ -- cgit v1.2.3 From 37608eea86a358ac6a18df0af55d4f77d08a1f30 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 16 Apr 2008 21:01:08 -0700 Subject: mlx4_core: Fix confusion between mlx4_event and mlx4_dev_event enums The struct mlx4_interface.event() method was supposed to get an enum mlx4_dev_event, but the driver code was actually passing in the hardware enum mlx4_event values. Fix up the callers of mlx4_dispatch_event() so that they pass in the right type of value, and fix up the event method in mlx4_ib so that it can handle the enum mlx4_dev_event values. This eliminates the need for the subtype parameter to the event method, so remove it. This also fixes the sparse warning drivers/net/mlx4/intf.c:127:48: warning: mixing different enum types drivers/net/mlx4/intf.c:127:48: int enum mlx4_event versus drivers/net/mlx4/intf.c:127:48: int enum mlx4_dev_event Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 14 ++++++++------ drivers/net/mlx4/catas.c | 2 +- drivers/net/mlx4/eq.c | 5 ++++- drivers/net/mlx4/intf.c | 8 ++------ drivers/net/mlx4/mlx4.h | 4 ++-- include/linux/mlx4/driver.h | 3 +-- 6 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 96a39b5c9254..d5512011999c 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -675,18 +675,20 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) } static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, - enum mlx4_dev_event event, int subtype, - int port) + enum mlx4_dev_event event, int port) { struct ib_event ibev; switch (event) { - case MLX4_EVENT_TYPE_PORT_CHANGE: - ibev.event = subtype == MLX4_PORT_CHANGE_SUBTYPE_ACTIVE ? - IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; + case MLX4_DEV_EVENT_PORT_UP: + ibev.event = IB_EVENT_PORT_ACTIVE; break; - case MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR: + case MLX4_DEV_EVENT_PORT_DOWN: + ibev.event = IB_EVENT_PORT_ERR; + break; + + case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: ibev.event = IB_EVENT_DEVICE_FATAL; break; diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c index 6b32ec94b3a8..aa9528779044 100644 --- a/drivers/net/mlx4/catas.c +++ b/drivers/net/mlx4/catas.c @@ -69,7 +69,7 @@ static void poll_catas(unsigned long dev_ptr) if (readl(priv->catas_err.map)) { dump_err_buf(dev); - mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0); + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); if (internal_err_reset) { spin_lock(&catas_lock); diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 9c36c2034030..e141a1513f07 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -202,7 +202,10 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) break; case MLX4_EVENT_TYPE_PORT_CHANGE: - mlx4_dispatch_event(dev, eqe->type, eqe->subtype, + mlx4_dispatch_event(dev, + eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_ACTIVE ? + MLX4_DEV_EVENT_PORT_UP : + MLX4_DEV_EVENT_PORT_DOWN, be32_to_cpu(eqe->event.port_change.port) >> 28); break; diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c index be5d9e90ccf2..4a6c4d526f1b 100644 --- a/drivers/net/mlx4/intf.c +++ b/drivers/net/mlx4/intf.c @@ -30,8 +30,6 @@ * SOFTWARE. */ -#include - #include "mlx4.h" struct mlx4_device_context { @@ -113,8 +111,7 @@ void mlx4_unregister_interface(struct mlx4_interface *intf) } EXPORT_SYMBOL_GPL(mlx4_unregister_interface); -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, - int subtype, int port) +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_device_context *dev_ctx; @@ -124,8 +121,7 @@ void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, list_for_each_entry(dev_ctx, &priv->ctx_list, list) if (dev_ctx->intf->event) - dev_ctx->intf->event(dev, dev_ctx->context, type, - subtype, port); + dev_ctx->intf->event(dev, dev_ctx->context, type, port); spin_unlock_irqrestore(&priv->ctx_lock, flags); } diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 53a1cdddfc13..73336810e652 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -42,6 +42,7 @@ #include #include +#include #include #define DRV_NAME "mlx4_core" @@ -313,8 +314,7 @@ void mlx4_catas_cleanup(void); int mlx4_restart_one(struct pci_dev *pdev); int mlx4_register_device(struct mlx4_dev *dev); void mlx4_unregister_device(struct mlx4_dev *dev); -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, - int subtype, int port); +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port); struct mlx4_dev_cap; struct mlx4_init_hca_param; diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h index 1b835ca49df1..53c5fdb6eac4 100644 --- a/include/linux/mlx4/driver.h +++ b/include/linux/mlx4/driver.h @@ -48,8 +48,7 @@ struct mlx4_interface { void * (*add) (struct mlx4_dev *dev); void (*remove)(struct mlx4_dev *dev, void *context); void (*event) (struct mlx4_dev *dev, void *context, - enum mlx4_dev_event event, int subtype, - int port); + enum mlx4_dev_event event, int port); struct list_head list; }; -- cgit v1.2.3 From 8ff095ec4bce7be943beff3b330562e2f0e42167 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 16 Apr 2008 21:01:10 -0700 Subject: IB/mlx4: Add IPoIB checksum offload support ConnectX devices support checksum generation and verification of TCP and UDP packets for UD IPoIB messages. This patch checks if the HCA supports this and sets the IB_DEVICE_UD_IP_CSUM capability flag if it does. It implements support for handling the IB_SEND_IP_CSUM send flag and setting the csum_ok field in receive work completions. Signed-off-by: Eli Cohen Signed-off-by: Ali Ayub Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/cq.c | 16 ++++++++++++++++ drivers/infiniband/hw/mlx4/main.c | 2 ++ drivers/infiniband/hw/mlx4/qp.c | 3 +++ drivers/net/mlx4/fw.c | 4 ++++ include/linux/mlx4/cq.h | 14 ++++++++++++-- include/linux/mlx4/qp.h | 10 ++++++---- 6 files changed, 43 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 7360bbafbe84..d2e32b03e2f7 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -297,6 +297,20 @@ static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe, wc->vendor_err = cqe->vendor_err_syndrome; } +static int mlx4_ib_ipoib_csum_ok(__be32 status, __be16 checksum) +{ + return ((status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | + MLX4_CQE_IPOIB_STATUS_IPV4F | + MLX4_CQE_IPOIB_STATUS_IPV4OPT | + MLX4_CQE_IPOIB_STATUS_IPV6 | + MLX4_CQE_IPOIB_STATUS_IPOK)) == + cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | + MLX4_CQE_IPOIB_STATUS_IPOK)) && + (status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_UDP | + MLX4_CQE_IPOIB_STATUS_TCP)) && + checksum == cpu_to_be16(0xffff); +} + static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_ib_qp **cur_qp, struct ib_wc *wc) @@ -434,6 +448,8 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; + wc->csum_ok = mlx4_ib_ipoib_csum_ok(cqe->ipoib_status, + cqe->checksum); } return 0; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index d5512011999c..6ea4746c2e9b 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -99,6 +99,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT) props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & 0xffffff; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index ac965ab28845..31b2b5b230bd 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1436,6 +1436,9 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | (wr->send_flags & IB_SEND_SOLICITED ? cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) | + ((wr->send_flags & IB_SEND_IP_CSUM) ? + cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | + MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) | qp->sq_signal_bits; if (wr->opcode == IB_WR_SEND_WITH_IMM || diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 61dc4951d6b0..f494c3e8bce3 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -696,6 +696,10 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) /* Check port for UD address vector: */ *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); + /* Enable IPoIB checksumming if we can: */ + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); + /* QPC/EEC/CQC/EQC/RDMARC attributes */ MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index 0181e0a57cbf..1243ebace561 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -45,11 +45,11 @@ struct mlx4_cqe { u8 sl; u8 reserved1; __be16 rlid; - u32 reserved2; + __be32 ipoib_status; __be32 byte_cnt; __be16 wqe_index; __be16 checksum; - u8 reserved3[3]; + u8 reserved2[3]; u8 owner_sr_opcode; }; @@ -85,6 +85,16 @@ enum { MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, }; +enum { + MLX4_CQE_IPOIB_STATUS_IPV4 = 1 << 22, + MLX4_CQE_IPOIB_STATUS_IPV4F = 1 << 23, + MLX4_CQE_IPOIB_STATUS_IPV6 = 1 << 24, + MLX4_CQE_IPOIB_STATUS_IPV4OPT = 1 << 25, + MLX4_CQE_IPOIB_STATUS_TCP = 1 << 26, + MLX4_CQE_IPOIB_STATUS_UDP = 1 << 27, + MLX4_CQE_IPOIB_STATUS_IPOK = 1 << 28, +}; + static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd, void __iomem *uar_page, spinlock_t *doorbell_lock) diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 09a2230923f2..31f9eb3ccbb3 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -158,10 +158,12 @@ struct mlx4_qp_context { #define MLX4_FW_VER_WQE_CTRL_NEC mlx4_fw_ver(2, 2, 232) enum { - MLX4_WQE_CTRL_NEC = 1 << 29, - MLX4_WQE_CTRL_FENCE = 1 << 6, - MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, - MLX4_WQE_CTRL_SOLICITED = 1 << 1, + MLX4_WQE_CTRL_NEC = 1 << 29, + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICITED = 1 << 1, + MLX4_WQE_CTRL_IP_CSUM = 1 << 4, + MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, }; struct mlx4_wqe_ctrl_seg { -- cgit v1.2.3 From b832be1e4007f4a54954ec68bd865ff05d6babca Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 16 Apr 2008 21:09:27 -0700 Subject: IB/mlx4: Add IPoIB LSO support Add TSO support to the mlx4_ib driver. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/cq.c | 3 ++ drivers/infiniband/hw/mlx4/main.c | 2 + drivers/infiniband/hw/mlx4/mlx4_ib.h | 5 +++ drivers/infiniband/hw/mlx4/qp.c | 72 +++++++++++++++++++++++++++++++----- drivers/net/mlx4/fw.c | 9 +++++ drivers/net/mlx4/fw.h | 1 + drivers/net/mlx4/main.c | 1 + include/linux/mlx4/device.h | 1 + include/linux/mlx4/qp.h | 5 +++ 9 files changed, 90 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index d2e32b03e2f7..7d70af7952b0 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -420,6 +420,9 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, case MLX4_OPCODE_BIND_MW: wc->opcode = IB_WC_BIND_MW; break; + case MLX4_OPCODE_LSO: + wc->opcode = IB_WC_LSO; + break; } } else { wc->byte_len = be32_to_cpu(cqe->byte_cnt); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 6ea4746c2e9b..e9330a0d6c03 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -101,6 +101,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; + if (dev->dev->caps.max_gso_sz) + props->device_cap_flags |= IB_DEVICE_UD_TSO; props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & 0xffffff; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 3726e451a327..3f8bd0a37b96 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -110,6 +110,10 @@ struct mlx4_ib_wq { unsigned tail; }; +enum mlx4_ib_qp_flags { + MLX4_IB_QP_LSO = 1 << 0 +}; + struct mlx4_ib_qp { struct ib_qp ibqp; struct mlx4_qp mqp; @@ -129,6 +133,7 @@ struct mlx4_ib_qp { struct mlx4_mtt mtt; int buf_size; struct mutex mutex; + u32 flags; u8 port; u8 alt_port; u8 atomic_rd_en; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 320c25fa74b1..2ba243084089 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -71,6 +71,7 @@ enum { static const __be32 mlx4_ib_opcode[] = { [IB_WR_SEND] = __constant_cpu_to_be32(MLX4_OPCODE_SEND), + [IB_WR_LSO] = __constant_cpu_to_be32(MLX4_OPCODE_LSO), [IB_WR_SEND_WITH_IMM] = __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM), [IB_WR_RDMA_WRITE] = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE), [IB_WR_RDMA_WRITE_WITH_IMM] = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM), @@ -242,7 +243,7 @@ static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) } } -static int send_wqe_overhead(enum ib_qp_type type) +static int send_wqe_overhead(enum ib_qp_type type, u32 flags) { /* * UD WQEs must have a datagram segment. @@ -253,7 +254,8 @@ static int send_wqe_overhead(enum ib_qp_type type) switch (type) { case IB_QPT_UD: return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_datagram_seg); + sizeof (struct mlx4_wqe_datagram_seg) + + ((flags & MLX4_IB_QP_LSO) ? 64 : 0); case IB_QPT_UC: return sizeof (struct mlx4_wqe_ctrl_seg) + sizeof (struct mlx4_wqe_raddr_seg); @@ -315,7 +317,7 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, /* Sanity check SQ size before proceeding */ if (cap->max_send_wr > dev->dev->caps.max_wqes || cap->max_send_sge > dev->dev->caps.max_sq_sg || - cap->max_inline_data + send_wqe_overhead(type) + + cap->max_inline_data + send_wqe_overhead(type, qp->flags) + sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) return -EINVAL; @@ -329,7 +331,7 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, s = max(cap->max_send_sge * sizeof (struct mlx4_wqe_data_seg), cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) + - send_wqe_overhead(type); + send_wqe_overhead(type, qp->flags); /* * Hermon supports shrinking WQEs, such that a single work @@ -394,7 +396,8 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, } qp->sq.max_gs = ((qp->sq_max_wqes_per_wr << qp->sq.wqe_shift) - - send_wqe_overhead(type)) / sizeof (struct mlx4_wqe_data_seg); + send_wqe_overhead(type, qp->flags)) / + sizeof (struct mlx4_wqe_data_seg); qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + (qp->sq.wqe_cnt << qp->sq.wqe_shift); @@ -503,6 +506,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, } else { qp->sq_no_prefetch = 0; + if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) + qp->flags |= MLX4_IB_QP_LSO; + err = set_kernel_sq_size(dev, &init_attr->cap, init_attr->qp_type, qp); if (err) goto err; @@ -673,7 +679,11 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, struct mlx4_ib_qp *qp; int err; - if (init_attr->create_flags) + /* We only support LSO, and only for kernel UD QPs. */ + if (init_attr->create_flags & ~IB_QP_CREATE_IPOIB_UD_LSO) + return ERR_PTR(-EINVAL); + if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO && + (pd->uobject || init_attr->qp_type != IB_QPT_UD)) return ERR_PTR(-EINVAL); switch (init_attr->qp_type) { @@ -879,10 +889,15 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, } } - if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || - ibqp->qp_type == IB_QPT_UD) + if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; - else if (attr_mask & IB_QP_PATH_MTU) { + else if (ibqp->qp_type == IB_QPT_UD) { + if (qp->flags & MLX4_IB_QP_LSO) + context->mtu_msgmax = (IB_MTU_4096 << 5) | + ilog2(dev->dev->caps.max_gso_sz); + else + context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; + } else if (attr_mask & IB_QP_PATH_MTU) { if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { printk(KERN_ERR "path MTU (%u) is invalid\n", attr->path_mtu); @@ -1399,6 +1414,34 @@ static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) dseg->addr = cpu_to_be64(sg->addr); } +static int build_lso_seg(struct mlx4_lso_seg *wqe, struct ib_send_wr *wr, + struct mlx4_ib_qp *qp, unsigned *lso_seg_len) +{ + unsigned halign = ALIGN(sizeof *wqe + wr->wr.ud.hlen, 16); + + /* + * This is a temporary limitation and will be removed in + * a forthcoming FW release: + */ + if (unlikely(halign > 64)) + return -EINVAL; + + if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) && + wr->num_sge > qp->sq.max_gs - (halign >> 4))) + return -EINVAL; + + memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen); + + /* make sure LSO header is written before overwriting stamping */ + wmb(); + + wqe->mss_hdr_size = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 | + wr->wr.ud.hlen); + + *lso_seg_len = halign; + return 0; +} + int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -1412,6 +1455,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, unsigned ind; int uninitialized_var(stamp); int uninitialized_var(size); + unsigned seglen; int i; spin_lock_irqsave(&qp->sq.lock, flags); @@ -1490,6 +1534,16 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, set_datagram_seg(wqe, wr); wqe += sizeof (struct mlx4_wqe_datagram_seg); size += sizeof (struct mlx4_wqe_datagram_seg) / 16; + + if (wr->opcode == IB_WR_LSO) { + err = build_lso_seg(wqe, wr, qp, &seglen); + if (unlikely(err)) { + *bad_wr = wr; + goto out; + } + wqe += seglen; + size += seglen / 16; + } break; case IB_QPT_SMI: diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index f494c3e8bce3..d82f2751d2c7 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -133,6 +133,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 #define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 #define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b +#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d #define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f #define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 #define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 @@ -215,6 +216,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->max_requester_per_qp = 1 << (field & 0x3f); MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); dev_cap->max_responder_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); + field &= 0x1f; + if (!field) + dev_cap->max_gso_sz = 0; + else + dev_cap->max_gso_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); dev_cap->max_rdma_global = 1 << (field & 0x3f); MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); @@ -377,6 +385,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); + mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); dump_dev_cap_flags(dev, dev_cap->flags); diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index e16dec890413..306cb9b0242d 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h @@ -96,6 +96,7 @@ struct mlx4_dev_cap { u8 bmme_flags; u32 reserved_lkey; u64 max_icm_sz; + int max_gso_sz; }; struct mlx4_adapter { diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 08bfc130a33e..7cfbe75114d1 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -159,6 +159,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); dev->caps.flags = dev_cap->flags; dev->caps.stat_rate_support = dev_cap->stat_rate_support; + dev->caps.max_gso_sz = dev_cap->max_gso_sz; return 0; } diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 6cdf813cd478..ff7df1a2222f 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -186,6 +186,7 @@ struct mlx4_caps { u32 flags; u16 stat_rate_support; u8 port_width_cap[MLX4_MAX_PORTS + 1]; + int max_gso_sz; }; struct mlx4_buf_list { diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 31f9eb3ccbb3..a5e43febee4f 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -219,6 +219,11 @@ struct mlx4_wqe_datagram_seg { __be32 reservd[2]; }; +struct mlx4_lso_seg { + __be32 mss_hdr_size; + __be32 header[0]; +}; + struct mlx4_wqe_bind_seg { __be32 flags1; __be32 flags2; -- cgit v1.2.3 From 3fdcb97f0b8d8a29117dc36acd0b15965d2a2160 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 16 Apr 2008 21:09:33 -0700 Subject: IB/mlx4: Add support for modifying CQ moderation parameters Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/cq.c | 8 +++++++ drivers/infiniband/hw/mlx4/main.c | 1 + drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 + drivers/net/mlx4/cq.c | 44 ++++++++++++++++++++++++++++++------ include/linux/mlx4/cmd.h | 2 +- include/linux/mlx4/cq.h | 3 +++ 6 files changed, 51 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 7d70af7952b0..e4fb64b118e3 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -85,6 +85,14 @@ static struct mlx4_cqe *next_cqe_sw(struct mlx4_ib_cq *cq) return get_sw_cqe(cq, cq->mcq.cons_index); } +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) +{ + struct mlx4_ib_cq *mcq = to_mcq(cq); + struct mlx4_ib_dev *dev = to_mdev(cq->device); + + return mlx4_cq_modify(dev->dev, &mcq->mcq, cq_count, cq_period); +} + struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *context, struct ib_udata *udata) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index e9330a0d6c03..76dd45c764b4 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -609,6 +609,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.post_send = mlx4_ib_post_send; ibdev->ib_dev.post_recv = mlx4_ib_post_recv; ibdev->ib_dev.create_cq = mlx4_ib_create_cq; + ibdev->ib_dev.modify_cq = mlx4_ib_modify_cq; ibdev->ib_dev.destroy_cq = mlx4_ib_destroy_cq; ibdev->ib_dev.poll_cq = mlx4_ib_poll_cq; ibdev->ib_dev.req_notify_cq = mlx4_ib_arm_cq; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 3f8bd0a37b96..ef8ad96e1432 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -254,6 +254,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, struct ib_udata *udata); int mlx4_ib_dereg_mr(struct ib_mr *mr); +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *context, struct ib_udata *udata); diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index d4441fee3d80..8c314341434f 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -38,6 +38,7 @@ #include #include +#include #include "mlx4.h" #include "icm.h" @@ -47,21 +48,19 @@ struct mlx4_cq_context { u16 reserved1[3]; __be16 page_offset; __be32 logsize_usrpage; - u8 reserved2; - u8 cq_period; - u8 reserved3; - u8 cq_max_count; - u8 reserved4[3]; + __be16 cq_period; + __be16 cq_max_count; + u8 reserved2[3]; u8 comp_eqn; u8 log_page_size; - u8 reserved5[2]; + u8 reserved3[2]; u8 mtt_base_addr_h; __be32 mtt_base_addr_l; __be32 last_notified_index; __be32 solicit_producer_index; __be32 consumer_index; __be32 producer_index; - u32 reserved6[2]; + u32 reserved4[2]; __be64 db_rec_addr; }; @@ -121,6 +120,13 @@ static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_TIME_CLASS_A); } +static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num, u32 opmod) +{ + return mlx4_cmd(dev, mailbox->dma, cq_num, opmod, MLX4_CMD_MODIFY_CQ, + MLX4_CMD_TIME_CLASS_A); +} + static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int cq_num) { @@ -129,6 +135,30 @@ static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_TIME_CLASS_A); } +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + u16 count, u16 period) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + cq_context = mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->cq_max_count = cpu_to_be16(count); + cq_context->cq_period = cpu_to_be16(period); + + err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_modify); + int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq) { diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 7d1eaa97de13..77323a72dd3c 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -81,7 +81,7 @@ enum { MLX4_CMD_SW2HW_CQ = 0x16, MLX4_CMD_HW2SW_CQ = 0x17, MLX4_CMD_QUERY_CQ = 0x18, - MLX4_CMD_RESIZE_CQ = 0x2c, + MLX4_CMD_MODIFY_CQ = 0x2c, /* SRQ commands */ MLX4_CMD_SW2HW_SRQ = 0x35, diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index 1243ebace561..f7c3511c594b 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -130,4 +130,7 @@ enum { MLX4_CQ_DB_REQ_NOT = 2 << 24 }; +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + u16 count, u16 period); + #endif /* MLX4_CQ_H */ -- cgit v1.2.3 From bbf8eed1a0f8949f7385146624f736f829992a70 Mon Sep 17 00:00:00 2001 From: Vladimir Sokolovsky Date: Wed, 16 Apr 2008 21:09:33 -0700 Subject: IB/mlx4: Add support for resizing CQs Signed-off-by: Vladimir Sokolovsky Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/cq.c | 292 +++++++++++++++++++++++++++++++---- drivers/infiniband/hw/mlx4/main.c | 2 + drivers/infiniband/hw/mlx4/mlx4_ib.h | 9 ++ drivers/net/mlx4/cq.c | 28 ++++ include/linux/mlx4/cq.h | 2 + 5 files changed, 300 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index e4fb64b118e3..3557e7edc9b6 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -93,6 +93,74 @@ int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) return mlx4_cq_modify(dev->dev, &mcq->mcq, cq_count, cq_period); } +static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int nent) +{ + int err; + + err = mlx4_buf_alloc(dev->dev, nent * sizeof(struct mlx4_cqe), + PAGE_SIZE * 2, &buf->buf); + + if (err) + goto out; + + err = mlx4_mtt_init(dev->dev, buf->buf.npages, buf->buf.page_shift, + &buf->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &buf->mtt); + +err_buf: + mlx4_buf_free(dev->dev, nent * sizeof(struct mlx4_cqe), + &buf->buf); + +out: + return err; +} + +static void mlx4_ib_free_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int cqe) +{ + mlx4_buf_free(dev->dev, (cqe + 1) * sizeof(struct mlx4_cqe), &buf->buf); +} + +static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *context, + struct mlx4_ib_cq_buf *buf, struct ib_umem **umem, + u64 buf_addr, int cqe) +{ + int err; + + *umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe), + IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(*umem)) + return PTR_ERR(*umem); + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(*umem), + ilog2((*umem)->page_size), &buf->mtt); + if (err) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &buf->mtt, *umem); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &buf->mtt); + +err_buf: + ib_umem_release(*umem); + + return err; +} + struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *context, struct ib_udata *udata) @@ -100,7 +168,6 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector struct mlx4_ib_dev *dev = to_mdev(ibdev); struct mlx4_ib_cq *cq; struct mlx4_uar *uar; - int buf_size; int err; if (entries < 1 || entries > dev->dev->caps.max_cqes) @@ -112,8 +179,10 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector entries = roundup_pow_of_two(entries + 1); cq->ibcq.cqe = entries - 1; - buf_size = entries * sizeof (struct mlx4_cqe); + mutex_init(&cq->resize_mutex); spin_lock_init(&cq->lock); + cq->resize_buf = NULL; + cq->resize_umem = NULL; if (context) { struct mlx4_ib_create_cq ucmd; @@ -123,21 +192,10 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector goto err_cq; } - cq->umem = ib_umem_get(context, ucmd.buf_addr, buf_size, - IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(cq->umem)) { - err = PTR_ERR(cq->umem); - goto err_cq; - } - - err = mlx4_mtt_init(dev->dev, ib_umem_page_count(cq->umem), - ilog2(cq->umem->page_size), &cq->buf.mtt); + err = mlx4_ib_get_cq_umem(dev, context, &cq->buf, &cq->umem, + ucmd.buf_addr, entries); if (err) - goto err_buf; - - err = mlx4_ib_umem_write_mtt(dev, &cq->buf.mtt, cq->umem); - if (err) - goto err_mtt; + goto err_cq; err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, &cq->db); @@ -155,19 +213,9 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector *cq->mcq.set_ci_db = 0; *cq->mcq.arm_db = 0; - if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &cq->buf.buf)) { - err = -ENOMEM; - goto err_db; - } - - err = mlx4_mtt_init(dev->dev, cq->buf.buf.npages, cq->buf.buf.page_shift, - &cq->buf.mtt); + err = mlx4_ib_alloc_cq_buf(dev, &cq->buf, entries); if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev->dev, &cq->buf.mtt, &cq->buf.buf); - if (err) - goto err_mtt; + goto err_db; uar = &dev->priv_uar; } @@ -195,12 +243,10 @@ err_dbmap: err_mtt: mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt); -err_buf: if (context) ib_umem_release(cq->umem); else - mlx4_buf_free(dev->dev, entries * sizeof (struct mlx4_cqe), - &cq->buf.buf); + mlx4_ib_free_cq_buf(dev, &cq->buf, entries); err_db: if (!context) @@ -212,6 +258,170 @@ err_cq: return ERR_PTR(err); } +static int mlx4_alloc_resize_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, + int entries) +{ + int err; + + if (cq->resize_buf) + return -EBUSY; + + cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); + if (!cq->resize_buf) + return -ENOMEM; + + err = mlx4_ib_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); + if (err) { + kfree(cq->resize_buf); + cq->resize_buf = NULL; + return err; + } + + cq->resize_buf->cqe = entries - 1; + + return 0; +} + +static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, + int entries, struct ib_udata *udata) +{ + struct mlx4_ib_resize_cq ucmd; + int err; + + if (cq->resize_umem) + return -EBUSY; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return -EFAULT; + + cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); + if (!cq->resize_buf) + return -ENOMEM; + + err = mlx4_ib_get_cq_umem(dev, cq->umem->context, &cq->resize_buf->buf, + &cq->resize_umem, ucmd.buf_addr, entries); + if (err) { + kfree(cq->resize_buf); + cq->resize_buf = NULL; + return err; + } + + cq->resize_buf->cqe = entries - 1; + + return 0; +} + +static int mlx4_ib_get_outstanding_cqes(struct mlx4_ib_cq *cq) +{ + u32 i; + + i = cq->mcq.cons_index; + while (get_sw_cqe(cq, i & cq->ibcq.cqe)) + ++i; + + return i - cq->mcq.cons_index; +} + +static void mlx4_ib_cq_resize_copy_cqes(struct mlx4_ib_cq *cq) +{ + struct mlx4_cqe *cqe; + int i; + + i = cq->mcq.cons_index; + cqe = get_cqe(cq, i & cq->ibcq.cqe); + while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) { + memcpy(get_cqe_from_buf(&cq->resize_buf->buf, + (i + 1) & cq->resize_buf->cqe), + get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe)); + cqe = get_cqe(cq, ++i & cq->ibcq.cqe); + } + ++cq->mcq.cons_index; +} + +int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibcq->device); + struct mlx4_ib_cq *cq = to_mcq(ibcq); + int outst_cqe; + int err; + + mutex_lock(&cq->resize_mutex); + + if (entries < 1 || entries > dev->dev->caps.max_cqes) { + err = -EINVAL; + goto out; + } + + entries = roundup_pow_of_two(entries + 1); + if (entries == ibcq->cqe + 1) { + err = 0; + goto out; + } + + if (ibcq->uobject) { + err = mlx4_alloc_resize_umem(dev, cq, entries, udata); + if (err) + goto out; + } else { + /* Can't be smaller then the number of outstanding CQEs */ + outst_cqe = mlx4_ib_get_outstanding_cqes(cq); + if (entries < outst_cqe + 1) { + err = 0; + goto out; + } + + err = mlx4_alloc_resize_buf(dev, cq, entries); + if (err) + goto out; + } + + err = mlx4_cq_resize(dev->dev, &cq->mcq, entries, &cq->resize_buf->buf.mtt); + if (err) + goto err_buf; + + if (ibcq->uobject) { + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + ib_umem_release(cq->umem); + cq->umem = cq->resize_umem; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + cq->resize_umem = NULL; + } else { + spin_lock_irq(&cq->lock); + if (cq->resize_buf) { + mlx4_ib_cq_resize_copy_cqes(cq); + mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + } + spin_unlock_irq(&cq->lock); + } + + goto out; + +err_buf: + if (!ibcq->uobject) + mlx4_ib_free_cq_buf(dev, &cq->resize_buf->buf, + cq->resize_buf->cqe); + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + + if (cq->resize_umem) { + ib_umem_release(cq->resize_umem); + cq->resize_umem = NULL; + } + +out: + mutex_unlock(&cq->resize_mutex); + return err; +} + int mlx4_ib_destroy_cq(struct ib_cq *cq) { struct mlx4_ib_dev *dev = to_mdev(cq->device); @@ -224,8 +434,7 @@ int mlx4_ib_destroy_cq(struct ib_cq *cq) mlx4_ib_db_unmap_user(to_mucontext(cq->uobject->context), &mcq->db); ib_umem_release(mcq->umem); } else { - mlx4_buf_free(dev->dev, (cq->cqe + 1) * sizeof (struct mlx4_cqe), - &mcq->buf.buf); + mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe + 1); mlx4_ib_db_free(dev, &mcq->db); } @@ -332,6 +541,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, u32 g_mlpath_rqpn; u16 wqe_ctr; +repoll: cqe = next_cqe_sw(cq); if (!cqe) return -EAGAIN; @@ -354,6 +564,22 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, return -EINVAL; } + /* Resize CQ in progress */ + if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_RESIZE)) { + if (cq->resize_buf) { + struct mlx4_ib_dev *dev = to_mdev(cq->ibcq.device); + + mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + } + + goto repoll; + } + if (!*cur_qp || (be32_to_cpu(cqe->my_qpn) & 0xffffff) != (*cur_qp)->mqp.qpn) { /* diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 76dd45c764b4..57885cd61937 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -571,6 +571,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) (1ull << IB_USER_VERBS_CMD_DEREG_MR) | (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | (1ull << IB_USER_VERBS_CMD_CREATE_QP) | (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | @@ -610,6 +611,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.post_recv = mlx4_ib_post_recv; ibdev->ib_dev.create_cq = mlx4_ib_create_cq; ibdev->ib_dev.modify_cq = mlx4_ib_modify_cq; + ibdev->ib_dev.resize_cq = mlx4_ib_resize_cq; ibdev->ib_dev.destroy_cq = mlx4_ib_destroy_cq; ibdev->ib_dev.poll_cq = mlx4_ib_poll_cq; ibdev->ib_dev.req_notify_cq = mlx4_ib_arm_cq; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index ef8ad96e1432..9e637323c155 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -78,13 +78,21 @@ struct mlx4_ib_cq_buf { struct mlx4_mtt mtt; }; +struct mlx4_ib_cq_resize { + struct mlx4_ib_cq_buf buf; + int cqe; +}; + struct mlx4_ib_cq { struct ib_cq ibcq; struct mlx4_cq mcq; struct mlx4_ib_cq_buf buf; + struct mlx4_ib_cq_resize *resize_buf; struct mlx4_ib_db db; spinlock_t lock; + struct mutex resize_mutex; struct ib_umem *umem; + struct ib_umem *resize_umem; }; struct mlx4_ib_mr { @@ -255,6 +263,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int mlx4_ib_dereg_mr(struct ib_mr *mr); int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); +int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata); struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *context, struct ib_udata *udata); diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 8c314341434f..caa5bcf54e35 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -159,6 +159,34 @@ int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, } EXPORT_SYMBOL_GPL(mlx4_cq_modify); +int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, + int entries, struct mlx4_mtt *mtt) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + u64 mtt_addr; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + cq_context = mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->logsize_usrpage = cpu_to_be32(ilog2(entries) << 24); + cq_context->log_page_size = mtt->page_shift - 12; + mtt_addr = mlx4_mtt_addr(dev, mtt); + cq_context->mtt_base_addr_h = mtt_addr >> 32; + cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + + err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_resize); + int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq) { diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index f7c3511c594b..071cf96cf01f 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -132,5 +132,7 @@ enum { int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, u16 count, u16 period); +int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, + int entries, struct mlx4_mtt *mtt); #endif /* MLX4_CQ_H */ -- cgit v1.2.3 From d7b906897e9caae452947e33674df0a2d6f7e10f Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 17 Apr 2008 07:46:24 +0200 Subject: [S390] genirq/clockevents: move irq affinity prototypes/inlines to interrupt.h > Generic code is not supposed to include irq.h. Replace this include > by linux/hardirq.h instead and add/replace an include of linux/irq.h > in asm header files where necessary. > This change should only matter for architectures that make use of > GENERIC_CLOCKEVENTS. > Architectures in question are mips, x86, arm, sh, powerpc, uml and sparc64. > > I did some cross compile tests for mips, x86_64, arm, powerpc and sparc64. > This patch fixes also build breakages caused by the include replacement in > tick-common.h. I generally dislike adding optional linux/* includes in asm/* includes - I'm nervous about this causing include loops. However, there's a separate point to be discussed here. That is, what interfaces are expected of every architecture in the kernel. If generic code wants to be able to set the affinity of interrupts, then that needs to become part of the interfaces listed in linux/interrupt.h rather than linux/irq.h. So what I suggest is this approach instead (against Linus' tree of a couple of days ago) - we move irq_set_affinity() and irq_can_set_affinity() to linux/interrupt.h, change the linux/irq.h includes to linux/interrupt.h and include asm/irq_regs.h where needed (asm/irq_regs.h is supposed to be rarely used include since not much touches the stacked parent context registers.) Build tested on ARM PXA family kernels and ARM's Realview platform kernels which both use genirq. [ tglx@linutronix.de: add GENERIC_HARDIRQ dependencies ] Signed-off-by: Russell King Signed-off-by: Thomas Gleixner Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- include/linux/interrupt.h | 19 +++++++++++++++++++ include/linux/irq.h | 10 ---------- kernel/time/tick-broadcast.c | 2 +- kernel/time/tick-common.c | 4 +++- kernel/time/tick-oneshot.c | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f8ab4ce70564..b5fef13148bd 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -102,6 +102,25 @@ extern void disable_irq_nosync(unsigned int irq); extern void disable_irq(unsigned int irq); extern void enable_irq(unsigned int irq); +#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) + +extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); +extern int irq_can_set_affinity(unsigned int irq); + +#else /* CONFIG_SMP */ + +static inline int irq_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + return -EINVAL; +} + +static inline int irq_can_set_affinity(unsigned int irq) +{ + return 0; +} + +#endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */ + #ifdef CONFIG_GENERIC_HARDIRQS /* * Special lockdep variants of irq disabling/enabling. diff --git a/include/linux/irq.h b/include/linux/irq.h index 176e5e790a44..1883a85625dd 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -228,21 +228,11 @@ static inline void set_pending_irq(unsigned int irq, cpumask_t mask) #endif /* CONFIG_GENERIC_PENDING_IRQ */ -extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); -extern int irq_can_set_affinity(unsigned int irq); - #else /* CONFIG_SMP */ #define move_native_irq(x) #define move_masked_irq(x) -static inline int irq_set_affinity(unsigned int irq, cpumask_t cpumask) -{ - return -EINVAL; -} - -static inline int irq_can_set_affinity(unsigned int irq) { return 0; } - #endif /* CONFIG_SMP */ #ifdef CONFIG_IRQBALANCE diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index e1bd50cbbf5d..fdfa0c745bb6 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 1bea399a9ef0..4f3886562b8c 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -14,12 +14,14 @@ #include #include #include -#include +#include #include #include #include #include +#include + #include "tick-internal.h" /* diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 0258d3115d54..450c04935b66 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From a332d86d3c262cddd3de0bfa90e1910de60b4f95 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 10 Feb 2008 09:04:12 +0100 Subject: hrtimer: add nanosleep specific restart_block member The back and forth typecasting of restart_block->args is horrible. We added a separate union member for futex already. Do the same for nanosleep. Signed-off-by: Thomas Gleixner --- include/linux/thread_info.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/linux') diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 421323e5a2d6..accd7bad35b0 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -9,6 +9,9 @@ #include +struct timespec; +struct compat_timespec; + /* * System call restart block. */ @@ -26,6 +29,15 @@ struct restart_block { u32 bitset; u64 time; } futex; + /* For nanosleep */ + struct { + clockid_t index; + struct timespec __user *rmtp; +#ifdef CONFIG_COMPAT + struct compat_timespec __user *compat_rmtp; +#endif + u64 expires; + } nanosleep; }; }; -- cgit v1.2.3 From 8e60e05fdc7344415fa69a3883b11f65db967b47 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Apr 2008 20:54:10 +0200 Subject: hrtimers: simplify lockdep handling In order to avoid the false positive from lockdep, each per-cpu base->lock has the separate lock class and migrate_hrtimers() uses double_spin_lock(). This is overcomplicated: except for migrate_hrtimers() we never take 2 locks at once, and migrate_hrtimers() can use spin_lock_nested(). Signed-off-by: Oleg Nesterov Cc: Arjan van de Ven Cc: Heiko Carstens Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- include/linux/hrtimer.h | 2 -- kernel/hrtimer.c | 9 ++++----- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 1ad56a7b2f74..56f3236da829 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -173,7 +173,6 @@ struct hrtimer_clock_base { * struct hrtimer_cpu_base - the per cpu clock bases * @lock: lock protecting the base and associated clock bases * and timers - * @lock_key: the lock_class_key for use with lockdep * @clock_base: array of clock bases for this cpu * @curr_timer: the timer which is executing a callback right now * @expires_next: absolute time of the next event which was scheduled @@ -189,7 +188,6 @@ struct hrtimer_clock_base { */ struct hrtimer_cpu_base { spinlock_t lock; - struct lock_class_key lock_key; struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; struct list_head cb_pending; #ifdef CONFIG_HIGH_RES_TIMERS diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 911e87d0440d..c642ef75069f 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1424,7 +1424,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu) int i; spin_lock_init(&cpu_base->lock); - lockdep_set_class(&cpu_base->lock, &cpu_base->lock_key); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) cpu_base->clock_base[i].cpu_base = cpu_base; @@ -1465,16 +1464,16 @@ static void migrate_hrtimers(int cpu) tick_cancel_sched_timer(cpu); local_irq_disable(); - double_spin_lock(&new_base->lock, &old_base->lock, - smp_processor_id() < cpu); + spin_lock(&new_base->lock); + spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { migrate_hrtimer_list(&old_base->clock_base[i], &new_base->clock_base[i]); } - double_spin_unlock(&new_base->lock, &old_base->lock, - smp_processor_id() < cpu); + spin_unlock(&old_base->lock); + spin_unlock(&new_base->lock); local_irq_enable(); put_cpu_var(hrtimer_bases); } -- cgit v1.2.3 From 3f3eafc921e2378954c28cfd0eb10910449f4c11 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Apr 2008 20:54:10 +0200 Subject: locking: remove unused double_spin_lock() double_spin_lock() has no callers, and it can't be used without additional lockdep annotations, remove it. Signed-off-by: Oleg Nesterov Cc: Arjan van de Ven Cc: Heiko Carstens Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- include/linux/spinlock.h | 37 ------------------------------------- 1 file changed, 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 1129ee0a7180..d311a090fae7 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -295,43 +295,6 @@ do { \ 1 : ({ local_irq_restore(flags); 0; }); \ }) -/* - * Locks two spinlocks l1 and l2. - * l1_first indicates if spinlock l1 should be taken first. - */ -static inline void double_spin_lock(spinlock_t *l1, spinlock_t *l2, - bool l1_first) - __acquires(l1) - __acquires(l2) -{ - if (l1_first) { - spin_lock(l1); - spin_lock(l2); - } else { - spin_lock(l2); - spin_lock(l1); - } -} - -/* - * Unlocks two spinlocks l1 and l2. - * l1_taken_first indicates if spinlock l1 was taken first and therefore - * should be released after spinlock l2. - */ -static inline void double_spin_unlock(spinlock_t *l1, spinlock_t *l2, - bool l1_taken_first) - __releases(l1) - __releases(l2) -{ - if (l1_taken_first) { - spin_unlock(l2); - spin_unlock(l1); - } else { - spin_unlock(l1); - spin_unlock(l2); - } -} - /* * Pull the atomic_t declaration: * (asm-mips/atomic.h needs above definitions) -- cgit v1.2.3 From 8b91de2e58318d1168bc13d164478c1a7217a63a Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 26 Feb 2008 09:53:20 -0500 Subject: Fix quota.h includes quota.h currently relies on asm/semaphore.h (through some chain; it doesn't actually include semaphore.h itself) to include wait.h. As well as being bad practice to rely on an implicit include, subsequent patches will break this. While I'm in this file, add atomic.h and list.h, and sort the list of includes. Signed-off-by: Matthew Wilcox --- include/linux/quota.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/quota.h b/include/linux/quota.h index 6e0393a5b2ea..eb560d031acd 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -160,14 +160,18 @@ enum { #ifdef __KERNEL__ -#include -#include +#include #include +#include +#include +#include #include #include #include +#include + extern spinlock_t dq_data_lock; /* Maximal numbers of writes for quota operation (insert/delete/update) -- cgit v1.2.3 From 64ac24e738823161693bf791f87adc802cf529ff Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 7 Mar 2008 21:55:58 -0500 Subject: Generic semaphore implementation Semaphores are no longer performance-critical, so a generic C implementation is better for maintainability, debuggability and extensibility. Thanks to Peter Zijlstra for fixing the lockdep warning. Thanks to Harvey Harrison for pointing out that the unlikely() was unnecessary. Signed-off-by: Matthew Wilcox Acked-by: Ingo Molnar --- arch/alpha/kernel/Makefile | 2 +- arch/alpha/kernel/alpha_ksyms.c | 9 -- arch/alpha/kernel/semaphore.c | 224 --------------------------- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/semaphore.c | 221 --------------------------- arch/avr32/kernel/Makefile | 2 +- arch/avr32/kernel/semaphore.c | 148 ------------------ arch/blackfin/Kconfig | 4 - arch/blackfin/kernel/bfin_ksyms.c | 5 - arch/cris/kernel/Makefile | 3 +- arch/cris/kernel/crisksyms.c | 7 - arch/cris/kernel/semaphore.c | 129 ---------------- arch/frv/kernel/Makefile | 2 +- arch/frv/kernel/frv_ksyms.c | 1 - arch/frv/kernel/semaphore.c | 155 ------------------- arch/h8300/kernel/Makefile | 2 +- arch/h8300/kernel/h8300_ksyms.c | 1 - arch/h8300/kernel/semaphore.c | 132 ---------------- arch/ia64/kernel/Makefile | 2 +- arch/ia64/kernel/ia64_ksyms.c | 6 - arch/ia64/kernel/semaphore.c | 165 -------------------- arch/m32r/kernel/Makefile | 2 +- arch/m32r/kernel/m32r_ksyms.c | 5 - arch/m32r/kernel/semaphore.c | 185 ---------------------- arch/m68k/kernel/Makefile | 2 +- arch/m68k/kernel/m68k_ksyms.c | 6 - arch/m68k/kernel/semaphore.c | 132 ---------------- arch/m68k/lib/Makefile | 2 +- arch/m68k/lib/semaphore.S | 53 ------- arch/m68knommu/kernel/Makefile | 2 +- arch/m68knommu/kernel/m68k_ksyms.c | 6 - arch/m68knommu/kernel/semaphore.c | 133 ---------------- arch/m68knommu/lib/Makefile | 2 +- arch/m68knommu/lib/semaphore.S | 66 -------- arch/mips/kernel/Makefile | 2 +- arch/mips/kernel/semaphore.c | 168 -------------------- arch/mn10300/kernel/Makefile | 2 +- arch/mn10300/kernel/semaphore.c | 149 ------------------ arch/parisc/kernel/Makefile | 2 +- arch/parisc/kernel/parisc_ksyms.c | 5 - arch/parisc/kernel/semaphore.c | 102 ------------- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/ppc_ksyms.c | 1 - arch/powerpc/kernel/semaphore.c | 135 ---------------- arch/ppc/kernel/semaphore.c | 131 ---------------- arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/s390_ksyms.c | 7 - arch/s390/kernel/semaphore.c | 108 ------------- arch/sh/kernel/Makefile_32 | 2 +- arch/sh/kernel/Makefile_64 | 2 +- arch/sh/kernel/semaphore.c | 139 ----------------- arch/sh/kernel/sh_ksyms_32.c | 7 - arch/sh/kernel/sh_ksyms_64.c | 4 - arch/sparc/kernel/Makefile | 2 +- arch/sparc/kernel/semaphore.c | 155 ------------------- arch/sparc/kernel/sparc_ksyms.c | 5 - arch/sparc64/kernel/Makefile | 2 +- arch/sparc64/kernel/semaphore.c | 254 ------------------------------- arch/sparc64/kernel/sparc64_ksyms.c | 6 - arch/um/Kconfig.i386 | 4 - arch/um/Kconfig.x86_64 | 4 - arch/um/sys-i386/ksyms.c | 12 -- arch/um/sys-ppc/Makefile | 8 +- arch/um/sys-x86_64/ksyms.c | 13 +- arch/v850/kernel/Makefile | 2 +- arch/v850/kernel/semaphore.c | 166 -------------------- arch/v850/kernel/v850_ksyms.c | 7 - arch/x86/Kconfig | 3 - arch/x86/kernel/i386_ksyms_32.c | 5 - arch/x86/kernel/x8664_ksyms_64.c | 6 - arch/x86/lib/semaphore_32.S | 83 ---------- arch/x86/lib/thunk_64.S | 5 - arch/xtensa/kernel/Makefile | 2 +- arch/xtensa/kernel/semaphore.c | 226 --------------------------- arch/xtensa/kernel/xtensa_ksyms.c | 9 -- include/asm-alpha/semaphore.h | 150 +----------------- include/asm-arm/semaphore-helper.h | 84 ---------- include/asm-arm/semaphore.h | 99 +----------- include/asm-avr32/semaphore.h | 109 +------------ include/asm-blackfin/semaphore-helper.h | 82 ---------- include/asm-blackfin/semaphore.h | 106 +------------ include/asm-cris/semaphore-helper.h | 78 ---------- include/asm-cris/semaphore.h | 134 +--------------- include/asm-frv/semaphore.h | 156 +------------------ include/asm-h8300/semaphore-helper.h | 85 ----------- include/asm-h8300/semaphore.h | 191 +---------------------- include/asm-ia64/semaphore.h | 100 +----------- include/asm-m32r/semaphore.h | 145 +----------------- include/asm-m68k/semaphore-helper.h | 142 ----------------- include/asm-m68k/semaphore.h | 164 +------------------- include/asm-m68knommu/semaphore-helper.h | 82 ---------- include/asm-m68knommu/semaphore.h | 154 +------------------ include/asm-mips/semaphore.h | 109 +------------ include/asm-mn10300/semaphore.h | 170 +-------------------- include/asm-parisc/semaphore-helper.h | 89 ----------- include/asm-parisc/semaphore.h | 146 +----------------- include/asm-powerpc/semaphore.h | 95 +----------- include/asm-s390/semaphore.h | 108 +------------ include/asm-sh/semaphore-helper.h | 89 ----------- include/asm-sh/semaphore.h | 116 +------------- include/asm-sparc/semaphore.h | 193 +---------------------- include/asm-sparc64/semaphore.h | 54 +------ include/asm-um/semaphore.h | 7 +- include/asm-v850/semaphore.h | 85 +---------- include/asm-x86/semaphore.h | 6 +- include/asm-x86/semaphore_32.h | 175 --------------------- include/asm-x86/semaphore_64.h | 180 ---------------------- include/asm-xtensa/semaphore.h | 100 +----------- include/linux/semaphore.h | 77 ++++++++++ kernel/Makefile | 2 +- kernel/semaphore.c | 187 +++++++++++++++++++++++ lib/Makefile | 1 - lib/semaphore-sleepers.c | 176 --------------------- 113 files changed, 314 insertions(+), 7679 deletions(-) delete mode 100644 arch/alpha/kernel/semaphore.c delete mode 100644 arch/arm/kernel/semaphore.c delete mode 100644 arch/avr32/kernel/semaphore.c delete mode 100644 arch/cris/kernel/semaphore.c delete mode 100644 arch/frv/kernel/semaphore.c delete mode 100644 arch/h8300/kernel/semaphore.c delete mode 100644 arch/ia64/kernel/semaphore.c delete mode 100644 arch/m32r/kernel/semaphore.c delete mode 100644 arch/m68k/kernel/semaphore.c delete mode 100644 arch/m68k/lib/semaphore.S delete mode 100644 arch/m68knommu/kernel/semaphore.c delete mode 100644 arch/m68knommu/lib/semaphore.S delete mode 100644 arch/mips/kernel/semaphore.c delete mode 100644 arch/mn10300/kernel/semaphore.c delete mode 100644 arch/parisc/kernel/semaphore.c delete mode 100644 arch/powerpc/kernel/semaphore.c delete mode 100644 arch/ppc/kernel/semaphore.c delete mode 100644 arch/s390/kernel/semaphore.c delete mode 100644 arch/sh/kernel/semaphore.c delete mode 100644 arch/sparc/kernel/semaphore.c delete mode 100644 arch/sparc64/kernel/semaphore.c delete mode 100644 arch/v850/kernel/semaphore.c delete mode 100644 arch/xtensa/kernel/semaphore.c delete mode 100644 include/asm-arm/semaphore-helper.h delete mode 100644 include/asm-blackfin/semaphore-helper.h delete mode 100644 include/asm-cris/semaphore-helper.h delete mode 100644 include/asm-h8300/semaphore-helper.h delete mode 100644 include/asm-m68k/semaphore-helper.h delete mode 100644 include/asm-m68knommu/semaphore-helper.h delete mode 100644 include/asm-parisc/semaphore-helper.h delete mode 100644 include/asm-sh/semaphore-helper.h delete mode 100644 include/asm-x86/semaphore_32.h delete mode 100644 include/asm-x86/semaphore_64.h create mode 100644 include/linux/semaphore.h create mode 100644 kernel/semaphore.c delete mode 100644 lib/semaphore-sleepers.c (limited to 'include/linux') diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index dccf05245d4d..ac706c1d7ada 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -7,7 +7,7 @@ EXTRA_AFLAGS := $(KBUILD_CFLAGS) EXTRA_CFLAGS := -Werror -Wno-sign-compare obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \ - irq_alpha.o signal.o setup.o ptrace.o time.o semaphore.o \ + irq_alpha.o signal.o setup.o ptrace.o time.o \ alpha_ksyms.o systbls.o err_common.o io.o obj-$(CONFIG_VGA_HOSE) += console.o diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index e9762a33b043..d96e742d4dc2 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -77,15 +77,6 @@ EXPORT_SYMBOL(__do_clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strnlen_user); -/* Semaphore helper functions. */ -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__up_wakeup); -EXPORT_SYMBOL(down); -EXPORT_SYMBOL(down_interruptible); -EXPORT_SYMBOL(down_trylock); -EXPORT_SYMBOL(up); - /* * SMP-specific symbols. */ diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c deleted file mode 100644 index 8d2982aa1b8d..000000000000 --- a/arch/alpha/kernel/semaphore.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Alpha semaphore implementation. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999, 2000 Richard Henderson - */ - -#include -#include -#include - -/* - * This is basically the PPC semaphore scheme ported to use - * the Alpha ll/sc sequences, so see the PPC code for - * credits. - */ - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - long old_count, tmp = 0; - - __asm__ __volatile__( - "1: ldl_l %0,%2\n" - " cmovgt %0,%0,%1\n" - " addl %1,%3,%1\n" - " stl_c %1,%2\n" - " beq %1,2f\n" - " mb\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "Ir" (incr), "1" (tmp), "m" (sem->count)); - - return old_count; -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - */ - -void __sched -__down_failed(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down failed(%p)\n", - tsk->comm, task_pid_nr(tsk), sem); -#endif - - tsk->state = TASK_UNINTERRUPTIBLE; - wmb(); - add_wait_queue_exclusive(&sem->wait, &wait); - - /* - * Try to get the semaphore. If the count is > 0, then we've - * got the semaphore; we decrement count and exit the loop. - * If the count is 0 or negative, we set it to -1, indicating - * that we are asleep, and then sleep. - */ - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - /* - * If there are any more sleepers, wake one of them up so - * that it can either get the semaphore, or set count to -1 - * indicating that there are still processes sleeping. - */ - wake_up(&sem->wait); - -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down acquired(%p)\n", - tsk->comm, task_pid_nr(tsk), sem); -#endif -} - -int __sched -__down_failed_interruptible(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - long ret = 0; - -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down failed(%p)\n", - tsk->comm, task_pid_nr(tsk), sem); -#endif - - tsk->state = TASK_INTERRUPTIBLE; - wmb(); - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - /* - * A signal is pending - give up trying. - * Set sem->count to 0 if it is negative, - * since we are no longer sleeping. - */ - __sem_update_count(sem, 0); - ret = -EINTR; - break; - } - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - wake_up(&sem->wait); - -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down %s(%p)\n", - current->comm, task_pid_nr(current), - (ret < 0 ? "interrupted" : "acquired"), sem); -#endif - return ret; -} - -void -__up_wakeup(struct semaphore *sem) -{ - /* - * Note that we incremented count in up() before we came here, - * but that was ineffective since the result was <= 0, and - * any negative value of count is equivalent to 0. - * This ends up setting count to 1, unless count is now > 0 - * (i.e. because some other cpu has called up() in the meantime), - * in which case we just increment count. - */ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -void __sched -down(struct semaphore *sem) -{ -#ifdef WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down(%p) from %p\n", - current->comm, task_pid_nr(current), sem, - atomic_read(&sem->count), __builtin_return_address(0)); -#endif - __down(sem); -} - -int __sched -down_interruptible(struct semaphore *sem) -{ -#ifdef WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down(%p) from %p\n", - current->comm, task_pid_nr(current), sem, - atomic_read(&sem->count), __builtin_return_address(0)); -#endif - return __down_interruptible(sem); -} - -int -down_trylock(struct semaphore *sem) -{ - int ret; - -#ifdef WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - ret = __down_trylock(sem); - -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): down_trylock %s from %p\n", - current->comm, task_pid_nr(current), - ret ? "failed" : "acquired", - __builtin_return_address(0)); -#endif - - return ret; -} - -void -up(struct semaphore *sem) -{ -#ifdef WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif -#ifdef CONFIG_DEBUG_SEMAPHORE - printk("%s(%d): up(%p) from %p\n", - current->comm, task_pid_nr(current), sem, - atomic_read(&sem->count), __builtin_return_address(0)); -#endif - __up(sem); -} diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 00d44c6fbfe9..6235f72a14f0 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -7,7 +7,7 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. obj-y := compat.o entry-armv.o entry-common.o irq.o \ - process.o ptrace.o semaphore.o setup.o signal.o \ + process.o ptrace.o setup.o signal.o \ sys_arm.o stacktrace.o time.o traps.o obj-$(CONFIG_ISA_DMA_API) += dma.o diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c deleted file mode 100644 index 981fe5c6ccbe..000000000000 --- a/arch/arm/kernel/semaphore.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * ARM semaphore implementation, taken from - * - * i386 semaphore implementation. - * - * (C) Copyright 1999 Linus Torvalds - * - * Modified for ARM by Russell King - * - * 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. - */ -#include -#include -#include -#include - -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is - * protected by the semaphore spinlock. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -static DEFINE_SPINLOCK(semaphore_lock); - -void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - wake_up(&sem->wait); -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers ++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. The - * "-1" is because we're still hoping to get - * the lock. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} - -/* - * Trylock failed - make sure we correct for - * having decremented the count. - * - * We could have done the trylock with a - * single "cmpxchg" without failure cases, - * but then it wouldn't work on a 386. - */ -int __down_trylock(struct semaphore * sem) -{ - int sleepers; - unsigned long flags; - - spin_lock_irqsave(&semaphore_lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic_add_negative(sleepers, &sem->count)) - wake_up(&sem->wait); - - spin_unlock_irqrestore(&semaphore_lock, flags); - return 1; -} - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - * - * ip contains the semaphore pointer on entry. Save the C-clobbered - * registers (r0 to r3 and lr), but not ip, as we use it as a return - * value in some cases.. - * To remain AAPCS compliant (64-bit stack align) we save r4 as well. - */ -asm(" .section .sched.text,\"ax\",%progbits \n\ - .align 5 \n\ - .globl __down_failed \n\ -__down_failed: \n\ - stmfd sp!, {r0 - r4, lr} \n\ - mov r0, ip \n\ - bl __down \n\ - ldmfd sp!, {r0 - r4, pc} \n\ - \n\ - .align 5 \n\ - .globl __down_interruptible_failed \n\ -__down_interruptible_failed: \n\ - stmfd sp!, {r0 - r4, lr} \n\ - mov r0, ip \n\ - bl __down_interruptible \n\ - mov ip, r0 \n\ - ldmfd sp!, {r0 - r4, pc} \n\ - \n\ - .align 5 \n\ - .globl __down_trylock_failed \n\ -__down_trylock_failed: \n\ - stmfd sp!, {r0 - r4, lr} \n\ - mov r0, ip \n\ - bl __down_trylock \n\ - mov ip, r0 \n\ - ldmfd sp!, {r0 - r4, pc} \n\ - \n\ - .align 5 \n\ - .globl __up_wakeup \n\ -__up_wakeup: \n\ - stmfd sp!, {r0 - r4, lr} \n\ - mov r0, ip \n\ - bl __up \n\ - ldmfd sp!, {r0 - r4, pc} \n\ - "); - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_interruptible_failed); -EXPORT_SYMBOL(__down_trylock_failed); -EXPORT_SYMBOL(__up_wakeup); diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index e4b6d122b033..18229d0d1861 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o vmlinux.lds obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o obj-y += syscall_table.o syscall-stubs.o irq.o -obj-y += setup.o traps.o semaphore.o ocd.o ptrace.o +obj-y += setup.o traps.o ocd.o ptrace.o obj-y += signal.o sys_avr32.o process.o time.o obj-y += init_task.o switch_to.o cpu.o obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o diff --git a/arch/avr32/kernel/semaphore.c b/arch/avr32/kernel/semaphore.c deleted file mode 100644 index 1e2705a05016..000000000000 --- a/arch/avr32/kernel/semaphore.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * AVR32 sempahore implementation. - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * Based on linux/arch/i386/kernel/semaphore.c - * Copyright (C) 1999 Linus Torvalds - * - * 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. - */ - -#include -#include -#include - -#include -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is protected - * by the spinlock in the semaphore's waitqueue head. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} -EXPORT_SYMBOL(__up); - -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * the wait_queue_head. - */ - if (atomic_add_return(sleepers - 1, &sem->count) >= 0) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - tsk->state = TASK_RUNNING; -} -EXPORT_SYMBOL(__down); - -int __sched __down_interruptible(struct semaphore *sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into the trylock - * failure case - we won't be sleeping, and we can't - * get the lock as it has contention. Just correct the - * count and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * the wait_queue_head. - */ - if (atomic_add_return(sleepers - 1, &sem->count) >= 0) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_INTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - - tsk->state = TASK_RUNNING; - return retval; -} -EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 589c6aca4803..2dd1f300a5cf 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -31,10 +31,6 @@ config ZONE_DMA bool default y -config SEMAPHORE_SLEEPERS - bool - default y - config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index 0bfbb269e350..053edff6c0d8 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -42,11 +42,6 @@ EXPORT_SYMBOL(ip_fast_csum); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(__down_interruptible); - EXPORT_SYMBOL(is_in_rom); EXPORT_SYMBOL(bfin_return_from_exception); diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile index c8e8ea570989..ee7bcd4d20b2 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -5,8 +5,7 @@ extra-y := vmlinux.lds -obj-y := process.o traps.o irq.o ptrace.o setup.o \ - time.o sys_cris.o semaphore.o +obj-y := process.o traps.o irq.o ptrace.o setup.o time.o sys_cris.o obj-$(CONFIG_MODULES) += crisksyms.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index 62f0e752915a..7ac000f6a888 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -49,12 +48,6 @@ EXPORT_SYMBOL(__negdi2); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -/* Semaphore functions */ -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); - /* Userspace access functions */ EXPORT_SYMBOL(__copy_user_zeroing); EXPORT_SYMBOL(__copy_user); diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c deleted file mode 100644 index f137a439041f..000000000000 --- a/arch/cris/kernel/semaphore.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in - */ - -#include -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index e8f73ed28b52..c36f70b6699a 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile @@ -9,7 +9,7 @@ extra-y:= head.o init_task.o vmlinux.lds obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \ - sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ + sys_frv.o time.o setup.o frv_ksyms.o \ debug-stub.o irq.o sleep.o uaccess.o obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index f772704b3d28..0316b3c50eff 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/frv/kernel/semaphore.c b/arch/frv/kernel/semaphore.c deleted file mode 100644 index 7ee3a147b471..000000000000 --- a/arch/frv/kernel/semaphore.c +++ /dev/null @@ -1,155 +0,0 @@ -/* semaphore.c: FR-V semaphores - * - * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - Derived from lib/rwsem-spinlock.c - * - * 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 -#include -#include - -struct sem_waiter { - struct list_head list; - struct task_struct *task; -}; - -#ifdef CONFIG_DEBUG_SEMAPHORE -void semtrace(struct semaphore *sem, const char *str) -{ - if (sem->debug) - printk("[%d] %s({%d,%d})\n", - current->pid, - str, - sem->counter, - list_empty(&sem->wait_list) ? 0 : 1); -} -#else -#define semtrace(SEM,STR) do { } while(0) -#endif - -/* - * wait for a token to be granted from a semaphore - * - entered with lock held and interrupts disabled - */ -void __down(struct semaphore *sem, unsigned long flags) -{ - struct task_struct *tsk = current; - struct sem_waiter waiter; - - semtrace(sem, "Entering __down"); - - /* set up my own style of waitqueue */ - waiter.task = tsk; - get_task_struct(tsk); - - list_add_tail(&waiter.list, &sem->wait_list); - - /* we don't need to touch the semaphore struct anymore */ - spin_unlock_irqrestore(&sem->wait_lock, flags); - - /* wait to be given the semaphore */ - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - - for (;;) { - if (list_empty(&waiter.list)) - break; - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - - tsk->state = TASK_RUNNING; - semtrace(sem, "Leaving __down"); -} - -EXPORT_SYMBOL(__down); - -/* - * interruptibly wait for a token to be granted from a semaphore - * - entered with lock held and interrupts disabled - */ -int __down_interruptible(struct semaphore *sem, unsigned long flags) -{ - struct task_struct *tsk = current; - struct sem_waiter waiter; - int ret; - - semtrace(sem,"Entering __down_interruptible"); - - /* set up my own style of waitqueue */ - waiter.task = tsk; - get_task_struct(tsk); - - list_add_tail(&waiter.list, &sem->wait_list); - - /* we don't need to touch the semaphore struct anymore */ - set_task_state(tsk, TASK_INTERRUPTIBLE); - - spin_unlock_irqrestore(&sem->wait_lock, flags); - - /* wait to be given the semaphore */ - ret = 0; - for (;;) { - if (list_empty(&waiter.list)) - break; - if (unlikely(signal_pending(current))) - goto interrupted; - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - - out: - tsk->state = TASK_RUNNING; - semtrace(sem, "Leaving __down_interruptible"); - return ret; - - interrupted: - spin_lock_irqsave(&sem->wait_lock, flags); - - if (!list_empty(&waiter.list)) { - list_del(&waiter.list); - ret = -EINTR; - } - - spin_unlock_irqrestore(&sem->wait_lock, flags); - if (ret == -EINTR) - put_task_struct(current); - goto out; -} - -EXPORT_SYMBOL(__down_interruptible); - -/* - * release a single token back to a semaphore - * - entered with lock held and interrupts disabled - */ -void __up(struct semaphore *sem) -{ - struct task_struct *tsk; - struct sem_waiter *waiter; - - semtrace(sem,"Entering __up"); - - /* grant the token to the process at the front of the queue */ - waiter = list_entry(sem->wait_list.next, struct sem_waiter, list); - - /* We must be careful not to touch 'waiter' after we set ->task = NULL. - * It is allocated on the waiter's stack and may become invalid at - * any time after that point (due to a wakeup from another source). - */ - list_del_init(&waiter->list); - tsk = waiter->task; - mb(); - waiter->task = NULL; - wake_up_process(tsk); - put_task_struct(tsk); - - semtrace(sem,"Leaving __up"); -} - -EXPORT_SYMBOL(__up); diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile index 874f6aefee65..6c248c3c5c3b 100644 --- a/arch/h8300/kernel/Makefile +++ b/arch/h8300/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := vmlinux.lds obj-y := process.o traps.o ptrace.o irq.o \ - sys_h8300.o time.o semaphore.o signal.o \ + sys_h8300.o time.o signal.o \ setup.o gpio.o init_task.o syscalls.o \ entry.o diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index d1b15267ac81..6866bd9c7fb4 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/h8300/kernel/semaphore.c b/arch/h8300/kernel/semaphore.c deleted file mode 100644 index d12cbbfe6ebd..000000000000 --- a/arch/h8300/kernel/semaphore.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in - */ - -#include -#include -#include - -#ifndef CONFIG_RMW_INSNS -spinlock_t semaphore_wake_lock; -#endif - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - - -#define DOWN_HEAD(task_state) \ - \ - \ - current->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - current->state = (task_state); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, current); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 33e5a598672d..13fd10e8699e 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ - salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ + salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ unwind.o mca.o mca_asm.o topology.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 8e7193d55528..6da1f20d7372 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -19,12 +19,6 @@ EXPORT_SYMBOL_GPL(empty_zero_page); EXPORT_SYMBOL(ip_fast_csum); /* hand-coded assembly */ EXPORT_SYMBOL(csum_ipv6_magic); -#include -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(__up); - #include EXPORT_SYMBOL(clear_page); diff --git a/arch/ia64/kernel/semaphore.c b/arch/ia64/kernel/semaphore.c deleted file mode 100644 index 2724ef3fbae2..000000000000 --- a/arch/ia64/kernel/semaphore.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * IA-64 semaphore implementation (derived from x86 version). - * - * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co - * David Mosberger-Tang - */ - -/* - * Semaphores are implemented using a two-way counter: The "count" - * variable is decremented for each process that tries to acquire the - * semaphore, while the "sleepers" variable is a count of such - * acquires. - * - * Notably, the inline "up()" and "down()" functions can efficiently - * test if they need to do any extra work (up needs to do something - * only if count was negative before the increment operation. - * - * "sleeping" and the contention routine ordering is protected - * by the spinlock in the semaphore's waitqueue head. - * - * Note that these functions are only called when there is contention - * on the lock, and as such all this is the "non-critical" part of the - * whole semaphore business. The critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -#include -#include - -#include -#include - -/* - * Logic: - * - Only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - When we go from a non-negative count to a negative do we - * (a) synchronize with the "sleepers" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void -__up (struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -void __sched __down (struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * the wait_queue_head. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - tsk->state = TASK_RUNNING; -} - -int __sched __down_interruptible (struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers ++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * wait_queue_head. The "-1" is because we're - * still hoping to get the semaphore. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_INTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - - tsk->state = TASK_RUNNING; - return retval; -} - -/* - * Trylock failed - make sure we correct for having decremented the - * count. - */ -int -__down_trylock (struct semaphore *sem) -{ - unsigned long flags; - int sleepers; - - spin_lock_irqsave(&sem->wait.lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock in the - * wait_queue_head. - */ - if (!atomic_add_negative(sleepers, &sem->count)) { - wake_up_locked(&sem->wait); - } - - spin_unlock_irqrestore(&sem->wait.lock, flags); - return 1; -} diff --git a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile index e97e26e87c9e..09200d4886e3 100644 --- a/arch/m32r/kernel/Makefile +++ b/arch/m32r/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o entry.o traps.o align.o irq.o setup.o time.o \ - m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o + m32r_ksyms.o sys_m32r.o signal.o ptrace.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c index 41a4c95e06d6..e6709fe950ba 100644 --- a/arch/m32r/kernel/m32r_ksyms.c +++ b/arch/m32r/kernel/m32r_ksyms.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -22,10 +21,6 @@ EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down_trylock); /* Networking helper routines. */ /* Delay loops */ diff --git a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c deleted file mode 100644 index 940c2d37cfd1..000000000000 --- a/arch/m32r/kernel/semaphore.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * linux/arch/m32r/semaphore.c - * orig : i386 2.6.4 - * - * M32R semaphore implementation. - * - * Copyright (c) 2002 - 2004 Hitoshi Yamamoto - */ - -/* - * i386 semaphore implementation. - * - * (C) Copyright 1999 Linus Torvalds - * - * Portions Copyright 1999 Red Hat, 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. - * - * rw semaphores implemented November 1999 by Benjamin LaHaise - */ -#include -#include -#include -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is protected - * by the spinlock in the semaphore's waitqueue head. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -asmlinkage void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -asmlinkage void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * the wait_queue_head. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - tsk->state = TASK_RUNNING; -} - -asmlinkage int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * wait_queue_head. The "-1" is because we're - * still hoping to get the semaphore. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_INTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - - tsk->state = TASK_RUNNING; - return retval; -} - -/* - * Trylock failed - make sure we correct for - * having decremented the count. - * - * We could have done the trylock with a - * single "cmpxchg" without failure cases, - * but then it wouldn't work on a 386. - */ -asmlinkage int __down_trylock(struct semaphore * sem) -{ - int sleepers; - unsigned long flags; - - spin_lock_irqsave(&sem->wait.lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock in the - * wait_queue_head. - */ - if (!atomic_add_negative(sleepers, &sem->count)) { - wake_up_locked(&sem->wait); - } - - spin_unlock_irqrestore(&sem->wait.lock, flags); - return 1; -} diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index a806208c7fb5..7a62a718143b 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -10,7 +10,7 @@ endif extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ - sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o + sys_m68k.o time.o setup.o m68k_ksyms.o devres.o devres-y = ../../../kernel/irq/devres.o diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 6fc69c74fe2e..d900e77e5363 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -1,5 +1,4 @@ #include -#include asmlinkage long long __ashldi3 (long long, int); asmlinkage long long __ashrdi3 (long long, int); @@ -15,8 +14,3 @@ EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__lshrdi3); EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - diff --git a/arch/m68k/kernel/semaphore.c b/arch/m68k/kernel/semaphore.c deleted file mode 100644 index d12cbbfe6ebd..000000000000 --- a/arch/m68k/kernel/semaphore.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in - */ - -#include -#include -#include - -#ifndef CONFIG_RMW_INSNS -spinlock_t semaphore_wake_lock; -#endif - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - - -#define DOWN_HEAD(task_state) \ - \ - \ - current->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - current->state = (task_state); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, current); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile index 6bbf19f96007..a18af095cd7c 100644 --- a/arch/m68k/lib/Makefile +++ b/arch/m68k/lib/Makefile @@ -5,4 +5,4 @@ EXTRA_AFLAGS := -traditional lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ - checksum.o string.o semaphore.o uaccess.o + checksum.o string.o uaccess.o diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S deleted file mode 100644 index 0215624c1602..000000000000 --- a/arch/m68k/lib/semaphore.S +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/arch/m68k/lib/semaphore.S - * - * Copyright (C) 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - */ - -#include -#include - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - */ -ENTRY(__down_failed) - moveml %a0/%d0/%d1,-(%sp) - movel %a1,-(%sp) - jbsr __down - movel (%sp)+,%a1 - moveml (%sp)+,%a0/%d0/%d1 - rts - -ENTRY(__down_failed_interruptible) - movel %a0,-(%sp) - movel %d1,-(%sp) - movel %a1,-(%sp) - jbsr __down_interruptible - movel (%sp)+,%a1 - movel (%sp)+,%d1 - movel (%sp)+,%a0 - rts - -ENTRY(__down_failed_trylock) - movel %a0,-(%sp) - movel %d1,-(%sp) - movel %a1,-(%sp) - jbsr __down_trylock - movel (%sp)+,%a1 - movel (%sp)+,%d1 - movel (%sp)+,%a0 - rts - -ENTRY(__up_wakeup) - moveml %a0/%d0/%d1,-(%sp) - movel %a1,-(%sp) - jbsr __up - movel (%sp)+,%a1 - moveml (%sp)+,%a0/%d0/%d1 - rts - diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile index 1524b39ad63f..f0eab3dedb5a 100644 --- a/arch/m68knommu/kernel/Makefile +++ b/arch/m68knommu/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := vmlinux.lds obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \ - semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o + setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_COMEMPCI) += comempci.o diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c index 53fad1490282..39fe0a7aec32 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68knommu/kernel/m68k_ksyms.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -39,11 +38,6 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/m68knommu/kernel/semaphore.c b/arch/m68knommu/kernel/semaphore.c deleted file mode 100644 index bce2bc7d87c6..000000000000 --- a/arch/m68knommu/kernel/semaphore.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in - */ - -#include -#include -#include -#include - -#ifndef CONFIG_RMW_INSNS -spinlock_t semaphore_wake_lock; -#endif - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - - -#define DOWN_HEAD(task_state) \ - \ - \ - current->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - current->state = (task_state); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, current); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/m68knommu/lib/Makefile b/arch/m68knommu/lib/Makefile index e051a7913987..d94d709665aa 100644 --- a/arch/m68knommu/lib/Makefile +++ b/arch/m68knommu/lib/Makefile @@ -4,4 +4,4 @@ lib-y := ashldi3.o ashrdi3.o lshrdi3.o \ muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \ - checksum.o semaphore.o memcpy.o memset.o delay.o + checksum.o memcpy.o memset.o delay.o diff --git a/arch/m68knommu/lib/semaphore.S b/arch/m68knommu/lib/semaphore.S deleted file mode 100644 index 87c746034376..000000000000 --- a/arch/m68knommu/lib/semaphore.S +++ /dev/null @@ -1,66 +0,0 @@ -/* - * linux/arch/m68k/lib/semaphore.S - * - * Copyright (C) 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - * - * MAR/1999 -- modified to support ColdFire (gerg@snapgear.com) - */ - -#include -#include - -/* - * "down_failed" is called with the eventual return address - * in %a0, and the address of the semaphore in %a1. We need - * to increment the number of waiters on the semaphore, - * call "__down()", and then eventually return to try again. - */ -ENTRY(__down_failed) -#ifdef CONFIG_COLDFIRE - subl #12,%sp - moveml %a0/%d0/%d1,(%sp) -#else - moveml %a0/%d0/%d1,-(%sp) -#endif - movel %a1,-(%sp) - jbsr __down - movel (%sp)+,%a1 - movel (%sp)+,%d0 - movel (%sp)+,%d1 - rts - -ENTRY(__down_failed_interruptible) - movel %a0,-(%sp) - movel %d1,-(%sp) - movel %a1,-(%sp) - jbsr __down_interruptible - movel (%sp)+,%a1 - movel (%sp)+,%d1 - rts - -ENTRY(__up_wakeup) -#ifdef CONFIG_COLDFIRE - subl #12,%sp - moveml %a0/%d0/%d1,(%sp) -#else - moveml %a0/%d0/%d1,-(%sp) -#endif - movel %a1,-(%sp) - jbsr __up - movel (%sp)+,%a1 - movel (%sp)+,%d0 - movel (%sp)+,%d1 - rts - -ENTRY(__down_failed_trylock) - movel %a0,-(%sp) - movel %d1,-(%sp) - movel %a1,-(%sp) - jbsr __down_trylock - movel (%sp)+,%a1 - movel (%sp)+,%d1 - movel (%sp)+,%a0 - rts - diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 9e78e1a4ca17..6fcdb6fda2e2 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ - ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ + ptrace.o reset.o setup.o signal.o syscall.o \ time.o topology.o traps.o unaligned.o obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c deleted file mode 100644 index 1265358cdca1..000000000000 --- a/arch/mips/kernel/semaphore.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * MIPS-specific semaphore code. - * - * Copyright (C) 1999 Cort Dougan - * Copyright (C) 2004 Ralf Baechle - * - * 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. - * - * April 2001 - Reworked by Paul Mackerras - * to eliminate the SMP races in the old version between the updates - * of `count' and `waking'. Now we use negative `count' values to - * indicate that some process(es) are waiting for the semaphore. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - * - * On machines without lld/scd we need a spinlock to make the manipulation of - * sem->count and sem->waking atomic. Scalability isn't an issue because - * this lock is used on UP only so it's just an empty variable. - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - if (cpu_has_llsc && R10000_LLSC_WAR) { - __asm__ __volatile__( - " .set mips3 \n" - "1: ll %0, %2 # __sem_update_count \n" - " sra %1, %0, 31 \n" - " not %1 \n" - " and %1, %0, %1 \n" - " addu %1, %1, %3 \n" - " sc %1, %2 \n" - " beqzl %1, 1b \n" - " .set mips0 \n" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (incr), "m" (sem->count)); - } else if (cpu_has_llsc) { - __asm__ __volatile__( - " .set mips3 \n" - "1: ll %0, %2 # __sem_update_count \n" - " sra %1, %0, 31 \n" - " not %1 \n" - " and %1, %0, %1 \n" - " addu %1, %1, %3 \n" - " sc %1, %2 \n" - " beqz %1, 1b \n" - " .set mips0 \n" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (incr), "m" (sem->count)); - } else { - static DEFINE_SPINLOCK(semaphore_lock); - unsigned long flags; - - spin_lock_irqsave(&semaphore_lock, flags); - old_count = atomic_read(&sem->count); - tmp = max_t(int, old_count, 0) + incr; - atomic_set(&sem->count, tmp); - spin_unlock_irqrestore(&semaphore_lock, flags); - } - - return old_count; -} - -void __up(struct semaphore *sem) -{ - /* - * Note that we incremented count in up() before we came here, - * but that was ineffective since the result was <= 0, and - * any negative value of count is equivalent to 0. - * This ends up setting count to 1, unless count is now > 0 - * (i.e. because some other cpu has called up() in the meantime), - * in which case we just increment count. - */ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -EXPORT_SYMBOL(__up); - -/* - * Note that when we come in to __down or __down_interruptible, - * we have already decremented count, but that decrement was - * ineffective since the result was < 0, and any negative value - * of count is equivalent to 0. - * Thus it is only when we decrement count from some value > 0 - * that we have actually got the semaphore. - */ -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - /* - * Try to get the semaphore. If the count is > 0, then we've - * got the semaphore; we decrement count and exit the loop. - * If the count is 0 or negative, we set it to -1, indicating - * that we are asleep, and then sleep. - */ - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - /* - * If there are any more sleepers, wake one of them up so - * that it can either get the semaphore, or set count to -1 - * indicating that there are still processes sleeping. - */ - wake_up(&sem->wait); -} - -EXPORT_SYMBOL(__down); - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - /* - * A signal is pending - give up trying. - * Set sem->count to 0 if it is negative, - * since we are no longer sleeping. - */ - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - wake_up(&sem->wait); - return retval; -} - -EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile index ef07c956170a..23f2ab67574c 100644 --- a/arch/mn10300/kernel/Makefile +++ b/arch/mn10300/kernel/Makefile @@ -3,7 +3,7 @@ # extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o semaphore.o signal.o entry.o fpu.o traps.o irq.o \ +obj-y := process.o signal.o entry.o fpu.o traps.o irq.o \ ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \ switch_to.o mn10300_ksyms.o kernel_execve.o diff --git a/arch/mn10300/kernel/semaphore.c b/arch/mn10300/kernel/semaphore.c deleted file mode 100644 index 9153c4039fd2..000000000000 --- a/arch/mn10300/kernel/semaphore.c +++ /dev/null @@ -1,149 +0,0 @@ -/* MN10300 Semaphore implementation - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#include -#include -#include - -struct sem_waiter { - struct list_head list; - struct task_struct *task; -}; - -#if SEMAPHORE_DEBUG -void semtrace(struct semaphore *sem, const char *str) -{ - if (sem->debug) - printk(KERN_DEBUG "[%d] %s({%d,%d})\n", - current->pid, - str, - atomic_read(&sem->count), - list_empty(&sem->wait_list) ? 0 : 1); -} -#else -#define semtrace(SEM, STR) do { } while (0) -#endif - -/* - * wait for a token to be granted from a semaphore - * - entered with lock held and interrupts disabled - */ -void __down(struct semaphore *sem, unsigned long flags) -{ - struct task_struct *tsk = current; - struct sem_waiter waiter; - - semtrace(sem, "Entering __down"); - - /* set up my own style of waitqueue */ - waiter.task = tsk; - get_task_struct(tsk); - - list_add_tail(&waiter.list, &sem->wait_list); - - /* we don't need to touch the semaphore struct anymore */ - spin_unlock_irqrestore(&sem->wait_lock, flags); - - /* wait to be given the semaphore */ - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - - for (;;) { - if (!waiter.task) - break; - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - - tsk->state = TASK_RUNNING; - semtrace(sem, "Leaving __down"); -} -EXPORT_SYMBOL(__down); - -/* - * interruptibly wait for a token to be granted from a semaphore - * - entered with lock held and interrupts disabled - */ -int __down_interruptible(struct semaphore *sem, unsigned long flags) -{ - struct task_struct *tsk = current; - struct sem_waiter waiter; - int ret; - - semtrace(sem, "Entering __down_interruptible"); - - /* set up my own style of waitqueue */ - waiter.task = tsk; - get_task_struct(tsk); - - list_add_tail(&waiter.list, &sem->wait_list); - - /* we don't need to touch the semaphore struct anymore */ - set_task_state(tsk, TASK_INTERRUPTIBLE); - - spin_unlock_irqrestore(&sem->wait_lock, flags); - - /* wait to be given the semaphore */ - ret = 0; - for (;;) { - if (!waiter.task) - break; - if (unlikely(signal_pending(current))) - goto interrupted; - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - - out: - tsk->state = TASK_RUNNING; - semtrace(sem, "Leaving __down_interruptible"); - return ret; - - interrupted: - spin_lock_irqsave(&sem->wait_lock, flags); - list_del(&waiter.list); - spin_unlock_irqrestore(&sem->wait_lock, flags); - - ret = 0; - if (!waiter.task) { - put_task_struct(current); - ret = -EINTR; - } - goto out; -} -EXPORT_SYMBOL(__down_interruptible); - -/* - * release a single token back to a semaphore - * - entered with lock held and interrupts disabled - */ -void __up(struct semaphore *sem) -{ - struct task_struct *tsk; - struct sem_waiter *waiter; - - semtrace(sem, "Entering __up"); - - /* grant the token to the process at the front of the queue */ - waiter = list_entry(sem->wait_list.next, struct sem_waiter, list); - - /* We must be careful not to touch 'waiter' after we set ->task = NULL. - * It is an allocated on the waiter's stack and may become invalid at - * any time after that point (due to a wakeup from another source). - */ - list_del_init(&waiter->list); - tsk = waiter->task; - smp_mb(); - waiter->task = NULL; - wake_up_process(tsk); - put_task_struct(tsk); - - semtrace(sem, "Leaving __up"); -} -EXPORT_SYMBOL(__up); diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index 27827bc3717e..1f6585a56f97 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -9,7 +9,7 @@ AFLAGS_pacache.o := -traditional obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \ pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \ - ptrace.o hardware.o inventory.o drivers.o semaphore.o \ + ptrace.o hardware.o inventory.o drivers.o \ signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \ process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \ topology.o diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 7aca704e96f0..5b7fc4aa044d 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -69,11 +69,6 @@ EXPORT_SYMBOL(memcpy_toio); EXPORT_SYMBOL(memcpy_fromio); EXPORT_SYMBOL(memset_io); -#include -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down); - extern void $$divI(void); extern void $$divU(void); extern void $$remI(void); diff --git a/arch/parisc/kernel/semaphore.c b/arch/parisc/kernel/semaphore.c deleted file mode 100644 index ee806bcc3726..000000000000 --- a/arch/parisc/kernel/semaphore.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard - */ - -#include -#include -#include -#include - -/* - * Semaphores are complex as we wish to avoid using two variables. - * `count' has multiple roles, depending on its value. If it is positive - * or zero, there are no waiters. The functions here will never be - * called; see - * - * When count is -1 it indicates there is at least one task waiting - * for the semaphore. - * - * When count is less than that, there are '- count - 1' wakeups - * pending. ie if it has value -3, there are 2 wakeups pending. - * - * Note that these functions are only called when there is contention - * on the lock, and as such all this is the "non-critical" part of the - * whole semaphore business. The critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - sem->count--; - wake_up(&sem->wait); -} - -#define wakers(count) (-1 - count) - -#define DOWN_HEAD \ - int ret = 0; \ - DECLARE_WAITQUEUE(wait, current); \ - \ - /* Note that someone is waiting */ \ - if (sem->count == 0) \ - sem->count = -1; \ - \ - /* protected by the sentry still -- use unlocked version */ \ - wait.flags = WQ_FLAG_EXCLUSIVE; \ - __add_wait_queue_tail(&sem->wait, &wait); \ - lost_race: \ - spin_unlock_irq(&sem->sentry); \ - -#define DOWN_TAIL \ - spin_lock_irq(&sem->sentry); \ - if (wakers(sem->count) == 0 && ret == 0) \ - goto lost_race; /* Someone stole our wakeup */ \ - __remove_wait_queue(&sem->wait, &wait); \ - current->state = TASK_RUNNING; \ - if (!waitqueue_active(&sem->wait) && (sem->count < 0)) \ - sem->count = wakers(sem->count); - -#define UPDATE_COUNT \ - sem->count += (sem->count < 0) ? 1 : - 1; - - -void __sched __down(struct semaphore * sem) -{ - DOWN_HEAD - - for(;;) { - set_task_state(current, TASK_UNINTERRUPTIBLE); - /* we can _read_ this without the sentry */ - if (sem->count != -1) - break; - schedule(); - } - - DOWN_TAIL - UPDATE_COUNT -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - DOWN_HEAD - - for(;;) { - set_task_state(current, TASK_INTERRUPTIBLE); - /* we can _read_ this without the sentry */ - if (sem->count != -1) - break; - - if (signal_pending(current)) { - ret = -EINTR; - break; - } - schedule(); - } - - DOWN_TAIL - - if (!ret) { - UPDATE_COUNT - } - - return ret; -} diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index c1baf9d5903f..b9dbfff9afe9 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,7 +12,7 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ +obj-y := cputable.o ptrace.o syscalls.o \ irq.o align.o signal_32.o pmc.o vdso.o \ init_task.o process.o systbl.o idle.o \ signal.o diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 9c98424277a8..65d14e6ddc3c 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/semaphore.c b/arch/powerpc/kernel/semaphore.c deleted file mode 100644 index 2f8c3c951394..000000000000 --- a/arch/powerpc/kernel/semaphore.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * PowerPC-specific semaphore code. - * - * Copyright (C) 1999 Cort Dougan - * - * 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. - * - * April 2001 - Reworked by Paul Mackerras - * to eliminate the SMP races in the old version between the updates - * of `count' and `waking'. Now we use negative `count' values to - * indicate that some process(es) are waiting for the semaphore. - */ - -#include -#include -#include - -#include -#include -#include - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - __asm__ __volatile__("\n" -"1: lwarx %0,0,%3\n" -" srawi %1,%0,31\n" -" andc %1,%0,%1\n" -" add %1,%1,%4\n" - PPC405_ERR77(0,%3) -" stwcx. %1,0,%3\n" -" bne 1b" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (&sem->count), "r" (incr), "m" (sem->count) - : "cc"); - - return old_count; -} - -void __up(struct semaphore *sem) -{ - /* - * Note that we incremented count in up() before we came here, - * but that was ineffective since the result was <= 0, and - * any negative value of count is equivalent to 0. - * This ends up setting count to 1, unless count is now > 0 - * (i.e. because some other cpu has called up() in the meantime), - * in which case we just increment count. - */ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} -EXPORT_SYMBOL(__up); - -/* - * Note that when we come in to __down or __down_interruptible, - * we have already decremented count, but that decrement was - * ineffective since the result was < 0, and any negative value - * of count is equivalent to 0. - * Thus it is only when we decrement count from some value > 0 - * that we have actually got the semaphore. - */ -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - /* - * Try to get the semaphore. If the count is > 0, then we've - * got the semaphore; we decrement count and exit the loop. - * If the count is 0 or negative, we set it to -1, indicating - * that we are asleep, and then sleep. - */ - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - /* - * If there are any more sleepers, wake one of them up so - * that it can either get the semaphore, or set count to -1 - * indicating that there are still processes sleeping. - */ - wake_up(&sem->wait); -} -EXPORT_SYMBOL(__down); - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - /* - * A signal is pending - give up trying. - * Set sem->count to 0 if it is negative, - * since we are no longer sleeping. - */ - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - wake_up(&sem->wait); - return retval; -} -EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c deleted file mode 100644 index 2fe429b27c14..000000000000 --- a/arch/ppc/kernel/semaphore.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * PowerPC-specific semaphore code. - * - * Copyright (C) 1999 Cort Dougan - * - * 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. - * - * April 2001 - Reworked by Paul Mackerras - * to eliminate the SMP races in the old version between the updates - * of `count' and `waking'. Now we use negative `count' values to - * indicate that some process(es) are waiting for the semaphore. - */ - -#include -#include -#include -#include -#include - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - __asm__ __volatile__("\n" -"1: lwarx %0,0,%3\n" -" srawi %1,%0,31\n" -" andc %1,%0,%1\n" -" add %1,%1,%4\n" - PPC405_ERR77(0,%3) -" stwcx. %1,0,%3\n" -" bne 1b" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (&sem->count), "r" (incr), "m" (sem->count) - : "cc"); - - return old_count; -} - -void __up(struct semaphore *sem) -{ - /* - * Note that we incremented count in up() before we came here, - * but that was ineffective since the result was <= 0, and - * any negative value of count is equivalent to 0. - * This ends up setting count to 1, unless count is now > 0 - * (i.e. because some other cpu has called up() in the meantime), - * in which case we just increment count. - */ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -/* - * Note that when we come in to __down or __down_interruptible, - * we have already decremented count, but that decrement was - * ineffective since the result was < 0, and any negative value - * of count is equivalent to 0. - * Thus it is only when we decrement count from some value > 0 - * that we have actually got the semaphore. - */ -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - smp_wmb(); - - /* - * Try to get the semaphore. If the count is > 0, then we've - * got the semaphore; we decrement count and exit the loop. - * If the count is 0 or negative, we set it to -1, indicating - * that we are asleep, and then sleep. - */ - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - /* - * If there are any more sleepers, wake one of them up so - * that it can either get the semaphore, or set count to -1 - * indicating that there are still processes sleeping. - */ - wake_up(&sem->wait); -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - smp_wmb(); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - /* - * A signal is pending - give up trying. - * Set sem->count to 0 if it is negative, - * since we are no longer sleeping. - */ - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - } - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 4d3e38392cb1..ce144b67f060 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -11,7 +11,7 @@ CFLAGS_smp.o := -Wno-nonnull obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o diag.o + s390_ext.o debug.o irq.o ipl.o dis.o diag.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 7234c737f825..48238a114ce9 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -26,13 +26,6 @@ EXPORT_SYMBOL(_ni_bitmap); EXPORT_SYMBOL(_zb_findmap); EXPORT_SYMBOL(_sb_findmap); -/* - * semaphore ops - */ -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); - /* * binfmt_elf loader */ diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c deleted file mode 100644 index 191303f6c1d8..000000000000 --- a/arch/s390/kernel/semaphore.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * linux/arch/s390/kernel/semaphore.c - * - * S390 version - * Copyright (C) 1998-2000 IBM Corporation - * Author(s): Martin Schwidefsky - * - * Derived from "linux/arch/i386/kernel/semaphore.c - * Copyright (C) 1999, Linus Torvalds - * - */ -#include -#include -#include - -#include - -/* - * Atomically update sem->count. Equivalent to: - * old_val = sem->count.counter; - * new_val = ((old_val >= 0) ? old_val : 0) + incr; - * sem->count.counter = new_val; - * return old_val; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_val, new_val; - - asm volatile( - " l %0,0(%3)\n" - "0: ltr %1,%0\n" - " jhe 1f\n" - " lhi %1,0\n" - "1: ar %1,%4\n" - " cs %0,%1,0(%3)\n" - " jl 0b\n" - : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count) - : "a" (&sem->count), "d" (incr), "m" (sem->count) - : "cc"); - return old_val; -} - -/* - * The inline function up() incremented count but the result - * was <= 0. This indicates that some process is waiting on - * the semaphore. The semaphore is free and we'll wake the - * first sleeping process, so we set count to 1 unless some - * other cpu has called up in the meantime in which case - * we just increment count by 1. - */ -void __up(struct semaphore *sem) -{ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -/* - * The inline function down() decremented count and the result - * was < 0. The wait loop will atomically test and update the - * semaphore counter following the rules: - * count > 0: decrement count, wake up queue and exit. - * count <= 0: set count to -1, go to sleep. - */ -void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - wake_up(&sem->wait); -} - -/* - * Same as __down() with an additional test for signals. - * If a signal is pending the count is updated as follows: - * count > 0: wake up queue and exit. - * count <= 0: set count to 0, wake up queue and exit. - */ -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - wake_up(&sem->wait); - return retval; -} - diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32 index 62bf373266f7..4bbdce36b92b 100644 --- a/arch/sh/kernel/Makefile_32 +++ b/arch/sh/kernel/Makefile_32 @@ -5,7 +5,7 @@ extra-y := head_32.o init_task.o vmlinux.lds obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \ - ptrace_32.o semaphore.o setup.o signal_32.o sys_sh.o sys_sh32.o \ + ptrace_32.o setup.o signal_32.o sys_sh.o sys_sh32.o \ syscalls_32.o time_32.o topology.o traps.o traps_32.o obj-y += cpu/ timers/ diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64 index e01283d49cbf..6edf53b93d94 100644 --- a/arch/sh/kernel/Makefile_64 +++ b/arch/sh/kernel/Makefile_64 @@ -1,7 +1,7 @@ extra-y := head_64.o init_task.o vmlinux.lds obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_64.o \ - ptrace_64.o semaphore.o setup.o signal_64.o sys_sh.o sys_sh64.o \ + ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \ syscalls_64.o time_64.o topology.o traps.o traps_64.o obj-y += cpu/ timers/ diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c deleted file mode 100644 index 184119eeae56..000000000000 --- a/arch/sh/kernel/semaphore.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Just taken from alpha implementation. - * This can't work well, perhaps. - */ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in - */ - -#include -#include -#include -#include -#include -#include - -DEFINE_SPINLOCK(semaphore_wake_lock); - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 45bb333fd9ec..6d405462cee8 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -48,12 +47,6 @@ EXPORT_SYMBOL(__copy_user); EXPORT_SYMBOL(get_vm_area); #endif -/* semaphore exports */ -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); - EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index b6410ce4bd1d..a310c9707f03 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -37,9 +36,6 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__put_user_asm_l); EXPORT_SYMBOL(__get_user_asm_l); EXPORT_SYMBOL(copy_page); diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index bf1b15d3f6f5..2712bb166f6f 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \ sys_sparc.o sunos_asm.o systbls.o \ time.o windows.o cpu.o devices.o sclow.o \ tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o una_asm.o muldiv.o semaphore.o \ + unaligned.o una_asm.o muldiv.o \ prom.o of_device.o devres.o devres-y = ../../../kernel/irq/devres.o diff --git a/arch/sparc/kernel/semaphore.c b/arch/sparc/kernel/semaphore.c deleted file mode 100644 index 0c37c1a7cd7e..000000000000 --- a/arch/sparc/kernel/semaphore.c +++ /dev/null @@ -1,155 +0,0 @@ -/* $Id: semaphore.c,v 1.7 2001/04/18 21:06:05 davem Exp $ */ - -/* sparc32 semaphore implementation, based on i386 version */ - -#include -#include -#include - -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is - * protected by the semaphore spinlock. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -static DEFINE_SPINLOCK(semaphore_lock); - -void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic24_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - wake_up(&sem->wait); -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers ++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic24_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. The - * "-1" is because we're still hoping to get - * the lock. - */ - if (!atomic24_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} - -/* - * Trylock failed - make sure we correct for - * having decremented the count. - */ -int __down_trylock(struct semaphore * sem) -{ - int sleepers; - unsigned long flags; - - spin_lock_irqsave(&semaphore_lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic24_add_negative(sleepers, &sem->count)) - wake_up(&sem->wait); - - spin_unlock_irqrestore(&semaphore_lock, flags); - return 1; -} diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index c1025e551650..97b1de0e9094 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -107,11 +107,6 @@ EXPORT_SYMBOL(___rw_read_try); EXPORT_SYMBOL(___rw_read_exit); EXPORT_SYMBOL(___rw_write_enter); #endif -/* semaphores */ -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(__down_interruptible); EXPORT_SYMBOL(sparc_valid_addr_bitmap); EXPORT_SYMBOL(phys_base); diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 1bf5b187de49..459462e80a12 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -10,7 +10,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o central.o pci.o starfire.o semaphore.o \ + unaligned.o central.o pci.o starfire.o \ power.o sbus.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c deleted file mode 100644 index 9974a6899551..000000000000 --- a/arch/sparc64/kernel/semaphore.c +++ /dev/null @@ -1,254 +0,0 @@ -/* semaphore.c: Sparc64 semaphore implementation. - * - * This is basically the PPC semaphore scheme ported to use - * the sparc64 atomic instructions, so see the PPC code for - * credits. - */ - -#include -#include -#include - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - __asm__ __volatile__("\n" -" ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n" -"1: ldsw [%3], %0\n" -" mov %0, %1\n" -" cmp %0, 0\n" -" movl %%icc, 0, %1\n" -" add %1, %4, %1\n" -" cas [%3], %0, %1\n" -" cmp %0, %1\n" -" membar #StoreLoad | #StoreStore\n" -" bne,pn %%icc, 1b\n" -" nop\n" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (&sem->count), "r" (incr), "m" (sem->count) - : "cc"); - - return old_count; -} - -static void __up(struct semaphore *sem) -{ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} - -void up(struct semaphore *sem) -{ - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count + 1; - * sem->count = new_val; - * if (old_val < 0) - * __up(sem); - * - * The (old_val < 0) test is equivalent to - * the more straightforward (new_val <= 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! up sem(%0)\n" -" membar #StoreLoad | #LoadLoad\n" -"1: lduw [%0], %%g1\n" -" add %%g1, 1, %%g7\n" -" cas [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" addcc %%g7, 1, %%g0\n" -" membar #StoreLoad | #StoreStore\n" -" ble,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %0, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %1\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : : "r" (sem), "i" (__up) - : "g1", "g2", "g3", "g7", "memory", "cc"); -} - -static void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - wake_up(&sem->wait); -} - -void __sched down(struct semaphore *sem) -{ - might_sleep(); - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * sem->count = new_val; - * if (old_val < 1) - * __down(sem); - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down sem(%0)\n" -"1: lduw [%0], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cas [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" cmp %%g7, 1\n" -" membar #StoreLoad | #StoreStore\n" -" bl,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %0, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %1\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : : "r" (sem), "i" (__down) - : "g1", "g2", "g3", "g7", "memory", "cc"); -} - -int down_trylock(struct semaphore *sem) -{ - int ret; - - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * if (old_val < 1) { - * ret = 1; - * } else { - * sem->count = new_val; - * ret = 0; - * } - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down_trylock sem(%1) ret(%0)\n" -"1: lduw [%1], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cmp %%g1, 1\n" -" bl,pn %%icc, 2f\n" -" mov 1, %0\n" -" cas [%1], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" mov 0, %0\n" -" membar #StoreLoad | #StoreStore\n" -"2:\n" - : "=&r" (ret) - : "r" (sem) - : "g1", "g7", "memory", "cc"); - - return ret; -} - -static int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - } - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} - -int __sched down_interruptible(struct semaphore *sem) -{ - int ret = 0; - - might_sleep(); - /* This atomically does: - * old_val = sem->count; - * new_val = sem->count - 1; - * sem->count = new_val; - * if (old_val < 1) - * ret = __down_interruptible(sem); - * - * The (old_val < 1) test is equivalent to - * the more straightforward (new_val < 0), - * but it is easier to test the former because - * of how the CAS instruction works. - */ - - __asm__ __volatile__("\n" -" ! down_interruptible sem(%2) ret(%0)\n" -"1: lduw [%2], %%g1\n" -" sub %%g1, 1, %%g7\n" -" cas [%2], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" bne,pn %%icc, 1b\n" -" cmp %%g7, 1\n" -" membar #StoreLoad | #StoreStore\n" -" bl,pn %%icc, 3f\n" -" nop\n" -"2:\n" -" .subsection 2\n" -"3: mov %2, %%g1\n" -" save %%sp, -160, %%sp\n" -" call %3\n" -" mov %%g1, %%o0\n" -" ba,pt %%xcc, 2b\n" -" restore\n" -" .previous\n" - : "=r" (ret) - : "0" (ret), "r" (sem), "i" (__down_interruptible) - : "g1", "g2", "g3", "g7", "memory", "cc"); - return ret; -} diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 51fa773f38c9..051b8d9cb989 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -130,12 +130,6 @@ EXPORT_SYMBOL(_mcount); EXPORT_SYMBOL(sparc64_get_clock_tick); -/* semaphores */ -EXPORT_SYMBOL(down); -EXPORT_SYMBOL(down_trylock); -EXPORT_SYMBOL(down_interruptible); -EXPORT_SYMBOL(up); - /* RW semaphores */ EXPORT_SYMBOL(__down_read); EXPORT_SYMBOL(__down_read_trylock); diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 index 3cd8a04d66d8..e09edfa560da 100644 --- a/arch/um/Kconfig.i386 +++ b/arch/um/Kconfig.i386 @@ -19,10 +19,6 @@ config 64BIT bool default n -config SEMAPHORE_SLEEPERS - bool - default y - config 3_LEVEL_PGTABLES bool "Three-level pagetables (EXPERIMENTAL)" default n diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64 index 6533b349f061..3fbe69e359ed 100644 --- a/arch/um/Kconfig.x86_64 +++ b/arch/um/Kconfig.x86_64 @@ -11,10 +11,6 @@ config RWSEM_GENERIC_SPINLOCK bool default y -config SEMAPHORE_SLEEPERS - bool - default y - config 3_LEVEL_PGTABLES bool default y diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c index 2a1eac1859ce..bfbefd30db8f 100644 --- a/arch/um/sys-i386/ksyms.c +++ b/arch/um/sys-i386/ksyms.c @@ -1,17 +1,5 @@ #include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/delay.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" #include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial); diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile index 08901526e893..b8bc844fd2c4 100644 --- a/arch/um/sys-ppc/Makefile +++ b/arch/um/sys-ppc/Makefile @@ -3,7 +3,7 @@ OBJ = built-in.o .S.o: $(CC) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o -OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ +OBJS = ptrace.o sigcontext.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel @@ -20,10 +20,6 @@ ptrace_user.o: ptrace_user.c sigcontext.o: sigcontext.c $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< -semaphore.c: - rm -f $@ - ln -s $(srctree)/arch/ppc/kernel/$@ $@ - checksum.S: rm -f $@ ln -s $(srctree)/arch/ppc/lib/$@ $@ @@ -66,4 +62,4 @@ misc.o: misc.S ppc_defs.h $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c +clean-files := $(OBJS) ppc_defs.h checksum.S mk_defs.c diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c index 12c593607c59..4d7d1a812d8f 100644 --- a/arch/um/sys-x86_64/ksyms.c +++ b/arch/um/sys-x86_64/ksyms.c @@ -1,16 +1,5 @@ #include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" -#include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); +#include "asm/string.h" /*XXX: we need them because they would be exported by x86_64 */ EXPORT_SYMBOL(__memcpy); diff --git a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile index 3930482bddc4..da5889c53576 100644 --- a/arch/v850/kernel/Makefile +++ b/arch/v850/kernel/Makefile @@ -11,7 +11,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \ +obj-y += intv.o entry.o process.o syscalls.o time.o setup.o \ signal.o irq.o mach.o ptrace.o bug.o obj-$(CONFIG_MODULES) += module.o v850_ksyms.o # chip-specific code diff --git a/arch/v850/kernel/semaphore.c b/arch/v850/kernel/semaphore.c deleted file mode 100644 index fc89fd661c99..000000000000 --- a/arch/v850/kernel/semaphore.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * arch/v850/kernel/semaphore.c -- Semaphore support - * - * Copyright (C) 1998-2000 IBM Corporation - * Copyright (C) 1999 Linus Torvalds - * - * 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. - * - * This file is a copy of the s390 version, arch/s390/kernel/semaphore.c - * Author(s): Martin Schwidefsky - * which was derived from the i386 version, linux/arch/i386/kernel/semaphore.c - */ - -#include -#include -#include - -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is - * protected by the semaphore spinlock. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -static DEFINE_SPINLOCK(semaphore_lock); - -void __sched __down(struct semaphore * sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - wake_up(&sem->wait); -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); - - spin_lock_irq(&semaphore_lock); - sem->sleepers ++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. The - * "-1" is because we're still hoping to get - * the lock. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); - - schedule(); - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); - } - spin_unlock_irq(&semaphore_lock); - tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); - return retval; -} - -/* - * Trylock failed - make sure we correct for - * having decremented the count. - */ -int __down_trylock(struct semaphore * sem) -{ - unsigned long flags; - int sleepers; - - spin_lock_irqsave(&semaphore_lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock. - */ - if (!atomic_add_negative(sleepers, &sem->count)) - wake_up(&sem->wait); - - spin_unlock_irqrestore(&semaphore_lock, flags); - return 1; -} diff --git a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c index 93575fdc874d..8d386a5dbc4a 100644 --- a/arch/v850/kernel/v850_ksyms.c +++ b/arch/v850/kernel/v850_ksyms.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -34,12 +33,6 @@ EXPORT_SYMBOL (memset); EXPORT_SYMBOL (memcpy); EXPORT_SYMBOL (memmove); -/* semaphores */ -EXPORT_SYMBOL (__down); -EXPORT_SYMBOL (__down_interruptible); -EXPORT_SYMBOL (__down_trylock); -EXPORT_SYMBOL (__up); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6c70fed0f9a0..e4b38861ea52 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -53,9 +53,6 @@ config STACKTRACE_SUPPORT config HAVE_LATENCYTOP_SUPPORT def_bool y -config SEMAPHORE_SLEEPERS - def_bool y - config FAST_CMPXCHG_LOCAL bool default y diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c index 061627806a2d..deb43785e923 100644 --- a/arch/x86/kernel/i386_ksyms_32.c +++ b/arch/x86/kernel/i386_ksyms_32.c @@ -1,13 +1,8 @@ #include -#include #include #include #include -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index a66e9c1a0537..95a993e18165 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -12,11 +11,6 @@ EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_2); EXPORT_SYMBOL(__get_user_4); diff --git a/arch/x86/lib/semaphore_32.S b/arch/x86/lib/semaphore_32.S index 3899bd37fdf0..648fe4741782 100644 --- a/arch/x86/lib/semaphore_32.S +++ b/arch/x86/lib/semaphore_32.S @@ -30,89 +30,6 @@ * value or just clobbered.. */ .section .sched.text, "ax" -ENTRY(__down_failed) - CFI_STARTPROC - FRAME - pushl %edx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edx,0 - pushl %ecx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ecx,0 - call __down - popl %ecx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ecx - popl %edx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edx - ENDFRAME - ret - CFI_ENDPROC - ENDPROC(__down_failed) - -ENTRY(__down_failed_interruptible) - CFI_STARTPROC - FRAME - pushl %edx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edx,0 - pushl %ecx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ecx,0 - call __down_interruptible - popl %ecx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ecx - popl %edx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edx - ENDFRAME - ret - CFI_ENDPROC - ENDPROC(__down_failed_interruptible) - -ENTRY(__down_failed_trylock) - CFI_STARTPROC - FRAME - pushl %edx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edx,0 - pushl %ecx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ecx,0 - call __down_trylock - popl %ecx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ecx - popl %edx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edx - ENDFRAME - ret - CFI_ENDPROC - ENDPROC(__down_failed_trylock) - -ENTRY(__up_wakeup) - CFI_STARTPROC - FRAME - pushl %edx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edx,0 - pushl %ecx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ecx,0 - call __up - popl %ecx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ecx - popl %edx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edx - ENDFRAME - ret - CFI_ENDPROC - ENDPROC(__up_wakeup) /* * rw spinlock fallbacks diff --git a/arch/x86/lib/thunk_64.S b/arch/x86/lib/thunk_64.S index 8b92d428ab02..e009251d4e9f 100644 --- a/arch/x86/lib/thunk_64.S +++ b/arch/x86/lib/thunk_64.S @@ -41,11 +41,6 @@ thunk rwsem_downgrade_thunk,rwsem_downgrade_wake #endif - thunk __down_failed,__down - thunk_retrax __down_failed_interruptible,__down_interruptible - thunk_retrax __down_failed_trylock,__down_trylock - thunk __up_wakeup,__up - #ifdef CONFIG_TRACE_IRQFLAGS thunk trace_hardirqs_on_thunk,trace_hardirqs_on thunk trace_hardirqs_off_thunk,trace_hardirqs_off diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile index f582d6a24ec2..7419dbccf027 100644 --- a/arch/xtensa/kernel/Makefile +++ b/arch/xtensa/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o vmlinux.lds -obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \ +obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o \ setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \ pci-dma.o init_task.o io.o diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c deleted file mode 100644 index 995c6410ae10..000000000000 --- a/arch/xtensa/kernel/semaphore.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * arch/xtensa/kernel/semaphore.c - * - * Generic semaphore code. Buyer beware. Do your own specific changes - * in - * - * 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. - * - * Copyright (C) 2001 - 2005 Tensilica Inc. - * - * Joe Taylor - * Chris Zankel - * Marc Gauthier - * Kevin Chea - */ - -#include -#include -#include -#include -#include - -/* - * These two _must_ execute atomically wrt each other. - */ - -static __inline__ void wake_one_more(struct semaphore * sem) -{ - atomic_inc((atomic_t *)&sem->sleepers); -} - -static __inline__ int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ - -static __inline__ int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * We must undo the sem->count down_trylock() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ - -static __inline__ int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers <= 0) - atomic_inc(&sem->count); - else { - sem->sleepers--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -DEFINE_SPINLOCK(semaphore_wake_lock); - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore * sem) -{ - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 60dbdb43fb4c..6e52cdd6166f 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -26,7 +26,6 @@ #include #include #include -#include #ifdef CONFIG_BLK_DEV_FD #include #endif @@ -71,14 +70,6 @@ EXPORT_SYMBOL(__umodsi3); EXPORT_SYMBOL(__udivdi3); EXPORT_SYMBOL(__umoddi3); -/* - * Semaphore operations - */ -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(__up); - #ifdef CONFIG_NET /* * Networking support diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h index f1e9278a9fe2..d9b2034ed1d2 100644 --- a/include/asm-alpha/semaphore.h +++ b/include/asm-alpha/semaphore.h @@ -1,149 +1 @@ -#ifndef _ALPHA_SEMAPHORE_H -#define _ALPHA_SEMAPHORE_H - -/* - * SMP- and interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1996, 2000 Richard Henderson - */ - -#include -#include -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - /* - * Logically, - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * except that gcc produces better initializing by parts yet. - */ - - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void down(struct semaphore *); -extern void __down_failed(struct semaphore *); -extern int down_interruptible(struct semaphore *); -extern int __down_failed_interruptible(struct semaphore *); -extern int down_trylock(struct semaphore *); -extern void up(struct semaphore *); -extern void __up_wakeup(struct semaphore *); - -/* - * Hidden out of line code is fun, but extremely messy. Rely on newer - * compilers to do a respectable job with this. The contention cases - * are handled out of line in arch/alpha/kernel/semaphore.c. - */ - -static inline void __down(struct semaphore *sem) -{ - long count; - might_sleep(); - count = atomic_dec_return(&sem->count); - if (unlikely(count < 0)) - __down_failed(sem); -} - -static inline int __down_interruptible(struct semaphore *sem) -{ - long count; - might_sleep(); - count = atomic_dec_return(&sem->count); - if (unlikely(count < 0)) - return __down_failed_interruptible(sem); - return 0; -} - -/* - * down_trylock returns 0 on success, 1 if we failed to get the lock. - */ - -static inline int __down_trylock(struct semaphore *sem) -{ - long ret; - - /* "Equivalent" C: - - do { - ret = ldl_l; - --ret; - if (ret < 0) - break; - ret = stl_c = ret; - } while (ret == 0); - */ - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " subl %0,1,%0\n" - " blt %0,2f\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - " mb\n" - "2:\n" - ".subsection 2\n" - "3: br 1b\n" - ".previous" - : "=&r" (ret), "=m" (sem->count) - : "m" (sem->count)); - - return ret < 0; -} - -static inline void __up(struct semaphore *sem) -{ - if (unlikely(atomic_inc_return(&sem->count) <= 0)) - __up_wakeup(sem); -} - -#if !defined(CONFIG_DEBUG_SEMAPHORE) -extern inline void down(struct semaphore *sem) -{ - __down(sem); -} -extern inline int down_interruptible(struct semaphore *sem) -{ - return __down_interruptible(sem); -} -extern inline int down_trylock(struct semaphore *sem) -{ - return __down_trylock(sem); -} -extern inline void up(struct semaphore *sem) -{ - __up(sem); -} -#endif - -#endif +#include diff --git a/include/asm-arm/semaphore-helper.h b/include/asm-arm/semaphore-helper.h deleted file mode 100644 index 1d7f1987edb9..000000000000 --- a/include/asm-arm/semaphore-helper.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef ASMARM_SEMAPHORE_HELPER_H -#define ASMARM_SEMAPHORE_HELPER_H - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (atomic_read(&sem->count) <= 0) - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking non zero interruptible - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_try_lock: - * 1 failed to lock - * 0 got the lock - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - atomic_inc(&sem->count); - else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff --git a/include/asm-arm/semaphore.h b/include/asm-arm/semaphore.h index 1c8b441f89e3..d9b2034ed1d2 100644 --- a/include/asm-arm/semaphore.h +++ b/include/asm-arm/semaphore.h @@ -1,98 +1 @@ -/* - * linux/include/asm-arm/semaphore.h - */ -#ifndef __ASM_ARM_SEMAPHORE_H -#define __ASM_ARM_SEMAPHORE_H - -#include -#include -#include -#include - -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INIT(name, cnt) \ -{ \ - .count = ATOMIC_INIT(cnt), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INIT(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX(struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED(struct semaphore *sem) -{ - sema_init(sem, 0); -} - -/* - * special register calling convention - */ -asmlinkage void __down_failed(void); -asmlinkage int __down_interruptible_failed(void); -asmlinkage int __down_trylock_failed(void); -asmlinkage void __up_wakeup(void); - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern int __down_trylock(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -/* - * This is ugly, but we want the default case to fall through. - * "__down" is the actual routine that waits... - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - __down_op(sem, __down_failed); -} - -/* - * This is ugly, but we want the default case to fall through. - * "__down_interruptible" is the actual routine that waits... - */ -static inline int down_interruptible (struct semaphore * sem) -{ - might_sleep(); - return __down_op_ret(sem, __down_interruptible_failed); -} - -static inline int down_trylock(struct semaphore *sem) -{ - return __down_op_ret(sem, __down_trylock_failed); -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - __up_op(sem, __up_wakeup); -} - -#endif +#include diff --git a/include/asm-avr32/semaphore.h b/include/asm-avr32/semaphore.h index feaf1d453386..d9b2034ed1d2 100644 --- a/include/asm-avr32/semaphore.h +++ b/include/asm-avr32/semaphore.h @@ -1,108 +1 @@ -/* - * SMP- and interrupt-safe semaphores. - * - * Copyright (C) 2006 Atmel Corporation - * - * Based on include/asm-i386/semaphore.h - * Copyright (C) 1996 Linus Torvalds - * - * 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. - */ -#ifndef __ASM_AVR32_SEMAPHORE_H -#define __ASM_AVR32_SEMAPHORE_H - -#include - -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -void __down(struct semaphore * sem); -int __down_interruptible(struct semaphore * sem); -void __up(struct semaphore * sem); - -/* - * This is ugly, but we want the default case to fall through. - * "__down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/i386/kernel/semaphore.c - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - if (unlikely(atomic_dec_return (&sem->count) < 0)) - __down (sem); -} - -/* - * Interruptible try to acquire a semaphore. If we obtained - * it, return zero. If we were interrupted, returns -EINTR - */ -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - if (unlikely(atomic_dec_return (&sem->count) < 0)) - ret = __down_interruptible (sem); - return ret; -} - -/* - * Non-blockingly attempt to down() a semaphore. - * Returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore * sem) -{ - return atomic_dec_if_positive(&sem->count) < 0; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - if (unlikely(atomic_inc_return (&sem->count) <= 0)) - __up (sem); -} - -#endif /*__ASM_AVR32_SEMAPHORE_H */ +#include diff --git a/include/asm-blackfin/semaphore-helper.h b/include/asm-blackfin/semaphore-helper.h deleted file mode 100644 index 9082b0dc3eb5..000000000000 --- a/include/asm-blackfin/semaphore-helper.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Based on M68K version, Lineo Inc. May 2001 */ - -#ifndef _BFIN_SEMAPHORE_HELPER_H -#define _BFIN_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * - */ - -#include - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore *sem) -{ - atomic_inc(&sem->waking); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - int ret; - unsigned long flags = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - int ret = 0; - unsigned long flags = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - int ret = 1; - unsigned long flags = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 0; - } else - atomic_inc(&sem->count); - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif /* _BFIN_SEMAPHORE_HELPER_H */ diff --git a/include/asm-blackfin/semaphore.h b/include/asm-blackfin/semaphore.h index 533f90fb2e4e..d9b2034ed1d2 100644 --- a/include/asm-blackfin/semaphore.h +++ b/include/asm-blackfin/semaphore.h @@ -1,105 +1 @@ -#ifndef _BFIN_SEMAPHORE_H -#define _BFIN_SEMAPHORE_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include -#include - -/* - * Interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * BFIN version by akbar hussain Lineo Inc April 2001 - * - */ - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX(struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED(struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down(struct semaphore *sem); -asmlinkage int __down_interruptible(struct semaphore *sem); -asmlinkage int __down_trylock(struct semaphore *sem); -asmlinkage void __up(struct semaphore *sem); - -extern spinlock_t semaphore_wake_lock; - -/* - * This is ugly, but we want the default case to fall through. - * "down_failed" is a special asm handler that calls the C - * routine that actually waits. - */ -static inline void down(struct semaphore *sem) -{ - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - __down(sem); -} - -static inline int down_interruptible(struct semaphore *sem) -{ - int ret = 0; - - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - ret = __down_interruptible(sem); - return (ret); -} - -static inline int down_trylock(struct semaphore *sem) -{ - int ret = 0; - - if (atomic_dec_return(&sem->count) < 0) - ret = __down_trylock(sem); - return ret; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore *sem) -{ - if (atomic_inc_return(&sem->count) <= 0) - __up(sem); -} - -#endif /* __ASSEMBLY__ */ -#endif /* _BFIN_SEMAPHORE_H */ +#include diff --git a/include/asm-cris/semaphore-helper.h b/include/asm-cris/semaphore-helper.h deleted file mode 100644 index 27bfeca1b981..000000000000 --- a/include/asm-cris/semaphore-helper.h +++ /dev/null @@ -1,78 +0,0 @@ -/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $ - * - * SMP- and interrupt-safe semaphores helper functions. Generic versions, no - * optimizations whatsoever... - * - */ - -#ifndef _ASM_SEMAPHORE_HELPER_H -#define _ASM_SEMAPHORE_HELPER_H - -#include -#include - -#define read(a) ((a)->counter) -#define inc(a) (((a)->counter)++) -#define dec(a) (((a)->counter)--) - -#define count_inc(a) ((*(a))++) - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - atomic_inc(&sem->waking); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - local_irq_save(flags); - if (read(&sem->waking) > 0) { - dec(&sem->waking); - ret = 1; - } - local_irq_restore(flags); - return ret; -} - -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - int ret = 0; - unsigned long flags; - - local_irq_save(flags); - if (read(&sem->waking) > 0) { - dec(&sem->waking); - ret = 1; - } else if (signal_pending(tsk)) { - inc(&sem->count); - ret = -EINTR; - } - local_irq_restore(flags); - return ret; -} - -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - int ret = 1; - unsigned long flags; - - local_irq_save(flags); - if (read(&sem->waking) <= 0) - inc(&sem->count); - else { - dec(&sem->waking); - ret = 0; - } - local_irq_restore(flags); - return ret; -} - -#endif /* _ASM_SEMAPHORE_HELPER_H */ - - diff --git a/include/asm-cris/semaphore.h b/include/asm-cris/semaphore.h index 31a4ac448195..d9b2034ed1d2 100644 --- a/include/asm-cris/semaphore.h +++ b/include/asm-cris/semaphore.h @@ -1,133 +1 @@ -/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */ - -/* On the i386 these are coded in asm, perhaps we should as well. Later.. */ - -#ifndef _CRIS_SEMAPHORE_H -#define _CRIS_SEMAPHORE_H - -#define RW_LOCK_BIAS 0x01000000 - -#include -#include -#include - -#include -#include - -/* - * CRIS semaphores, implemented in C-only so far. - */ - -struct semaphore { - atomic_t count; - atomic_t waking; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .waking = ATOMIC_INIT(0), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern int __down_trylock(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -/* notice - we probably can do cli/sti here instead of saving */ - -static inline void down(struct semaphore * sem) -{ - unsigned long flags; - int failed; - - might_sleep(); - - /* atomically decrement the semaphores count, and if its negative, we wait */ - cris_atomic_save(sem, flags); - failed = --(sem->count.counter) < 0; - cris_atomic_restore(sem, flags); - if(failed) { - __down(sem); - } -} - -/* - * This version waits in interruptible state so that the waiting - * process can be killed. The down_interruptible routine - * returns negative for signalled and zero for semaphore acquired. - */ - -static inline int down_interruptible(struct semaphore * sem) -{ - unsigned long flags; - int failed; - - might_sleep(); - - /* atomically decrement the semaphores count, and if its negative, we wait */ - cris_atomic_save(sem, flags); - failed = --(sem->count.counter) < 0; - cris_atomic_restore(sem, flags); - if(failed) - failed = __down_interruptible(sem); - return(failed); -} - -static inline int down_trylock(struct semaphore * sem) -{ - unsigned long flags; - int failed; - - cris_atomic_save(sem, flags); - failed = --(sem->count.counter) < 0; - cris_atomic_restore(sem, flags); - if(failed) - failed = __down_trylock(sem); - return(failed); - -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - unsigned long flags; - int wakeup; - - /* atomically increment the semaphores count, and if it was negative, we wake people */ - cris_atomic_save(sem, flags); - wakeup = ++(sem->count.counter) <= 0; - cris_atomic_restore(sem, flags); - if(wakeup) { - __up(sem); - } -} - -#endif +#include diff --git a/include/asm-frv/semaphore.h b/include/asm-frv/semaphore.h index d7aaa1911a1a..d9b2034ed1d2 100644 --- a/include/asm-frv/semaphore.h +++ b/include/asm-frv/semaphore.h @@ -1,155 +1 @@ -/* semaphore.h: semaphores for the FR-V - * - * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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 _ASM_SEMAPHORE_H -#define _ASM_SEMAPHORE_H - -#define RW_LOCK_BIAS 0x01000000 - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -/* - * the semaphore definition - * - if counter is >0 then there are tokens available on the semaphore for down to collect - * - if counter is <=0 then there are no spare tokens, and anyone that wants one must wait - * - if wait_list is not empty, then there are processes waiting for the semaphore - */ -struct semaphore { - unsigned counter; - spinlock_t wait_lock; - struct list_head wait_list; -#ifdef CONFIG_DEBUG_SEMAPHORE - unsigned __magic; -#endif -}; - -#ifdef CONFIG_DEBUG_SEMAPHORE -# define __SEM_DEBUG_INIT(name) , (long)&(name).__magic -#else -# define __SEM_DEBUG_INIT(name) -#endif - - -#define __SEMAPHORE_INITIALIZER(name,count) \ -{ count, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __SEM_DEBUG_INIT(name) } - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore *sem, unsigned long flags); -extern int __down_interruptible(struct semaphore *sem, unsigned long flags); -extern void __up(struct semaphore *sem); - -static inline void down(struct semaphore *sem) -{ - unsigned long flags; - -#ifdef CONFIG_DEBUG_SEMAPHORE - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - if (likely(sem->counter > 0)) { - sem->counter--; - spin_unlock_irqrestore(&sem->wait_lock, flags); - } - else { - __down(sem, flags); - } -} - -static inline int down_interruptible(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - -#ifdef CONFIG_DEBUG_SEMAPHORE - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - if (likely(sem->counter > 0)) { - sem->counter--; - spin_unlock_irqrestore(&sem->wait_lock, flags); - } - else { - ret = __down_interruptible(sem, flags); - } - return ret; -} - -/* - * non-blockingly attempt to down() a semaphore. - * - returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore *sem) -{ - unsigned long flags; - int success = 0; - -#ifdef CONFIG_DEBUG_SEMAPHORE - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - if (sem->counter > 0) { - sem->counter--; - success = 1; - } - spin_unlock_irqrestore(&sem->wait_lock, flags); - return !success; -} - -static inline void up(struct semaphore *sem) -{ - unsigned long flags; - -#ifdef CONFIG_DEBUG_SEMAPHORE - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - if (!list_empty(&sem->wait_list)) - __up(sem); - else - sem->counter++; - spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -static inline int sem_getcount(struct semaphore *sem) -{ - return sem->counter; -} - -#endif /* __ASSEMBLY__ */ - -#endif +#include diff --git a/include/asm-h8300/semaphore-helper.h b/include/asm-h8300/semaphore-helper.h deleted file mode 100644 index 4fea36be5fd8..000000000000 --- a/include/asm-h8300/semaphore-helper.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _H8300_SEMAPHORE_HELPER_H -#define _H8300_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * - * based on - * m68k version by Andreas Schwab - */ - -#include - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - atomic_inc((atomic_t *)&sem->sleepers); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 1; - if (sem->sleepers <= 0) - atomic_inc(&sem->count); - else { - sem->sleepers--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff --git a/include/asm-h8300/semaphore.h b/include/asm-h8300/semaphore.h index f3ffff83ff09..d9b2034ed1d2 100644 --- a/include/asm-h8300/semaphore.h +++ b/include/asm-h8300/semaphore.h @@ -1,190 +1 @@ -#ifndef _H8300_SEMAPHORE_H -#define _H8300_SEMAPHORE_H - -#define RW_LOCK_BIAS 0x01000000 - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#include -#include - -/* - * Interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * H8/300 version by Yoshinori Sato - */ - - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -extern spinlock_t semaphore_wake_lock; - -/* - * This is ugly, but we want the default case to fall through. - * "down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/m68k/lib/semaphore.S - */ -static inline void down(struct semaphore * sem) -{ - register atomic_t *count asm("er0"); - - might_sleep(); - - count = &(sem->count); - __asm__ __volatile__( - "stc ccr,r3l\n\t" - "orc #0x80,ccr\n\t" - "mov.l %2, er1\n\t" - "dec.l #1,er1\n\t" - "mov.l er1,%0\n\t" - "bpl 1f\n\t" - "ldc r3l,ccr\n\t" - "mov.l %1,er0\n\t" - "jsr @___down\n\t" - "bra 2f\n" - "1:\n\t" - "ldc r3l,ccr\n" - "2:" - : "=m"(*count) - : "g"(sem),"m"(*count) - : "cc", "er1", "er2", "er3"); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - register atomic_t *count asm("er0"); - - might_sleep(); - - count = &(sem->count); - __asm__ __volatile__( - "stc ccr,r1l\n\t" - "orc #0x80,ccr\n\t" - "mov.l %3, er2\n\t" - "dec.l #1,er2\n\t" - "mov.l er2,%1\n\t" - "bpl 1f\n\t" - "ldc r1l,ccr\n\t" - "mov.l %2,er0\n\t" - "jsr @___down_interruptible\n\t" - "bra 2f\n" - "1:\n\t" - "ldc r1l,ccr\n\t" - "sub.l %0,%0\n\t" - "2:\n\t" - : "=r" (count),"=m" (*count) - : "g"(sem),"m"(*count) - : "cc", "er1", "er2", "er3"); - return (int)count; -} - -static inline int down_trylock(struct semaphore * sem) -{ - register atomic_t *count asm("er0"); - - count = &(sem->count); - __asm__ __volatile__( - "stc ccr,r3l\n\t" - "orc #0x80,ccr\n\t" - "mov.l %3,er2\n\t" - "dec.l #1,er2\n\t" - "mov.l er2,%0\n\t" - "bpl 1f\n\t" - "ldc r3l,ccr\n\t" - "jmp @3f\n\t" - LOCK_SECTION_START(".align 2\n\t") - "3:\n\t" - "mov.l %2,er0\n\t" - "jsr @___down_trylock\n\t" - "jmp @2f\n\t" - LOCK_SECTION_END - "1:\n\t" - "ldc r3l,ccr\n\t" - "sub.l %1,%1\n" - "2:" - : "=m" (*count),"=r"(count) - : "g"(sem),"m"(*count) - : "cc", "er1","er2", "er3"); - return (int)count; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - register atomic_t *count asm("er0"); - - count = &(sem->count); - __asm__ __volatile__( - "stc ccr,r3l\n\t" - "orc #0x80,ccr\n\t" - "mov.l %2,er1\n\t" - "inc.l #1,er1\n\t" - "mov.l er1,%0\n\t" - "ldc r3l,ccr\n\t" - "sub.l er2,er2\n\t" - "cmp.l er2,er1\n\t" - "bgt 1f\n\t" - "mov.l %1,er0\n\t" - "jsr @___up\n" - "1:" - : "=m"(*count) - : "g"(sem),"m"(*count) - : "cc", "er1", "er2", "er3"); -} - -#endif /* __ASSEMBLY__ */ - -#endif +#include diff --git a/include/asm-ia64/semaphore.h b/include/asm-ia64/semaphore.h index d8393d11288d..d9b2034ed1d2 100644 --- a/include/asm-ia64/semaphore.h +++ b/include/asm-ia64/semaphore.h @@ -1,99 +1 @@ -#ifndef _ASM_IA64_SEMAPHORE_H -#define _ASM_IA64_SEMAPHORE_H - -/* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - */ - -#include -#include - -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) - -static inline void -sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void -init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void -init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down (struct semaphore * sem); -extern int __down_interruptible (struct semaphore * sem); -extern int __down_trylock (struct semaphore * sem); -extern void __up (struct semaphore * sem); - -/* - * Atomically decrement the semaphore's count. If it goes negative, - * block the calling thread in the TASK_UNINTERRUPTIBLE state. - */ -static inline void -down (struct semaphore *sem) -{ - might_sleep(); - if (ia64_fetchadd(-1, &sem->count.counter, acq) < 1) - __down(sem); -} - -/* - * Atomically decrement the semaphore's count. If it goes negative, - * block the calling thread in the TASK_INTERRUPTIBLE state. - */ -static inline int -down_interruptible (struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - if (ia64_fetchadd(-1, &sem->count.counter, acq) < 1) - ret = __down_interruptible(sem); - return ret; -} - -static inline int -down_trylock (struct semaphore *sem) -{ - int ret = 0; - - if (ia64_fetchadd(-1, &sem->count.counter, acq) < 1) - ret = __down_trylock(sem); - return ret; -} - -static inline void -up (struct semaphore * sem) -{ - if (ia64_fetchadd(1, &sem->count.counter, rel) <= -1) - __up(sem); -} - -#endif /* _ASM_IA64_SEMAPHORE_H */ +#include diff --git a/include/asm-m32r/semaphore.h b/include/asm-m32r/semaphore.h index b5bf95a6f2b4..d9b2034ed1d2 100644 --- a/include/asm-m32r/semaphore.h +++ b/include/asm-m32r/semaphore.h @@ -1,144 +1 @@ -#ifndef _ASM_M32R_SEMAPHORE_H -#define _ASM_M32R_SEMAPHORE_H - -#include - -#ifdef __KERNEL__ - -/* - * SMP- and interrupt-safe semaphores.. - * - * Copyright (C) 1996 Linus Torvalds - * Copyright (C) 2004, 2006 Hirokazu Takata - */ - -#include -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ -/* - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * - * i'd rather use the more flexible initialization above, but sadly - * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well. - */ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -/* - * Atomically decrement the semaphore's count. If it goes negative, - * block the calling thread in the TASK_UNINTERRUPTIBLE state. - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - if (unlikely(atomic_dec_return(&sem->count) < 0)) - __down(sem); -} - -/* - * Interruptible try to acquire a semaphore. If we obtained - * it, return zero. If we were interrupted, returns -EINTR - */ -static inline int down_interruptible(struct semaphore * sem) -{ - int result = 0; - - might_sleep(); - if (unlikely(atomic_dec_return(&sem->count) < 0)) - result = __down_interruptible(sem); - - return result; -} - -/* - * Non-blockingly attempt to down() a semaphore. - * Returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore * sem) -{ - unsigned long flags; - long count; - int result = 0; - - local_irq_save(flags); - __asm__ __volatile__ ( - "# down_trylock \n\t" - DCACHE_CLEAR("%0", "r4", "%1") - M32R_LOCK" %0, @%1; \n\t" - "addi %0, #-1; \n\t" - M32R_UNLOCK" %0, @%1; \n\t" - : "=&r" (count) - : "r" (&sem->count) - : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r4" -#endif /* CONFIG_CHIP_M32700_TS1 */ - ); - local_irq_restore(flags); - - if (unlikely(count < 0)) - result = __down_trylock(sem); - - return result; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - if (unlikely(atomic_inc_return(&sem->count) <= 0)) - __up(sem); -} - -#endif /* __KERNEL__ */ - -#endif /* _ASM_M32R_SEMAPHORE_H */ +#include diff --git a/include/asm-m68k/semaphore-helper.h b/include/asm-m68k/semaphore-helper.h deleted file mode 100644 index eef30ba0b499..000000000000 --- a/include/asm-m68k/semaphore-helper.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef _M68K_SEMAPHORE_HELPER_H -#define _M68K_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - */ - -#include - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - atomic_inc(&sem->waking); -} - -#ifndef CONFIG_RMW_INSNS -extern spinlock_t semaphore_wake_lock; -#endif - -static inline int waking_non_zero(struct semaphore *sem) -{ - int ret; -#ifndef CONFIG_RMW_INSNS - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -#else - int tmp1, tmp2; - - __asm__ __volatile__ - ("1: movel %1,%2\n" - " jle 2f\n" - " subql #1,%2\n" - " casl %1,%2,%3\n" - " jne 1b\n" - " moveq #1,%0\n" - "2:" - : "=d" (ret), "=d" (tmp1), "=d" (tmp2) - : "m" (sem->waking), "0" (0), "1" (sem->waking)); -#endif - - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - int ret; -#ifndef CONFIG_RMW_INSNS - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -#else - int tmp1, tmp2; - - __asm__ __volatile__ - ("1: movel %1,%2\n" - " jle 2f\n" - " subql #1,%2\n" - " casl %1,%2,%3\n" - " jne 1b\n" - " moveq #1,%0\n" - " jra %a4\n" - "2:" - : "=d" (ret), "=d" (tmp1), "=d" (tmp2) - : "m" (sem->waking), "i" (&&next), "0" (0), "1" (sem->waking)); - if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } -next: -#endif - - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - int ret; -#ifndef CONFIG_RMW_INSNS - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 1; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 0; - } else - atomic_inc(&sem->count); - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -#else - int tmp1, tmp2; - - __asm__ __volatile__ - ("1: movel %1,%2\n" - " jle 2f\n" - " subql #1,%2\n" - " casl %1,%2,%3\n" - " jne 1b\n" - " moveq #0,%0\n" - "2:" - : "=d" (ret), "=d" (tmp1), "=d" (tmp2) - : "m" (sem->waking), "0" (1), "1" (sem->waking)); - if (ret) - atomic_inc(&sem->count); -#endif - return ret; -} - -#endif diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h index 64d6b119bb0a..d9b2034ed1d2 100644 --- a/include/asm-m68k/semaphore.h +++ b/include/asm-m68k/semaphore.h @@ -1,163 +1 @@ -#ifndef _M68K_SEMAPHORE_H -#define _M68K_SEMAPHORE_H - -#define RW_LOCK_BIAS 0x01000000 - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include -#include - -#include -#include - -/* - * Interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - */ - - -struct semaphore { - atomic_t count; - atomic_t waking; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .waking = ATOMIC_INIT(0), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -/* - * This is ugly, but we want the default case to fall through. - * "down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/m68k/lib/semaphore.S - */ -static inline void down(struct semaphore *sem) -{ - register struct semaphore *sem1 __asm__ ("%a1") = sem; - - might_sleep(); - __asm__ __volatile__( - "| atomic down operation\n\t" - "subql #1,%0@\n\t" - "jmi 2f\n\t" - "1:\n" - LOCK_SECTION_START(".even\n\t") - "2:\tpea 1b\n\t" - "jbra __down_failed\n" - LOCK_SECTION_END - : /* no outputs */ - : "a" (sem1) - : "memory"); -} - -static inline int down_interruptible(struct semaphore *sem) -{ - register struct semaphore *sem1 __asm__ ("%a1") = sem; - register int result __asm__ ("%d0"); - - might_sleep(); - __asm__ __volatile__( - "| atomic interruptible down operation\n\t" - "subql #1,%1@\n\t" - "jmi 2f\n\t" - "clrl %0\n" - "1:\n" - LOCK_SECTION_START(".even\n\t") - "2:\tpea 1b\n\t" - "jbra __down_failed_interruptible\n" - LOCK_SECTION_END - : "=d" (result) - : "a" (sem1) - : "memory"); - return result; -} - -static inline int down_trylock(struct semaphore *sem) -{ - register struct semaphore *sem1 __asm__ ("%a1") = sem; - register int result __asm__ ("%d0"); - - __asm__ __volatile__( - "| atomic down trylock operation\n\t" - "subql #1,%1@\n\t" - "jmi 2f\n\t" - "clrl %0\n" - "1:\n" - LOCK_SECTION_START(".even\n\t") - "2:\tpea 1b\n\t" - "jbra __down_failed_trylock\n" - LOCK_SECTION_END - : "=d" (result) - : "a" (sem1) - : "memory"); - return result; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore *sem) -{ - register struct semaphore *sem1 __asm__ ("%a1") = sem; - - __asm__ __volatile__( - "| atomic up operation\n\t" - "addql #1,%0@\n\t" - "jle 2f\n" - "1:\n" - LOCK_SECTION_START(".even\n\t") - "2:\t" - "pea 1b\n\t" - "jbra __up_wakeup\n" - LOCK_SECTION_END - : /* no outputs */ - : "a" (sem1) - : "memory"); -} - -#endif /* __ASSEMBLY__ */ - -#endif +#include diff --git a/include/asm-m68knommu/semaphore-helper.h b/include/asm-m68knommu/semaphore-helper.h deleted file mode 100644 index 43da7bc483c7..000000000000 --- a/include/asm-m68knommu/semaphore-helper.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef _M68K_SEMAPHORE_HELPER_H -#define _M68K_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - */ - - -/* - * These two _must_ execute atomically wrt each other. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - atomic_inc(&sem->waking); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 0; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - ret = 1; - if (atomic_read(&sem->waking) > 0) { - atomic_dec(&sem->waking); - ret = 0; - } else - atomic_inc(&sem->count); - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff --git a/include/asm-m68knommu/semaphore.h b/include/asm-m68knommu/semaphore.h index 5779eb6c0689..d9b2034ed1d2 100644 --- a/include/asm-m68knommu/semaphore.h +++ b/include/asm-m68knommu/semaphore.h @@ -1,153 +1 @@ -#ifndef _M68K_SEMAPHORE_H -#define _M68K_SEMAPHORE_H - -#define RW_LOCK_BIAS 0x01000000 - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#include -#include - -/* - * Interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * m68k version by Andreas Schwab - */ - - -struct semaphore { - atomic_t count; - atomic_t waking; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .waking = ATOMIC_INIT(0), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -extern spinlock_t semaphore_wake_lock; - -/* - * This is ugly, but we want the default case to fall through. - * "down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/m68k/lib/semaphore.S - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - __asm__ __volatile__( - "| atomic down operation\n\t" - "movel %0, %%a1\n\t" - "lea %%pc@(1f), %%a0\n\t" - "subql #1, %%a1@\n\t" - "jmi __down_failed\n" - "1:" - : /* no outputs */ - : "g" (sem) - : "cc", "%a0", "%a1", "memory"); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret; - - might_sleep(); - __asm__ __volatile__( - "| atomic down operation\n\t" - "movel %1, %%a1\n\t" - "lea %%pc@(1f), %%a0\n\t" - "subql #1, %%a1@\n\t" - "jmi __down_failed_interruptible\n\t" - "clrl %%d0\n" - "1: movel %%d0, %0\n" - : "=d" (ret) - : "g" (sem) - : "cc", "%d0", "%a0", "%a1", "memory"); - return(ret); -} - -static inline int down_trylock(struct semaphore * sem) -{ - register struct semaphore *sem1 __asm__ ("%a1") = sem; - register int result __asm__ ("%d0"); - - __asm__ __volatile__( - "| atomic down trylock operation\n\t" - "subql #1,%1@\n\t" - "jmi 2f\n\t" - "clrl %0\n" - "1:\n" - ".section .text.lock,\"ax\"\n" - ".even\n" - "2:\tpea 1b\n\t" - "jbra __down_failed_trylock\n" - ".previous" - : "=d" (result) - : "a" (sem1) - : "memory"); - return result; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - __asm__ __volatile__( - "| atomic up operation\n\t" - "movel %0, %%a1\n\t" - "lea %%pc@(1f), %%a0\n\t" - "addql #1, %%a1@\n\t" - "jle __up_wakeup\n" - "1:" - : /* no outputs */ - : "g" (sem) - : "cc", "%a0", "%a1", "memory"); -} - -#endif /* __ASSEMBLY__ */ - -#endif +#include diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index fdf8042b784b..d9b2034ed1d2 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -1,108 +1 @@ -/* - * 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. - * - * Copyright (C) 1996 Linus Torvalds - * Copyright (C) 1998, 99, 2000, 01, 04 Ralf Baechle - * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc. - * Copyright (C) 2000, 01 MIPS Technologies, Inc. - * - * In all honesty, little of the old MIPS code left - the PPC64 variant was - * just looking nice and portable so I ripped it. Credits to whoever wrote - * it. - */ -#ifndef __ASM_SEMAPHORE_H -#define __ASM_SEMAPHORE_H - -/* - * Remove spinlock-based RW semaphores; RW semaphore definitions are - * now in rwsem.h and we use the generic lib/rwsem.c implementation. - * Rework semaphores to use atomic_dec_if_positive. - * -- Paul Mackerras (paulus@samba.org) - */ - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -struct semaphore { - /* - * Note that any negative value of count is equivalent to 0, - * but additionally indicates that some process(es) might be - * sleeping on `wait'. - */ - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX(struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED(struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - - /* - * Try to get the semaphore, take the slow path if we fail. - */ - if (unlikely(atomic_dec_return(&sem->count) < 0)) - __down(sem); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - - if (unlikely(atomic_dec_return(&sem->count) < 0)) - ret = __down_interruptible(sem); - return ret; -} - -static inline int down_trylock(struct semaphore * sem) -{ - return atomic_dec_if_positive(&sem->count) < 0; -} - -static inline void up(struct semaphore * sem) -{ - if (unlikely(atomic_inc_return(&sem->count) <= 0)) - __up(sem); -} - -#endif /* __KERNEL__ */ - -#endif /* __ASM_SEMAPHORE_H */ +#include diff --git a/include/asm-mn10300/semaphore.h b/include/asm-mn10300/semaphore.h index 5a9e1ad0b253..d9b2034ed1d2 100644 --- a/include/asm-mn10300/semaphore.h +++ b/include/asm-mn10300/semaphore.h @@ -1,169 +1 @@ -/* MN10300 Semaphores - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef _ASM_SEMAPHORE_H -#define _ASM_SEMAPHORE_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#define SEMAPHORE_DEBUG 0 - -/* - * the semaphore definition - * - if count is >0 then there are tokens available on the semaphore for down - * to collect - * - if count is <=0 then there are no spare tokens, and anyone that wants one - * must wait - * - if wait_list is not empty, then there are processes waiting for the - * semaphore - */ -struct semaphore { - atomic_t count; /* it's not really atomic, it's - * just that certain modules - * expect to be able to access - * it directly */ - spinlock_t wait_lock; - struct list_head wait_list; -#if SEMAPHORE_DEBUG - unsigned __magic; -#endif -}; - -#if SEMAPHORE_DEBUG -# define __SEM_DEBUG_INIT(name) , (long)&(name).__magic -#else -# define __SEM_DEBUG_INIT(name) -#endif - - -#define __SEMAPHORE_INITIALIZER(name, init_count) \ -{ \ - .count = ATOMIC_INIT(init_count), \ - .wait_lock = __SPIN_LOCK_UNLOCKED((name).wait_lock), \ - .wait_list = LIST_HEAD_INIT((name).wait_list) \ - __SEM_DEBUG_INIT(name) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) -#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0) - -static inline void sema_init(struct semaphore *sem, int val) -{ - *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); -} - -static inline void init_MUTEX(struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED(struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore *sem, unsigned long flags); -extern int __down_interruptible(struct semaphore *sem, unsigned long flags); -extern void __up(struct semaphore *sem); - -static inline void down(struct semaphore *sem) -{ - unsigned long flags; - int count; - -#if SEMAPHORE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - count = atomic_read(&sem->count); - if (likely(count > 0)) { - atomic_set(&sem->count, count - 1); - spin_unlock_irqrestore(&sem->wait_lock, flags); - } else { - __down(sem, flags); - } -} - -static inline int down_interruptible(struct semaphore *sem) -{ - unsigned long flags; - int count, ret = 0; - -#if SEMAPHORE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - count = atomic_read(&sem->count); - if (likely(count > 0)) { - atomic_set(&sem->count, count - 1); - spin_unlock_irqrestore(&sem->wait_lock, flags); - } else { - ret = __down_interruptible(sem, flags); - } - return ret; -} - -/* - * non-blockingly attempt to down() a semaphore. - * - returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore *sem) -{ - unsigned long flags; - int count, success = 0; - -#if SEMAPHORE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - count = atomic_read(&sem->count); - if (likely(count > 0)) { - atomic_set(&sem->count, count - 1); - success = 1; - } - spin_unlock_irqrestore(&sem->wait_lock, flags); - return !success; -} - -static inline void up(struct semaphore *sem) -{ - unsigned long flags; - -#if SEMAPHORE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - spin_lock_irqsave(&sem->wait_lock, flags); - if (!list_empty(&sem->wait_list)) - __up(sem); - else - atomic_set(&sem->count, atomic_read(&sem->count) + 1); - spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -static inline int sem_getcount(struct semaphore *sem) -{ - return atomic_read(&sem->count); -} - -#endif /* __ASSEMBLY__ */ - -#endif +#include diff --git a/include/asm-parisc/semaphore-helper.h b/include/asm-parisc/semaphore-helper.h deleted file mode 100644 index 387f7c1277a2..000000000000 --- a/include/asm-parisc/semaphore-helper.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _ASM_PARISC_SEMAPHORE_HELPER_H -#define _ASM_PARISC_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * which we have. Let the rest of the losers suck eggs. - */ -static __inline__ void wake_one_more(struct semaphore * sem) -{ - atomic_inc((atomic_t *)&sem->waking); -} - -static __inline__ int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static __inline__ int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * We must undo the sem->count down_trylock() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static __inline__ int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - atomic_inc(&sem->count); - else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif /* _ASM_PARISC_SEMAPHORE_HELPER_H */ diff --git a/include/asm-parisc/semaphore.h b/include/asm-parisc/semaphore.h index a16271cdc748..d9b2034ed1d2 100644 --- a/include/asm-parisc/semaphore.h +++ b/include/asm-parisc/semaphore.h @@ -1,145 +1 @@ -/* SMP- and interrupt-safe semaphores. - * PA-RISC version by Matthew Wilcox - * - * Linux/PA-RISC Project (http://www.parisc-linux.org/) - * Copyright (C) 1996 Linus Torvalds - * Copyright (C) 1999-2001 Matthew Wilcox < willy at debian d0T org > - * Copyright (C) 2000 Grant Grundler < grundler a debian 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. - * - * 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; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ASM_PARISC_SEMAPHORE_H -#define _ASM_PARISC_SEMAPHORE_H - -#include -#include -#include - -#include - -/* - * The `count' is initialised to the number of people who are allowed to - * take the lock. (Normally we want a mutex, so this is `1'). if - * `count' is positive, the lock can be taken. if it's 0, no-one is - * waiting on it. if it's -1, at least one task is waiting. - */ -struct semaphore { - spinlock_t sentry; - int count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .sentry = SPIN_LOCK_UNLOCKED, \ - .count = n, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -static inline int sem_getcount(struct semaphore *sem) -{ - return sem->count; -} - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -/* Semaphores can be `tried' from irq context. So we have to disable - * interrupts while we're messing with the semaphore. Sorry. - */ - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - spin_lock_irq(&sem->sentry); - if (sem->count > 0) { - sem->count--; - } else { - __down(sem); - } - spin_unlock_irq(&sem->sentry); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - might_sleep(); - spin_lock_irq(&sem->sentry); - if (sem->count > 0) { - sem->count--; - } else { - ret = __down_interruptible(sem); - } - spin_unlock_irq(&sem->sentry); - return ret; -} - -/* - * down_trylock returns 0 on success, 1 if we failed to get the lock. - * May not sleep, but must preserve irq state - */ -static inline int down_trylock(struct semaphore * sem) -{ - unsigned long flags; - int count; - - spin_lock_irqsave(&sem->sentry, flags); - count = sem->count - 1; - if (count >= 0) - sem->count = count; - spin_unlock_irqrestore(&sem->sentry, flags); - return (count < 0); -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - */ -static inline void up(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&sem->sentry, flags); - if (sem->count < 0) { - __up(sem); - } else { - sem->count++; - } - spin_unlock_irqrestore(&sem->sentry, flags); -} - -#endif /* _ASM_PARISC_SEMAPHORE_H */ +#include diff --git a/include/asm-powerpc/semaphore.h b/include/asm-powerpc/semaphore.h index 48dd32e07749..d9b2034ed1d2 100644 --- a/include/asm-powerpc/semaphore.h +++ b/include/asm-powerpc/semaphore.h @@ -1,94 +1 @@ -#ifndef _ASM_POWERPC_SEMAPHORE_H -#define _ASM_POWERPC_SEMAPHORE_H - -/* - * Remove spinlock-based RW semaphores; RW semaphore definitions are - * now in rwsem.h and we use the generic lib/rwsem.c implementation. - * Rework semaphores to use atomic_dec_if_positive. - * -- Paul Mackerras (paulus@samba.org) - */ - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -struct semaphore { - /* - * Note that any negative value of count is equivalent to 0, - * but additionally indicates that some process(es) might be - * sleeping on `wait'. - */ - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - - /* - * Try to get the semaphore, take the slow path if we fail. - */ - if (unlikely(atomic_dec_return(&sem->count) < 0)) - __down(sem); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - - if (unlikely(atomic_dec_return(&sem->count) < 0)) - ret = __down_interruptible(sem); - return ret; -} - -static inline int down_trylock(struct semaphore * sem) -{ - return atomic_dec_if_positive(&sem->count) < 0; -} - -static inline void up(struct semaphore * sem) -{ - if (unlikely(atomic_inc_return(&sem->count) <= 0)) - __up(sem); -} - -#endif /* __KERNEL__ */ - -#endif /* _ASM_POWERPC_SEMAPHORE_H */ +#include diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h index 0e7001ad8392..d9b2034ed1d2 100644 --- a/include/asm-s390/semaphore.h +++ b/include/asm-s390/semaphore.h @@ -1,107 +1 @@ -/* - * include/asm-s390/semaphore.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/semaphore.h" - * (C) Copyright 1996 Linus Torvalds - */ - -#ifndef _S390_SEMAPHORE_H -#define _S390_SEMAPHORE_H - -#include -#include -#include -#include - -struct semaphore { - /* - * Note that any negative value of count is equivalent to 0, - * but additionally indicates that some process(es) might be - * sleeping on `wait'. - */ - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name,count) \ - { ATOMIC_INIT(count), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) } - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - __down(sem); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - ret = __down_interruptible(sem); - return ret; -} - -static inline int down_trylock(struct semaphore * sem) -{ - int old_val, new_val; - - /* - * This inline assembly atomically implements the equivalent - * to the following C code: - * old_val = sem->count.counter; - * if ((new_val = old_val) > 0) - * sem->count.counter = --new_val; - * In the ppc code this is called atomic_dec_if_positive. - */ - asm volatile( - " l %0,0(%3)\n" - "0: ltr %1,%0\n" - " jle 1f\n" - " ahi %1,-1\n" - " cs %0,%1,0(%3)\n" - " jl 0b\n" - "1:" - : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count.counter) - : "a" (&sem->count.counter), "m" (sem->count.counter) - : "cc", "memory"); - return old_val <= 0; -} - -static inline void up(struct semaphore * sem) -{ - if (atomic_inc_return(&sem->count) <= 0) - __up(sem); -} - -#endif +#include diff --git a/include/asm-sh/semaphore-helper.h b/include/asm-sh/semaphore-helper.h deleted file mode 100644 index bd8230c369ca..000000000000 --- a/include/asm-sh/semaphore-helper.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __ASM_SH_SEMAPHORE_HELPER_H -#define __ASM_SH_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * which we have. Let the rest of the losers suck eggs. - */ -static __inline__ void wake_one_more(struct semaphore * sem) -{ - atomic_inc((atomic_t *)&sem->sleepers); -} - -static __inline__ int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static __inline__ int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers > 0) { - sem->sleepers--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * We must undo the sem->count down_trylock() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static __inline__ int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->sleepers <= 0) - atomic_inc(&sem->count); - else { - sem->sleepers--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif /* __ASM_SH_SEMAPHORE_HELPER_H */ diff --git a/include/asm-sh/semaphore.h b/include/asm-sh/semaphore.h index 9e5a37c4dce2..d9b2034ed1d2 100644 --- a/include/asm-sh/semaphore.h +++ b/include/asm-sh/semaphore.h @@ -1,115 +1 @@ -#ifndef __ASM_SH_SEMAPHORE_H -#define __ASM_SH_SEMAPHORE_H - -#include - -#ifdef __KERNEL__ -/* - * SMP- and interrupt-safe semaphores. - * - * (C) Copyright 1996 Linus Torvalds - * - * SuperH verison by Niibe Yutaka - * (Currently no asm implementation but generic C code...) - */ - -#include -#include -#include - -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ -/* - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * - * i'd rather use the more flexible initialization above, but sadly - * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. - */ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -#if 0 -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); -#endif - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -extern spinlock_t semaphore_wake_lock; - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - __down(sem); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - if (atomic_dec_return(&sem->count) < 0) - ret = __down_interruptible(sem); - return ret; -} - -static inline int down_trylock(struct semaphore * sem) -{ - int ret = 0; - - if (atomic_dec_return(&sem->count) < 0) - ret = __down_trylock(sem); - return ret; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - */ -static inline void up(struct semaphore * sem) -{ - if (atomic_inc_return(&sem->count) <= 0) - __up(sem); -} - -#endif -#endif /* __ASM_SH_SEMAPHORE_H */ +#include diff --git a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h index 8018f9f4d497..d9b2034ed1d2 100644 --- a/include/asm-sparc/semaphore.h +++ b/include/asm-sparc/semaphore.h @@ -1,192 +1 @@ -#ifndef _SPARC_SEMAPHORE_H -#define _SPARC_SEMAPHORE_H - -/* Dinky, good for nothing, just barely irq safe, Sparc semaphores. */ - -#ifdef __KERNEL__ - -#include -#include -#include - -struct semaphore { - atomic24_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC24_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic24_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void __down(struct semaphore * sem); -extern int __down_interruptible(struct semaphore * sem); -extern int __down_trylock(struct semaphore * sem); -extern void __up(struct semaphore * sem); - -static inline void down(struct semaphore * sem) -{ - register volatile int *ptr asm("g1"); - register int increment asm("g2"); - - might_sleep(); - - ptr = &(sem->count.counter); - increment = 1; - - __asm__ __volatile__( - "mov %%o7, %%g4\n\t" - "call ___atomic24_sub\n\t" - " add %%o7, 8, %%o7\n\t" - "tst %%g2\n\t" - "bl 2f\n\t" - " nop\n" - "1:\n\t" - ".subsection 2\n" - "2:\n\t" - "save %%sp, -64, %%sp\n\t" - "mov %%g1, %%l1\n\t" - "mov %%g5, %%l5\n\t" - "call %3\n\t" - " mov %%g1, %%o0\n\t" - "mov %%l1, %%g1\n\t" - "ba 1b\n\t" - " restore %%l5, %%g0, %%g5\n\t" - ".previous\n" - : "=&r" (increment) - : "0" (increment), "r" (ptr), "i" (__down) - : "g3", "g4", "g7", "memory", "cc"); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - register volatile int *ptr asm("g1"); - register int increment asm("g2"); - - might_sleep(); - - ptr = &(sem->count.counter); - increment = 1; - - __asm__ __volatile__( - "mov %%o7, %%g4\n\t" - "call ___atomic24_sub\n\t" - " add %%o7, 8, %%o7\n\t" - "tst %%g2\n\t" - "bl 2f\n\t" - " clr %%g2\n" - "1:\n\t" - ".subsection 2\n" - "2:\n\t" - "save %%sp, -64, %%sp\n\t" - "mov %%g1, %%l1\n\t" - "mov %%g5, %%l5\n\t" - "call %3\n\t" - " mov %%g1, %%o0\n\t" - "mov %%l1, %%g1\n\t" - "mov %%l5, %%g5\n\t" - "ba 1b\n\t" - " restore %%o0, %%g0, %%g2\n\t" - ".previous\n" - : "=&r" (increment) - : "0" (increment), "r" (ptr), "i" (__down_interruptible) - : "g3", "g4", "g7", "memory", "cc"); - - return increment; -} - -static inline int down_trylock(struct semaphore * sem) -{ - register volatile int *ptr asm("g1"); - register int increment asm("g2"); - - ptr = &(sem->count.counter); - increment = 1; - - __asm__ __volatile__( - "mov %%o7, %%g4\n\t" - "call ___atomic24_sub\n\t" - " add %%o7, 8, %%o7\n\t" - "tst %%g2\n\t" - "bl 2f\n\t" - " clr %%g2\n" - "1:\n\t" - ".subsection 2\n" - "2:\n\t" - "save %%sp, -64, %%sp\n\t" - "mov %%g1, %%l1\n\t" - "mov %%g5, %%l5\n\t" - "call %3\n\t" - " mov %%g1, %%o0\n\t" - "mov %%l1, %%g1\n\t" - "mov %%l5, %%g5\n\t" - "ba 1b\n\t" - " restore %%o0, %%g0, %%g2\n\t" - ".previous\n" - : "=&r" (increment) - : "0" (increment), "r" (ptr), "i" (__down_trylock) - : "g3", "g4", "g7", "memory", "cc"); - - return increment; -} - -static inline void up(struct semaphore * sem) -{ - register volatile int *ptr asm("g1"); - register int increment asm("g2"); - - ptr = &(sem->count.counter); - increment = 1; - - __asm__ __volatile__( - "mov %%o7, %%g4\n\t" - "call ___atomic24_add\n\t" - " add %%o7, 8, %%o7\n\t" - "tst %%g2\n\t" - "ble 2f\n\t" - " nop\n" - "1:\n\t" - ".subsection 2\n" - "2:\n\t" - "save %%sp, -64, %%sp\n\t" - "mov %%g1, %%l1\n\t" - "mov %%g5, %%l5\n\t" - "call %3\n\t" - " mov %%g1, %%o0\n\t" - "mov %%l1, %%g1\n\t" - "ba 1b\n\t" - " restore %%l5, %%g0, %%g5\n\t" - ".previous\n" - : "=&r" (increment) - : "0" (increment), "r" (ptr), "i" (__up) - : "g3", "g4", "g7", "memory", "cc"); -} - -#endif /* __KERNEL__ */ - -#endif /* !(_SPARC_SEMAPHORE_H) */ +#include diff --git a/include/asm-sparc64/semaphore.h b/include/asm-sparc64/semaphore.h index 7f7c0c4e024f..d9b2034ed1d2 100644 --- a/include/asm-sparc64/semaphore.h +++ b/include/asm-sparc64/semaphore.h @@ -1,53 +1 @@ -#ifndef _SPARC64_SEMAPHORE_H -#define _SPARC64_SEMAPHORE_H - -/* These are actually reasonable on the V9. - * - * See asm-ppc/semaphore.h for implementation commentary, - * only sparc64 specific issues are commented here. - */ -#ifdef __KERNEL__ - -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, count) \ - { ATOMIC_INIT(count), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) } - -#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern void up(struct semaphore *sem); -extern void down(struct semaphore *sem); -extern int down_trylock(struct semaphore *sem); -extern int down_interruptible(struct semaphore *sem); - -#endif /* __KERNEL__ */ - -#endif /* !(_SPARC64_SEMAPHORE_H) */ +#include diff --git a/include/asm-um/semaphore.h b/include/asm-um/semaphore.h index ff13c34de421..d9b2034ed1d2 100644 --- a/include/asm-um/semaphore.h +++ b/include/asm-um/semaphore.h @@ -1,6 +1 @@ -#ifndef __UM_SEMAPHORE_H -#define __UM_SEMAPHORE_H - -#include "asm/arch/semaphore.h" - -#endif +#include diff --git a/include/asm-v850/semaphore.h b/include/asm-v850/semaphore.h index 10ed0ccf37df..d9b2034ed1d2 100644 --- a/include/asm-v850/semaphore.h +++ b/include/asm-v850/semaphore.h @@ -1,84 +1 @@ -#ifndef __V850_SEMAPHORE_H__ -#define __V850_SEMAPHORE_H__ - -#include -#include -#include -#include - -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name,count) \ - { ATOMIC_INIT (count), 0, \ - __WAIT_QUEUE_HEAD_INITIALIZER ((name).wait) } - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER (name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC (name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init (sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init (sem, 0); -} - -/* - * special register calling convention - */ -asmlinkage void __down_failed (void); -asmlinkage int __down_interruptible_failed (void); -asmlinkage int __down_trylock_failed (void); -asmlinkage void __up_wakeup (void); - -extern void __down (struct semaphore * sem); -extern int __down_interruptible (struct semaphore * sem); -extern int __down_trylock (struct semaphore * sem); -extern void __up (struct semaphore * sem); - -static inline void down (struct semaphore * sem) -{ - might_sleep(); - if (atomic_dec_return (&sem->count) < 0) - __down (sem); -} - -static inline int down_interruptible (struct semaphore * sem) -{ - int ret = 0; - might_sleep(); - if (atomic_dec_return (&sem->count) < 0) - ret = __down_interruptible (sem); - return ret; -} - -static inline int down_trylock (struct semaphore *sem) -{ - int ret = 0; - if (atomic_dec_return (&sem->count) < 0) - ret = __down_trylock (sem); - return ret; -} - -static inline void up (struct semaphore * sem) -{ - if (atomic_inc_return (&sem->count) <= 0) - __up (sem); -} - -#endif /* __V850_SEMAPHORE_H__ */ +#include diff --git a/include/asm-x86/semaphore.h b/include/asm-x86/semaphore.h index 572c0b67a6b0..d9b2034ed1d2 100644 --- a/include/asm-x86/semaphore.h +++ b/include/asm-x86/semaphore.h @@ -1,5 +1 @@ -#ifdef CONFIG_X86_32 -# include "semaphore_32.h" -#else -# include "semaphore_64.h" -#endif +#include diff --git a/include/asm-x86/semaphore_32.h b/include/asm-x86/semaphore_32.h deleted file mode 100644 index ac96d3804d0c..000000000000 --- a/include/asm-x86/semaphore_32.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef _I386_SEMAPHORE_H -#define _I386_SEMAPHORE_H - -#include - -#ifdef __KERNEL__ - -/* - * SMP- and interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * Modified 1996-12-23 by Dave Grothe to fix bugs in - * the original code and to make semaphore waits - * interruptible so that processes waiting on - * semaphores can be killed. - * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper - * functions in asm/sempahore-helper.h while fixing a - * potential and subtle race discovered by Ulrich Schmid - * in down_interruptible(). Since I started to play here I - * also implemented the `trylock' semaphore operation. - * 1999-07-02 Artur Skawina - * Optimized "0(ecx)" -> "(ecx)" (the assembler does not - * do this). Changed calling sequences from push/jmp to - * traditional call/ret. - * Modified 2001-01-01 Andreas Franck - * Some hacks to ensure compatibility with recent - * GCC snapshots, to avoid stack corruption when compiling - * with -fomit-frame-pointer. It's not sure if this will - * be fixed in GCC, as our previous implementation was a - * bit dubious. - * - * If you would like to see an analysis of this implementation, please - * ftp to gcom.com and download the file - * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz. - * - */ - -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ -/* - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * - * i'd rather use the more flexible initialization above, but sadly - * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. - */ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -extern asmregparm void __down_failed(atomic_t *count_ptr); -extern asmregparm int __down_failed_interruptible(atomic_t *count_ptr); -extern asmregparm int __down_failed_trylock(atomic_t *count_ptr); -extern asmregparm void __up_wakeup(atomic_t *count_ptr); - -/* - * This is ugly, but we want the default case to fall through. - * "__down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/i386/kernel/semaphore.c - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - __asm__ __volatile__( - "# atomic down operation\n\t" - LOCK_PREFIX "decl %0\n\t" /* --sem->count */ - "jns 2f\n" - "\tlea %0,%%eax\n\t" - "call __down_failed\n" - "2:" - :"+m" (sem->count) - : - :"memory","ax"); -} - -/* - * Interruptible try to acquire a semaphore. If we obtained - * it, return zero. If we were interrupted, returns -EINTR - */ -static inline int down_interruptible(struct semaphore * sem) -{ - int result; - - might_sleep(); - __asm__ __volatile__( - "# atomic interruptible down operation\n\t" - "xorl %0,%0\n\t" - LOCK_PREFIX "decl %1\n\t" /* --sem->count */ - "jns 2f\n\t" - "lea %1,%%eax\n\t" - "call __down_failed_interruptible\n" - "2:" - :"=&a" (result), "+m" (sem->count) - : - :"memory"); - return result; -} - -/* - * Non-blockingly attempt to down() a semaphore. - * Returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore * sem) -{ - int result; - - __asm__ __volatile__( - "# atomic interruptible down operation\n\t" - "xorl %0,%0\n\t" - LOCK_PREFIX "decl %1\n\t" /* --sem->count */ - "jns 2f\n\t" - "lea %1,%%eax\n\t" - "call __down_failed_trylock\n\t" - "2:\n" - :"=&a" (result), "+m" (sem->count) - : - :"memory"); - return result; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - */ -static inline void up(struct semaphore * sem) -{ - __asm__ __volatile__( - "# atomic up operation\n\t" - LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ - "jg 1f\n\t" - "lea %0,%%eax\n\t" - "call __up_wakeup\n" - "1:" - :"+m" (sem->count) - : - :"memory","ax"); -} - -#endif -#endif diff --git a/include/asm-x86/semaphore_64.h b/include/asm-x86/semaphore_64.h deleted file mode 100644 index 79694306bf7d..000000000000 --- a/include/asm-x86/semaphore_64.h +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef _X86_64_SEMAPHORE_H -#define _X86_64_SEMAPHORE_H - -#include - -#ifdef __KERNEL__ - -/* - * SMP- and interrupt-safe semaphores.. - * - * (C) Copyright 1996 Linus Torvalds - * - * Modified 1996-12-23 by Dave Grothe to fix bugs in - * the original code and to make semaphore waits - * interruptible so that processes waiting on - * semaphores can be killed. - * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper - * functions in asm/sempahore-helper.h while fixing a - * potential and subtle race discovered by Ulrich Schmid - * in down_interruptible(). Since I started to play here I - * also implemented the `trylock' semaphore operation. - * 1999-07-02 Artur Skawina - * Optimized "0(ecx)" -> "(ecx)" (the assembler does not - * do this). Changed calling sequences from push/jmp to - * traditional call/ret. - * Modified 2001-01-01 Andreas Franck - * Some hacks to ensure compatibility with recent - * GCC snapshots, to avoid stack corruption when compiling - * with -fomit-frame-pointer. It's not sure if this will - * be fixed in GCC, as our previous implementation was a - * bit dubious. - * - * If you would like to see an analysis of this implementation, please - * ftp to gcom.com and download the file - * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz. - * - */ - -#include -#include -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ -/* - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * - * i'd rather use the more flexible initialization above, but sadly - * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. - */ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down_failed(void /* special register calling convention */); -asmlinkage int __down_failed_interruptible(void /* params in registers */); -asmlinkage int __down_failed_trylock(void /* params in registers */); -asmlinkage void __up_wakeup(void /* special register calling convention */); - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -/* - * This is ugly, but we want the default case to fall through. - * "__down_failed" is a special asm handler that calls the C - * routine that actually waits. See arch/x86_64/kernel/semaphore.c - */ -static inline void down(struct semaphore * sem) -{ - might_sleep(); - - __asm__ __volatile__( - "# atomic down operation\n\t" - LOCK_PREFIX "decl %0\n\t" /* --sem->count */ - "jns 1f\n\t" - "call __down_failed\n" - "1:" - :"=m" (sem->count) - :"D" (sem) - :"memory"); -} - -/* - * Interruptible try to acquire a semaphore. If we obtained - * it, return zero. If we were interrupted, returns -EINTR - */ -static inline int down_interruptible(struct semaphore * sem) -{ - int result; - - might_sleep(); - - __asm__ __volatile__( - "# atomic interruptible down operation\n\t" - "xorl %0,%0\n\t" - LOCK_PREFIX "decl %1\n\t" /* --sem->count */ - "jns 2f\n\t" - "call __down_failed_interruptible\n" - "2:\n" - :"=&a" (result), "=m" (sem->count) - :"D" (sem) - :"memory"); - return result; -} - -/* - * Non-blockingly attempt to down() a semaphore. - * Returns zero if we acquired it - */ -static inline int down_trylock(struct semaphore * sem) -{ - int result; - - __asm__ __volatile__( - "# atomic interruptible down operation\n\t" - "xorl %0,%0\n\t" - LOCK_PREFIX "decl %1\n\t" /* --sem->count */ - "jns 2f\n\t" - "call __down_failed_trylock\n\t" - "2:\n" - :"=&a" (result), "=m" (sem->count) - :"D" (sem) - :"memory","cc"); - return result; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - * The default case (no contention) will result in NO - * jumps for both down() and up(). - */ -static inline void up(struct semaphore * sem) -{ - __asm__ __volatile__( - "# atomic up operation\n\t" - LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ - "jg 1f\n\t" - "call __up_wakeup\n" - "1:" - :"=m" (sem->count) - :"D" (sem) - :"memory"); -} -#endif /* __KERNEL__ */ -#endif diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h index 3e04167cd9dc..d9b2034ed1d2 100644 --- a/include/asm-xtensa/semaphore.h +++ b/include/asm-xtensa/semaphore.h @@ -1,99 +1 @@ -/* - * linux/include/asm-xtensa/semaphore.h - * - * 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. - * - * Copyright (C) 2001 - 2005 Tensilica Inc. - */ - -#ifndef _XTENSA_SEMAPHORE_H -#define _XTENSA_SEMAPHORE_H - -#include -#include -#include -#include - -struct semaphore { - atomic_t count; - int sleepers; - wait_queue_head_t wait; -}; - -#define __SEMAPHORE_INITIALIZER(name,n) \ -{ \ - .count = ATOMIC_INIT(n), \ - .sleepers = 0, \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -} - -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) - -#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) - -static inline void sema_init (struct semaphore *sem, int val) -{ - atomic_set(&sem->count, val); - sem->sleepers = 0; - init_waitqueue_head(&sem->wait); -} - -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - -asmlinkage void __down(struct semaphore * sem); -asmlinkage int __down_interruptible(struct semaphore * sem); -asmlinkage int __down_trylock(struct semaphore * sem); -asmlinkage void __up(struct semaphore * sem); - -extern spinlock_t semaphore_wake_lock; - -static inline void down(struct semaphore * sem) -{ - might_sleep(); - - if (atomic_sub_return(1, &sem->count) < 0) - __down(sem); -} - -static inline int down_interruptible(struct semaphore * sem) -{ - int ret = 0; - - might_sleep(); - - if (atomic_sub_return(1, &sem->count) < 0) - ret = __down_interruptible(sem); - return ret; -} - -static inline int down_trylock(struct semaphore * sem) -{ - int ret = 0; - - if (atomic_sub_return(1, &sem->count) < 0) - ret = __down_trylock(sem); - return ret; -} - -/* - * Note! This is subtle. We jump to wake people up only if - * the semaphore was negative (== somebody was waiting on it). - */ -static inline void up(struct semaphore * sem) -{ - if (atomic_add_return(1, &sem->count) <= 0) - __up(sem); -} - -#endif /* _XTENSA_SEMAPHORE_H */ +#include diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h new file mode 100644 index 000000000000..b3c691b089b2 --- /dev/null +++ b/include/linux/semaphore.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008 Intel Corporation + * Author: Matthew Wilcox + * + * Distributed under the terms of the GNU GPL, version 2 + * + * Counting semaphores allow up to tasks to acquire the semaphore + * simultaneously. + */ +#ifndef __LINUX_SEMAPHORE_H +#define __LINUX_SEMAPHORE_H + +#include +#include + +/* + * The spinlock controls access to the other members of the semaphore. + * 'count' is decremented by every task which calls down*() and incremented + * by every call to up(). Thus, if it is positive, it indicates how many + * more tasks may acquire the lock. If it is negative, it indicates how + * many tasks are waiting for the lock. Tasks waiting for the lock are + * kept on the wait_list. + */ +struct semaphore { + spinlock_t lock; + int count; + struct list_head wait_list; +}; + +#define __SEMAPHORE_INITIALIZER(name, n) \ +{ \ + .lock = __SPIN_LOCK_UNLOCKED((name).lock), \ + .count = n, \ + .wait_list = LIST_HEAD_INIT((name).wait_list), \ +} + +#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) + +static inline void sema_init(struct semaphore *sem, int val) +{ + static struct lock_class_key __key; + *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); + lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0); +} + +#define init_MUTEX(sem) sema_init(sem, 1) +#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) + +/* + * Attempt to acquire the semaphore. If another task is already holding the + * semaphore, sleep until the semaphore is released. + */ +extern void down(struct semaphore *sem); + +/* + * As down(), except the sleep may be interrupted by a signal. If it is, + * this function will return -EINTR. + */ +extern int __must_check down_interruptible(struct semaphore *sem); + +/* + * As down(), except this function will not sleep. It will return 0 if it + * acquired the semaphore and 1 if the semaphore was contended. This + * function may be called from any context, including interrupt and softirq. + */ +extern int __must_check down_trylock(struct semaphore *sem); + +/* + * Release the semaphore. Unlike mutexes, up() may be called from any + * context and even by tasks which have never called down(). + */ +extern void up(struct semaphore *sem); + +#endif /* __LINUX_SEMAPHORE_H */ diff --git a/kernel/Makefile b/kernel/Makefile index 6c584c55a6e9..f45c69e69688 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ - hrtimer.o rwsem.o nsproxy.o srcu.o \ + hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ notifier.o ksysfs.o pm_qos_params.o obj-$(CONFIG_SYSCTL) += sysctl_check.o diff --git a/kernel/semaphore.c b/kernel/semaphore.c new file mode 100644 index 000000000000..d5a72702f261 --- /dev/null +++ b/kernel/semaphore.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2008 Intel Corporation + * Author: Matthew Wilcox + * + * Distributed under the terms of the GNU GPL, version 2 + */ + +#include +#include +#include +#include +#include +#include + +/* + * Some notes on the implementation: + * + * down_trylock() and up() can be called from interrupt context. + * So we have to disable interrupts when taking the lock. + * + * The ->count variable, if positive, defines how many more tasks can + * acquire the semaphore. If negative, it represents how many tasks are + * waiting on the semaphore (*). If zero, no tasks are waiting, and no more + * tasks can acquire the semaphore. + * + * (*) Except for the window between one task calling up() and the task + * sleeping in a __down_common() waking up. In order to avoid a third task + * coming in and stealing the second task's wakeup, we leave the ->count + * negative. If we have a more complex situation, the ->count may become + * zero or negative (eg a semaphore with count = 2, three tasks attempt to + * acquire it, one sleeps, two finish and call up(), the second task to call + * up() notices that the list is empty and just increments count). + */ + +static noinline void __down(struct semaphore *sem); +static noinline int __down_interruptible(struct semaphore *sem); +static noinline void __up(struct semaphore *sem); + +void down(struct semaphore *sem) +{ + unsigned long flags; + + spin_lock_irqsave(&sem->lock, flags); + if (unlikely(sem->count-- <= 0)) + __down(sem); + spin_unlock_irqrestore(&sem->lock, flags); +} +EXPORT_SYMBOL(down); + +int down_interruptible(struct semaphore *sem) +{ + unsigned long flags; + int result = 0; + + spin_lock_irqsave(&sem->lock, flags); + if (unlikely(sem->count-- <= 0)) + result = __down_interruptible(sem); + spin_unlock_irqrestore(&sem->lock, flags); + + return result; +} +EXPORT_SYMBOL(down_interruptible); + +/** + * down_trylock - try to acquire the semaphore, without waiting + * @sem: the semaphore to be acquired + * + * Try to acquire the semaphore atomically. Returns 0 if the mutex has + * been acquired successfully and 1 if it is contended. + * + * NOTE: This return value is inverted from both spin_trylock and + * mutex_trylock! Be careful about this when converting code. + * + * Unlike mutex_trylock, this function can be used from interrupt context, + * and the semaphore can be released by any task or interrupt. + */ +int down_trylock(struct semaphore *sem) +{ + unsigned long flags; + int count; + + spin_lock_irqsave(&sem->lock, flags); + count = sem->count - 1; + if (likely(count >= 0)) + sem->count = count; + spin_unlock_irqrestore(&sem->lock, flags); + + return (count < 0); +} +EXPORT_SYMBOL(down_trylock); + +void up(struct semaphore *sem) +{ + unsigned long flags; + + spin_lock_irqsave(&sem->lock, flags); + if (likely(sem->count >= 0)) + sem->count++; + else + __up(sem); + spin_unlock_irqrestore(&sem->lock, flags); +} +EXPORT_SYMBOL(up); + +/* Functions for the contended case */ + +struct semaphore_waiter { + struct list_head list; + struct task_struct *task; + int up; +}; + +/* + * Wake up a process waiting on a semaphore. We need to call this from both + * __up and __down_common as it's possible to race a task into the semaphore + * if it comes in at just the right time between two tasks calling up() and + * a third task waking up. This function assumes the wait_list is already + * checked for being non-empty. + */ +static noinline void __sched __up_down_common(struct semaphore *sem) +{ + struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, + struct semaphore_waiter, list); + list_del(&waiter->list); + waiter->up = 1; + wake_up_process(waiter->task); +} + +/* + * Because this function is inlined, the 'state' parameter will be constant, + * and thus optimised away by the compiler. + */ +static inline int __sched __down_common(struct semaphore *sem, long state) +{ + int result = 0; + struct task_struct *task = current; + struct semaphore_waiter waiter; + + list_add_tail(&waiter.list, &sem->wait_list); + waiter.task = task; + waiter.up = 0; + + for (;;) { + if (state == TASK_INTERRUPTIBLE && signal_pending(task)) + goto interrupted; + __set_task_state(task, state); + spin_unlock_irq(&sem->lock); + schedule(); + spin_lock_irq(&sem->lock); + if (waiter.up) + goto woken; + } + + interrupted: + list_del(&waiter.list); + result = -EINTR; + woken: + /* + * Account for the process which woke us up. For the case where + * we're interrupted, we need to increment the count on our own + * behalf. I don't believe we can hit the case where the + * sem->count hits zero, *and* there's a second task sleeping, + * but it doesn't hurt, that's not a commonly exercised path and + * it's not a performance path either. + */ + if (unlikely((++sem->count >= 0) && !list_empty(&sem->wait_list))) + __up_down_common(sem); + return result; +} + +static noinline void __sched __down(struct semaphore *sem) +{ + __down_common(sem, TASK_UNINTERRUPTIBLE); +} + +static noinline int __sched __down_interruptible(struct semaphore *sem) +{ + return __down_common(sem, TASK_INTERRUPTIBLE); +} + +static noinline void __sched __up(struct semaphore *sem) +{ + if (unlikely(list_empty(&sem->wait_list))) + sem->count++; + else + __up_down_common(sem); +} diff --git a/lib/Makefile b/lib/Makefile index 23de261a4c83..28dba90d5020 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o -lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o diff --git a/lib/semaphore-sleepers.c b/lib/semaphore-sleepers.c deleted file mode 100644 index 0198782cdacb..000000000000 --- a/lib/semaphore-sleepers.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * i386 and x86-64 semaphore implementation. - * - * (C) Copyright 1999 Linus Torvalds - * - * Portions Copyright 1999 Red Hat, 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. - * - * rw semaphores implemented November 1999 by Benjamin LaHaise - */ -#include -#include -#include -#include - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to acquire the semaphore, while the "sleeping" - * variable is a count of such acquires. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * "sleeping" and the contention routine ordering is protected - * by the spinlock in the semaphore's waitqueue head. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ - -/* - * Logic: - * - only on a boundary condition do we need to care. When we go - * from a negative count to a non-negative, we wake people up. - * - when we go from a non-negative count to a negative do we - * (a) synchronize with the "sleeper" count and (b) make sure - * that we're on the wakeup list before we synchronize so that - * we cannot lose wakeup events. - */ - -void __up(struct semaphore *sem) -{ - wake_up(&sem->wait); -} - -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * the wait_queue_head. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_UNINTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - tsk->state = TASK_RUNNING; -} - -int __sched __down_interruptible(struct semaphore *sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - unsigned long flags; - - tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irqsave(&sem->wait.lock, flags); - add_wait_queue_exclusive_locked(&sem->wait, &wait); - - sem->sleepers++; - for (;;) { - int sleepers = sem->sleepers; - - /* - * With signals pending, this turns into - * the trylock failure case - we won't be - * sleeping, and we* can't get the lock as - * it has contention. Just correct the count - * and exit. - */ - if (signal_pending(current)) { - retval = -EINTR; - sem->sleepers = 0; - atomic_add(sleepers, &sem->count); - break; - } - - /* - * Add "everybody else" into it. They aren't - * playing, because we own the spinlock in - * wait_queue_head. The "-1" is because we're - * still hoping to get the semaphore. - */ - if (!atomic_add_negative(sleepers - 1, &sem->count)) { - sem->sleepers = 0; - break; - } - sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irqrestore(&sem->wait.lock, flags); - - schedule(); - - spin_lock_irqsave(&sem->wait.lock, flags); - tsk->state = TASK_INTERRUPTIBLE; - } - remove_wait_queue_locked(&sem->wait, &wait); - wake_up_locked(&sem->wait); - spin_unlock_irqrestore(&sem->wait.lock, flags); - - tsk->state = TASK_RUNNING; - return retval; -} - -/* - * Trylock failed - make sure we correct for - * having decremented the count. - * - * We could have done the trylock with a - * single "cmpxchg" without failure cases, - * but then it wouldn't work on a 386. - */ -int __down_trylock(struct semaphore *sem) -{ - int sleepers; - unsigned long flags; - - spin_lock_irqsave(&sem->wait.lock, flags); - sleepers = sem->sleepers + 1; - sem->sleepers = 0; - - /* - * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock in the - * wait_queue_head. - */ - if (!atomic_add_negative(sleepers, &sem->count)) { - wake_up_locked(&sem->wait); - } - - spin_unlock_irqrestore(&sem->wait.lock, flags); - return 1; -} -- cgit v1.2.3 From f06d96865861c3dd01520f47e2e61c899db1631f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 14 Mar 2008 13:19:33 -0400 Subject: Introduce down_killable() down_killable() is the functional counterpart of mutex_lock_killable. Signed-off-by: Matthew Wilcox --- include/linux/semaphore.h | 6 ++++++ kernel/semaphore.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'include/linux') diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index b3c691b089b2..88f2a28cc0f1 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -61,6 +61,12 @@ extern void down(struct semaphore *sem); */ extern int __must_check down_interruptible(struct semaphore *sem); +/* + * As down_interruptible(), except the sleep may only be interrupted by + * signals which are fatal to this process. + */ +extern int __must_check down_killable(struct semaphore *sem); + /* * As down(), except this function will not sleep. It will return 0 if it * acquired the semaphore and 1 if the semaphore was contended. This diff --git a/kernel/semaphore.c b/kernel/semaphore.c index d5a72702f261..2da2aed950f3 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c @@ -34,6 +34,7 @@ static noinline void __down(struct semaphore *sem); static noinline int __down_interruptible(struct semaphore *sem); +static noinline int __down_killable(struct semaphore *sem); static noinline void __up(struct semaphore *sem); void down(struct semaphore *sem) @@ -61,6 +62,20 @@ int down_interruptible(struct semaphore *sem) } EXPORT_SYMBOL(down_interruptible); +int down_killable(struct semaphore *sem) +{ + unsigned long flags; + int result = 0; + + spin_lock_irqsave(&sem->lock, flags); + if (unlikely(sem->count-- <= 0)) + result = __down_killable(sem); + spin_unlock_irqrestore(&sem->lock, flags); + + return result; +} +EXPORT_SYMBOL(down_killable); + /** * down_trylock - try to acquire the semaphore, without waiting * @sem: the semaphore to be acquired @@ -143,6 +158,8 @@ static inline int __sched __down_common(struct semaphore *sem, long state) for (;;) { if (state == TASK_INTERRUPTIBLE && signal_pending(task)) goto interrupted; + if (state == TASK_KILLABLE && fatal_signal_pending(task)) + goto interrupted; __set_task_state(task, state); spin_unlock_irq(&sem->lock); schedule(); @@ -178,6 +195,11 @@ static noinline int __sched __down_interruptible(struct semaphore *sem) return __down_common(sem, TASK_INTERRUPTIBLE); } +static noinline int __sched __down_killable(struct semaphore *sem) +{ + return __down_common(sem, TASK_KILLABLE); +} + static noinline void __sched __up(struct semaphore *sem) { if (unlikely(list_empty(&sem->wait_list))) -- cgit v1.2.3 From f1241c87a16c4fe9f4f51d6ed3589f031c505e8d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 14 Mar 2008 13:43:13 -0400 Subject: Add down_timeout and change ACPI to use it ACPI currently emulates a timeout for semaphores with calls to down_trylock and sleep. This produces horrible behaviour in terms of fairness and excessive wakeups. Now that we have a unified semaphore implementation, adding a real down_trylock is almost trivial. Signed-off-by: Matthew Wilcox --- drivers/acpi/osl.c | 89 +++++++++++------------------------------------ include/linux/semaphore.h | 6 ++++ kernel/semaphore.c | 42 ++++++++++++++++++---- 3 files changed, 62 insertions(+), 75 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a697fb6cf050..a498a6cc68fe 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -4,6 +4,8 @@ * Copyright (C) 2000 Andrew Henroid * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (c) 2008 Intel Corporation + * Author: Matthew Wilcox * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -37,15 +39,18 @@ #include #include #include -#include -#include -#include -#include -#include - #include #include #include +#include +#include + +#include +#include + +#include +#include +#include #define _COMPONENT ACPI_OS_SERVICES ACPI_MODULE_NAME("osl"); @@ -764,7 +769,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) { struct semaphore *sem = NULL; - sem = acpi_os_allocate(sizeof(struct semaphore)); if (!sem) return AE_NO_MEMORY; @@ -791,12 +795,12 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) { struct semaphore *sem = (struct semaphore *)handle; - if (!sem) return AE_BAD_PARAMETER; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); + BUG_ON(!list_empty(&sem->wait_list)); kfree(sem); sem = NULL; @@ -804,21 +808,15 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) } /* - * TODO: The kernel doesn't have a 'down_timeout' function -- had to - * improvise. The process is to sleep for one scheduler quantum - * until the semaphore becomes available. Downside is that this - * may result in starvation for timeout-based waits when there's - * lots of semaphore activity. - * * TODO: Support for units > 1? */ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) { acpi_status status = AE_OK; struct semaphore *sem = (struct semaphore *)handle; + long jiffies; int ret = 0; - if (!sem || (units < 1)) return AE_BAD_PARAMETER; @@ -828,58 +826,14 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); - /* - * This can be called during resume with interrupts off. - * Like boot-time, we should be single threaded and will - * always get the lock if we try -- timeout or not. - * If this doesn't succeed, then we will oops courtesy of - * might_sleep() in down(). - */ - if (!down_trylock(sem)) - return AE_OK; - - switch (timeout) { - /* - * No Wait: - * -------- - * A zero timeout value indicates that we shouldn't wait - just - * acquire the semaphore if available otherwise return AE_TIME - * (a.k.a. 'would block'). - */ - case 0: - if (down_trylock(sem)) - status = AE_TIME; - break; - - /* - * Wait Indefinitely: - * ------------------ - */ - case ACPI_WAIT_FOREVER: - down(sem); - break; - - /* - * Wait w/ Timeout: - * ---------------- - */ - default: - // TODO: A better timeout algorithm? - { - int i = 0; - static const int quantum_ms = 1000 / HZ; - - ret = down_trylock(sem); - for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) { - schedule_timeout_interruptible(1); - ret = down_trylock(sem); - } - - if (ret != 0) - status = AE_TIME; - } - break; - } + if (timeout == ACPI_WAIT_FOREVER) + jiffies = MAX_SCHEDULE_TIMEOUT; + else + jiffies = msecs_to_jiffies(timeout); + + ret = down_timeout(sem, jiffies); + if (ret) + status = AE_TIME; if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, @@ -902,7 +856,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) { struct semaphore *sem = (struct semaphore *)handle; - if (!sem || (units < 1)) return AE_BAD_PARAMETER; diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index 88f2a28cc0f1..a107aebd9148 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -74,6 +74,12 @@ extern int __must_check down_killable(struct semaphore *sem); */ extern int __must_check down_trylock(struct semaphore *sem); +/* + * As down(), except this function will return -ETIME if it fails to + * acquire the semaphore within the specified number of jiffies. + */ +extern int __must_check down_timeout(struct semaphore *sem, long jiffies); + /* * Release the semaphore. Unlike mutexes, up() may be called from any * context and even by tasks which have never called down(). diff --git a/kernel/semaphore.c b/kernel/semaphore.c index 2da2aed950f3..5a12a8558982 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c @@ -35,6 +35,7 @@ static noinline void __down(struct semaphore *sem); static noinline int __down_interruptible(struct semaphore *sem); static noinline int __down_killable(struct semaphore *sem); +static noinline int __down_timeout(struct semaphore *sem, long jiffies); static noinline void __up(struct semaphore *sem); void down(struct semaphore *sem) @@ -104,6 +105,20 @@ int down_trylock(struct semaphore *sem) } EXPORT_SYMBOL(down_trylock); +int down_timeout(struct semaphore *sem, long jiffies) +{ + unsigned long flags; + int result = 0; + + spin_lock_irqsave(&sem->lock, flags); + if (unlikely(sem->count-- <= 0)) + result = __down_timeout(sem, jiffies); + spin_unlock_irqrestore(&sem->lock, flags); + + return result; +} +EXPORT_SYMBOL(down_timeout); + void up(struct semaphore *sem) { unsigned long flags; @@ -142,10 +157,12 @@ static noinline void __sched __up_down_common(struct semaphore *sem) } /* - * Because this function is inlined, the 'state' parameter will be constant, - * and thus optimised away by the compiler. + * Because this function is inlined, the 'state' parameter will be + * constant, and thus optimised away by the compiler. Likewise the + * 'timeout' parameter for the cases without timeouts. */ -static inline int __sched __down_common(struct semaphore *sem, long state) +static inline int __sched __down_common(struct semaphore *sem, long state, + long timeout) { int result = 0; struct task_struct *task = current; @@ -160,14 +177,20 @@ static inline int __sched __down_common(struct semaphore *sem, long state) goto interrupted; if (state == TASK_KILLABLE && fatal_signal_pending(task)) goto interrupted; + if (timeout <= 0) + goto timed_out; __set_task_state(task, state); spin_unlock_irq(&sem->lock); - schedule(); + timeout = schedule_timeout(timeout); spin_lock_irq(&sem->lock); if (waiter.up) goto woken; } + timed_out: + list_del(&waiter.list); + result = -ETIME; + goto woken; interrupted: list_del(&waiter.list); result = -EINTR; @@ -187,17 +210,22 @@ static inline int __sched __down_common(struct semaphore *sem, long state) static noinline void __sched __down(struct semaphore *sem) { - __down_common(sem, TASK_UNINTERRUPTIBLE); + __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } static noinline int __sched __down_interruptible(struct semaphore *sem) { - return __down_common(sem, TASK_INTERRUPTIBLE); + return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } static noinline int __sched __down_killable(struct semaphore *sem) { - return __down_common(sem, TASK_KILLABLE); + return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT); +} + +static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies) +{ + return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies); } static noinline void __sched __up(struct semaphore *sem) -- cgit v1.2.3 From b17170b2fac96705db3188f093f89e8e838418e4 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 14 Mar 2008 14:35:22 -0400 Subject: Simplify semaphore implementation By removing the negative values of 'count' and relying on the wait_list to indicate whether we have any waiters, we can simplify the implementation by removing the protection against an unlikely race condition. Thanks to David Howells for his suggestions. Signed-off-by: Matthew Wilcox --- include/linux/semaphore.h | 9 ++---- kernel/semaphore.c | 78 +++++++++++++++-------------------------------- 2 files changed, 27 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index a107aebd9148..a7125daaff90 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -15,15 +15,12 @@ /* * The spinlock controls access to the other members of the semaphore. - * 'count' is decremented by every task which calls down*() and incremented - * by every call to up(). Thus, if it is positive, it indicates how many - * more tasks may acquire the lock. If it is negative, it indicates how - * many tasks are waiting for the lock. Tasks waiting for the lock are - * kept on the wait_list. + * 'count' represents how many more tasks can acquire this semaphore. + * Tasks waiting for the lock are kept on the wait_list. */ struct semaphore { spinlock_t lock; - int count; + unsigned int count; struct list_head wait_list; }; diff --git a/kernel/semaphore.c b/kernel/semaphore.c index 5a12a8558982..bef977b16966 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c @@ -18,18 +18,8 @@ * down_trylock() and up() can be called from interrupt context. * So we have to disable interrupts when taking the lock. * - * The ->count variable, if positive, defines how many more tasks can - * acquire the semaphore. If negative, it represents how many tasks are - * waiting on the semaphore (*). If zero, no tasks are waiting, and no more - * tasks can acquire the semaphore. - * - * (*) Except for the window between one task calling up() and the task - * sleeping in a __down_common() waking up. In order to avoid a third task - * coming in and stealing the second task's wakeup, we leave the ->count - * negative. If we have a more complex situation, the ->count may become - * zero or negative (eg a semaphore with count = 2, three tasks attempt to - * acquire it, one sleeps, two finish and call up(), the second task to call - * up() notices that the list is empty and just increments count). + * The ->count variable defines how many more tasks can acquire the + * semaphore. If it's zero, there may be tasks waiting on the list. */ static noinline void __down(struct semaphore *sem); @@ -43,7 +33,9 @@ void down(struct semaphore *sem) unsigned long flags; spin_lock_irqsave(&sem->lock, flags); - if (unlikely(sem->count-- <= 0)) + if (likely(sem->count > 0)) + sem->count--; + else __down(sem); spin_unlock_irqrestore(&sem->lock, flags); } @@ -55,7 +47,9 @@ int down_interruptible(struct semaphore *sem) int result = 0; spin_lock_irqsave(&sem->lock, flags); - if (unlikely(sem->count-- <= 0)) + if (likely(sem->count > 0)) + sem->count--; + else result = __down_interruptible(sem); spin_unlock_irqrestore(&sem->lock, flags); @@ -69,7 +63,9 @@ int down_killable(struct semaphore *sem) int result = 0; spin_lock_irqsave(&sem->lock, flags); - if (unlikely(sem->count-- <= 0)) + if (likely(sem->count > 0)) + sem->count--; + else result = __down_killable(sem); spin_unlock_irqrestore(&sem->lock, flags); @@ -111,7 +107,9 @@ int down_timeout(struct semaphore *sem, long jiffies) int result = 0; spin_lock_irqsave(&sem->lock, flags); - if (unlikely(sem->count-- <= 0)) + if (likely(sem->count > 0)) + sem->count--; + else result = __down_timeout(sem, jiffies); spin_unlock_irqrestore(&sem->lock, flags); @@ -124,7 +122,7 @@ void up(struct semaphore *sem) unsigned long flags; spin_lock_irqsave(&sem->lock, flags); - if (likely(sem->count >= 0)) + if (likely(list_empty(&sem->wait_list))) sem->count++; else __up(sem); @@ -140,22 +138,6 @@ struct semaphore_waiter { int up; }; -/* - * Wake up a process waiting on a semaphore. We need to call this from both - * __up and __down_common as it's possible to race a task into the semaphore - * if it comes in at just the right time between two tasks calling up() and - * a third task waking up. This function assumes the wait_list is already - * checked for being non-empty. - */ -static noinline void __sched __up_down_common(struct semaphore *sem) -{ - struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, - struct semaphore_waiter, list); - list_del(&waiter->list); - waiter->up = 1; - wake_up_process(waiter->task); -} - /* * Because this function is inlined, the 'state' parameter will be * constant, and thus optimised away by the compiler. Likewise the @@ -164,7 +146,6 @@ static noinline void __sched __up_down_common(struct semaphore *sem) static inline int __sched __down_common(struct semaphore *sem, long state, long timeout) { - int result = 0; struct task_struct *task = current; struct semaphore_waiter waiter; @@ -184,28 +165,16 @@ static inline int __sched __down_common(struct semaphore *sem, long state, timeout = schedule_timeout(timeout); spin_lock_irq(&sem->lock); if (waiter.up) - goto woken; + return 0; } timed_out: list_del(&waiter.list); - result = -ETIME; - goto woken; + return -ETIME; + interrupted: list_del(&waiter.list); - result = -EINTR; - woken: - /* - * Account for the process which woke us up. For the case where - * we're interrupted, we need to increment the count on our own - * behalf. I don't believe we can hit the case where the - * sem->count hits zero, *and* there's a second task sleeping, - * but it doesn't hurt, that's not a commonly exercised path and - * it's not a performance path either. - */ - if (unlikely((++sem->count >= 0) && !list_empty(&sem->wait_list))) - __up_down_common(sem); - return result; + return -EINTR; } static noinline void __sched __down(struct semaphore *sem) @@ -230,8 +199,9 @@ static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies) static noinline void __sched __up(struct semaphore *sem) { - if (unlikely(list_empty(&sem->wait_list))) - sem->count++; - else - __up_down_common(sem); + struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, + struct semaphore_waiter, list); + list_del(&waiter->list); + waiter->up = 1; + wake_up_process(waiter->task); } -- cgit v1.2.3 From 714493cd5468f42ca3c4f730a9c17c203abd5059 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 11 Apr 2008 15:23:52 -0400 Subject: Improve semaphore documentation Move documentation from semaphore.h to semaphore.c as requested by Andrew Morton. Also reformat to kernel-doc style and add some more notes about the implementation. Signed-off-by: Matthew Wilcox --- include/linux/semaphore.h | 39 ++--------------------- kernel/semaphore.c | 79 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index a7125daaff90..9cae64b00d6b 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -4,8 +4,7 @@ * * Distributed under the terms of the GNU GPL, version 2 * - * Counting semaphores allow up to tasks to acquire the semaphore - * simultaneously. + * Please see kernel/semaphore.c for documentation of these functions */ #ifndef __LINUX_SEMAPHORE_H #define __LINUX_SEMAPHORE_H @@ -13,11 +12,7 @@ #include #include -/* - * The spinlock controls access to the other members of the semaphore. - * 'count' represents how many more tasks can acquire this semaphore. - * Tasks waiting for the lock are kept on the wait_list. - */ +/* Please don't access any members of this structure directly */ struct semaphore { spinlock_t lock; unsigned int count; @@ -46,41 +41,11 @@ static inline void sema_init(struct semaphore *sem, int val) #define init_MUTEX(sem) sema_init(sem, 1) #define init_MUTEX_LOCKED(sem) sema_init(sem, 0) -/* - * Attempt to acquire the semaphore. If another task is already holding the - * semaphore, sleep until the semaphore is released. - */ extern void down(struct semaphore *sem); - -/* - * As down(), except the sleep may be interrupted by a signal. If it is, - * this function will return -EINTR. - */ extern int __must_check down_interruptible(struct semaphore *sem); - -/* - * As down_interruptible(), except the sleep may only be interrupted by - * signals which are fatal to this process. - */ extern int __must_check down_killable(struct semaphore *sem); - -/* - * As down(), except this function will not sleep. It will return 0 if it - * acquired the semaphore and 1 if the semaphore was contended. This - * function may be called from any context, including interrupt and softirq. - */ extern int __must_check down_trylock(struct semaphore *sem); - -/* - * As down(), except this function will return -ETIME if it fails to - * acquire the semaphore within the specified number of jiffies. - */ extern int __must_check down_timeout(struct semaphore *sem, long jiffies); - -/* - * Release the semaphore. Unlike mutexes, up() may be called from any - * context and even by tasks which have never called down(). - */ extern void up(struct semaphore *sem); #endif /* __LINUX_SEMAPHORE_H */ diff --git a/kernel/semaphore.c b/kernel/semaphore.c index bef977b16966..5c2942e768cd 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c @@ -3,6 +3,26 @@ * Author: Matthew Wilcox * * Distributed under the terms of the GNU GPL, version 2 + * + * This file implements counting semaphores. + * A counting semaphore may be acquired 'n' times before sleeping. + * See mutex.c for single-acquisition sleeping locks which enforce + * rules which allow code to be debugged more easily. + */ + +/* + * Some notes on the implementation: + * + * The spinlock controls access to the other members of the semaphore. + * down_trylock() and up() can be called from interrupt context, so we + * have to disable interrupts when taking the lock. It turns out various + * parts of the kernel expect to be able to use down() on a semaphore in + * interrupt context when they know it will succeed, so we have to use + * irqsave variants for down(), down_interruptible() and down_killable() + * too. + * + * The ->count variable represents how many more tasks can acquire this + * semaphore. If it's zero, there may be tasks waiting on the wait_list. */ #include @@ -12,22 +32,23 @@ #include #include -/* - * Some notes on the implementation: - * - * down_trylock() and up() can be called from interrupt context. - * So we have to disable interrupts when taking the lock. - * - * The ->count variable defines how many more tasks can acquire the - * semaphore. If it's zero, there may be tasks waiting on the list. - */ - static noinline void __down(struct semaphore *sem); static noinline int __down_interruptible(struct semaphore *sem); static noinline int __down_killable(struct semaphore *sem); static noinline int __down_timeout(struct semaphore *sem, long jiffies); static noinline void __up(struct semaphore *sem); +/** + * down - acquire the semaphore + * @sem: the semaphore to be acquired + * + * Acquires the semaphore. If no more tasks are allowed to acquire the + * semaphore, calling this function will put the task to sleep until the + * semaphore is released. + * + * Use of this function is deprecated, please use down_interruptible() or + * down_killable() instead. + */ void down(struct semaphore *sem) { unsigned long flags; @@ -41,6 +62,15 @@ void down(struct semaphore *sem) } EXPORT_SYMBOL(down); +/** + * down_interruptible - acquire the semaphore unless interrupted + * @sem: the semaphore to be acquired + * + * Attempts to acquire the semaphore. If no more tasks are allowed to + * acquire the semaphore, calling this function will put the task to sleep. + * If the sleep is interrupted by a signal, this function will return -EINTR. + * If the semaphore is successfully acquired, this function returns 0. + */ int down_interruptible(struct semaphore *sem) { unsigned long flags; @@ -57,6 +87,16 @@ int down_interruptible(struct semaphore *sem) } EXPORT_SYMBOL(down_interruptible); +/** + * down_killable - acquire the semaphore unless killed + * @sem: the semaphore to be acquired + * + * Attempts to acquire the semaphore. If no more tasks are allowed to + * acquire the semaphore, calling this function will put the task to sleep. + * If the sleep is interrupted by a fatal signal, this function will return + * -EINTR. If the semaphore is successfully acquired, this function returns + * 0. + */ int down_killable(struct semaphore *sem) { unsigned long flags; @@ -78,7 +118,7 @@ EXPORT_SYMBOL(down_killable); * @sem: the semaphore to be acquired * * Try to acquire the semaphore atomically. Returns 0 if the mutex has - * been acquired successfully and 1 if it is contended. + * been acquired successfully or 1 if it it cannot be acquired. * * NOTE: This return value is inverted from both spin_trylock and * mutex_trylock! Be careful about this when converting code. @@ -101,6 +141,16 @@ int down_trylock(struct semaphore *sem) } EXPORT_SYMBOL(down_trylock); +/** + * down_timeout - acquire the semaphore within a specified time + * @sem: the semaphore to be acquired + * @jiffies: how long to wait before failing + * + * Attempts to acquire the semaphore. If no more tasks are allowed to + * acquire the semaphore, calling this function will put the task to sleep. + * If the semaphore is not released within the specified number of jiffies, + * this function returns -ETIME. It returns 0 if the semaphore was acquired. + */ int down_timeout(struct semaphore *sem, long jiffies) { unsigned long flags; @@ -117,6 +167,13 @@ int down_timeout(struct semaphore *sem, long jiffies) } EXPORT_SYMBOL(down_timeout); +/** + * up - release the semaphore + * @sem: the semaphore to release + * + * Release the semaphore. Unlike mutexes, up() may be called from any + * context and even by tasks which have never called down(). + */ void up(struct semaphore *sem) { unsigned long flags; -- cgit v1.2.3 From c33fa9f5609e918824446ef9a75319d4a802f1f4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 17 Apr 2008 20:05:36 +0200 Subject: uaccess: add probe_kernel_write() add probe_kernel_read() and probe_kernel_write(). Uninlined and restricted to kernel range memory only, as suggested by Linus. Signed-off-by: Ingo Molnar Reviewed-by: Thomas Gleixner --- include/linux/uaccess.h | 22 ++++++++++++++++++++++ mm/Makefile | 2 +- mm/maccess.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 mm/maccess.c (limited to 'include/linux') diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 975c963e5789..fec6decfb983 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -84,4 +84,26 @@ static inline unsigned long __copy_from_user_nocache(void *to, ret; \ }) +/* + * probe_kernel_read(): safely attempt to read from a location + * @dst: pointer to the buffer that shall take the data + * @src: address to read from + * @size: size of the data chunk + * + * Safely read from address @src to the buffer at @dst. If a kernel fault + * happens, handle that and return -EFAULT. + */ +extern long probe_kernel_read(void *dst, void *src, size_t size); + +/* + * probe_kernel_write(): safely attempt to write to a location + * @dst: address to write to + * @src: pointer to the data that shall be written + * @size: size of the data chunk + * + * Safely write to address @dst from the buffer at @src. If a kernel fault + * happens, handle that and return -EFAULT. + */ +extern long probe_kernel_write(void *dst, void *src, size_t size); + #endif /* __LINUX_UACCESS_H__ */ diff --git a/mm/Makefile b/mm/Makefile index a5b0dd93427a..18c143b3c46c 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ vmalloc.o obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ - page_alloc.o page-writeback.o pdflush.o \ + maccess.o page_alloc.o page-writeback.o pdflush.o \ readahead.o swap.o truncate.o vmscan.o \ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ page_isolation.o $(mmu-y) diff --git a/mm/maccess.c b/mm/maccess.c new file mode 100644 index 000000000000..24f81b971403 --- /dev/null +++ b/mm/maccess.c @@ -0,0 +1,49 @@ +/* + * Access kernel memory without faulting. + */ +#include +#include +#include + +/** + * probe_kernel_read(): safely attempt to read from a location + * @dst: pointer to the buffer that shall take the data + * @src: address to read from + * @size: size of the data chunk + * + * Safely read from address @src to the buffer at @dst. If a kernel fault + * happens, handle that and return -EFAULT. + */ +long probe_kernel_read(void *dst, void *src, size_t size) +{ + long ret; + + pagefault_disable(); + ret = __copy_from_user_inatomic(dst, + (__force const void __user *)src, size); + pagefault_enable(); + + return ret ? -EFAULT : 0; +} +EXPORT_SYMBOL_GPL(probe_kernel_read); + +/** + * probe_kernel_write(): safely attempt to write to a location + * @dst: address to write to + * @src: pointer to the data that shall be written + * @size: size of the data chunk + * + * Safely write to address @dst from the buffer at @src. If a kernel fault + * happens, handle that and return -EFAULT. + */ +long probe_kernel_write(void *dst, void *src, size_t size) +{ + long ret; + + pagefault_disable(); + ret = __copy_to_user_inatomic((__force void __user *)dst, src, size); + pagefault_enable(); + + return ret ? -EFAULT : 0; +} +EXPORT_SYMBOL_GPL(probe_kernel_write); -- cgit v1.2.3 From dc7d552705215ac50a0617fcf51bb9c736255b8e Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 17 Apr 2008 20:05:37 +0200 Subject: kgdb: core kgdb core code. Handles the protocol and the arch details. [ mingo@elte.hu: heavily modified, simplified and cleaned up. ] [ xemul@openvz.org: use find_task_by_pid_ns ] Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar Signed-off-by: Jan Kiszka Reviewed-by: Thomas Gleixner --- include/linux/kgdb.h | 271 ++++++++ kernel/Makefile | 1 + kernel/kgdb.c | 1693 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig.debug | 2 + lib/Kconfig.kgdb | 27 + 5 files changed, 1994 insertions(+) create mode 100644 include/linux/kgdb.h create mode 100644 kernel/kgdb.c create mode 100644 lib/Kconfig.kgdb (limited to 'include/linux') diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h new file mode 100644 index 000000000000..b0985b79b638 --- /dev/null +++ b/include/linux/kgdb.h @@ -0,0 +1,271 @@ +/* + * This provides the callbacks and functions that KGDB needs to share between + * the core, I/O and arch-specific portions. + * + * Author: Amit Kale and + * Tom Rini + * + * 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc. + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#ifndef _KGDB_H_ +#define _KGDB_H_ + +#include +#include +#include + +#include +#include + +struct pt_regs; + +/* + * kgdb_skipexception - Bail out of KGDB when we've been triggered. + * @exception: Exception vector number + * @regs: Current &struct pt_regs. + * + * On some architectures we need to skip a breakpoint exception when + * it occurs after a breakpoint has been removed. + */ +extern int kgdb_skipexception(int exception, struct pt_regs *regs); + +/* + * kgdb_post_primary_code - Save error vector/code numbers. + * @regs: Original pt_regs. + * @e_vector: Original error vector. + * @err_code: Original error code. + * + * This is needed on architectures which support SMP and KGDB. + * This function is called after all the secondary cpus have been put + * to a know spin state and the primary CPU has control over KGDB. + */ +extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, + int err_code); + +/* + * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. + * @regs: Current &struct pt_regs. + * + * This function will be called if the particular architecture must + * disable hardware debugging while it is processing gdb packets or + * handling exception. + */ +extern void kgdb_disable_hw_debug(struct pt_regs *regs); + +struct tasklet_struct; +struct task_struct; +struct uart_port; + +/* To enter the debugger explicitly. */ +void kgdb_breakpoint(void); + +extern int kgdb_connected; + +extern atomic_t kgdb_setting_breakpoint; +extern atomic_t kgdb_cpu_doing_single_step; + +extern struct task_struct *kgdb_usethread; +extern struct task_struct *kgdb_contthread; + +enum kgdb_bptype { + BP_BREAKPOINT = 0, + BP_HARDWARE_BREAKPOINT, + BP_WRITE_WATCHPOINT, + BP_READ_WATCHPOINT, + BP_ACCESS_WATCHPOINT +}; + +enum kgdb_bpstate { + BP_UNDEFINED = 0, + BP_REMOVED, + BP_SET, + BP_ACTIVE +}; + +struct kgdb_bkpt { + unsigned long bpt_addr; + unsigned char saved_instr[BREAK_INSTR_SIZE]; + enum kgdb_bptype type; + enum kgdb_bpstate state; +}; + +#ifndef KGDB_MAX_BREAKPOINTS +# define KGDB_MAX_BREAKPOINTS 1000 +#endif + +#define KGDB_HW_BREAKPOINT 1 + +/* + * Functions each KGDB-supporting architecture must provide: + */ + +/* + * kgdb_arch_init - Perform any architecture specific initalization. + * + * This function will handle the initalization of any architecture + * specific callbacks. + */ +extern int kgdb_arch_init(void); + +/* + * kgdb_arch_exit - Perform any architecture specific uninitalization. + * + * This function will handle the uninitalization of any architecture + * specific callbacks, for dynamic registration and unregistration. + */ +extern void kgdb_arch_exit(void); + +/* + * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @regs: The &struct pt_regs of the current process. + * + * Convert the pt_regs in @regs into the format for registers that + * GDB expects, stored in @gdb_regs. + */ +extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +/* + * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @p: The &struct task_struct of the desired process. + * + * Convert the register values of the sleeping process in @p to + * the format that GDB expects. + * This function is called when kgdb does not have access to the + * &struct pt_regs and therefore it should fill the gdb registers + * @gdb_regs with what has been saved in &struct thread_struct + * thread field during switch_to. + */ +extern void +sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); + +/* + * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. + * @gdb_regs: A pointer to hold the registers we've received from GDB. + * @regs: A pointer to a &struct pt_regs to hold these values in. + * + * Convert the GDB regs in @gdb_regs into the pt_regs, and store them + * in @regs. + */ +extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +/* + * kgdb_arch_handle_exception - Handle architecture specific GDB packets. + * @vector: The error vector of the exception that happened. + * @signo: The signal number of the exception that happened. + * @err_code: The error code of the exception that happened. + * @remcom_in_buffer: The buffer of the packet we have read. + * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. + * @regs: The &struct pt_regs of the current process. + * + * This function MUST handle the 'c' and 's' command packets, + * as well packets to set / remove a hardware breakpoint, if used. + * If there are additional packets which the hardware needs to handle, + * they are handled here. The code should return -1 if it wants to + * process more packets, and a %0 or %1 if it wants to exit from the + * kgdb callback. + */ +extern int +kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *regs); + +/* + * kgdb_roundup_cpus - Get other CPUs into a holding pattern + * @flags: Current IRQ state + * + * On SMP systems, we need to get the attention of the other CPUs + * and get them be in a known state. This should do what is needed + * to get the other CPUs to call kgdb_wait(). Note that on some arches, + * the NMI approach is not used for rounding up all the CPUs. For example, + * in case of MIPS, smp_call_function() is used to roundup CPUs. In + * this case, we have to make sure that interrupts are enabled before + * calling smp_call_function(). The argument to this function is + * the flags that will be used when restoring the interrupts. There is + * local_irq_save() call before kgdb_roundup_cpus(). + * + * On non-SMP systems, this is not called. + */ +extern void kgdb_roundup_cpus(unsigned long flags); + +/* Optional functions. */ +extern int kgdb_validate_break_address(unsigned long addr); +extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); +extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); + +/* + * struct kgdb_arch - Describe architecture specific values. + * @gdb_bpt_instr: The instruction to trigger a breakpoint. + * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. + * @set_breakpoint: Allow an architecture to specify how to set a software + * breakpoint. + * @remove_breakpoint: Allow an architecture to specify how to remove a + * software breakpoint. + * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware + * breakpoint. + * @remove_hw_breakpoint: Allow an architecture to specify how to remove a + * hardware breakpoint. + * @remove_all_hw_break: Allow an architecture to specify how to remove all + * hardware breakpoints. + * @correct_hw_break: Allow an architecture to specify how to correct the + * hardware debug registers. + */ +struct kgdb_arch { + unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; + unsigned long flags; + + int (*set_breakpoint)(unsigned long, char *); + int (*remove_breakpoint)(unsigned long, char *); + int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); + int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); + void (*remove_all_hw_break)(void); + void (*correct_hw_break)(void); +}; + +/* + * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB. + * @name: Name of the I/O driver. + * @read_char: Pointer to a function that will return one char. + * @write_char: Pointer to a function that will write one char. + * @flush: Pointer to a function that will flush any pending writes. + * @init: Pointer to a function that will initialize the device. + * @pre_exception: Pointer to a function that will do any prep work for + * the I/O driver. + * @post_exception: Pointer to a function that will do any cleanup work + * for the I/O driver. + */ +struct kgdb_io { + const char *name; + int (*read_char) (void); + void (*write_char) (u8); + void (*flush) (void); + int (*init) (void); + void (*pre_exception) (void); + void (*post_exception) (void); +}; + +extern struct kgdb_arch arch_kgdb_ops; + +extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); +extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); + +extern int kgdb_hex2long(char **ptr, long *long_val); +extern int kgdb_mem2hex(char *mem, char *buf, int count); +extern int kgdb_hex2mem(char *buf, char *mem, int count); + +extern int kgdb_isremovedbreak(unsigned long addr); + +extern int +kgdb_handle_exception(int ex_vector, int signo, int err_code, + struct pt_regs *regs); +extern int kgdb_nmicallback(int cpu, void *regs); + +extern int kgdb_single_step; +extern atomic_t kgdb_active; + +#endif /* _KGDB_H_ */ diff --git a/kernel/Makefile b/kernel/Makefile index 6c584c55a6e9..05c8003718ee 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o diff --git a/kernel/kgdb.c b/kernel/kgdb.c new file mode 100644 index 000000000000..017ee782bc08 --- /dev/null +++ b/kernel/kgdb.c @@ -0,0 +1,1693 @@ +/* + * KGDB stub. + * + * Maintainer: Jason Wessel + * + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * Copyright (C) 2002-2004 Timesys Corporation + * Copyright (C) 2003-2004 Amit S. Kale + * Copyright (C) 2004 Pavel Machek + * Copyright (C) 2004-2006 Tom Rini + * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. + * Copyright (C) 2005-2008 Wind River Systems, Inc. + * Copyright (C) 2007 MontaVista Software, Inc. + * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar + * + * Contributors at various stages not listed above: + * Jason Wessel ( jason.wessel@windriver.com ) + * George Anzinger + * Anurekh Saxena (anurekh.saxena@timesys.com) + * Lake Stevens Instrument Division (Glenn Engel) + * Jim Kingdon, Cygnus Support. + * + * Original KGDB stub: David Grothe , + * Tigran Aivazian + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int kgdb_break_asap; + +struct kgdb_state { + int ex_vector; + int signo; + int err_code; + int cpu; + int pass_exception; + long threadid; + long kgdb_usethreadid; + struct pt_regs *linux_regs; +}; + +static struct debuggerinfo_struct { + void *debuggerinfo; + struct task_struct *task; +} kgdb_info[NR_CPUS]; + +/** + * kgdb_connected - Is a host GDB connected to us? + */ +int kgdb_connected; +EXPORT_SYMBOL_GPL(kgdb_connected); + +/* All the KGDB handlers are installed */ +static int kgdb_io_module_registered; + +/* Guard for recursive entry */ +static int exception_level; + +static struct kgdb_io *kgdb_io_ops; +static DEFINE_SPINLOCK(kgdb_registration_lock); + +/* kgdb console driver is loaded */ +static int kgdb_con_registered; +/* determine if kgdb console output should be used */ +static int kgdb_use_con; + +static int __init opt_kgdb_con(char *str) +{ + kgdb_use_con = 1; + return 0; +} + +early_param("kgdbcon", opt_kgdb_con); + +module_param(kgdb_use_con, int, 0644); + +/* + * Holds information about breakpoints in a kernel. These breakpoints are + * added and removed by gdb. + */ +static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { + [0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED } +}; + +/* + * The CPU# of the active CPU, or -1 if none: + */ +atomic_t kgdb_active = ATOMIC_INIT(-1); + +/* + * We use NR_CPUs not PERCPU, in case kgdb is used to debug early + * bootup code (which might not have percpu set up yet): + */ +static atomic_t passive_cpu_wait[NR_CPUS]; +static atomic_t cpu_in_kgdb[NR_CPUS]; +atomic_t kgdb_setting_breakpoint; + +struct task_struct *kgdb_usethread; +struct task_struct *kgdb_contthread; + +int kgdb_single_step; + +/* Our I/O buffers. */ +static char remcom_in_buffer[BUFMAX]; +static char remcom_out_buffer[BUFMAX]; + +/* Storage for the registers, in GDB format. */ +static unsigned long gdb_regs[(NUMREGBYTES + + sizeof(unsigned long) - 1) / + sizeof(unsigned long)]; + +/* to keep track of the CPU which is doing the single stepping*/ +atomic_t kgdb_cpu_doing_single_step = ATOMIC_INIT(-1); + +/* + * If you are debugging a problem where roundup (the collection of + * all other CPUs) is a problem [this should be extremely rare], + * then use the nokgdbroundup option to avoid roundup. In that case + * the other CPUs might interfere with your debugging context, so + * use this with care: + */ +int kgdb_do_roundup = 1; + +static int __init opt_nokgdbroundup(char *str) +{ + kgdb_do_roundup = 0; + + return 0; +} + +early_param("nokgdbroundup", opt_nokgdbroundup); + +/* + * Finally, some KGDB code :-) + */ + +/* + * Weak aliases for breakpoint management, + * can be overriden by architectures when needed: + */ +int __weak kgdb_validate_break_address(unsigned long addr) +{ + char tmp_variable[BREAK_INSTR_SIZE]; + + return probe_kernel_read(tmp_variable, (char *)addr, BREAK_INSTR_SIZE); +} + +int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) +{ + int err; + + err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE); + if (err) + return err; + + return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, + BREAK_INSTR_SIZE); +} + +int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) +{ + return probe_kernel_write((char *)addr, + (char *)bundle, BREAK_INSTR_SIZE); +} + +unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +int __weak kgdb_arch_init(void) +{ + return 0; +} + +/** + * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. + * @regs: Current &struct pt_regs. + * + * This function will be called if the particular architecture must + * disable hardware debugging while it is processing gdb packets or + * handling exception. + */ +void __weak kgdb_disable_hw_debug(struct pt_regs *regs) +{ +} + +/* + * GDB remote protocol parser: + */ + +static const char hexchars[] = "0123456789abcdef"; + +static int hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + return -1; +} + +/* scan for the sequence $# */ +static void get_packet(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + do { + /* + * Spin and wait around for the start character, ignore all + * other characters: + */ + while ((ch = (kgdb_io_ops->read_char())) != '$') + /* nothing */; + + kgdb_connected = 1; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* + * now, read until a # or end of buffer is found: + */ + while (count < (BUFMAX - 1)) { + ch = kgdb_io_ops->read_char(); + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(kgdb_io_ops->read_char()) << 4; + xmitcsum += hex(kgdb_io_ops->read_char()); + + if (checksum != xmitcsum) + /* failed checksum */ + kgdb_io_ops->write_char('-'); + else + /* successful transfer */ + kgdb_io_ops->write_char('+'); + if (kgdb_io_ops->flush) + kgdb_io_ops->flush(); + } + } while (checksum != xmitcsum); +} + +/* + * Send the packet in buffer. + * Check for gdb connection if asked for. + */ +static void put_packet(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* + * $#. + */ + while (1) { + kgdb_io_ops->write_char('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + kgdb_io_ops->write_char(ch); + checksum += ch; + count++; + } + + kgdb_io_ops->write_char('#'); + kgdb_io_ops->write_char(hexchars[checksum >> 4]); + kgdb_io_ops->write_char(hexchars[checksum & 0xf]); + if (kgdb_io_ops->flush) + kgdb_io_ops->flush(); + + /* Now see what we get in reply. */ + ch = kgdb_io_ops->read_char(); + + if (ch == 3) + ch = kgdb_io_ops->read_char(); + + /* If we get an ACK, we are done. */ + if (ch == '+') + return; + + /* + * If we get the start of another packet, this means + * that GDB is attempting to reconnect. We will NAK + * the packet being sent, and stop trying to send this + * packet. + */ + if (ch == '$') { + kgdb_io_ops->write_char('-'); + if (kgdb_io_ops->flush) + kgdb_io_ops->flush(); + return; + } + } +} + +static char *pack_hex_byte(char *pkt, u8 byte) +{ + *pkt++ = hexchars[byte >> 4]; + *pkt++ = hexchars[byte & 0xf]; + + return pkt; +} + +/* + * Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null). May return an error. + */ +int kgdb_mem2hex(char *mem, char *buf, int count) +{ + char *tmp; + int err; + + /* + * We use the upper half of buf as an intermediate buffer for the + * raw memory copy. Hex conversion will work against this one. + */ + tmp = buf + count; + + err = probe_kernel_read(tmp, mem, count); + if (!err) { + while (count > 0) { + buf = pack_hex_byte(buf, *tmp); + tmp++; + count--; + } + + *buf = 0; + } + + return err; +} + +/* + * Copy the binary array pointed to by buf into mem. Fix $, #, and + * 0x7d escaped with 0x7d. Return a pointer to the character after + * the last byte written. + */ +static int kgdb_ebin2mem(char *buf, char *mem, int count) +{ + int err = 0; + char c; + + while (count-- > 0) { + c = *buf++; + if (c == 0x7d) + c = *buf++ ^ 0x20; + + err = probe_kernel_write(mem, &c, 1); + if (err) + break; + + mem++; + } + + return err; +} + +/* + * Convert the hex array pointed to by buf into binary to be placed in mem. + * Return a pointer to the character AFTER the last byte written. + * May return an error. + */ +int kgdb_hex2mem(char *buf, char *mem, int count) +{ + char *tmp_raw; + char *tmp_hex; + + /* + * We use the upper half of buf as an intermediate buffer for the + * raw memory that is converted from hex. + */ + tmp_raw = buf + count * 2; + + tmp_hex = tmp_raw - 1; + while (tmp_hex >= buf) { + tmp_raw--; + *tmp_raw = hex(*tmp_hex--); + *tmp_raw |= hex(*tmp_hex--) << 4; + } + + return probe_kernel_write(mem, tmp_raw, count); +} + +/* + * While we find nice hex chars, build a long_val. + * Return number of chars processed. + */ +int kgdb_hex2long(char **ptr, long *long_val) +{ + int hex_val; + int num = 0; + + *long_val = 0; + + while (**ptr) { + hex_val = hex(**ptr); + if (hex_val < 0) + break; + + *long_val = (*long_val << 4) | hex_val; + num++; + (*ptr)++; + } + + return num; +} + +/* Write memory due to an 'M' or 'X' packet. */ +static int write_mem_msg(int binary) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + unsigned long length; + int err; + + if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && + kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { + if (binary) + err = kgdb_ebin2mem(ptr, (char *)addr, length); + else + err = kgdb_hex2mem(ptr, (char *)addr, length); + if (err) + return err; + if (CACHE_FLUSH_IS_SAFE) + flush_icache_range(addr, addr + length + 1); + return 0; + } + + return -EINVAL; +} + +static void error_packet(char *pkt, int error) +{ + error = -error; + pkt[0] = 'E'; + pkt[1] = hexchars[(error / 10)]; + pkt[2] = hexchars[(error % 10)]; + pkt[3] = '\0'; +} + +/* + * Thread ID accessors. We represent a flat TID space to GDB, where + * the per CPU idle threads (which under Linux all have PID 0) are + * remapped to negative TIDs. + */ + +#define BUF_THREAD_ID_SIZE 16 + +static char *pack_threadid(char *pkt, unsigned char *id) +{ + char *limit; + + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *id++); + + return pkt; +} + +static void int_to_threadref(unsigned char *id, int value) +{ + unsigned char *scan; + int i = 4; + + scan = (unsigned char *)id; + while (i--) + *scan++ = 0; + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} + +static struct task_struct *getthread(struct pt_regs *regs, int tid) +{ + /* + * Non-positive TIDs are remapped idle tasks: + */ + if (tid <= 0) + return idle_task(-tid); + + /* + * find_task_by_pid_ns() does not take the tasklist lock anymore + * but is nicely RCU locked - hence is a pretty resilient + * thing to use: + */ + return find_task_by_pid_ns(tid, &init_pid_ns); +} + +/* + * CPU debug state control: + */ + +#ifdef CONFIG_SMP +static void kgdb_wait(struct pt_regs *regs) +{ + unsigned long flags; + int cpu; + + local_irq_save(flags); + cpu = raw_smp_processor_id(); + kgdb_info[cpu].debuggerinfo = regs; + kgdb_info[cpu].task = current; + /* + * Make sure the above info reaches the primary CPU before + * our cpu_in_kgdb[] flag setting does: + */ + smp_wmb(); + atomic_set(&cpu_in_kgdb[cpu], 1); + + /* + * The primary CPU must be active to enter here, but this is + * guard in case the primary CPU had not been selected if + * this was an entry via nmi. + */ + while (atomic_read(&kgdb_active) == -1) + cpu_relax(); + + /* Wait till primary CPU goes completely into the debugger. */ + while (!atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) + cpu_relax(); + + /* Wait till primary CPU is done with debugging */ + while (atomic_read(&passive_cpu_wait[cpu])) + cpu_relax(); + + kgdb_info[cpu].debuggerinfo = NULL; + kgdb_info[cpu].task = NULL; + + /* fix up hardware debug registers on local cpu */ + if (arch_kgdb_ops.correct_hw_break) + arch_kgdb_ops.correct_hw_break(); + + /* Signal the primary CPU that we are done: */ + atomic_set(&cpu_in_kgdb[cpu], 0); + local_irq_restore(flags); +} +#endif + +/* + * Some architectures need cache flushes when we set/clear a + * breakpoint: + */ +static void kgdb_flush_swbreak_addr(unsigned long addr) +{ + if (!CACHE_FLUSH_IS_SAFE) + return; + + if (current->mm) { + flush_cache_range(current->mm->mmap_cache, + addr, addr + BREAK_INSTR_SIZE); + } else { + flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + } +} + +/* + * SW breakpoint management: + */ +static int kgdb_activate_sw_breakpoints(void) +{ + unsigned long addr; + int error = 0; + int i; + + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != BP_SET) + continue; + + addr = kgdb_break[i].bpt_addr; + error = kgdb_arch_set_breakpoint(addr, + kgdb_break[i].saved_instr); + if (error) + return error; + + kgdb_flush_swbreak_addr(addr); + kgdb_break[i].state = BP_ACTIVE; + } + return 0; +} + +static int kgdb_set_sw_break(unsigned long addr) +{ + int err = kgdb_validate_break_address(addr); + int breakno = -1; + int i; + + if (err) + return err; + + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == BP_SET) && + (kgdb_break[i].bpt_addr == addr)) + return -EEXIST; + } + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state == BP_REMOVED && + kgdb_break[i].bpt_addr == addr) { + breakno = i; + break; + } + } + + if (breakno == -1) { + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state == BP_UNDEFINED) { + breakno = i; + break; + } + } + } + + if (breakno == -1) + return -E2BIG; + + kgdb_break[breakno].state = BP_SET; + kgdb_break[breakno].type = BP_BREAKPOINT; + kgdb_break[breakno].bpt_addr = addr; + + return 0; +} + +static int kgdb_deactivate_sw_breakpoints(void) +{ + unsigned long addr; + int error = 0; + int i; + + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != BP_ACTIVE) + continue; + addr = kgdb_break[i].bpt_addr; + error = kgdb_arch_remove_breakpoint(addr, + kgdb_break[i].saved_instr); + if (error) + return error; + + kgdb_flush_swbreak_addr(addr); + kgdb_break[i].state = BP_SET; + } + return 0; +} + +static int kgdb_remove_sw_break(unsigned long addr) +{ + int i; + + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == BP_SET) && + (kgdb_break[i].bpt_addr == addr)) { + kgdb_break[i].state = BP_REMOVED; + return 0; + } + } + return -ENOENT; +} + +int kgdb_isremovedbreak(unsigned long addr) +{ + int i; + + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == BP_REMOVED) && + (kgdb_break[i].bpt_addr == addr)) + return 1; + } + return 0; +} + +int remove_all_break(void) +{ + unsigned long addr; + int error; + int i; + + /* Clear memory breakpoints. */ + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != BP_SET) + continue; + addr = kgdb_break[i].bpt_addr; + error = kgdb_arch_remove_breakpoint(addr, + kgdb_break[i].saved_instr); + if (error) + return error; + kgdb_break[i].state = BP_REMOVED; + } + + /* Clear hardware breakpoints. */ + if (arch_kgdb_ops.remove_all_hw_break) + arch_kgdb_ops.remove_all_hw_break(); + + return 0; +} + +/* + * Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs: + */ +static inline int shadow_pid(int realpid) +{ + if (realpid) + return realpid; + + return -1-raw_smp_processor_id(); +} + +static char gdbmsgbuf[BUFMAX + 1]; + +static void kgdb_msg_write(const char *s, int len) +{ + char *bufptr; + int wcount; + int i; + + /* 'O'utput */ + gdbmsgbuf[0] = 'O'; + + /* Fill and send buffers... */ + while (len > 0) { + bufptr = gdbmsgbuf + 1; + + /* Calculate how many this time */ + if ((len << 1) > (BUFMAX - 2)) + wcount = (BUFMAX - 2) >> 1; + else + wcount = len; + + /* Pack in hex chars */ + for (i = 0; i < wcount; i++) + bufptr = pack_hex_byte(bufptr, s[i]); + *bufptr = '\0'; + + /* Move up */ + s += wcount; + len -= wcount; + + /* Write packet */ + put_packet(gdbmsgbuf); + } +} + +/* + * Return true if there is a valid kgdb I/O module. Also if no + * debugger is attached a message can be printed to the console about + * waiting for the debugger to attach. + * + * The print_wait argument is only to be true when called from inside + * the core kgdb_handle_exception, because it will wait for the + * debugger to attach. + */ +static int kgdb_io_ready(int print_wait) +{ + if (!kgdb_io_ops) + return 0; + if (kgdb_connected) + return 1; + if (atomic_read(&kgdb_setting_breakpoint)) + return 1; + if (print_wait) + printk(KERN_CRIT "KGDB: Waiting for remote debugger\n"); + return 1; +} + +/* + * All the functions that start with gdb_cmd are the various + * operations to implement the handlers for the gdbserial protocol + * where KGDB is communicating with an external debugger + */ + +/* Handle the '?' status packets */ +static void gdb_cmd_status(struct kgdb_state *ks) +{ + /* + * We know that this packet is only sent + * during initial connect. So to be safe, + * we clear out our breakpoints now in case + * GDB is reconnecting. + */ + remove_all_break(); + + remcom_out_buffer[0] = 'S'; + pack_hex_byte(&remcom_out_buffer[1], ks->signo); +} + +/* Handle the 'g' get registers request */ +static void gdb_cmd_getregs(struct kgdb_state *ks) +{ + struct task_struct *thread; + void *local_debuggerinfo; + int i; + + thread = kgdb_usethread; + if (!thread) { + thread = kgdb_info[ks->cpu].task; + local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo; + } else { + local_debuggerinfo = NULL; + for (i = 0; i < NR_CPUS; i++) { + /* + * Try to find the task on some other + * or possibly this node if we do not + * find the matching task then we try + * to approximate the results. + */ + if (thread == kgdb_info[i].task) + local_debuggerinfo = kgdb_info[i].debuggerinfo; + } + } + + /* + * All threads that don't have debuggerinfo should be + * in __schedule() sleeping, since all other CPUs + * are in kgdb_wait, and thus have debuggerinfo. + */ + if (local_debuggerinfo) { + pt_regs_to_gdb_regs(gdb_regs, local_debuggerinfo); + } else { + /* + * Pull stuff saved during switch_to; nothing + * else is accessible (or even particularly + * relevant). + * + * This should be enough for a stack trace. + */ + sleeping_thread_to_gdb_regs(gdb_regs, thread); + } + kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); +} + +/* Handle the 'G' set registers request */ +static void gdb_cmd_setregs(struct kgdb_state *ks) +{ + kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES); + + if (kgdb_usethread && kgdb_usethread != current) { + error_packet(remcom_out_buffer, -EINVAL); + } else { + gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs); + strcpy(remcom_out_buffer, "OK"); + } +} + +/* Handle the 'm' memory read bytes */ +static void gdb_cmd_memread(struct kgdb_state *ks) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long length; + unsigned long addr; + int err; + + if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && + kgdb_hex2long(&ptr, &length) > 0) { + err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); + if (err) + error_packet(remcom_out_buffer, err); + } else { + error_packet(remcom_out_buffer, -EINVAL); + } +} + +/* Handle the 'M' memory write bytes */ +static void gdb_cmd_memwrite(struct kgdb_state *ks) +{ + int err = write_mem_msg(0); + + if (err) + error_packet(remcom_out_buffer, err); + else + strcpy(remcom_out_buffer, "OK"); +} + +/* Handle the 'X' memory binary write bytes */ +static void gdb_cmd_binwrite(struct kgdb_state *ks) +{ + int err = write_mem_msg(1); + + if (err) + error_packet(remcom_out_buffer, err); + else + strcpy(remcom_out_buffer, "OK"); +} + +/* Handle the 'D' or 'k', detach or kill packets */ +static void gdb_cmd_detachkill(struct kgdb_state *ks) +{ + int error; + + /* The detach case */ + if (remcom_in_buffer[0] == 'D') { + error = remove_all_break(); + if (error < 0) { + error_packet(remcom_out_buffer, error); + } else { + strcpy(remcom_out_buffer, "OK"); + kgdb_connected = 0; + } + put_packet(remcom_out_buffer); + } else { + /* + * Assume the kill case, with no exit code checking, + * trying to force detach the debugger: + */ + remove_all_break(); + kgdb_connected = 0; + } +} + +/* Handle the 'R' reboot packets */ +static int gdb_cmd_reboot(struct kgdb_state *ks) +{ + /* For now, only honor R0 */ + if (strcmp(remcom_in_buffer, "R0") == 0) { + printk(KERN_CRIT "Executing emergency reboot\n"); + strcpy(remcom_out_buffer, "OK"); + put_packet(remcom_out_buffer); + + /* + * Execution should not return from + * machine_emergency_restart() + */ + machine_emergency_restart(); + kgdb_connected = 0; + + return 1; + } + return 0; +} + +/* Handle the 'q' query packets */ +static void gdb_cmd_query(struct kgdb_state *ks) +{ + struct task_struct *thread; + unsigned char thref[8]; + char *ptr; + int i; + + switch (remcom_in_buffer[1]) { + case 's': + case 'f': + if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + + if (remcom_in_buffer[1] == 'f') + ks->threadid = 1; + + remcom_out_buffer[0] = 'm'; + ptr = remcom_out_buffer + 1; + + for (i = 0; i < 17; ks->threadid++) { + thread = getthread(ks->linux_regs, ks->threadid); + if (thread) { + int_to_threadref(thref, ks->threadid); + pack_threadid(ptr, thref); + ptr += BUF_THREAD_ID_SIZE; + *(ptr++) = ','; + i++; + } + } + *(--ptr) = '\0'; + break; + + case 'C': + /* Current thread id */ + strcpy(remcom_out_buffer, "QC"); + ks->threadid = shadow_pid(current->pid); + int_to_threadref(thref, ks->threadid); + pack_threadid(remcom_out_buffer + 2, thref); + break; + case 'T': + if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + ks->threadid = 0; + ptr = remcom_in_buffer + 17; + kgdb_hex2long(&ptr, &ks->threadid); + if (!getthread(ks->linux_regs, ks->threadid)) { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + if (ks->threadid > 0) { + kgdb_mem2hex(getthread(ks->linux_regs, + ks->threadid)->comm, + remcom_out_buffer, 16); + } else { + static char tmpstr[23 + BUF_THREAD_ID_SIZE]; + + sprintf(tmpstr, "Shadow task %d for pid 0", + (int)(-ks->threadid-1)); + kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr)); + } + break; + } +} + +/* Handle the 'H' task query packets */ +static void gdb_cmd_task(struct kgdb_state *ks) +{ + struct task_struct *thread; + char *ptr; + + switch (remcom_in_buffer[1]) { + case 'g': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &ks->threadid); + thread = getthread(ks->linux_regs, ks->threadid); + if (!thread && ks->threadid > 0) { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + kgdb_usethread = thread; + ks->kgdb_usethreadid = ks->threadid; + strcpy(remcom_out_buffer, "OK"); + break; + case 'c': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &ks->threadid); + if (!ks->threadid) { + kgdb_contthread = NULL; + } else { + thread = getthread(ks->linux_regs, ks->threadid); + if (!thread && ks->threadid > 0) { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + kgdb_contthread = thread; + } + strcpy(remcom_out_buffer, "OK"); + break; + } +} + +/* Handle the 'T' thread query packets */ +static void gdb_cmd_thread(struct kgdb_state *ks) +{ + char *ptr = &remcom_in_buffer[1]; + struct task_struct *thread; + + kgdb_hex2long(&ptr, &ks->threadid); + thread = getthread(ks->linux_regs, ks->threadid); + if (thread) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, -EINVAL); +} + +/* Handle the 'z' or 'Z' breakpoint remove or set packets */ +static void gdb_cmd_break(struct kgdb_state *ks) +{ + /* + * Since GDB-5.3, it's been drafted that '0' is a software + * breakpoint, '1' is a hardware breakpoint, so let's do that. + */ + char *bpt_type = &remcom_in_buffer[1]; + char *ptr = &remcom_in_buffer[2]; + unsigned long addr; + unsigned long length; + int error = 0; + + if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') { + /* Unsupported */ + if (*bpt_type > '4') + return; + } else { + if (*bpt_type != '0' && *bpt_type != '1') + /* Unsupported. */ + return; + } + + /* + * Test if this is a hardware breakpoint, and + * if we support it: + */ + if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)) + /* Unsupported. */ + return; + + if (*(ptr++) != ',') { + error_packet(remcom_out_buffer, -EINVAL); + return; + } + if (!kgdb_hex2long(&ptr, &addr)) { + error_packet(remcom_out_buffer, -EINVAL); + return; + } + if (*(ptr++) != ',' || + !kgdb_hex2long(&ptr, &length)) { + error_packet(remcom_out_buffer, -EINVAL); + return; + } + + if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') + error = kgdb_set_sw_break(addr); + else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') + error = kgdb_remove_sw_break(addr); + else if (remcom_in_buffer[0] == 'Z') + error = arch_kgdb_ops.set_hw_breakpoint(addr, + (int)length, *bpt_type); + else if (remcom_in_buffer[0] == 'z') + error = arch_kgdb_ops.remove_hw_breakpoint(addr, + (int) length, *bpt_type); + + if (error == 0) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, error); +} + +/* Handle the 'C' signal / exception passing packets */ +static int gdb_cmd_exception_pass(struct kgdb_state *ks) +{ + /* C09 == pass exception + * C15 == detach kgdb, pass exception + */ + if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') { + + ks->pass_exception = 1; + remcom_in_buffer[0] = 'c'; + + } else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') { + + ks->pass_exception = 1; + remcom_in_buffer[0] = 'D'; + remove_all_break(); + kgdb_connected = 0; + return 1; + + } else { + error_packet(remcom_out_buffer, -EINVAL); + return 0; + } + + /* Indicate fall through */ + return -1; +} + +/* + * This function performs all gdbserial command procesing + */ +static int gdb_serial_stub(struct kgdb_state *ks) +{ + int error = 0; + int tmp; + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + if (kgdb_connected) { + unsigned char thref[8]; + char *ptr; + + /* Reply to host that an exception has occurred */ + ptr = remcom_out_buffer; + *ptr++ = 'T'; + ptr = pack_hex_byte(ptr, ks->signo); + ptr += strlen(strcpy(ptr, "thread:")); + int_to_threadref(thref, shadow_pid(current->pid)); + ptr = pack_threadid(ptr, thref); + *ptr++ = ';'; + put_packet(remcom_out_buffer); + } + + kgdb_usethread = kgdb_info[ks->cpu].task; + ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); + ks->pass_exception = 0; + + while (1) { + error = 0; + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + get_packet(remcom_in_buffer); + + switch (remcom_in_buffer[0]) { + case '?': /* gdbserial status */ + gdb_cmd_status(ks); + break; + case 'g': /* return the value of the CPU registers */ + gdb_cmd_getregs(ks); + break; + case 'G': /* set the value of the CPU registers - return OK */ + gdb_cmd_setregs(ks); + break; + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + gdb_cmd_memread(ks); + break; + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ + gdb_cmd_memwrite(ks); + break; + case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ + gdb_cmd_binwrite(ks); + break; + /* kill or detach. KGDB should treat this like a + * continue. + */ + case 'D': /* Debugger detach */ + case 'k': /* Debugger detach via kill */ + gdb_cmd_detachkill(ks); + goto default_handle; + case 'R': /* Reboot */ + if (gdb_cmd_reboot(ks)) + goto default_handle; + break; + case 'q': /* query command */ + gdb_cmd_query(ks); + break; + case 'H': /* task related */ + gdb_cmd_task(ks); + break; + case 'T': /* Query thread status */ + gdb_cmd_thread(ks); + break; + case 'z': /* Break point remove */ + case 'Z': /* Break point set */ + gdb_cmd_break(ks); + break; + case 'C': /* Exception passing */ + tmp = gdb_cmd_exception_pass(ks); + if (tmp > 0) + goto default_handle; + if (tmp == 0) + break; + /* Fall through on tmp < 0 */ + case 'c': /* Continue packet */ + case 's': /* Single step packet */ + if (kgdb_contthread && kgdb_contthread != current) { + /* Can't switch threads in kgdb */ + error_packet(remcom_out_buffer, -EINVAL); + break; + } + kgdb_activate_sw_breakpoints(); + /* Fall through to default processing */ + default: +default_handle: + error = kgdb_arch_handle_exception(ks->ex_vector, + ks->signo, + ks->err_code, + remcom_in_buffer, + remcom_out_buffer, + ks->linux_regs); + /* + * Leave cmd processing on error, detach, + * kill, continue, or single step. + */ + if (error >= 0 || remcom_in_buffer[0] == 'D' || + remcom_in_buffer[0] == 'k') { + error = 0; + goto kgdb_exit; + } + + } + + /* reply to the request */ + put_packet(remcom_out_buffer); + } + +kgdb_exit: + if (ks->pass_exception) + error = 1; + return error; +} + +static int kgdb_reenter_check(struct kgdb_state *ks) +{ + unsigned long addr; + + if (atomic_read(&kgdb_active) != raw_smp_processor_id()) + return 0; + + /* Panic on recursive debugger calls: */ + exception_level++; + addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs); + kgdb_deactivate_sw_breakpoints(); + + /* + * If the break point removed ok at the place exception + * occurred, try to recover and print a warning to the end + * user because the user planted a breakpoint in a place that + * KGDB needs in order to function. + */ + if (kgdb_remove_sw_break(addr) == 0) { + exception_level = 0; + kgdb_skipexception(ks->ex_vector, ks->linux_regs); + kgdb_activate_sw_breakpoints(); + printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed\n"); + WARN_ON_ONCE(1); + + return 1; + } + remove_all_break(); + kgdb_skipexception(ks->ex_vector, ks->linux_regs); + + if (exception_level > 1) { + dump_stack(); + panic("Recursive entry to debugger"); + } + + printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n"); + dump_stack(); + panic("Recursive entry to debugger"); + + return 1; +} + +/* + * kgdb_handle_exception() - main entry point from a kernel exception + * + * Locking hierarchy: + * interface locks, if any (begin_session) + * kgdb lock (kgdb_active) + */ +int +kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) +{ + struct kgdb_state kgdb_var; + struct kgdb_state *ks = &kgdb_var; + unsigned long flags; + int error = 0; + int i, cpu; + + ks->cpu = raw_smp_processor_id(); + ks->ex_vector = evector; + ks->signo = signo; + ks->ex_vector = evector; + ks->err_code = ecode; + ks->kgdb_usethreadid = 0; + ks->linux_regs = regs; + + if (kgdb_reenter_check(ks)) + return 0; /* Ouch, double exception ! */ + +acquirelock: + /* + * Interrupts will be restored by the 'trap return' code, except when + * single stepping. + */ + local_irq_save(flags); + + cpu = raw_smp_processor_id(); + + /* + * Acquire the kgdb_active lock: + */ + while (atomic_cmpxchg(&kgdb_active, -1, cpu) != -1) + cpu_relax(); + + /* + * Do not start the debugger connection on this CPU if the last + * instance of the exception handler wanted to come into the + * debugger on a different CPU via a single step + */ + if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && + atomic_read(&kgdb_cpu_doing_single_step) != cpu) { + + atomic_set(&kgdb_active, -1); + local_irq_restore(flags); + + goto acquirelock; + } + + if (!kgdb_io_ready(1)) { + error = 1; + goto kgdb_restore; /* No I/O connection, so resume the system */ + } + + /* + * Don't enter if we have hit a removed breakpoint. + */ + if (kgdb_skipexception(ks->ex_vector, ks->linux_regs)) + goto kgdb_restore; + + /* Call the I/O driver's pre_exception routine */ + if (kgdb_io_ops->pre_exception) + kgdb_io_ops->pre_exception(); + + kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs; + kgdb_info[ks->cpu].task = current; + + kgdb_disable_hw_debug(ks->linux_regs); + + /* + * Get the passive CPU lock which will hold all the non-primary + * CPU in a spin state while the debugger is active + */ + if (!kgdb_single_step || !kgdb_contthread) { + for (i = 0; i < NR_CPUS; i++) + atomic_set(&passive_cpu_wait[i], 1); + } + +#ifdef CONFIG_SMP + /* Signal the other CPUs to enter kgdb_wait() */ + if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup) + kgdb_roundup_cpus(flags); +#endif + + /* + * spin_lock code is good enough as a barrier so we don't + * need one here: + */ + atomic_set(&cpu_in_kgdb[ks->cpu], 1); + + /* + * Wait for the other CPUs to be notified and be waiting for us: + */ + for_each_online_cpu(i) { + while (!atomic_read(&cpu_in_kgdb[i])) + cpu_relax(); + } + + /* + * At this point the primary processor is completely + * in the debugger and all secondary CPUs are quiescent + */ + kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); + kgdb_deactivate_sw_breakpoints(); + kgdb_single_step = 0; + kgdb_contthread = NULL; + exception_level = 0; + + /* Talk to debugger with gdbserial protocol */ + error = gdb_serial_stub(ks); + + /* Call the I/O driver's post_exception routine */ + if (kgdb_io_ops->post_exception) + kgdb_io_ops->post_exception(); + + kgdb_info[ks->cpu].debuggerinfo = NULL; + kgdb_info[ks->cpu].task = NULL; + atomic_set(&cpu_in_kgdb[ks->cpu], 0); + + if (!kgdb_single_step || !kgdb_contthread) { + for (i = NR_CPUS-1; i >= 0; i--) + atomic_set(&passive_cpu_wait[i], 0); + /* + * Wait till all the CPUs have quit + * from the debugger. + */ + for_each_online_cpu(i) { + while (atomic_read(&cpu_in_kgdb[i])) + cpu_relax(); + } + } + +kgdb_restore: + /* Free kgdb_active */ + atomic_set(&kgdb_active, -1); + local_irq_restore(flags); + + return error; +} + +int kgdb_nmicallback(int cpu, void *regs) +{ +#ifdef CONFIG_SMP + if (!atomic_read(&cpu_in_kgdb[cpu]) && + atomic_read(&kgdb_active) != cpu) { + kgdb_wait((struct pt_regs *)regs); + return 0; + } +#endif + return 1; +} + +void kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + unsigned long flags; + + /* If we're debugging, or KGDB has not connected, don't try + * and print. */ + if (!kgdb_connected || atomic_read(&kgdb_active) != -1) + return; + + local_irq_save(flags); + kgdb_msg_write(s, count); + local_irq_restore(flags); +} + +static struct console kgdbcons = { + .name = "kgdb", + .write = kgdb_console_write, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, +}; + +#ifdef CONFIG_MAGIC_SYSRQ +static void sysrq_handle_gdb(int key, struct tty_struct *tty) +{ + if (!kgdb_io_ops) { + printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); + return; + } + if (!kgdb_connected) + printk(KERN_CRIT "Entering KGDB\n"); + + kgdb_breakpoint(); +} + +static struct sysrq_key_op sysrq_gdb_op = { + .handler = sysrq_handle_gdb, + .help_msg = "Gdb", + .action_msg = "GDB", +}; +#endif + +static void kgdb_register_callbacks(void) +{ + if (!kgdb_io_module_registered) { + kgdb_io_module_registered = 1; + kgdb_arch_init(); +#ifdef CONFIG_MAGIC_SYSRQ + register_sysrq_key('g', &sysrq_gdb_op); +#endif + if (kgdb_use_con && !kgdb_con_registered) { + register_console(&kgdbcons); + kgdb_con_registered = 1; + } + } +} + +static void kgdb_unregister_callbacks(void) +{ + /* + * When this routine is called KGDB should unregister from the + * panic handler and clean up, making sure it is not handling any + * break exceptions at the time. + */ + if (kgdb_io_module_registered) { + kgdb_io_module_registered = 0; + kgdb_arch_exit(); +#ifdef CONFIG_MAGIC_SYSRQ + unregister_sysrq_key('g', &sysrq_gdb_op); +#endif + if (kgdb_con_registered) { + unregister_console(&kgdbcons); + kgdb_con_registered = 0; + } + } +} + +static void kgdb_initial_breakpoint(void) +{ + kgdb_break_asap = 0; + + printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n"); + kgdb_breakpoint(); +} + +/** + * kkgdb_register_io_module - register KGDB IO module + * @new_kgdb_io_ops: the io ops vector + * + * Register it with the KGDB core. + */ +int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops) +{ + int err; + + spin_lock(&kgdb_registration_lock); + + if (kgdb_io_ops) { + spin_unlock(&kgdb_registration_lock); + + printk(KERN_ERR "kgdb: Another I/O driver is already " + "registered with KGDB.\n"); + return -EBUSY; + } + + if (new_kgdb_io_ops->init) { + err = new_kgdb_io_ops->init(); + if (err) { + spin_unlock(&kgdb_registration_lock); + return err; + } + } + + kgdb_io_ops = new_kgdb_io_ops; + + spin_unlock(&kgdb_registration_lock); + + printk(KERN_INFO "kgdb: Registered I/O driver %s.\n", + new_kgdb_io_ops->name); + + /* Arm KGDB now. */ + kgdb_register_callbacks(); + + if (kgdb_break_asap) + kgdb_initial_breakpoint(); + + return 0; +} +EXPORT_SYMBOL_GPL(kgdb_register_io_module); + +/** + * kkgdb_unregister_io_module - unregister KGDB IO module + * @old_kgdb_io_ops: the io ops vector + * + * Unregister it with the KGDB core. + */ +void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops) +{ + BUG_ON(kgdb_connected); + + /* + * KGDB is no longer able to communicate out, so + * unregister our callbacks and reset state. + */ + kgdb_unregister_callbacks(); + + spin_lock(&kgdb_registration_lock); + + WARN_ON_ONCE(kgdb_io_ops != old_kgdb_io_ops); + kgdb_io_ops = NULL; + + spin_unlock(&kgdb_registration_lock); + + printk(KERN_INFO + "kgdb: Unregistered I/O driver %s, debugger disabled.\n", + old_kgdb_io_ops->name); +} +EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); + +/** + * kgdb_breakpoint - generate breakpoint exception + * + * This function will generate a breakpoint exception. It is used at the + * beginning of a program to sync up with a debugger and can be used + * otherwise as a quick means to stop program execution and "break" into + * the debugger. + */ +void kgdb_breakpoint(void) +{ + atomic_set(&kgdb_setting_breakpoint, 1); + wmb(); /* Sync point before breakpoint */ + arch_kgdb_breakpoint(); + wmb(); /* Sync point after breakpoint */ + atomic_set(&kgdb_setting_breakpoint, 0); +} +EXPORT_SYMBOL_GPL(kgdb_breakpoint); + +static int __init opt_kgdb_wait(char *str) +{ + kgdb_break_asap = 1; + + if (kgdb_io_module_registered) + kgdb_initial_breakpoint(); + + return 0; +} + +early_param("kgdbwait", opt_kgdb_wait); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0796c1a090c0..e601d0e7ac5d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -622,3 +622,5 @@ config PROVIDE_OHCI1394_DMA_INIT See Documentation/debugging-via-ohci1394.txt for more information. source "samples/Kconfig" + +source "lib/Kconfig.kgdb" diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb new file mode 100644 index 000000000000..9631ba3baaf3 --- /dev/null +++ b/lib/Kconfig.kgdb @@ -0,0 +1,27 @@ + +menuconfig KGDB + bool "KGDB: kernel debugging with remote gdb" + select FRAME_POINTER + depends on HAVE_ARCH_KGDB + depends on DEBUG_KERNEL && EXPERIMENTAL + help + If you say Y here, it will be possible to remotely debug the + kernel using gdb. Documentation of kernel debugger is available + at http://kgdb.sourceforge.net as well as in DocBook form + in Documentation/DocBook/. If unsure, say N. + +config HAVE_ARCH_KGDB_SHADOW_INFO + bool + +config HAVE_ARCH_KGDB + bool + +config KGDB_SERIAL_CONSOLE + tristate "KGDB: use kgdb over the serial console" + depends on KGDB + select CONSOLE_POLL + select MAGIC_SYSRQ + default y + help + Share a serial console with kgdb. Sysrq-g must be used + to break in initially. -- cgit v1.2.3 From f2d937f3bf00665ccf048b3b6616ef95859b0945 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 17 Apr 2008 20:05:37 +0200 Subject: consoles: polling support, kgdboc polled console handling support, to access a console in an irq-less way while in debug or irq context. absolutely zero impact as long as CONFIG_CONSOLE_POLL is disabled. (which is the default) [ jan.kiszka@siemens.com: lots of cleanups ] [ mingo@elte.hu: redesign, splitups, cleanups. ] Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar Signed-off-by: Jan Kiszka Reviewed-by: Thomas Gleixner --- drivers/char/tty_io.c | 47 +++++++++++++ drivers/serial/8250.c | 58 +++++++++++++++ drivers/serial/Kconfig | 3 + drivers/serial/Makefile | 1 + drivers/serial/kgdboc.c | 163 +++++++++++++++++++++++++++++++++++++++++++ drivers/serial/serial_core.c | 72 ++++++++++++++++++- include/linux/serial_core.h | 4 ++ include/linux/tty_driver.h | 12 ++++ 8 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 drivers/serial/kgdboc.c (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 613ec816ce60..4d3c7018f0c3 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1155,6 +1155,48 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) return NULL; } +#ifdef CONFIG_CONSOLE_POLL + +/** + * tty_find_polling_driver - find device of a polled tty + * @name: name string to match + * @line: pointer to resulting tty line nr + * + * This routine returns a tty driver structure, given a name + * and the condition that the tty driver is capable of polled + * operation. + */ +struct tty_driver *tty_find_polling_driver(char *name, int *line) +{ + struct tty_driver *p, *res = NULL; + int tty_line = 0; + char *str; + + mutex_lock(&tty_mutex); + /* Search through the tty devices to look for a match */ + list_for_each_entry(p, &tty_drivers, tty_drivers) { + str = name + strlen(p->name); + tty_line = simple_strtoul(str, &str, 10); + if (*str == ',') + str++; + if (*str == '\0') + str = 0; + + if (tty_line >= 0 && tty_line <= p->num && p->poll_init && + !p->poll_init(p, tty_line, str)) { + + res = p; + *line = tty_line; + break; + } + } + mutex_unlock(&tty_mutex); + + return res; +} +EXPORT_SYMBOL_GPL(tty_find_polling_driver); +#endif + /** * tty_check_change - check for POSIX terminal changes * @tty: tty to check @@ -3850,6 +3892,11 @@ void tty_set_operations(struct tty_driver *driver, driver->write_proc = op->write_proc; driver->tiocmget = op->tiocmget; driver->tiocmset = op->tiocmset; +#ifdef CONFIG_CONSOLE_POLL + driver->poll_init = op->poll_init; + driver->poll_get_char = op->poll_get_char; + driver->poll_put_char = op->poll_put_char; +#endif } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 77f7a7f0646e..96a585e1cee8 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1740,6 +1740,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) } } +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned char lsr = serial_inp(up, UART_LSR); + + while (!(lsr & UART_LSR_DR)) + lsr = serial_inp(up, UART_LSR); + + return serial_inp(up, UART_RX); +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = (struct uart_8250_port *)port; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(up, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_TX, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_IER, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; @@ -2386,6 +2440,10 @@ static struct uart_ops serial8250_pops = { .request_port = serial8250_request_port, .config_port = serial8250_config_port, .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif }; static struct uart_8250_port serial8250_ports[UART_NR]; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index cf627cd1b4c8..f7cd9504d811 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -961,6 +961,9 @@ config SERIAL_CORE config SERIAL_CORE_CONSOLE bool +config CONSOLE_POLL + bool + config SERIAL_68328 bool "68328 serial support" depends on M68328 || M68EZ328 || M68VZ328 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 640cfe44a56d..3cbea5494724 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o +obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c new file mode 100644 index 000000000000..341830791608 --- /dev/null +++ b/drivers/serial/kgdboc.c @@ -0,0 +1,163 @@ +/* + * Based on the same principle as kgdboe using the NETPOLL api, this + * driver uses a console polling api to implement a gdb serial inteface + * which is multiplexed on a console port. + * + * Maintainer: Jason Wessel + * + * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include +#include +#include +#include + +#define MAX_CONFIG_LEN 40 + +static struct kgdb_io kgdboc_io_ops; + +/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ +static int configured = -1; + +static char config[MAX_CONFIG_LEN]; +static struct kparam_string kps = { + .string = config, + .maxlen = MAX_CONFIG_LEN, +}; + +static struct tty_driver *kgdb_tty_driver; +static int kgdb_tty_line; + +static int kgdboc_option_setup(char *opt) +{ + if (strlen(opt) > MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + strcpy(config, opt); + + return 0; +} + +__setup("kgdboc=", kgdboc_option_setup); + +static int configure_kgdboc(void) +{ + struct tty_driver *p; + int tty_line = 0; + int err; + + err = kgdboc_option_setup(config); + if (err || !strlen(config) || isspace(config[0])) + goto noconfig; + + err = -ENODEV; + + p = tty_find_polling_driver(config, &tty_line); + if (!p) + goto noconfig; + + kgdb_tty_driver = p; + kgdb_tty_line = tty_line; + + err = kgdb_register_io_module(&kgdboc_io_ops); + if (err) + goto noconfig; + + configured = 1; + + return 0; + +noconfig: + config[0] = 0; + configured = 0; + + return err; +} + +static int __init init_kgdboc(void) +{ + /* Already configured? */ + if (configured == 1) + return 0; + + return configure_kgdboc(); +} + +static void cleanup_kgdboc(void) +{ + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + +static int kgdboc_get_char(void) +{ + return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line); +} + +static void kgdboc_put_char(u8 chr) +{ + kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); +} + +static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) +{ + if (strlen(kmessage) >= MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + + /* Only copy in the string if the init function has not run yet */ + if (configured < 0) { + strcpy(config, kmessage); + return 0; + } + + if (kgdb_connected) { + printk(KERN_ERR + "kgdboc: Cannot reconfigure while KGDB is connected.\n"); + + return -EBUSY; + } + + strcpy(config, kmessage); + + if (configured == 1) + cleanup_kgdboc(); + + /* Go and configure with the new params. */ + return configure_kgdboc(); +} + +static void kgdboc_pre_exp_handler(void) +{ + /* Increment the module count when the debugger is active */ + if (!kgdb_connected) + try_module_get(THIS_MODULE); +} + +static void kgdboc_post_exp_handler(void) +{ + /* decrement the module count when the debugger detaches */ + if (!kgdb_connected) + module_put(THIS_MODULE); +} + +static struct kgdb_io kgdboc_io_ops = { + .name = "kgdboc", + .read_char = kgdboc_get_char, + .write_char = kgdboc_put_char, + .pre_exception = kgdboc_pre_exp_handler, + .post_exception = kgdboc_post_exp_handler, +}; + +module_init(init_kgdboc); +module_exit(cleanup_kgdboc); +module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); +MODULE_PARM_DESC(kgdboc, "[,baud]"); +MODULE_DESCRIPTION("KGDB Console TTY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 0f5a17987cca..4d7eecbead9b 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1827,7 +1827,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) * options. The format of the string is , * eg: 115200n8r */ -void __init +void uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) { char *s = options; @@ -1842,6 +1842,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) if (*s) *flow = *s; } +EXPORT_SYMBOL_GPL(uart_parse_options); struct baud_rates { unsigned int rate; @@ -1872,7 +1873,7 @@ static const struct baud_rates baud_rates[] = { * @bits: number of data bits * @flow: flow control character - 'r' (rts) */ -int __init +int uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow) { @@ -1924,10 +1925,16 @@ uart_set_options(struct uart_port *port, struct console *co, port->mctrl |= TIOCM_DTR; port->ops->set_termios(port, &termios, &dummy); - co->cflag = termios.c_cflag; + /* + * Allow the setting of the UART parameters with a NULL console + * too: + */ + if (co) + co->cflag = termios.c_cflag; return 0; } +EXPORT_SYMBOL_GPL(uart_set_options); #endif /* CONFIG_SERIAL_CORE_CONSOLE */ static void uart_change_pm(struct uart_state *state, int pm_state) @@ -2182,6 +2189,60 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } } +#ifdef CONFIG_CONSOLE_POLL + +static int uart_poll_init(struct tty_driver *driver, int line, char *options) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (!state || !state->port) + return -1; + + port = state->port; + if (!(port->ops->poll_get_char && port->ops->poll_put_char)) + return -1; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(port, NULL, baud, parity, bits, flow); + } + + return 0; +} + +static int uart_poll_get_char(struct tty_driver *driver, int line) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->port) + return -1; + + port = state->port; + return port->ops->poll_get_char(port); +} + +static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->port) + return; + + port = state->port; + port->ops->poll_put_char(port, ch); +} +#endif + static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, @@ -2206,6 +2267,11 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = uart_poll_init, + .poll_get_char = uart_poll_get_char, + .poll_put_char = uart_poll_put_char, +#endif }; /** diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 289942fc6655..7cb094a82456 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -213,6 +213,10 @@ struct uart_ops { void (*config_port)(struct uart_port *, int); int (*verify_port)(struct uart_port *, struct serial_struct *); int (*ioctl)(struct uart_port *, unsigned int, unsigned long); +#ifdef CONFIG_CONSOLE_POLL + void (*poll_put_char)(struct uart_port *, unsigned char); + int (*poll_get_char)(struct uart_port *); +#endif }; #define UART_CONFIG_TYPE (1 << 0) diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 85c95cd39bc3..21f69aca4505 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -125,6 +125,7 @@ #include struct tty_struct; +struct tty_driver; struct tty_operations { int (*open)(struct tty_struct * tty, struct file * filp); @@ -157,6 +158,11 @@ struct tty_operations { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +#ifdef CONFIG_CONSOLE_POLL + int (*poll_init)(struct tty_driver *driver, int line, char *options); + int (*poll_get_char)(struct tty_driver *driver, int line); + void (*poll_put_char)(struct tty_driver *driver, int line, char ch); +#endif }; struct tty_driver { @@ -220,6 +226,11 @@ struct tty_driver { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +#ifdef CONFIG_CONSOLE_POLL + int (*poll_init)(struct tty_driver *driver, int line, char *options); + int (*poll_get_char)(struct tty_driver *driver, int line); + void (*poll_put_char)(struct tty_driver *driver, int line, char ch); +#endif struct list_head tty_drivers; }; @@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines); void put_tty_driver(struct tty_driver *driver); void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op); +extern struct tty_driver *tty_find_polling_driver(char *name, int *line); /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 -- cgit v1.2.3 From 7c3078b637882303b1dcf6a16229d0e35f6b60a5 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Fri, 15 Feb 2008 14:55:54 -0600 Subject: kgdb: clocksource watchdog In order to not trip the clocksource watchdog, kgdb must touch the clocksource watchdog on the return to normal system run state. Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar --- include/linux/clocksource.h | 1 + kernel/kgdb.c | 4 ++++ kernel/time/clocksource.c | 12 ++++++++++++ 3 files changed, 17 insertions(+) (limited to 'include/linux') diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 85778a4b1209..35094479ca55 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -216,6 +216,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c, /* used to install a new clocksource */ extern int clocksource_register(struct clocksource*); extern void clocksource_unregister(struct clocksource*); +extern void clocksource_touch_watchdog(void); extern struct clocksource* clocksource_get_next(void); extern void clocksource_change_rating(struct clocksource *cs, int rating); extern void clocksource_resume(void); diff --git a/kernel/kgdb.c b/kernel/kgdb.c index 017ee782bc08..e3f603740425 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c @@ -28,6 +28,7 @@ * kind, whether express or implied. */ #include +#include #include #include #include @@ -574,6 +575,7 @@ static void kgdb_wait(struct pt_regs *regs) /* Signal the primary CPU that we are done: */ atomic_set(&cpu_in_kgdb[cpu], 0); + clocksource_touch_watchdog(); local_irq_restore(flags); } #endif @@ -1396,6 +1398,7 @@ acquirelock: atomic_read(&kgdb_cpu_doing_single_step) != cpu) { atomic_set(&kgdb_active, -1); + clocksource_touch_watchdog(); local_irq_restore(flags); goto acquirelock; @@ -1487,6 +1490,7 @@ acquirelock: kgdb_restore: /* Free kgdb_active */ atomic_set(&kgdb_active, -1); + clocksource_touch_watchdog(); local_irq_restore(flags); return error; diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 7f60097d443a..f61402b1f2d0 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -221,6 +221,18 @@ void clocksource_resume(void) spin_unlock_irqrestore(&clocksource_lock, flags); } +/** + * clocksource_touch_watchdog - Update watchdog + * + * Update the watchdog after exception contexts such as kgdb so as not + * to incorrectly trip the watchdog. + * + */ +void clocksource_touch_watchdog(void) +{ + clocksource_resume_watchdog(); +} + /** * clocksource_get_next - Returns the selected clocksource * -- cgit v1.2.3 From e3e2aaf7dc0d82a055e084cfd48b9257c0c66b68 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 Mar 2008 13:43:45 -0500 Subject: kgdb: add documentation Add in the kgdb documentation for kgdb. Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/kgdb.tmpl | 435 ++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 6 + include/linux/kgdb.h | 52 +++-- 4 files changed, 473 insertions(+), 22 deletions(-) create mode 100644 Documentation/DocBook/kgdb.tmpl (limited to 'include/linux') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 300e1707893f..e471bc466a7e 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -9,7 +9,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml networking.xml \ - kernel-api.xml filesystems.xml lsm.xml usb.xml \ + kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl new file mode 100644 index 000000000000..95e5f84cbf56 --- /dev/null +++ b/Documentation/DocBook/kgdb.tmpl @@ -0,0 +1,435 @@ + + + + + + Using kgdb and the kgdb Internals + + + + Jason + Wessel + +
+ jason.wessel@windriver.com +
+
+
+
+ + + + Tom + Rini + +
+ trini@kernel.crashing.org +
+
+
+
+ + + + Amit S. + Kale + +
+ amitkale@linsyssoft.com +
+
+
+
+ + + 2008 + Wind River Systems, Inc. + + + 2004-2005 + MontaVista Software, Inc. + + + 2004 + Amit S. Kale + + + + + This file is licensed under the terms of the GNU General Public License + version 2. This program is licensed "as is" without any warranty of any + kind, whether express or implied. + + + +
+ + + + Introduction + + kgdb is a source level debugger for linux kernel. It is used along + with gdb to debug a linux kernel. The expectation is that gdb can + be used to "break in" to the kernel to inspect memory, variables + and look through a cal stack information similar to what an + application developer would use gdb for. It is possible to place + breakpoints in kernel code and perform some limited execution + stepping. + + + Two machines are required for using kgdb. One of these machines is a + development machine and the other is a test machine. The kernel + to be debugged runs on the test machine. The development machine + runs an instance of gdb against the vmlinux file which contains + the symbols (not boot image such as bzImage, zImage, uImage...). + In gdb the developer specifies the connection parameters and + connects to kgdb. Depending on which kgdb I/O modules exist in + the kernel for a given architecture, it may be possible to debug + the test machine's kernel with the development machine using a + rs232 or ethernet connection. + + + + Compiling a kernel + + To enable CONFIG_KGDB, look under the "Kernel debugging" + and then select "KGDB: kernel debugging with remote gdb". + + + Next you should choose one of more I/O drivers to interconnect debugging + host and debugged target. Early boot debugging requires a KGDB + I/O driver that supports early debugging and the driver must be + built into the kernel directly. Kgdb I/O driver configuration + takes place via kernel or module parameters, see following + chapter. + + + The kgdb test compile options are described in the kgdb test suite chapter. + + + + + Enable kgdb for debugging + + In order to use kgdb you must activate it by passing configuration + information to one of the kgdb I/O drivers. If you do not pass any + configuration information kgdb will not do anything at all. Kgdb + will only actively hook up to the kernel trap hooks if a kgdb I/O + driver is loaded and configured. If you unconfigure a kgdb I/O + driver, kgdb will unregister all the kernel hook points. + + + All drivers can be reconfigured at run time, if + CONFIG_SYSFS and CONFIG_MODULES + are enabled, by echo'ing a new config string to + /sys/module/<driver>/parameter/<option>. + The driver can be unconfigured by passing an empty string. You cannot + change the configuration while the debugger is attached. Make sure + to detach the debugger with the detach command + prior to trying unconfigure a kgdb I/O driver. + + + Kernel parameter: kgdbwait + + The Kernel command line option kgdbwait makes + kgdb wait for a debugger connection during booting of a kernel. You + can only use this option you compiled a kgdb I/O driver into the + kernel and you specified the I/O driver configuration as a kernel + command line option. The kgdbwait parameter should always follow the + configuration parameter for the kgdb I/O driver in the kernel + command line else the I/O driver will not be configured prior to + asking the kernel to use it to wait. + + + The kernel will stop and wait as early as the I/O driver and + architecture will allow when you use this option. If you build the + kgdb I/O driver as a kernel module kgdbwait will not do anything. + + + + Kernel parameter: kgdboc + + The kgdboc driver was originally an abbreviation meant to stand for + "kgdb over console". Kgdboc is designed to work with a single + serial port as example, and it was meant to cover the circumstance + where you wanted to use a serial console as your primary console as + well as using it to perform kernel debugging. + + + Using kgdboc + + You can configure kgdboc via sysfs or a module or kernel boot line + parameter depending on if you build with CONFIG_KGDBOC as a module + or built-in. + + From the module load or build-in + kgdboc=<tty-device>,[baud] + + The example here would be if your console port was typically ttyS0, you would use something like kgdboc=ttyS0,115200 or on the ARM Versatile AB you would likely use kgdboc=ttyAMA0,115200 + + + From sysfs + echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc + + + + + NOTE: Kgdboc does not support interrupting the target via the + gdb remote protocol. You must manually send a sysrq-g unless you + have a proxy that splits console output to a terminal problem and + has a separate port for the debugger to connect to that sends the + sysrq-g for you. + + When using kgdboc with no debugger proxy, you can end up + connecting the debugger for one of two entry points. If an + exception occurs after you have loaded kgdboc a message should print + on the console stating it is waiting for the debugger. In case you + disconnect your terminal program and then connect the debugger in + its place. If you want to interrupt the target system and forcibly + enter a debug session you have to issue a Sysrq sequence and then + type the letter g. Then you disconnect the + terminal session and connect gdb. Your options if you don't like + this are to hack gdb to send the sysrq-g for you as well as on the + initial connect, or to use a debugger proxy that allows an + unmodified gdb to do the debugging. + + + + kgdboc internals + + The kgdboc driver is actually a very thin driver that relies on the + underlying low level to the hardware driver having "polling hooks" + which the to which the tty driver is attached. In the initial + implementation of kgdboc it the serial_core was changed to expose a + low level uart hook for doing polled mode reading and writing of a + single character while in an atomic context. When kgdb makes an I/O + request to the debugger, kgdboc invokes a call back in the serial + core which in turn uses the call back in the uart driver. It is + certainly possible to extend kgdboc to work with non-uart based + consoles in the future. + + + When using kgdboc with a uart, the uart driver must implement two callbacks in the struct uart_ops. Example from drivers/8250.c: +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif + + Any implementation specifics around creating a polling driver use the + #ifdef CONFIG_CONSOLE_POLL, as shown above. + Keep in mind that polling hooks have to be implemented in such a way + that they can be called from an atomic context and have to restore + the state of the uart chip on return such that the system can return + to normal when the debugger detaches. You need to be very careful + with any kind of lock you consider, because failing here is most + going to mean pressing the reset button. + + + + + Kernel parameter: kgdbcon + + Kgdb supports using the gdb serial protocol to send console messages + to the debugger when the debugger is connected and running. There + are two ways to activate this feature. + + Activate with the kernel command line option: + kgdbcon + + Use sysfs before configuring an io driver + + echo 1 > /sys/module/kgdb/parameters/kgdb_use_con + + + NOTE: If you do this after you configure the kgdb I/O driver, the + setting will not take effect until the next point the I/O is + reconfigured. + + + + + + IMPORTANT NOTE: Using this option with kgdb over the console + (kgdboc) or kgdb over ethernet (kgdboe) is not supported. + + + + + Connecting gdb + + If you are using kgdboc, you need to have used kgdbwait as a boot + argument, issued a sysrq-g, or the system you are going to debug + has already taken an exception and is waiting for the debugger to + attach before you can connect gdb. + + + If you are not using different kgdb I/O driver other than kgdboc, + you should be able to connect and the target will automatically + respond. + + + Example (using a serial port): + + + % gdb ./vmlinux + (gdb) set remotebaud 115200 + (gdb) target remote /dev/ttyS0 + + + Example (kgdb to a terminal server): + + + % gdb ./vmlinux + (gdb) target remote udp:192.168.2.2:6443 + + + Example (kgdb over ethernet): + + + % gdb ./vmlinux + (gdb) target remote udp:192.168.2.2:6443 + + + Once connected, you can debug a kernel the way you would debug an + application program. + + + If you are having problems connecting or something is going + seriously wrong while debugging, it will most often be the case + that you want to enable gdb to be verbose about its target + communications. You do this prior to issuing the target + remote command by typing in: set remote debug 1 + + + + kgdb Test Suite + + When kgdb is enabled in the kernel config you can also elect to + enable the config parameter KGDB_TESTS. Turning this on will + enable a special kgdb I/O module which is designed to test the + kgdb internal functions. + + + The kgdb tests are mainly intended for developers to test the kgdb + internals as well as a tool for developing a new kgdb architecture + specific implementation. These tests are not really for end users + of the Linux kernel. The primary source of documentation would be + to look in the drivers/misc/kgdbts.c file. + + + The kgdb test suite can also be configured at compile time to run + the core set of tests by setting the kernel config parameter + KGDB_TESTS_ON_BOOT. This particular option is aimed at automated + regression testing and does not require modifying the kernel boot + config arguments. If this is turned on, the kgdb test suite can + be disabled by specifying "kgdbts=" as a kernel boot argument. + + + + Architecture Specifics + + Kgdb is organized into three basic components: + + kgdb core + + The kgdb core is found in kernel/kgdb.c. It contains: + + All the logic to implement the gdb serial protocol + A generic OS exception handler which includes sync'ing the processors into a stopped state on an multi cpu system. + The API to talk to the kgdb I/O drivers + The API to make calls to the arch specific kgdb implementation + The logic to perform safe memory reads and writes to memory while using the debugger + A full implementation for software breakpoints unless overridden by the arch + + + + kgdb arch specific implementation + + This implementation is generally found in arch/*/kernel/kgdb.c. + As an example, arch/x86/kernel/kgdb.c contains the specifics to + implement HW breakpoint as well as the initialization to + dynamically register and unregister for the trap handlers on + this architecture. The arch specific portion implements: + + contains an arch specific trap catcher which + invokes kgdb_handle_exception() to start kgdb about doing its + work + translation to and from gdb specific packet format to pt_regs + Registration and unregistration of architecture specific trap hooks + Any special exception handling and cleanup + NMI exception handling and cleanup + (optional)HW breakpoints + + + + kgdb I/O driver + + Each kgdb I/O driver has to provide an configuration + initialization, and cleanup handler for when it + unloads/unconfigures. Any given kgdb I/O driver has to operate + very closely with the hardware and must do it in such a way that + does not enable interrupts or change other parts of the system + context without completely restoring them. Every kgdb I/O + driver must provide a read and write character interface. The + kgdb core will repeatedly "poll" a kgdb I/O driver for characters + when it needs input. The I/O driver is expected to return + immediately if there is no data available. Doing so allows for + the future possibility to touch watch dog hardware in such a way + as to have a target system not reset when these are enabled. + + + + + + If you are intent on adding kgdb architecture specific support + for a new architecture, the architecture should define + HAVE_ARCH_KGDB in the architecture specific + Kconfig file. This will enable kgdb for the architecture, and + at that point you must create an architecture specific kgdb + implementation. + + + There are a few flags which must be set on every architecture in + their <asm/kgdb.h> file. These are: + + + + NUMREGBYTES: The size in bytes of all of the registers, so + that we can ensure they will all fit into a packet. + + + BUFMAX: The size in bytes of the buffer GDB will read into. + This must be larger than NUMREGBYTES. + + + CACHE_FLUSH_IS_SAFE: Set to 1 if it is always safe to call + flush_cache_range or flush_icache_range. On some architectures, + these functions may not be safe to call on SMP since we keep other + CPUs in a holding pattern. + + + + + + There are also the following functions for the common backend, + found in kernel/kgdb.c, that must be supplied by the + architecture-specific backend unless marked as (optional), in + which case a default function maybe used if the architecture + does not need to provide a specific implementation. + +!Iinclude/linux/kgdb.h + + + Credits + + The following people have contributed to this document: + + Amit Kaleamitkale@linsyssoft.com + Tom Rinitrini@kernel.crashing.org + Jason Wesseljason.wessel@windriver.com + + + +
+ diff --git a/MAINTAINERS b/MAINTAINERS index e46775868019..3eceebb48c92 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2319,6 +2319,12 @@ L: linux-kernel@vger.kernel.org L: kexec@lists.infradead.org S: Maintained +KGDB +P: Jason Wessel +M: jason.wessel@windriver.com +L: kgdb-bugreport@lists.sourceforge.net +S: Maintained + KPROBES P: Ananth N Mavinakayanahalli M: ananth@in.ibm.com diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index b0985b79b638..9757b1a6d9dc 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -22,31 +22,34 @@ struct pt_regs; -/* - * kgdb_skipexception - Bail out of KGDB when we've been triggered. +/** + * kgdb_skipexception - (optional) exit kgdb_handle_exception early * @exception: Exception vector number * @regs: Current &struct pt_regs. * - * On some architectures we need to skip a breakpoint exception when - * it occurs after a breakpoint has been removed. + * On some architectures it is required to skip a breakpoint + * exception when it occurs after a breakpoint has been removed. + * This can be implemented in the architecture specific portion of + * for kgdb. */ extern int kgdb_skipexception(int exception, struct pt_regs *regs); -/* - * kgdb_post_primary_code - Save error vector/code numbers. +/** + * kgdb_post_primary_code - (optional) Save error vector/code numbers. * @regs: Original pt_regs. * @e_vector: Original error vector. * @err_code: Original error code. * - * This is needed on architectures which support SMP and KGDB. - * This function is called after all the secondary cpus have been put - * to a know spin state and the primary CPU has control over KGDB. + * This is usually needed on architectures which support SMP and + * KGDB. This function is called after all the secondary cpus have + * been put to a know spin state and the primary CPU has control over + * KGDB. */ extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code); -/* - * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. +/** + * kgdb_disable_hw_debug - (optional) Disable hardware debugging hook * @regs: Current &struct pt_regs. * * This function will be called if the particular architecture must @@ -59,7 +62,14 @@ struct tasklet_struct; struct task_struct; struct uart_port; -/* To enter the debugger explicitly. */ +/** + * kgdb_breakpoint - compiled in breakpoint + * + * This will be impelmented a static inline per architecture. This + * function is called by the kgdb core to execute an architecture + * specific trap to cause kgdb to enter the exception processing. + * + */ void kgdb_breakpoint(void); extern int kgdb_connected; @@ -102,7 +112,7 @@ struct kgdb_bkpt { * Functions each KGDB-supporting architecture must provide: */ -/* +/** * kgdb_arch_init - Perform any architecture specific initalization. * * This function will handle the initalization of any architecture @@ -110,7 +120,7 @@ struct kgdb_bkpt { */ extern int kgdb_arch_init(void); -/* +/** * kgdb_arch_exit - Perform any architecture specific uninitalization. * * This function will handle the uninitalization of any architecture @@ -118,7 +128,7 @@ extern int kgdb_arch_init(void); */ extern void kgdb_arch_exit(void); -/* +/** * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs * @gdb_regs: A pointer to hold the registers in the order GDB wants. * @regs: The &struct pt_regs of the current process. @@ -128,7 +138,7 @@ extern void kgdb_arch_exit(void); */ extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); -/* +/** * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs * @gdb_regs: A pointer to hold the registers in the order GDB wants. * @p: The &struct task_struct of the desired process. @@ -143,7 +153,7 @@ extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); -/* +/** * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. * @gdb_regs: A pointer to hold the registers we've received from GDB. * @regs: A pointer to a &struct pt_regs to hold these values in. @@ -153,7 +163,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); */ extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs); -/* +/** * kgdb_arch_handle_exception - Handle architecture specific GDB packets. * @vector: The error vector of the exception that happened. * @signo: The signal number of the exception that happened. @@ -175,7 +185,7 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code, char *remcom_out_buffer, struct pt_regs *regs); -/* +/** * kgdb_roundup_cpus - Get other CPUs into a holding pattern * @flags: Current IRQ state * @@ -198,7 +208,7 @@ extern int kgdb_validate_break_address(unsigned long addr); extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); -/* +/** * struct kgdb_arch - Describe architecture specific values. * @gdb_bpt_instr: The instruction to trigger a breakpoint. * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. @@ -227,7 +237,7 @@ struct kgdb_arch { void (*correct_hw_break)(void); }; -/* +/** * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB. * @name: Name of the I/O driver. * @read_char: Pointer to a function that will return one char. -- cgit v1.2.3 From cac1f3c8a80f3fc0b4489d1d3ba29214677ffab2 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 15 Apr 2008 12:49:21 -0400 Subject: phylib: factor out get_phy_id from within get_phy_device We were already doing what amounts to a get_phy_id from within get_phy_device, and rather than duplicate this for the TBIPA probing, we might as well just factor it out and make it available instead. Signed-off-by: Paul Gortmaker Acked-by: Andy Fleming Signed-off-by: Jeff Garzik --- drivers/net/phy/phy_device.c | 38 +++++++++++++++++++++++++++++--------- include/linux/phy.h | 1 + 2 files changed, 30 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f4c4fd85425f..8b1121b02f98 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -86,35 +86,55 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) EXPORT_SYMBOL(phy_device_create); /** - * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * get_phy_id - reads the specified addr for its ID. * @bus: the target MII bus * @addr: PHY address on the MII bus + * @phy_id: where to store the ID retrieved. * * Description: Reads the ID registers of the PHY at @addr on the - * @bus, then allocates and returns the phy_device to represent it. + * @bus, stores it in @phy_id and returns zero on success. */ -struct phy_device * get_phy_device(struct mii_bus *bus, int addr) +int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) { int phy_reg; - u32 phy_id; - struct phy_device *dev = NULL; /* Grab the bits from PHYIR1, and put them * in the upper half */ phy_reg = bus->read(bus, addr, MII_PHYSID1); if (phy_reg < 0) - return ERR_PTR(phy_reg); + return -EIO; - phy_id = (phy_reg & 0xffff) << 16; + *phy_id = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ phy_reg = bus->read(bus, addr, MII_PHYSID2); if (phy_reg < 0) - return ERR_PTR(phy_reg); + return -EIO; + + *phy_id |= (phy_reg & 0xffff); + + return 0; +} + +/** + * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * @bus: the target MII bus + * @addr: PHY address on the MII bus + * + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, then allocates and returns the phy_device to represent it. + */ +struct phy_device * get_phy_device(struct mii_bus *bus, int addr) +{ + struct phy_device *dev = NULL; + u32 phy_id; + int r; - phy_id |= (phy_reg & 0xffff); + r = get_phy_id(bus, addr, &phy_id); + if (r) + return ERR_PTR(r); /* If the phy_id is all Fs, there is no device there */ if (0xffffffff == phy_id) diff --git a/include/linux/phy.h b/include/linux/phy.h index 2d838448415c..779cbcd65f62 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -381,6 +381,7 @@ struct phy_driver { int phy_read(struct phy_device *phydev, u16 regnum); int phy_write(struct phy_device *phydev, u16 regnum, u16 val); +int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id); struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); -- cgit v1.2.3 From cf48062658e7ab3bc55e10c65676c3c73c16f8bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 24 Jan 2008 00:05:14 +0900 Subject: libata: prefer hardreset When both soft and hard resets are available, libata preferred softreset till now. The logic behind it was to be softer to devices; however, this doesn't really help much. Rationales for the change: * BIOS may freeze lock certain things during boot and softreset can't unlock those. This by itself is okay but during operation PHY event or other error conditions can trigger hardreset and the device may end up with different configuration. For example, after a hardreset, previously unlockable HPA can be unlocked resulting in different device size and thus revalidation failure. Similar condition can occur during or after resume. * Certain ATAPI devices require hardreset to recover after certain error conditions. On PATA, this is done by issuing the DEVICE RESET command. On SATA, COMRESET has equivalent effect. The problem is that DEVICE RESET needs its own execution protocol. For SFF controllers with bare TF access, it can be easily implemented but more advanced controllers (e.g. ahci and sata_sil24) require specialized implementations. Simply using hardreset solves the problem nicely. * COMRESET initialization sequence is the norm in SATA land and many SATA devices don't work properly if only SRST is used. For example, some PMPs behave this way and libata works around by always issuing hardreset if the host supports PMP. Like the above example, libata has developed a number of mechanisms aiming to promote softreset to hardreset if softreset is not going to work. This approach is time consuming and error prone. Also, note that, dependingon how you read the specs, it could be argued that PMP fan-out ports require COMRESET to start operation. In fact, all the PMPs on the market except one don't work properly if COMRESET is not issued to fan-out ports after PMP reset. * COMRESET is an integral part of SATA connection and any working device should be able to handle COMRESET properly. After all, it's the way to signal hardreset during reboot. This is the most used and recommended (at least by the ahci spec) method of resetting devices. So, this patch makes libata prefer hardreset over softreset by making the following changes. * Rename ATA_EH_RESET_MASK to ATA_EH_RESET and use it whereever ATA_EH_{SOFT|HARD}RESET used to be used. ATA_EH_{SOFT|HARD}RESET is now only used to tell prereset whether soft or hard reset will be issued. * Strip out now unneeded promote-to-hardreset logics from ata_eh_reset(), ata_std_prereset(), sata_pmp_std_prereset() and other places. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 10 ++--- drivers/ata/libata-core.c | 19 ++------- drivers/ata/libata-eh.c | 99 +++++++++++++++++------------------------------ drivers/ata/libata-pmp.c | 28 ++++---------- drivers/ata/libata-scsi.c | 4 +- drivers/ata/sata_fsl.c | 2 +- drivers/ata/sata_mv.c | 31 ++++----------- drivers/ata/sata_nv.c | 12 +++--- drivers/ata/sata_sil24.c | 54 +++++++++++++------------- drivers/ata/sata_via.c | 2 +- include/linux/libata.h | 8 ++-- 11 files changed, 101 insertions(+), 168 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b1eb4e24c86a..f6bbd52b1547 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1663,7 +1663,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); active_ehi->err_mask |= AC_ERR_HSM; - active_ehi->action |= ATA_EH_SOFTRESET; + active_ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(active_ehi, "unknown FIS %08x %08x %08x %08x" , unk[0], unk[1], unk[2], unk[3]); @@ -1671,19 +1671,19 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { active_ehi->err_mask |= AC_ERR_HSM; - active_ehi->action |= ATA_EH_SOFTRESET; + active_ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(active_ehi, "incorrect PMP"); } if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { host_ehi->err_mask |= AC_ERR_HOST_BUS; - host_ehi->action |= ATA_EH_SOFTRESET; + host_ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(host_ehi, "host bus error"); } if (irq_stat & PORT_IRQ_IF_ERR) { host_ehi->err_mask |= AC_ERR_ATA_BUS; - host_ehi->action |= ATA_EH_SOFTRESET; + host_ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(host_ehi, "interface fatal error"); } @@ -1771,7 +1771,7 @@ static void ahci_port_intr(struct ata_port *ap) /* while resetting, invalid completions are expected */ if (unlikely(rc < 0 && !resetting)) { ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ata_port_freeze(ap); } } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index be95fdb69726..02e7ba43a3b3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3949,17 +3949,6 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; - /* handle link resume */ - if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (link->flags & ATA_LFLAG_HRST_TO_RESUME)) - ehc->i.action |= ATA_EH_HARDRESET; - - /* Some PMPs don't work with only SRST, force hardreset if PMP - * is supported. - */ - if (ap->flags & ATA_FLAG_PMP) - ehc->i.action |= ATA_EH_HARDRESET; - /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; @@ -6055,9 +6044,9 @@ void ata_qc_issue(struct ata_queued_cmd *qc) if (ata_sg_setup(qc)) goto sg_err; - /* if device is sleeping, schedule softreset and abort the link */ + /* if device is sleeping, schedule reset and abort the link */ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) { - link->eh_info.action |= ATA_EH_SOFTRESET; + link->eh_info.action |= ATA_EH_RESET; ata_ehi_push_desc(&link->eh_info, "waking up from sleep"); ata_link_abort(link); return; @@ -6634,7 +6623,7 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) */ void ata_host_resume(struct ata_host *host) { - ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, + ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET, ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); host->dev->power.power_state = PMSG_ON; @@ -7171,7 +7160,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ehi->probe_mask = (1 << ata_link_max_devices(&ap->link)) - 1; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ap->pflags &= ~ATA_PFLAG_INITIALIZING; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a5830329eda4..f7cae6400155 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1079,16 +1079,9 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, spin_lock_irqsave(ap->lock, flags); - /* Reset is represented by combination of actions and EHI - * flags. Suck in all related bits before clearing eh_info to - * avoid losing requested action. - */ - if (action & ATA_EH_RESET_MASK) { - ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; + /* suck in and clear reset modifier */ + if (action & ATA_EH_RESET) { ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; - - /* make sure all reset actions are cleared & clear EHI flags */ - action |= ATA_EH_RESET_MASK; ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } @@ -1117,11 +1110,9 @@ void ata_eh_done(struct ata_link *link, struct ata_device *dev, { struct ata_eh_context *ehc = &link->eh_context; - /* if reset is complete, clear all reset actions & reset modifier */ - if (action & ATA_EH_RESET_MASK) { - action |= ATA_EH_RESET_MASK; + /* if reset is complete, clear reset modifier */ + if (action & ATA_EH_RESET) ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; - } ata_eh_clear_action(link, dev, &ehc->i, action); } @@ -1329,20 +1320,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) if (serror & SERR_PERSISTENT) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } if (serror & (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; } if (serror & SERR_PROTOCOL) { err_mask |= AC_ERR_HSM; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; } if (serror & SERR_INTERNAL) { err_mask |= AC_ERR_SYSTEM; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } /* Determine whether a hotplug event has occurred. Both @@ -1448,7 +1439,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) { qc->err_mask |= AC_ERR_HSM; - return ATA_EH_SOFTRESET; + return ATA_EH_RESET; } if (stat & (ATA_ERR | ATA_DF)) @@ -1484,7 +1475,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; return action; } @@ -1685,7 +1676,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ if (sata_down_spd_limit(link) == 0) { - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; goto done; } @@ -1705,7 +1696,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, dev->spdn_cnt++; if (ata_down_xfermask_limit(dev, sel) == 0) { - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; goto done; } } @@ -1719,7 +1710,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; goto done; } } @@ -1764,9 +1755,9 @@ static void ata_eh_link_autopsy(struct ata_link *link) ehc->i.serror |= serror; ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { - /* SError read failed, force hardreset and probing */ + /* SError read failed, force reset and probing */ ata_ehi_schedule_probe(&ehc->i); - ehc->i.action |= ATA_EH_HARDRESET; + ehc->i.action |= ATA_EH_RESET; ehc->i.err_mask |= AC_ERR_OTHER; } @@ -1814,7 +1805,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) - ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_RESET; else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) || (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV))) ehc->i.action |= ATA_EH_REVALIDATE; @@ -2118,7 +2109,6 @@ int ata_eh_reset(struct ata_link *link, int classify, int try = 0; struct ata_device *dev; unsigned long deadline, now; - unsigned int tmp_action; ata_reset_fn_t reset; unsigned long flags; u32 sstatus; @@ -2129,7 +2119,7 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->pflags |= ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); - ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); ata_link_for_each_dev(dev, link) { /* If we issue an SRST then an ATA drive (not ATAPI) @@ -2159,17 +2149,15 @@ int ata_eh_reset(struct ata_link *link, int classify, goto done; } - /* Determine which reset to use and record in ehc->i.action. - * prereset() may examine and modify it. - */ - if (softreset && (!hardreset || (!(lflags & ATA_LFLAG_NO_SRST) && - !sata_set_spd_needed(link) && - !(ehc->i.action & ATA_EH_HARDRESET)))) - tmp_action = ATA_EH_SOFTRESET; - else - tmp_action = ATA_EH_HARDRESET; - - ehc->i.action = (ehc->i.action & ~ATA_EH_RESET_MASK) | tmp_action; + /* prefer hardreset */ + ehc->i.action &= ~ATA_EH_RESET; + if (hardreset) { + reset = hardreset; + ehc->i.action = ATA_EH_HARDRESET; + } else { + reset = softreset; + ehc->i.action = ATA_EH_SOFTRESET; + } if (prereset) { rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT); @@ -2177,7 +2165,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == -ENOENT) { ata_link_printk(link, KERN_DEBUG, "port disabled. ignoring.\n"); - ehc->i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET; ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; @@ -2190,12 +2178,8 @@ int ata_eh_reset(struct ata_link *link, int classify, } } - /* prereset() might have modified ehc->i.action */ - if (ehc->i.action & ATA_EH_HARDRESET) - reset = hardreset; - else if (ehc->i.action & ATA_EH_SOFTRESET) - reset = softreset; - else { + /* prereset() might have cleared ATA_EH_RESET */ + if (!(ehc->i.action & ATA_EH_RESET)) { /* prereset told us not to reset, bang classes and return */ ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; @@ -2203,14 +2187,6 @@ int ata_eh_reset(struct ata_link *link, int classify, goto out; } - /* did prereset() screw up? if so, fix up to avoid oopsing */ - if (!reset) { - if (softreset) - reset = softreset; - else - reset = hardreset; - } - retry: deadline = jiffies + ata_eh_reset_timeouts[try++]; @@ -2240,7 +2216,7 @@ int ata_eh_reset(struct ata_link *link, int classify, goto fail; } - ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); rc = ata_do_reset(link, reset, classes, deadline); } @@ -2290,7 +2266,7 @@ int ata_eh_reset(struct ata_link *link, int classify, postreset(link, classes); /* reset successful, schedule revalidation */ - ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_done(link, NULL, ATA_EH_RESET); ehc->i.action |= ATA_EH_REVALIDATE; rc = 0; @@ -2548,7 +2524,7 @@ static int ata_eh_schedule_probe(struct ata_device *dev) ata_eh_detach_dev(dev); ata_dev_init(dev); ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_RESET; ehc->saved_xfer_mode[dev->devno] = 0; ehc->saved_ncq_enabled &= ~(1 << dev->devno); @@ -2592,12 +2568,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) return 1; } else { - /* soft didn't work? be haaaaard */ - if (ehc->i.flags & ATA_EHI_DID_RESET) - ehc->i.action |= ATA_EH_HARDRESET; - else - ehc->i.action |= ATA_EH_SOFTRESET; - + ehc->i.action |= ATA_EH_RESET; return 0; } } @@ -2690,7 +2661,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ehc->i.action = 0; /* do we need to reset? */ - if (ehc->i.action & ATA_EH_RESET_MASK) + if (ehc->i.action & ATA_EH_RESET) reset = 1; ata_link_for_each_dev(dev, link) @@ -2708,7 +2679,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; - if (!(ehc->i.action & ATA_EH_RESET_MASK)) + if (!(ehc->i.action & ATA_EH_RESET)) continue; rc = ata_eh_reset(link, ata_link_nr_vacant(link), diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index d91f5090ba9d..8439fc8efdd6 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -194,15 +194,6 @@ int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; - /* force HRST? */ - if (link->flags & ATA_LFLAG_NO_SRST) - ehc->i.action |= ATA_EH_HARDRESET; - - /* handle link resume */ - if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (link->flags & ATA_LFLAG_HRST_TO_RESUME)) - ehc->i.action |= ATA_EH_HARDRESET; - /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; @@ -445,7 +436,7 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) link->flags = 0; ehc->i.probe_mask |= 1; - ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_RESET; ehc->i.flags |= ATA_EHI_RESUME_LINK; } @@ -840,13 +831,12 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, retry: ehc->classes[0] = ATA_DEV_UNKNOWN; - if (ehc->i.action & ATA_EH_RESET_MASK) { + if (ehc->i.action & ATA_EH_RESET) { struct ata_link *tlink; ata_eh_freeze_port(ap); /* reset */ - ehc->i.action = ATA_EH_HARDRESET; rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, postreset); if (rc) { @@ -890,11 +880,11 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, reval_failed = 1; ata_dev_printk(dev, KERN_WARNING, - "retrying hardreset%s\n", + "retrying reset%s\n", sleep ? " in 5 secs" : ""); if (sleep) ssleep(5); - ehc->i.action |= ATA_EH_HARDRESET; + ehc->i.action |= ATA_EH_RESET; goto retry; } else { ata_dev_printk(dev, KERN_ERR, "failed to recover PMP " @@ -938,10 +928,8 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) /* Some PMPs require hardreset sequence to get * SError.N working. */ - if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) && - (link->eh_context.i.flags & ATA_EHI_RESUME_LINK)) - sata_link_hardreset(link, sata_deb_timing_normal, - jiffies + ATA_TMOUT_INTERNAL_QUICK); + sata_link_hardreset(link, sata_deb_timing_normal, + jiffies + ATA_TMOUT_INTERNAL_QUICK); /* unconditionally clear SError.N */ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); @@ -1124,7 +1112,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap, link_fail: if (sata_pmp_handle_link_fail(link, link_tries)) { - pmp_ehc->i.action |= ATA_EH_HARDRESET; + pmp_ehc->i.action |= ATA_EH_RESET; goto retry; } @@ -1142,7 +1130,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap, if (--pmp_tries) { ata_port_printk(ap, KERN_WARNING, "failed to recover PMP, retrying in 5 secs\n"); - pmp_ehc->i.action |= ATA_EH_HARDRESET; + pmp_ehc->i.action |= ATA_EH_RESET; ssleep(5); goto retry; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 15795394b0a8..1f036a7b14f3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3508,7 +3508,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, ata_port_for_each_link(link, ap) { struct ata_eh_info *ehi = &link->eh_info; ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; } } else { struct ata_device *dev = ata_find_dev(ap, devno); @@ -3516,7 +3516,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, if (dev) { struct ata_eh_info *ehi = &dev->link->eh_info; ehi->probe_mask |= 1 << dev->devno; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ehi->flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 9d1e3cad4aa9..fbd423ad23bb 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -996,7 +996,7 @@ static void sata_fsl_error_intr(struct ata_port *ap) /* handle fatal errors */ if (hstatus & FATAL_ERROR_DECODE) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; /* how will fatal error interrupts be completed ?? */ freeze = 1; } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 6ebebde8454a..a4944c8ad46d 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1524,14 +1524,14 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR)) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; ata_ehi_push_desc(ehi, "parity error"); } if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ? "dev disconnect" : "dev connect"); - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } if (IS_GEN_I(hpriv)) { @@ -1555,7 +1555,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) sata_scr_read(&ap->link, SCR_ERROR, &serr); sata_scr_write_flush(&ap->link, SCR_ERROR, serr); err_mask = AC_ERR_ATA_BUS; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } } @@ -1564,7 +1564,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (!err_mask) { err_mask = AC_ERR_OTHER; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } ehi->serror |= serr; @@ -1780,7 +1780,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) ata_ehi_push_desc(ehi, "PCI err cause 0x%08x", err_cause); err_mask = AC_ERR_HOST_BUS; - ehi->action = ATA_EH_HARDRESET; + ehi->action = ATA_EH_RESET; qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; @@ -2449,28 +2449,13 @@ static int mv_prereset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &link->eh_context; - int rc; - rc = mv_stop_dma(ap); - if (rc) - ehc->i.action |= ATA_EH_HARDRESET; + mv_stop_dma(ap); - if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) { + if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET; - ehc->i.action |= ATA_EH_HARDRESET; - } - - /* if we're about to do hardreset, nothing more to do */ - if (ehc->i.action & ATA_EH_HARDRESET) - return 0; - - if (ata_link_online(link)) - rc = ata_wait_ready(ap, deadline); - else - rc = -ENODEV; - return rc; + return 0; } static int mv_hardreset(struct ata_link *link, unsigned int *class, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index ed5473bf7a0a..ce02e15c857c 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -929,7 +929,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) "notifier for tag %d with no cmd?\n", cpb_num); ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ata_port_freeze(ap); return 1; } @@ -1892,7 +1892,7 @@ static void nv_swncq_error_handler(struct ata_port *ap) if (ap->link.sactive) { nv_swncq_ncq_stop(ap); - ehc->i.action |= ATA_EH_HARDRESET; + ehc->i.action |= ATA_EH_RESET; } ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, @@ -2173,7 +2173,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); ehi->err_mask |= AC_ERR_HOST_BUS; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; return -EINVAL; } @@ -2188,7 +2188,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" "(%08x->%08x)", pp->qc_active, sactive); ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_HARDRESET; + ehi->action |= ATA_EH_RESET; return -EINVAL; } for (i = 0; i < ATA_MAX_QUEUE; i++) { @@ -2324,7 +2324,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis); ehi->err_mask |= AC_ERR_DEV; ehi->serror |= serror; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ata_port_freeze(ap); return; } @@ -2356,7 +2356,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) { ata_ehi_push_desc(ehi, "illegal fis transaction"); ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_HARDRESET; + ehi->action |= ATA_EH_RESET; goto irq_error; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index df7988df7908..aa8d0323c9bb 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -286,45 +286,45 @@ static struct sil24_cerr_info { "device error via D2H FIS" }, [PORT_CERR_SDB] = { AC_ERR_DEV, 0, "device error via SDB FIS" }, - [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_RESET, "error in data FIS" }, - [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_RESET, "failed to transmit command FIS" }, - [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_RESET, "protocol mismatch" }, - [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_RESET, "data directon mismatch" }, - [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_RESET, "ran out of SGEs while writing" }, - [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_RESET, "ran out of SGEs while reading" }, - [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_RESET, "invalid data directon for ATAPI CDB" }, - [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, + [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_RESET, "SGT not on qword boundary" }, - [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI target abort while fetching SGT" }, - [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI master abort while fetching SGT" }, - [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI parity error while fetching SGT" }, - [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, + [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_RESET, "PRB not on qword boundary" }, - [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI target abort while fetching PRB" }, - [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI master abort while fetching PRB" }, - [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI parity error while fetching PRB" }, - [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "undefined error while transferring data" }, - [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI target abort while transferring data" }, - [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI master abort while transferring data" }, - [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_RESET, "PCI parity error while transferring data" }, - [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_RESET, "FIS received while sending service FIS" }, }; @@ -616,7 +616,7 @@ static int sil24_init_port(struct ata_port *ap) if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { pp->do_port_rst = 1; - ap->link.eh_context.i.action |= ATA_EH_HARDRESET; + ap->link.eh_context.i.action |= ATA_EH_RESET; return -EIO; } @@ -1022,7 +1022,7 @@ static void sil24_error_intr(struct ata_port *ap) if (irq_stat & PORT_IRQ_UNK_FIS) { ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(ehi, "unknown FIS"); freeze = 1; } @@ -1043,7 +1043,7 @@ static void sil24_error_intr(struct ata_port *ap) */ if (ap->nr_active_links >= 3) { ehi->err_mask |= AC_ERR_OTHER; - ehi->action |= ATA_EH_HARDRESET; + ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(ehi, "PMP DMA CS errata"); pp->do_port_rst = 1; freeze = 1; @@ -1064,7 +1064,7 @@ static void sil24_error_intr(struct ata_port *ap) irq_stat); } else { err_mask |= AC_ERR_HSM; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; freeze = 1; } } else @@ -1078,12 +1078,12 @@ static void sil24_error_intr(struct ata_port *ap) if (ci && ci->desc) { err_mask |= ci->err_mask; action |= ci->action; - if (action & ATA_EH_RESET_MASK) + if (action & ATA_EH_RESET) freeze = 1; ata_ehi_push_desc(ehi, "%s", ci->desc); } else { err_mask |= AC_ERR_OTHER; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; freeze = 1; ata_ehi_push_desc(ehi, "unknown command error %d", cerr); @@ -1153,7 +1153,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (rc < 0) { struct ata_eh_info *ehi = &ap->link.eh_info; ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ata_port_freeze(ap); return; } diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 0d03f44824fb..c0e0f1d18d50 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -320,7 +320,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) if (!online) { /* tell EH to bail */ - ehc->i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET; return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 37ee881c42ac..c63cfb3b222b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -292,12 +292,12 @@ enum { /* reset / recovery action types */ ATA_EH_REVALIDATE = (1 << 0), - ATA_EH_SOFTRESET = (1 << 1), - ATA_EH_HARDRESET = (1 << 2), + ATA_EH_SOFTRESET = (1 << 1), /* meaningful only in ->prereset */ + ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */ + ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_LPM = (1 << 4), /* link power management action */ - ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, /* ata_eh_info->flags */ @@ -1097,7 +1097,7 @@ extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi) { ehi->flags |= ATA_EHI_RESUME_LINK; - ehi->action |= ATA_EH_SOFTRESET; + ehi->action |= ATA_EH_RESET; ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; } -- cgit v1.2.3 From d692abd92f22a81b38d52c39601871003262841c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 24 Jan 2008 00:05:14 +0900 Subject: libata: kill ATA_LFLAG_HRST_TO_RESUME Now that hardreset is the preferred method of resetting, there's no need for ATA_LFLAG_HRST_TO_RESUME flag. Kill it. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-pmp.c | 16 ---------------- drivers/ata/sata_nv.c | 5 ----- drivers/ata/sata_sil.c | 5 ----- include/linux/libata.h | 1 - 5 files changed, 1 insertion(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f6bbd52b1547..66d6c8821087 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -416,7 +416,7 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 8439fc8efdd6..7f8bcffa81ad 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -453,9 +453,6 @@ static void sata_pmp_quirks(struct ata_port *ap) if (vendor == 0x1095 && devid == 0x3726) { /* sil3726 quirks */ ata_port_for_each_link(link, ap) { - /* SError.N need a kick in the ass to get working */ - link->flags |= ATA_LFLAG_HRST_TO_RESUME; - /* class code report is unreliable */ if (link->pmp < 5) link->flags |= ATA_LFLAG_ASSUME_ATA; @@ -468,9 +465,6 @@ static void sata_pmp_quirks(struct ata_port *ap) } else if (vendor == 0x1095 && devid == 0x4723) { /* sil4723 quirks */ ata_port_for_each_link(link, ap) { - /* SError.N need a kick in the ass to get working */ - link->flags |= ATA_LFLAG_HRST_TO_RESUME; - /* class code report is unreliable */ if (link->pmp < 2) link->flags |= ATA_LFLAG_ASSUME_ATA; @@ -483,9 +477,6 @@ static void sata_pmp_quirks(struct ata_port *ap) } else if (vendor == 0x1095 && devid == 0x4726) { /* sil4726 quirks */ ata_port_for_each_link(link, ap) { - /* SError.N need a kick in the ass to get working */ - link->flags |= ATA_LFLAG_HRST_TO_RESUME; - /* Class code report is unreliable and SRST * times out under certain configurations. * Config device can be at port 0 or 5 and @@ -513,13 +504,6 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; - } else if (vendor == 0x11ab && devid == 0x4140) { - /* Marvell 88SM4140 quirks. Fan-out ports require PHY - * reset to work; other than that, it behaves very - * nicely. - */ - ata_port_for_each_link(link, ap) - link->flags |= ATA_LFLAG_HRST_TO_RESUME; } } diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index ce02e15c857c..75b76535c720 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -579,7 +579,6 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, - .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -590,7 +589,6 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, - .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -601,7 +599,6 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, - .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -613,7 +610,6 @@ static const struct ata_port_info nv_port_info[] = { .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_NCQ, - .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -625,7 +621,6 @@ static const struct ata_port_info nv_port_info[] = { .sht = &nv_swncq_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_NCQ, - .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 0b8191b52f97..7052915a31b6 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -60,7 +60,6 @@ enum { SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, - SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME, /* * Controller IDs @@ -215,7 +214,6 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, - .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -225,7 +223,6 @@ static const struct ata_port_info sil_port_info[] = { { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, - .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -234,7 +231,6 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3512 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, - .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -243,7 +239,6 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3114 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, - .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, diff --git a/include/linux/libata.h b/include/linux/libata.h index c63cfb3b222b..1524af6f018b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -163,7 +163,6 @@ enum { ATA_DEV_NONE = 9, /* no device */ /* struct ata_link flags */ - ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ -- cgit v1.2.3 From 672b2d65ba83a6f3f801fd3d58851aa9c0725a54 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 24 Jan 2008 00:05:14 +0900 Subject: libata: kill ATA_EHI_RESUME_LINK ATA_EHI_RESUME_LINK has two functions - promote reset to hardreset if ATA_LFLAG_HRST_TO_RESUME is set and preventing EH from shortcutting reset action when probing is requested. The former is gone now and the latter can easily be achieved by making EH to perform at least one reset if reset is requested, which also makes more sense than depending on RESUME_LINK flag. As ATA_EHI_RESUME_LINK was the only EHI reset modifier, this also kills reset modifier handling. Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 21 ++++++++------------- drivers/ata/libata-pmp.c | 1 - drivers/ata/libata-scsi.c | 1 - include/linux/libata.h | 3 --- 4 files changed, 8 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f7cae6400155..e6584fa7f456 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1079,12 +1079,6 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, spin_lock_irqsave(ap->lock, flags); - /* suck in and clear reset modifier */ - if (action & ATA_EH_RESET) { - ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; - ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; - } - ata_eh_clear_action(link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) @@ -1110,10 +1104,6 @@ void ata_eh_done(struct ata_link *link, struct ata_device *dev, { struct ata_eh_context *ehc = &link->eh_context; - /* if reset is complete, clear reset modifier */ - if (action & ATA_EH_RESET) - ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; - ata_eh_clear_action(link, dev, &ehc->i, action); } @@ -2491,6 +2481,7 @@ static int ata_link_nr_vacant(struct ata_link *link) static int ata_eh_skip_recovery(struct ata_link *link) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; @@ -2498,9 +2489,13 @@ static int ata_eh_skip_recovery(struct ata_link *link) if (link->flags & ATA_LFLAG_DISABLED) return 1; - /* thaw frozen port, resume link and recover failed devices */ - if ((link->ap->pflags & ATA_PFLAG_FROZEN) || - (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) + /* thaw frozen port and recover failed devices */ + if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link)) + return 0; + + /* reset at least once if reset is requested */ + if ((ehc->i.action & ATA_EH_RESET) && + !(ehc->i.flags & ATA_EHI_DID_RESET)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 7f8bcffa81ad..df1d3252b9e6 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -437,7 +437,6 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) link->flags = 0; ehc->i.probe_mask |= 1; ehc->i.action |= ATA_EH_RESET; - ehc->i.flags |= ATA_EHI_RESUME_LINK; } return 0; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 1f036a7b14f3..caffca7dd76f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3517,7 +3517,6 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, struct ata_eh_info *ehi = &dev->link->eh_info; ehi->probe_mask |= 1 << dev->devno; ehi->action |= ATA_EH_RESET; - ehi->flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 1524af6f018b..4093e3b6a8b7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -301,7 +301,6 @@ enum { /* ata_eh_info->flags */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ - ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ ATA_EHI_QUIET = (1 << 3), /* be quiet */ @@ -312,7 +311,6 @@ enum { ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */ ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, - ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, /* max tries if error condition is still set after ->error_handler */ ATA_EH_MAX_TRIES = 5, @@ -1095,7 +1093,6 @@ extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi) { - ehi->flags |= ATA_EHI_RESUME_LINK; ehi->action |= ATA_EH_RESET; ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; } -- cgit v1.2.3 From 8cebf274dd1c955a6e03385a85fd6569ce445946 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 24 Jan 2008 00:05:14 +0900 Subject: libata: kill ATA_LFLAG_SKIP_D2H_BSY Some controllers can't reliably record the initial D2H FIS after SATA link is brought online for whatever reason. Advanced controllers which don't have traditional TF register based interface often have this problem as they don't really have the TF registers to update while the controller and link are being initialized. SKIP_D2H_BSY works around the problem by skipping the wait for device readiness before issuing SRST, so for such controllers libata issues SRST blindly and hopes for the best. Now that libata defaults to hardreset, this workaround is no longer necessary. For controllers which have support for hardreset, SRST is never issued by itself. It is only issued as follow-up SRST for device classification and PMP initialization, so there's no need to wait for it from prereset. Kill ATA_LFLAG_SKIP_D2H_BSY. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 7 ------- drivers/ata/libata-core.c | 6 ++---- drivers/ata/sata_fsl.c | 2 -- drivers/ata/sata_sil24.c | 4 ---- include/linux/libata.h | 2 -- 5 files changed, 2 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 66d6c8821087..1bd258e5390f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -198,7 +198,6 @@ enum { ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | ATA_FLAG_IPM, - AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, ICH_MAP = 0x90, /* ICH MAP register */ }; @@ -407,7 +406,6 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -416,7 +414,6 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, @@ -425,7 +422,6 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -436,7 +432,6 @@ static const struct ata_port_info ahci_port_info[] = { AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -447,7 +442,6 @@ static const struct ata_port_info ahci_port_info[] = { AHCI_HFLAG_MV_PATA), .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -457,7 +451,6 @@ static const struct ata_port_info ahci_port_info[] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, - .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 02e7ba43a3b3..baef749ec528 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3962,10 +3962,8 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) "link for reset (errno=%d)\n", rc); } - /* Wait for !BSY if the controller can wait for the first D2H - * Reg FIS and we don't know that no device is attached. - */ - if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { + /* wait for !BSY if we don't know that no device is attached */ + if (!ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index fbd423ad23bb..d23b690ed1a1 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -35,7 +35,6 @@ enum { SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ), - SATA_FSL_HOST_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH, SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */ @@ -1241,7 +1240,6 @@ static const struct ata_port_operations sata_fsl_ops = { static const struct ata_port_info sata_fsl_port_info[] = { { .flags = SATA_FSL_HOST_FLAGS, - .link_flags = SATA_FSL_HOST_LFLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .udma_mask = 0x7f, /* udma 0-6 */ .port_ops = &sata_fsl_ops, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index aa8d0323c9bb..ba0c00e8ee7f 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -254,7 +254,6 @@ enum { ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | ATA_FLAG_PMP, - SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf, @@ -449,7 +448,6 @@ static const struct ata_port_info sil24_port_info[] = { { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | SIL24_FLAG_PCIX_IRQ_WOC, - .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -458,7 +456,6 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3132 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), - .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -467,7 +464,6 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3131/sil_3531 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), - .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 4093e3b6a8b7..6eec11957e54 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -163,8 +163,6 @@ enum { ATA_DEV_NONE = 9, /* no device */ /* struct ata_link flags */ - ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H - * Register FIS clearing BSY */ ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ -- cgit v1.2.3 From b558edddb1c42c70a30cfe494984d4be409f7b2b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 24 Jan 2008 00:05:14 +0900 Subject: libata: kill ata_ehi_schedule_probe() ata_ehi_schedule_probe() was created to hide details of link-resuming reset magic. Now that all the softreset workarounds are gone, scheduling probe is very simple - set probe_mask and request RESET. Kill ata_ehi_schedule_probe() and open code it. This also increases consistency as ata_ehi_schedule_probe() couldn't cover individual device probings so they were open-coded even when the helper existed. While at it, define ATA_ALL_DEVICES as mask of all possible devices on a link and always use it when requesting probe on link level for simplicity and consistency. Setting extra bits in the probe_mask doesn't hurt anybody. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 3 +-- drivers/ata/libata-eh.c | 2 +- drivers/ata/libata-pmp.c | 12 ++++++++---- drivers/ata/libata-scsi.c | 2 +- include/linux/libata.h | 12 ++++-------- 5 files changed, 15 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index baef749ec528..4dc429fd0056 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7156,8 +7156,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ehi->probe_mask = - (1 << ata_link_max_devices(&ap->link)) - 1; + ehi->probe_mask |= ATA_ALL_DEVICES; ehi->action |= ATA_EH_RESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e6584fa7f456..0d0a2c0ab9e7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1746,7 +1746,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { /* SError read failed, force reset and probing */ - ata_ehi_schedule_probe(&ehc->i); + ehc->i.probe_mask |= ATA_ALL_DEVICES; ehc->i.action |= ATA_EH_RESET; ehc->i.err_mask |= AC_ERR_OTHER; } diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index df1d3252b9e6..39e036c8a2bc 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -435,7 +435,7 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) struct ata_eh_context *ehc = &link->eh_context; link->flags = 0; - ehc->i.probe_mask |= 1; + ehc->i.probe_mask |= ATA_ALL_DEVICES; ehc->i.action |= ATA_EH_RESET; } @@ -831,8 +831,12 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, ata_eh_thaw_port(ap); /* PMP is reset, SErrors cannot be trusted, scan all */ - ata_port_for_each_link(tlink, ap) - ata_ehi_schedule_probe(&tlink->eh_context.i); + ata_port_for_each_link(tlink, ap) { + struct ata_eh_context *ehc = &tlink->eh_context; + + ehc->i.probe_mask |= ATA_ALL_DEVICES; + ehc->i.action |= ATA_EH_RESET; + } } /* If revalidation is requested, revalidate and reconfigure; @@ -847,7 +851,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, tries--; if (rc == -ENODEV) { - ehc->i.probe_mask |= 1; + ehc->i.probe_mask |= ATA_ALL_DEVICES; detach = 1; /* give it just two more chances */ tries = min(tries, 2); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index caffca7dd76f..798ba5e45710 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3507,7 +3507,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, ata_port_for_each_link(link, ap) { struct ata_eh_info *ehi = &link->eh_info; - ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1; + ehi->probe_mask |= ATA_ALL_DEVICES; ehi->action |= ATA_EH_RESET; } } else { diff --git a/include/linux/libata.h b/include/linux/libata.h index 6eec11957e54..bc60132c7d33 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -122,6 +122,8 @@ enum { ATAPI_MAX_DRAIN = 16 << 10, + ATA_ALL_DEVICES = (1 << ATA_MAX_DEVICES) - 1, + ATA_SHT_EMULATED = 1, ATA_SHT_CMD_PER_LUN = 1, ATA_SHT_THIS_ID = -1, @@ -1089,17 +1091,11 @@ extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); -static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi) -{ - ehi->action |= ATA_EH_RESET; - ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; -} - static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) { - ata_ehi_schedule_probe(ehi); + ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; ehi->flags |= ATA_EHI_HOTPLUGGED; - ehi->action |= ATA_EH_ENABLE_LINK; + ehi->action |= ATA_EH_RESET | ATA_EH_ENABLE_LINK; ehi->err_mask |= AC_ERR_ATA_BUS; } -- cgit v1.2.3 From c1bc899f5805771926c9198e2ab4d77122c356a1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:47 +0900 Subject: libata: reorganize ata_port_operations Over the time, ops in ata_port_operations has become a bit confusing. Reorganize. SFF/BMDMA ops are separated into separate a group as they will be taken out of ata_port_operations later. Signed-off-by: Tejun Heo --- include/linux/libata.h | 117 ++++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index bc60132c7d33..9476a479691b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -665,69 +665,74 @@ struct ata_port { }; struct ata_port_operations { - void (*dev_config) (struct ata_device *); + /* + * Command execution + */ + int (*qc_defer)(struct ata_queued_cmd *qc); + int (*check_atapi_dma)(struct ata_queued_cmd *qc); + void (*qc_prep)(struct ata_queued_cmd *qc); + unsigned int (*qc_issue)(struct ata_queued_cmd *qc); - void (*set_piomode) (struct ata_port *, struct ata_device *); - void (*set_dmamode) (struct ata_port *, struct ata_device *); - unsigned long (*mode_filter) (struct ata_device *, unsigned long); + /* + * Configuration and exception handling + */ + int (*cable_detect)(struct ata_port *ap); + unsigned long (*mode_filter)(struct ata_device *dev, unsigned long xfer_mask); + void (*set_piomode)(struct ata_port *ap, struct ata_device *dev); + void (*set_dmamode)(struct ata_port *ap, struct ata_device *dev); + int (*set_mode)(struct ata_link *link, struct ata_device **r_failed_dev); - void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf); - void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); + void (*dev_config)(struct ata_device *dev); - void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); + void (*freeze)(struct ata_port *ap); + void (*thaw)(struct ata_port *ap); + void (*error_handler)(struct ata_port *ap); + void (*post_internal_cmd)(struct ata_queued_cmd *qc); + + /* + * Optional features + */ + int (*scr_read)(struct ata_port *ap, unsigned int sc_reg, u32 *val); + int (*scr_write)(struct ata_port *ap, unsigned int sc_reg, u32 val); + void (*pmp_attach)(struct ata_port *ap); + void (*pmp_detach)(struct ata_port *ap); + int (*enable_pm)(struct ata_port *ap, enum link_pm policy); + void (*disable_pm)(struct ata_port *ap); + + /* + * Start, stop, suspend and resume + */ + int (*port_suspend)(struct ata_port *ap, pm_message_t mesg); + int (*port_resume)(struct ata_port *ap); + int (*port_start)(struct ata_port *ap); + void (*port_stop)(struct ata_port *ap); + void (*host_stop)(struct ata_host *host); + + /* + * SFF / taskfile oriented ops + */ + void (*dev_select)(struct ata_port *ap, unsigned int device); u8 (*check_status)(struct ata_port *ap); u8 (*check_altstatus)(struct ata_port *ap); - void (*dev_select)(struct ata_port *ap, unsigned int device); - - void (*phy_reset) (struct ata_port *ap); /* obsolete */ - int (*set_mode) (struct ata_link *link, struct ata_device **r_failed_dev); - - int (*cable_detect) (struct ata_port *ap); - - int (*check_atapi_dma) (struct ata_queued_cmd *qc); - - void (*bmdma_setup) (struct ata_queued_cmd *qc); - void (*bmdma_start) (struct ata_queued_cmd *qc); - - unsigned int (*data_xfer) (struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw); - - int (*qc_defer) (struct ata_queued_cmd *qc); - void (*qc_prep) (struct ata_queued_cmd *qc); - unsigned int (*qc_issue) (struct ata_queued_cmd *qc); - - /* port multiplier */ - void (*pmp_attach) (struct ata_port *ap); - void (*pmp_detach) (struct ata_port *ap); - - /* Error handlers. ->error_handler overrides ->eng_timeout and - * indicates that new-style EH is in place. + void (*tf_load)(struct ata_port *ap, const struct ata_taskfile *tf); + void (*tf_read)(struct ata_port *ap, struct ata_taskfile *tf); + void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); + unsigned int (*data_xfer)(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw); + u8 (*irq_on)(struct ata_port *); + + void (*irq_clear)(struct ata_port *); + void (*bmdma_setup)(struct ata_queued_cmd *qc); + void (*bmdma_start)(struct ata_queued_cmd *qc); + void (*bmdma_stop)(struct ata_queued_cmd *qc); + u8 (*bmdma_status)(struct ata_port *ap); + + /* + * Obsolete */ - void (*eng_timeout) (struct ata_port *ap); /* obsolete */ - - void (*freeze) (struct ata_port *ap); - void (*thaw) (struct ata_port *ap); - void (*error_handler) (struct ata_port *ap); - void (*post_internal_cmd) (struct ata_queued_cmd *qc); - + void (*phy_reset)(struct ata_port *ap); + void (*eng_timeout)(struct ata_port *ap); irq_handler_t irq_handler; - void (*irq_clear) (struct ata_port *); - u8 (*irq_on) (struct ata_port *); - - int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val); - int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val); - - int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); - int (*port_resume) (struct ata_port *ap); - int (*enable_pm) (struct ata_port *ap, enum link_pm policy); - void (*disable_pm) (struct ata_port *ap); - int (*port_start) (struct ata_port *ap); - void (*port_stop) (struct ata_port *ap); - - void (*host_stop) (struct ata_host *host); - - void (*bmdma_stop) (struct ata_queued_cmd *qc); - u8 (*bmdma_status) (struct ata_port *ap); }; struct ata_port_info { -- cgit v1.2.3 From 358f9a77a668660729e705fde9c3cf69f013aa98 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:47 +0900 Subject: libata: implement and use ata_noop_irq_clear() ->irq_clear() is used to clear IRQ bit of a SFF controller and isn't useful for drivers which don't use libata SFF HSM implementation. However, it's a required callback and many drivers implement their own noop version as placeholder. This patch implements ata_noop_irq_clear and use it to replace those custom placeholders. Also, SFF drivers which don't support BMDMA don't need to use ata_bmdma_irq_clear(). It becomes noop if BMDMA address isn't initialized. Convert them to use ata_noop_irq_clear(). Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 12 +++--------- drivers/ata/libata-core.c | 1 + drivers/ata/libata-sff.c | 8 ++++++++ drivers/ata/pata_ali.c | 2 +- drivers/ata/pata_at32.c | 7 +------ drivers/ata/pata_icside.c | 7 +------ drivers/ata/pata_isapnp.c | 2 +- drivers/ata/pata_ixp4xx_cf.c | 2 +- drivers/ata/pata_legacy.c | 22 +++++++++++----------- drivers/ata/pata_mpc52xx.c | 2 +- drivers/ata/pata_mpiix.c | 2 +- drivers/ata/pata_ns87410.c | 2 +- drivers/ata/pata_pcmcia.c | 4 ++-- drivers/ata/pata_platform.c | 2 +- drivers/ata/pata_qdi.c | 4 ++-- drivers/ata/pata_rb500_cf.c | 6 +----- drivers/ata/pata_winbond.c | 2 +- drivers/ata/pdc_adma.c | 8 +------- drivers/ata/sata_fsl.c | 7 +------ drivers/ata/sata_inic162x.c | 7 +------ drivers/ata/sata_mv.c | 11 +++-------- drivers/ata/sata_qstor.c | 8 +------- drivers/ata/sata_sil24.c | 8 +------- include/linux/libata.h | 1 + 24 files changed, 47 insertions(+), 90 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1bd258e5390f..492e521715d6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -244,7 +244,6 @@ static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); -static void ahci_irq_clear(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); @@ -307,7 +306,7 @@ static const struct ata_port_operations ahci_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, - .irq_clear = ahci_irq_clear, + .irq_clear = ata_noop_irq_clear, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -343,7 +342,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, - .irq_clear = ahci_irq_clear, + .irq_clear = ata_noop_irq_clear, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -377,7 +376,7 @@ static const struct ata_port_operations ahci_p5wdh_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, - .irq_clear = ahci_irq_clear, + .irq_clear = ata_noop_irq_clear, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -1769,11 +1768,6 @@ static void ahci_port_intr(struct ata_port *ap) } } -static void ahci_irq_clear(struct ata_port *ap) -{ - /* TODO */ -} - static irqreturn_t ahci_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4dc429fd0056..394edf937cf2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7824,6 +7824,7 @@ EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); +EXPORT_SYMBOL_GPL(ata_noop_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_bmdma_freeze); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 20dc572fb45a..1cf03d41aa33 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -302,6 +302,14 @@ void ata_bmdma_irq_clear(struct ata_port *ap) iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); } +/** + * ata_noop_irq_clear - Noop placeholder for irq_clear + * @ap: Port associated with this ATA transaction. + */ +void ata_noop_irq_clear(struct ata_port *ap) +{ +} + /** * ata_bmdma_status - Read PCI IDE BMDMA status * @ap: Port associated with this ATA transaction. diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 3814aebefb2d..84b748aef386 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -380,7 +380,7 @@ static struct ata_port_operations ali_early_port_ops = { .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c index db057b183d60..27c959f35c2c 100644 --- a/drivers/ata/pata_at32.c +++ b/drivers/ata/pata_at32.c @@ -166,11 +166,6 @@ static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) } } -static void pata_at32_irq_clear(struct ata_port *ap) -{ - /* No DMA controller yet */ -} - static struct scsi_host_template at32_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -208,7 +203,7 @@ static struct ata_port_operations at32_port_ops = { .data_xfer = ata_data_xfer, - .irq_clear = pata_at32_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index f97068be2d79..e1230cae7ff1 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -322,11 +322,6 @@ static struct scsi_host_template pata_icside_sht = { .bios_param = ata_std_bios_param, }; -/* wish this was exported from libata-core */ -static void ata_dummy_noret(struct ata_port *port) -{ -} - static void pata_icside_postreset(struct ata_link *link, unsigned int *classes) { struct ata_port *ap = link->ap; @@ -380,7 +375,7 @@ static struct ata_port_operations pata_icside_port_ops = { .error_handler = pata_icside_error_handler, .post_internal_cmd = pata_icside_bmdma_stop, - .irq_clear = ata_dummy_noret, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .bmdma_stop = pata_icside_bmdma_stop, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 4320e7986321..ef561de0c24d 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -55,7 +55,7 @@ static struct ata_port_operations isapnp_port_ops = { .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 030878fedeb5..83e38cc077e1 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -126,7 +126,7 @@ static struct ata_port_operations ixp4xx_port_ops = { .cable_detect = ata_cable_40wire, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_port_start, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 50fe08ebe23c..6ac02f7d5289 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -252,7 +252,7 @@ static struct ata_port_operations simple_port_ops = { .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -279,7 +279,7 @@ static struct ata_port_operations legacy_port_ops = { .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -393,7 +393,7 @@ static struct ata_port_operations pdc20230_port_ops = { .data_xfer = pdc_data_xfer_vlb, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -447,7 +447,7 @@ static struct ata_port_operations ht6560a_port_ops = { .data_xfer = ata_data_xfer, /* Check vlb/noirq */ .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -512,7 +512,7 @@ static struct ata_port_operations ht6560b_port_ops = { .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -633,7 +633,7 @@ static struct ata_port_operations opti82c611a_port_ops = { .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -765,7 +765,7 @@ static struct ata_port_operations opti82c46x_port_ops = { .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -950,7 +950,7 @@ static struct ata_port_operations qdi6500_port_ops = { .data_xfer = vlb32_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -977,7 +977,7 @@ static struct ata_port_operations qdi6580_port_ops = { .data_xfer = vlb32_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -1004,7 +1004,7 @@ static struct ata_port_operations qdi6580dp_port_ops = { .data_xfer = vlb32_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -1095,7 +1095,7 @@ static struct ata_port_operations winbond_port_ops = { .data_xfer = vlb32_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 5413ebfa72e5..d84e0c8ea02f 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -296,7 +296,7 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index c0d9e0cf208c..ced6372749b3 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -187,7 +187,7 @@ static struct ata_port_operations mpiix_port_ops = { .qc_issue = mpiix_qc_issue_prot, .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 9fe66fd75017..d182bdf31ee1 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -182,7 +182,7 @@ static struct ata_port_operations ns87410_port_ops = { .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 3e7f6a9da28b..9881a9e004a4 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -164,7 +164,7 @@ static struct ata_port_operations pcmcia_port_ops = { .data_xfer = ata_data_xfer_noirq, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -189,7 +189,7 @@ static struct ata_port_operations pcmcia_8bit_port_ops = { .data_xfer = ata_data_xfer_8bit, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index aad7adc6ea56..a8429f5c3006 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -86,7 +86,7 @@ static struct ata_port_operations pata_platform_port_ops = { .data_xfer = ata_data_xfer_noirq, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_dummy_ret0, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 9f308ed76cc8..60238d5748a7 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -191,7 +191,7 @@ static struct ata_port_operations qdi6500_port_ops = { .data_xfer = qdi_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, @@ -217,7 +217,7 @@ static struct ata_port_operations qdi6580_port_ops = { .data_xfer = qdi_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c index 4ce9b03fe6c8..08c32af1c84d 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb500_cf.c @@ -117,10 +117,6 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } -static void rb500_pata_irq_clear(struct ata_port *ap) -{ -} - static int rb500_pata_port_start(struct ata_port *ap) { return 0; @@ -144,7 +140,7 @@ static struct ata_port_operations rb500_pata_port_ops = { .error_handler = ata_bmdma_error_handler, .irq_handler = rb500_pata_irq_handler, - .irq_clear = rb500_pata_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = rb500_pata_port_start, diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 99c92eda217b..5318248782bb 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -159,7 +159,7 @@ static struct ata_port_operations winbond_port_ops = { .data_xfer = winbond_data_xfer, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = ata_sff_port_start, diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 8e1b7e9c0ae4..bc2d12a2da30 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -138,7 +138,6 @@ static unsigned 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_freeze(struct ata_port *ap); static void adma_thaw(struct ata_port *ap); static void adma_error_handler(struct ata_port *ap); @@ -174,7 +173,7 @@ static const struct ata_port_operations adma_ata_ops = { .freeze = adma_freeze, .thaw = adma_thaw, .error_handler = adma_error_handler, - .irq_clear = adma_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .port_start = adma_port_start, .port_stop = adma_port_stop, @@ -223,11 +222,6 @@ 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(struct ata_port *ap) { void __iomem *chan = ADMA_PORT_REGS(ap); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index d23b690ed1a1..031a512cbaa8 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -933,11 +933,6 @@ static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) } } -static void sata_fsl_irq_clear(struct ata_port *ap) -{ - /* unused */ -} - static void sata_fsl_error_intr(struct ata_port *ap) { struct ata_link *link = &ap->link; @@ -1223,7 +1218,7 @@ static const struct ata_port_operations sata_fsl_ops = { .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, - .irq_clear = sata_fsl_irq_clear, + .irq_clear = ata_noop_irq_clear, .scr_read = sata_fsl_scr_read, .scr_write = sata_fsl_scr_write, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 59e65edc5820..74f14369dc8d 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -266,11 +266,6 @@ static u8 inic_bmdma_status(struct ata_port *ap) return ATA_DMA_INTR; } -static void inic_irq_clear(struct ata_port *ap) -{ - /* noop */ -} - static void inic_host_intr(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); @@ -555,7 +550,7 @@ static struct ata_port_operations inic_port_ops = { .bmdma_stop = inic_bmdma_stop, .bmdma_status = inic_bmdma_status, - .irq_clear = inic_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .qc_prep = ata_qc_prep, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index a4944c8ad46d..b3b3da4eaa03 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -461,7 +461,6 @@ struct mv_hw_ops { void (*reset_bus)(struct ata_host *host, void __iomem *mmio); }; -static void mv_irq_clear(struct ata_port *ap); static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); @@ -564,7 +563,7 @@ static const struct ata_port_operations mv5_ops = { .qc_issue = mv_qc_issue, .data_xfer = ata_data_xfer, - .irq_clear = mv_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .error_handler = mv_error_handler, @@ -592,7 +591,7 @@ static const struct ata_port_operations mv6_ops = { .qc_issue = mv_qc_issue, .data_xfer = ata_data_xfer, - .irq_clear = mv_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .error_handler = mv_error_handler, @@ -620,7 +619,7 @@ static const struct ata_port_operations mv_iie_ops = { .qc_issue = mv_qc_issue, .data_xfer = ata_data_xfer, - .irq_clear = mv_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .error_handler = mv_error_handler, @@ -801,10 +800,6 @@ static inline int mv_get_hc_count(unsigned long port_flags) return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } -static void mv_irq_clear(struct ata_port *ap) -{ -} - static void mv_set_edma_ptrs(void __iomem *port_mmio, struct mv_host_priv *hpriv, struct mv_port_priv *pp) diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 91cc12c82040..3c8e97f251f9 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -121,7 +121,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); -static void qs_irq_clear(struct ata_port *ap); static void qs_freeze(struct ata_port *ap); static void qs_thaw(struct ata_port *ap); static void qs_error_handler(struct ata_port *ap); @@ -157,7 +156,7 @@ static const struct ata_port_operations qs_ata_ops = { .freeze = qs_freeze, .thaw = qs_thaw, .error_handler = qs_error_handler, - .irq_clear = qs_irq_clear, + .irq_clear = ata_noop_irq_clear, .irq_on = ata_irq_on, .scr_read = qs_scr_read, .scr_write = qs_scr_write, @@ -211,11 +210,6 @@ static u8 qs_bmdma_status(struct ata_port *ap) return 0; } -static void qs_irq_clear(struct ata_port *ap) -{ - /* nothing */ -} - static inline void qs_enter_reg_mode(struct ata_port *ap) { u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index ba0c00e8ee7f..b85464d51f68 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -348,7 +348,6 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static int sil24_qc_defer(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); -static void sil24_irq_clear(struct ata_port *ap); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); @@ -416,7 +415,7 @@ static const struct ata_port_operations sil24_ops = { .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, - .irq_clear = sil24_irq_clear, + .irq_clear = ata_noop_irq_clear, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, @@ -921,11 +920,6 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) return 0; } -static void sil24_irq_clear(struct ata_port *ap) -{ - /* unused */ -} - static void sil24_pmp_attach(struct ata_port *ap) { sil24_config_pmp(ap, 1); diff --git a/include/linux/libata.h b/include/linux/libata.h index 9476a479691b..639298af583e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -896,6 +896,7 @@ extern void ata_bmdma_start(struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); +extern void ata_noop_irq_clear(struct ata_port *ap); extern void ata_bmdma_freeze(struct ata_port *ap); extern void ata_bmdma_thaw(struct ata_port *ap); extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, -- cgit v1.2.3 From 68d1d07b510bb57a504588adc2bd2758adea0965 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:49 +0900 Subject: libata: implement and use SHT initializers libata lets low level drivers build scsi_host_template and register it to the SCSI layer. This allows low level drivers high level of flexibility but also burdens them with lots of boilerplate entries. This patch implements SHT initializers which can be used to initialize all the boilerplate entries in a sht. Three variants of them are implemented - BASE, BMDMA and NCQ - for different types of drivers. Note that entries can be overriden by putting individual initializers after the helper macro. All sht tables are identical before and after this patch. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 15 +---------- drivers/ata/ata_generic.c | 16 +----------- drivers/ata/ata_piix.c | 16 +----------- drivers/ata/pata_acpi.c | 17 +----------- drivers/ata/pata_ali.c | 16 +----------- drivers/ata/pata_amd.c | 16 +----------- drivers/ata/pata_artop.c | 16 +----------- drivers/ata/pata_at32.c | 16 +----------- drivers/ata/pata_atiixp.c | 15 +---------- drivers/ata/pata_bf54x.c | 14 +--------- drivers/ata/pata_cmd640.c | 16 +----------- drivers/ata/pata_cmd64x.c | 16 +----------- drivers/ata/pata_cs5520.c | 15 +---------- drivers/ata/pata_cs5530.c | 17 ++---------- drivers/ata/pata_cs5535.c | 16 +----------- drivers/ata/pata_cs5536.c | 16 +----------- drivers/ata/pata_cypress.c | 16 +----------- drivers/ata/pata_efar.c | 16 +----------- drivers/ata/pata_hpt366.c | 16 +----------- drivers/ata/pata_hpt37x.c | 16 +----------- drivers/ata/pata_hpt3x2n.c | 16 +----------- drivers/ata/pata_hpt3x3.c | 16 +----------- drivers/ata/pata_icside.c | 14 +--------- drivers/ata/pata_isapnp.c | 16 +----------- drivers/ata/pata_it8213.c | 16 +----------- drivers/ata/pata_it821x.c | 16 +----------- drivers/ata/pata_ixp4xx_cf.c | 16 +----------- drivers/ata/pata_jmicron.c | 17 +----------- drivers/ata/pata_legacy.c | 16 +----------- drivers/ata/pata_marvell.c | 17 +----------- drivers/ata/pata_mpc52xx.c | 16 +----------- drivers/ata/pata_mpiix.c | 16 +----------- drivers/ata/pata_netcell.c | 17 +----------- drivers/ata/pata_ninja32.c | 16 +----------- drivers/ata/pata_ns87410.c | 16 +----------- drivers/ata/pata_ns87415.c | 16 +----------- drivers/ata/pata_oldpiix.c | 16 +----------- drivers/ata/pata_opti.c | 16 +----------- drivers/ata/pata_optidma.c | 16 +----------- drivers/ata/pata_pcmcia.c | 16 +----------- drivers/ata/pata_pdc2027x.c | 16 +----------- drivers/ata/pata_pdc202xx_old.c | 16 +----------- drivers/ata/pata_platform.c | 16 +----------- drivers/ata/pata_qdi.c | 16 +----------- drivers/ata/pata_radisys.c | 16 +----------- drivers/ata/pata_rb500_cf.c | 17 +----------- drivers/ata/pata_rz1000.c | 16 +----------- drivers/ata/pata_sc1200.c | 17 ++---------- drivers/ata/pata_scc.c | 16 +----------- drivers/ata/pata_serverworks.c | 16 +----------- drivers/ata/pata_sil680.c | 16 +----------- drivers/ata/pata_sis.c | 16 +----------- drivers/ata/pata_sl82c105.c | 16 +----------- drivers/ata/pata_triflex.c | 16 +----------- drivers/ata/pata_via.c | 16 +----------- drivers/ata/pata_winbond.c | 16 +----------- drivers/ata/pdc_adma.c | 14 +--------- drivers/ata/sata_fsl.c | 14 +--------- drivers/ata/sata_inic162x.c | 16 +----------- drivers/ata/sata_mv.c | 28 ++------------------ drivers/ata/sata_nv.c | 42 +++--------------------------- drivers/ata/sata_promise.c | 14 +--------- drivers/ata/sata_qstor.c | 14 +--------- drivers/ata/sata_sil.c | 16 +----------- drivers/ata/sata_sil24.c | 14 +--------- drivers/ata/sata_sis.c | 16 +----------- drivers/ata/sata_svw.c | 16 +----------- drivers/ata/sata_sx4.c | 14 +--------- drivers/ata/sata_uli.c | 16 +----------- drivers/ata/sata_via.c | 16 +----------- drivers/ata/sata_vsc.c | 16 +----------- include/linux/libata.h | 57 +++++++++++++++++++++++++++++++++++++++++ 72 files changed, 133 insertions(+), 1086 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c6ea44a7f2a9..8862595cb2cf 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -62,7 +62,6 @@ enum { AHCI_MAX_PORTS = 32, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, - AHCI_USE_CLUSTERING = 1, AHCI_MAX_CMDS = 32, AHCI_CMD_SZ = 32, AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, @@ -274,22 +273,10 @@ static struct class_device_attribute *ahci_shost_attrs[] = { }; static struct scsi_host_template ahci_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT(DRV_NAME), .can_queue = AHCI_MAX_CMDS - 1, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = AHCI_MAX_SG, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = AHCI_USE_CLUSTERING, - .proc_name = DRV_NAME, .dma_boundary = AHCI_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, .shost_attrs = ahci_shost_attrs, }; diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index db4c3cb78fda..5c64ce134c6c 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -95,21 +95,7 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) } static struct scsi_host_template generic_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations generic_port_ops = { diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 067760a16889..9f887b2c92df 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -291,21 +291,7 @@ static struct pci_driver piix_pci_driver = { }; static struct scsi_host_template piix_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations piix_pata_ops = { diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index bdc3b9d7395c..187545c0898a 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -232,22 +232,7 @@ static int pacpi_port_start(struct ata_port *ap) } static struct scsi_host_template pacpi_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - /* Use standard CHS mapping rules */ - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations pacpi_ops = { diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 84b748aef386..f3d6d9b345ba 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -339,21 +339,7 @@ static int ali_check_atapi_dma(struct ata_queued_cmd *qc) } static struct scsi_host_template ali_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; /* diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 5e1bc13a756b..90d786dfbec3 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -353,21 +353,7 @@ static void nv_host_stop(struct ata_host *host) } static struct scsi_host_template amd_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations amd33_port_ops = { diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index a238c7bd0bba..7bfb7e8bdca2 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -314,21 +314,7 @@ static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template artop_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations artop6210_ops = { diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c index 27c959f35c2c..d7b7b7fde362 100644 --- a/drivers/ata/pata_at32.c +++ b/drivers/ata/pata_at32.c @@ -167,21 +167,7 @@ static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template at32_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations at32_port_ops = { diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 408bdc1a9776..645c47271ff5 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -221,21 +221,8 @@ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc) } static struct scsi_host_template atiixp_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BMDMA_SHT(DRV_NAME), .sg_tablesize = LIBATA_DUMB_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static struct ata_port_operations atiixp_port_ops = { diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 146c202d5834..6c75fcac3cf4 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1357,21 +1357,9 @@ static int bfin_port_start(struct ata_port *ap) } static struct scsi_host_template bfin_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = SG_NONE, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations bfin_pata_ops = { diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 0ef1d1ded1f8..26562b814400 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -166,21 +166,7 @@ static int cmd640_port_start(struct ata_port *ap) } static struct scsi_host_template cmd640_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations cmd640_port_ops = { diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e8c1262341ee..6aea05cc0940 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -266,21 +266,7 @@ static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc) } static struct scsi_host_template cmd64x_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations cmd64x_port_ops = { diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 44ad2c9d488f..7e643099a444 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -140,21 +140,8 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template cs5520_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BMDMA_SHT(DRV_NAME), .sg_tablesize = LIBATA_DUMB_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static struct ata_port_operations cs5520_port_ops = { diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index f876aeddf1a1..0bb03dabcf18 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -161,21 +161,8 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc) } static struct scsi_host_template cs5530_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_DUMB_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), + .sg_tablesize = LIBATA_DUMB_MAX_PRD, }; static struct ata_port_operations cs5530_port_ops = { diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 01324530d052..48a18349c1d8 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -158,21 +158,7 @@ static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template cs5535_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations cs5535_port_ops = { diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 391aa888f8fd..f02d9107ef3b 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -221,21 +221,7 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template cs5536_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations cs5536_port_ops = { diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index fc5f9c4e5d87..07fa1ab36315 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -110,21 +110,7 @@ static void cy82c693_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template cy82c693_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations cy82c693_port_ops = { diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index dc33220fe5b2..8700d9dcd8c9 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -233,21 +233,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template efar_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations efar_ops = { diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index a82089048f58..a30028de41c0 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -290,21 +290,7 @@ static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template hpt36x_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; /* diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 2ddcd07a7518..7d6fac43e2f9 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -619,21 +619,7 @@ static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc) static struct scsi_host_template hpt37x_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; /* diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 3a517cb9bd3e..aa380c46b168 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -339,21 +339,7 @@ static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc) } static struct scsi_host_template hpt3x2n_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; /* diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index c09f95a4a0d1..9837ab0181e8 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -102,21 +102,7 @@ static int hpt3x3_atapi_dma(struct ata_queued_cmd *qc) } static struct scsi_host_template hpt3x3_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations hpt3x3_port_ops = { diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index e1230cae7ff1..88a1c7ae0a4d 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -305,21 +305,9 @@ static int icside_dma_init(struct pata_icside_info *info) static struct scsi_host_template pata_icside_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = PATA_ICSIDE_MAX_SG, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = DRV_NAME, .dma_boundary = ~0, /* no dma boundaries */ - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static void pata_icside_postreset(struct ata_link *link, unsigned int *classes) diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index ef561de0c24d..91ca4d50db04 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -20,21 +20,7 @@ #define DRV_VERSION "0.2.2" static struct scsi_host_template isapnp_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations isapnp_port_ops = { diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 25c49c2e1519..678a05b304d8 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -243,21 +243,7 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template it8213_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations it8213_ops = { diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 6bdbb7140dfa..7d969c911731 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -632,21 +632,7 @@ static int it821x_port_start(struct ata_port *ap) } static struct scsi_host_template it821x_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations it821x_smart_port_ops = { diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 6eb8cc9a3f12..b7e8e825a869 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -88,21 +88,7 @@ static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev, } static struct scsi_host_template ixp4xx_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations ixp4xx_port_ops = { diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 7d36fa85435a..69781af7b1bb 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -122,22 +122,7 @@ static void jmicron_error_handler(struct ata_port *ap) /* No PIO or DMA methods needed for this device */ static struct scsi_host_template jmicron_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - /* Use standard CHS mapping rules */ - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations jmicron_ops = { diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6ac02f7d5289..5329b954c5f2 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -208,21 +208,7 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) } static struct scsi_host_template legacy_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; /* diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index c4ee9b45301f..9de6e429d0d1 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -92,22 +92,7 @@ static void marvell_error_handler(struct ata_port *ap) /* No PIO or DMA methods needed for this device */ static struct scsi_host_template marvell_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - /* Use standard CHS mapping rules */ - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations marvell_ops = { diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index fefe71dbed1a..4117b618a9d9 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -265,21 +265,7 @@ mpc52xx_ata_error_handler(struct ata_port *ap) static struct scsi_host_template mpc52xx_ata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations mpc52xx_ata_port_ops = { diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index ced6372749b3..e8e6837110b4 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -151,21 +151,7 @@ static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc) } static struct scsi_host_template mpiix_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations mpiix_port_ops = { diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 9fd1a84c01d3..11f200a2a156 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -21,22 +21,7 @@ /* No PIO or DMA methods needed for this device */ static struct scsi_host_template netcell_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - /* Use standard CHS mapping rules */ - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations netcell_ops = { diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 15dd649f89ee..ce3b07cab8bc 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -79,21 +79,7 @@ static void ninja32_dev_select(struct ata_port *ap, unsigned int device) } static struct scsi_host_template ninja32_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations ninja32_port_ops = { diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index d182bdf31ee1..d2f85f107d15 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -144,21 +144,7 @@ static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc) } static struct scsi_host_template ns87410_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations ns87410_port_ops = { diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 93eb958cb0c9..78d634423cbf 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -366,21 +366,7 @@ static const struct ata_port_operations ns87415_pata_ops = { }; static struct scsi_host_template ns87415_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 44da09ace52c..45f9b3eb5b45 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -220,21 +220,7 @@ static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc) static struct scsi_host_template oldpiix_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations oldpiix_pata_ops = { diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 1e865f138d1c..1deacfa0be07 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -165,21 +165,7 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template opti_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations opti_port_ops = { diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 3f9d03599f23..7495758a86fe 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -350,21 +350,7 @@ static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed) } static struct scsi_host_template optidma_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations optidma_port_ops = { diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 9881a9e004a4..c05b36c94d51 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -128,21 +128,7 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev, static struct scsi_host_template pcmcia_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations pcmcia_port_ops = { diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 511c89b9bae8..229d9acd934a 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -129,21 +129,7 @@ static struct pci_driver pdc2027x_pci_driver = { }; static struct scsi_host_template pdc2027x_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations pdc2027x_pata100_ops = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 3ed866723e0c..564ee0798ec1 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -262,21 +262,7 @@ static int pdc2026x_check_atapi_dma(struct ata_queued_cmd *qc) } static struct scsi_host_template pdc202xx_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations pdc2024x_port_ops = { diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 602f5562d6fb..cd2d03a4591a 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -47,21 +47,7 @@ static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unu } static struct scsi_host_template pata_platform_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations pata_platform_port_ops = { diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 60238d5748a7..ccb8682300b8 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -154,21 +154,7 @@ static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, } static struct scsi_host_template qdi_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations qdi6500_port_ops = { diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 8109b08fc024..3981bf84d093 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -185,21 +185,7 @@ static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc) static struct scsi_host_template radisys_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations radisys_pata_ops = { diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c index 22cb9e1a02f5..4543c980342c 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb500_cf.c @@ -142,22 +142,7 @@ static struct ata_port_operations rb500_pata_port_ops = { /* ------------------------------------------------------------------------ */ static struct scsi_host_template rb500_pata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, - .proc_name = DRV_NAME, - - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .dma_boundary = ATA_DMA_BOUNDARY, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, + ATA_PIO_SHT(DRV_NAME), }; /* ------------------------------------------------------------------------ */ diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 75b252111106..80909a607d36 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -53,21 +53,7 @@ static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) static struct scsi_host_template rz1000_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations rz1000_port_ops = { diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 725a8586cd6e..38ce6e12ee3d 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -179,21 +179,8 @@ static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc) } static struct scsi_host_template sc1200_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_DUMB_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), + .sg_tablesize = LIBATA_DUMB_MAX_PRD, }; static struct ata_port_operations sc1200_port_ops = { diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 6c016deeaed8..1833e9ef522e 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -968,21 +968,7 @@ static void scc_port_stop (struct ata_port *ap) } static struct scsi_host_template scc_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations scc_pata_ops = { diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 6702df37cfed..318a36988900 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -298,21 +298,7 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev } static struct scsi_host_template serverworks_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations serverworks_osb4_port_ops = { diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index f4dc09718cab..7812815a34c3 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -192,21 +192,7 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template sil680_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations sil680_port_ops = { diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index abda90f51247..dcd8457a8377 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -514,21 +514,7 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template sis_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations sis_133_ops = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 6c37181341ea..ece366bced0c 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -235,21 +235,7 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc) } static struct scsi_host_template sl82c105_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations sl82c105_port_ops = { diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 403eafcffe12..510569957d10 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -180,21 +180,7 @@ static void triflex_bmdma_stop(struct ata_queued_cmd *qc) } static struct scsi_host_template triflex_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations triflex_port_ops = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 24430f70f00e..a7bc860e1310 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -335,21 +335,7 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) } static struct scsi_host_template via_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations via_port_ops = { diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 5318248782bb..9bafae9d5fe0 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -122,21 +122,7 @@ static unsigned int winbond_data_xfer(struct ata_device *dev, } static struct scsi_host_template winbond_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_PIO_SHT(DRV_NAME), }; static struct ata_port_operations winbond_port_ops = { diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index bc2d12a2da30..fdf62de57cfc 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -143,21 +143,9 @@ static void adma_thaw(struct ata_port *ap); static void adma_error_handler(struct ata_port *ap); static struct scsi_host_template adma_ata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, - .proc_name = DRV_NAME, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = LIBATA_MAX_PRD, .dma_boundary = ADMA_DMA_BOUNDARY, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .emulated = ATA_SHT_EMULATED, }; static const struct ata_port_operations adma_ata_ops = { diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 8389ecac62cd..f50381b4ba06 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1191,22 +1191,10 @@ static int sata_fsl_init_controller(struct ata_host *host) * scsi mid-layer and libata interface structures */ static struct scsi_host_template sata_fsl_sht = { - .module = THIS_MODULE, - .name = "sata_fsl", - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT("sata_fsl"), .can_queue = SATA_FSL_QUEUE_DEPTH, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = SATA_FSL_MAX_PRD_USABLE, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = "sata_fsl", .dma_boundary = ATA_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations sata_fsl_ops = { diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 74f14369dc8d..bb853df865da 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -109,21 +109,7 @@ struct inic_port_priv { }; static struct scsi_host_template inic_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const int scr_map[] = { diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 4685bce745bb..52d41edadb72 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -514,40 +514,16 @@ static int __mv_stop_dma(struct ata_port *ap); * PRDs for 64K boundaries in mv_fill_sg(). */ static struct scsi_host_template mv5_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = MV_MAX_SG_CT / 2, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = 1, - .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static struct scsi_host_template mv6_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT(DRV_NAME), .can_queue = MV_MAX_Q_DEPTH - 1, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = MV_MAX_SG_CT / 2, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = 1, - .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations mv5_ops = { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index bd5b6c35ee5d..9e2b4cef48f2 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -385,59 +385,23 @@ static struct pci_driver nv_pci_driver = { }; static struct scsi_host_template nv_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static struct scsi_host_template nv_adma_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT(DRV_NAME), .can_queue = NV_ADMA_MAX_CPBS, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = DRV_NAME, .dma_boundary = NV_ADMA_DMA_BOUNDARY, .slave_configure = nv_adma_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static struct scsi_host_template nv_swncq_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT(DRV_NAME), .can_queue = ATA_MAX_QUEUE, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - .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 = nv_swncq_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations nv_generic_ops = { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 11c1afea2db2..37c32ab3b23b 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -155,21 +155,9 @@ static int pdc_pata_cable_detect(struct ata_port *ap); static int pdc_sata_cable_detect(struct ata_port *ap); static struct scsi_host_template pdc_ata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = PDC_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations pdc_sata_ops = { diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 3c8e97f251f9..2566d0926aab 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -126,21 +126,9 @@ static void qs_thaw(struct ata_port *ap); static void qs_error_handler(struct ata_port *ap); static struct scsi_host_template qs_ata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = QS_MAX_PRD, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ENABLE_CLUSTERING, - .proc_name = DRV_NAME, .dma_boundary = QS_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations qs_ata_ops = { diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 53f0bae3be43..738c1a8ae3b6 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -167,21 +167,7 @@ static struct pci_driver sil_pci_driver = { }; static struct scsi_host_template sil_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations sil_ops = { diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index b85464d51f68..7fa63950d81a 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -384,22 +384,10 @@ static struct pci_driver sil24_pci_driver = { }; static struct scsi_host_template sil24_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .change_queue_depth = ata_scsi_change_queue_depth, + ATA_NCQ_SHT(DRV_NAME), .can_queue = SIL24_MAX_CMDS, - .this_id = ATA_SHT_THIS_ID, .sg_tablesize = SIL24_MAX_SGE, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations sil24_ops = { diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index a8adef9786b7..4becb7fde5e7 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -86,21 +86,7 @@ static struct pci_driver sis_pci_driver = { }; static struct scsi_host_template sis_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations sis_ops = { diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index aa690142fa90..c8768396e006 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -327,24 +327,10 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start, static struct scsi_host_template k2_sata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, + ATA_BMDMA_SHT(DRV_NAME), #ifdef CONFIG_PPC_OF .proc_info = k2_sata_proc_info, #endif - .bios_param = ata_std_bios_param, }; diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index e3d56bc6726d..1802f92180e4 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -236,21 +236,9 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static struct scsi_host_template pdc_sata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, + ATA_BASE_SHT(DRV_NAME), .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, }; static const struct ata_port_operations pdc_20621_ops = { diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index f7fc0450478b..764d7064fa59 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -76,21 +76,7 @@ static struct pci_driver uli_pci_driver = { }; static struct scsi_host_template uli_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations uli_ops = { diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index f66ffd7da54e..9be877cb7f57 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -100,21 +100,7 @@ static struct pci_driver svia_pci_driver = { }; static struct scsi_host_template svia_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; static const struct ata_port_operations vt6420_sata_ops = { diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 099a2ba4cd4f..fd6855f0bf48 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -300,21 +300,7 @@ out: static struct scsi_host_template vsc_sata_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .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, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, + ATA_BMDMA_SHT(DRV_NAME), }; diff --git a/include/linux/libata.h b/include/linux/libata.h index 639298af583e..eccc38e17568 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1070,6 +1070,63 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +/* + * Base operations to inherit from and initializers for sht + * + * Operations + * + * base : Common to all libata drivers. + * sata : SATA controllers w/ native interface. + * pmp : SATA controllers w/ PMP support. + * sff : SFF ATA controllers w/o BMDMA support. + * bmdma : SFF ATA controllers w/ BMDMA support. + * + * sht initializers + * + * BASE : Common to all libata drivers. The user must set + * sg_tablesize and dma_boundary. + * PIO : SFF ATA controllers w/ only PIO support. + * BMDMA : SFF ATA controllers w/ BMDMA support. sg_tablesize and + * dma_boundary are set to BMDMA limits. + * NCQ : SATA controllers supporting NCQ. The user must set + * sg_tablesize, dma_boundary and can_queue. + */ +extern const struct ata_port_operations ata_base_port_ops; +extern const struct ata_port_operations sata_port_ops; +extern const struct ata_port_operations sata_pmp_port_ops; +extern const struct ata_port_operations ata_sff_port_ops; +extern const struct ata_port_operations ata_bmdma_port_ops; + +#define ATA_BASE_SHT(drv_name) \ + .module = THIS_MODULE, \ + .name = drv_name, \ + .ioctl = ata_scsi_ioctl, \ + .queuecommand = ata_scsi_queuecmd, \ + .can_queue = ATA_DEF_QUEUE, \ + .this_id = ATA_SHT_THIS_ID, \ + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, \ + .emulated = ATA_SHT_EMULATED, \ + .use_clustering = ATA_SHT_USE_CLUSTERING, \ + .proc_name = drv_name, \ + .slave_configure = ata_scsi_slave_config, \ + .slave_destroy = ata_scsi_slave_destroy, \ + .bios_param = ata_std_bios_param + +/* PIO only, sg_tablesize and dma_boundary limits can be removed */ +#define ATA_PIO_SHT(drv_name) \ + ATA_BASE_SHT(drv_name), \ + .sg_tablesize = LIBATA_MAX_PRD, \ + .dma_boundary = ATA_DMA_BOUNDARY + +#define ATA_BMDMA_SHT(drv_name) \ + ATA_BASE_SHT(drv_name), \ + .sg_tablesize = LIBATA_MAX_PRD, \ + .dma_boundary = ATA_DMA_BOUNDARY + +#define ATA_NCQ_SHT(drv_name) \ + ATA_BASE_SHT(drv_name), \ + .change_queue_depth = ata_scsi_change_queue_depth + /* * printk helpers */ -- cgit v1.2.3 From 029cfd6b74fc5c517865fad78cf4a3ea8d9b664a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:49 +0900 Subject: libata: implement and use ops inheritance libata lets low level drivers build ata_port_operations table and register it with libata core layer. This allows low level drivers high level of flexibility but also burdens them with lots of boilerplate entries. This becomes worse for drivers which support related similar controllers which differ slightly. They share most of the operations except for a few. However, the driver still needs to list all operations for each variant. This results in large number of duplicate entries, which is not only inefficient but also error-prone as it becomes very difficult to tell what the actual differences are. This duplicate boilerplates all over the low level drivers also make updating the core layer exteremely difficult and error-prone. When compounded with multi-branched development model, it ends up accumulating inconsistencies over time. Some of those inconsistencies cause immediate problems and fixed. Others just remain there dormant making maintenance increasingly difficult. To rectify the problem, this patch implements ata_port_operations inheritance. To allow LLDs to easily re-use their own ops tables overriding only specific methods, this patch implements poor man's class inheritance. An ops table has ->inherits field which can be set to any ops table as long as it doesn't create a loop. When the host is started, the inheritance chain is followed and any operation which isn't specified is taken from the nearest ancestor which has it specified. This operation is called finalization and done only once per an ops table and the LLD doesn't have to do anything special about it other than making the ops table non-const such that libata can update it. libata provides four base ops tables lower drivers can inherit from - base, sata, pmp, sff and bmdma. To avoid overriding these ops accidentaly, these ops are declared const and LLDs should always inherit these instead of using them directly. After finalization, all the ops table are identical before and after the patch except for setting .irq_handler to ata_interrupt in drivers which didn't use to. The .irq_handler doesn't have any actual effect and the field will soon be removed by later patch. * sata_sx4 is still using old style EH and currently doesn't take advantage of ops inheritance. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 94 ++------------- drivers/ata/ata_generic.c | 31 +---- drivers/ata/ata_piix.c | 149 +++-------------------- drivers/ata/libata-core.c | 113 ++++++++++++++++- drivers/ata/pata_acpi.c | 35 +----- drivers/ata/pata_ali.c | 122 ++----------------- drivers/ata/pata_amd.c | 191 ++++------------------------- drivers/ata/pata_artop.c | 61 +--------- drivers/ata/pata_at32.c | 23 +--- drivers/ata/pata_atiixp.c | 32 +---- drivers/ata/pata_bf54x.c | 4 +- drivers/ata/pata_cmd640.c | 33 +---- drivers/ata/pata_cmd64x.c | 96 ++------------- drivers/ata/pata_cs5520.c | 29 +---- drivers/ata/pata_cs5530.c | 31 +---- drivers/ata/pata_cs5535.c | 31 +---- drivers/ata/pata_cs5536.c | 31 +---- drivers/ata/pata_cypress.c | 31 +---- drivers/ata/pata_efar.c | 30 +---- drivers/ata/pata_hpt366.c | 32 +---- drivers/ata/pata_hpt37x.c | 122 ++----------------- drivers/ata/pata_hpt3x2n.c | 32 +---- drivers/ata/pata_hpt3x3.c | 33 +---- drivers/ata/pata_icside.c | 32 ++--- drivers/ata/pata_isapnp.c | 21 +--- drivers/ata/pata_it8213.c | 31 +---- drivers/ata/pata_it821x.c | 57 ++------- drivers/ata/pata_ixp4xx_cf.c | 23 +--- drivers/ata/pata_jmicron.c | 31 +---- drivers/ata/pata_legacy.c | 260 +++------------------------------------- drivers/ata/pata_marvell.c | 33 +---- drivers/ata/pata_mpc52xx.c | 18 +-- drivers/ata/pata_mpiix.c | 23 +--- drivers/ata/pata_netcell.c | 32 +---- drivers/ata/pata_ninja32.c | 30 +---- drivers/ata/pata_ns87410.c | 25 +--- drivers/ata/pata_ns87415.c | 68 ++--------- drivers/ata/pata_oldpiix.c | 31 +---- drivers/ata/pata_opti.c | 23 +--- drivers/ata/pata_optidma.c | 63 +--------- drivers/ata/pata_pcmcia.c | 48 +------- drivers/ata/pata_pdc2027x.c | 56 +-------- drivers/ata/pata_pdc202xx_old.c | 75 +++--------- drivers/ata/pata_platform.c | 24 +--- drivers/ata/pata_qdi.c | 47 +------- drivers/ata/pata_radisys.c | 32 +---- drivers/ata/pata_rb500_cf.c | 16 +-- drivers/ata/pata_rz1000.c | 25 +--- drivers/ata/pata_sc1200.c | 33 +---- drivers/ata/pata_scc.c | 7 +- drivers/ata/pata_serverworks.c | 63 +--------- drivers/ata/pata_sil680.c | 30 +---- drivers/ata/pata_sis.c | 177 +++------------------------ drivers/ata/pata_sl82c105.c | 34 +----- drivers/ata/pata_triflex.c | 32 +---- drivers/ata/pata_via.c | 61 +--------- drivers/ata/pata_winbond.c | 25 +--- drivers/ata/pdc_adma.c | 19 +-- drivers/ata/sata_fsl.c | 5 +- drivers/ata/sata_inic162x.c | 19 +-- drivers/ata/sata_mv.c | 66 ++-------- drivers/ata/sata_nv.c | 113 +++-------------- drivers/ata/sata_promise.c | 62 +++------- drivers/ata/sata_qstor.c | 20 ++-- drivers/ata/sata_sil.c | 21 +--- drivers/ata/sata_sil24.c | 20 ++-- drivers/ata/sata_sis.c | 23 +--- drivers/ata/sata_svw.c | 18 +-- drivers/ata/sata_sx4.c | 3 +- drivers/ata/sata_uli.c | 28 +---- drivers/ata/sata_via.c | 88 ++------------ drivers/ata/sata_vsc.c | 19 +-- include/linux/libata.h | 23 +++- 73 files changed, 523 insertions(+), 2996 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8862595cb2cf..dacb3ef0c3e6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -280,118 +280,46 @@ static struct scsi_host_template ahci_sht = { .shost_attrs = ahci_shost_attrs, }; -static const struct ata_port_operations ahci_ops = { +static struct ata_port_operations ahci_ops = { + .inherits = &sata_pmp_port_ops, + .check_status = ahci_check_status, .check_altstatus = ahci_check_status, - .dev_select = ata_noop_dev_select, - - .dev_config = ahci_dev_config, .tf_read = ahci_tf_read, - .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, - .irq_clear = ata_noop_irq_clear, - - .scr_read = ahci_scr_read, - .scr_write = ahci_scr_write, - .freeze = ahci_freeze, .thaw = ahci_thaw, - .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, - - .pmp_attach = ahci_pmp_attach, - .pmp_detach = ahci_pmp_detach, - -#ifdef CONFIG_PM - .port_suspend = ahci_port_suspend, - .port_resume = ahci_port_resume, -#endif - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, - - .port_start = ahci_port_start, - .port_stop = ahci_port_stop, -}; - -static const struct ata_port_operations ahci_vt8251_ops = { - .check_status = ahci_check_status, - .check_altstatus = ahci_check_status, - .dev_select = ata_noop_dev_select, - .dev_config = ahci_dev_config, - .tf_read = ahci_tf_read, - - .qc_defer = sata_pmp_qc_defer_cmd_switch, - .qc_prep = ahci_qc_prep, - .qc_issue = ahci_qc_issue, - - .irq_clear = ata_noop_irq_clear, - .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, - - .freeze = ahci_freeze, - .thaw = ahci_thaw, - - .error_handler = ahci_vt8251_error_handler, - .post_internal_cmd = ahci_post_internal_cmd, - .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, + .enable_pm = ahci_enable_alpm, + .disable_pm = ahci_disable_alpm, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, #endif - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, - .port_start = ahci_port_start, .port_stop = ahci_port_stop, }; -static const struct ata_port_operations ahci_p5wdh_ops = { - .check_status = ahci_check_status, - .check_altstatus = ahci_check_status, - .dev_select = ata_noop_dev_select, - - .dev_config = ahci_dev_config, - - .tf_read = ahci_tf_read, - - .qc_defer = sata_pmp_qc_defer_cmd_switch, - .qc_prep = ahci_qc_prep, - .qc_issue = ahci_qc_issue, - - .irq_clear = ata_noop_irq_clear, - - .scr_read = ahci_scr_read, - .scr_write = ahci_scr_write, - - .freeze = ahci_freeze, - .thaw = ahci_thaw, +static struct ata_port_operations ahci_vt8251_ops = { + .inherits = &ahci_ops, + .error_handler = ahci_vt8251_error_handler, +}; +static struct ata_port_operations ahci_p5wdh_ops = { + .inherits = &ahci_ops, .error_handler = ahci_p5wdh_error_handler, - .post_internal_cmd = ahci_post_internal_cmd, - - .pmp_attach = ahci_pmp_attach, - .pmp_detach = ahci_pmp_detach, - -#ifdef CONFIG_PM - .port_suspend = ahci_port_suspend, - .port_resume = ahci_port_resume, -#endif - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, - - .port_start = ahci_port_start, - .port_stop = ahci_port_stop, }; #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 5c64ce134c6c..0b5b515ae159 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -99,36 +99,9 @@ static struct scsi_host_template generic_sht = { }; static struct ata_port_operations generic_port_ops = { - .set_mode = generic_set_mode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_bmdma_port_ops, .cable_detect = ata_cable_unknown, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_mode = generic_set_mode, }; static int all_generic_ide; /* Set to claim all devices */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 9f887b2c92df..bb46b61a7c6b 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -294,155 +294,34 @@ static struct scsi_host_template piix_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations piix_pata_ops = { +static struct ata_port_operations piix_pata_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = piix_pata_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, +}; - .port_start = ata_sff_port_start, +static struct ata_port_operations piix_vmw_ops = { + .inherits = &piix_pata_ops, + .bmdma_status = piix_vmw_bmdma_status, }; -static const struct ata_port_operations ich_pata_ops = { - .set_piomode = piix_set_piomode, - .set_dmamode = ich_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = piix_pata_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, +static struct ata_port_operations ich_pata_ops = { + .inherits = &piix_pata_ops, .cable_detect = ich_pata_cable_detect, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_dmamode = ich_set_dmamode, }; -static const struct ata_port_operations piix_sata_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, +static struct ata_port_operations piix_sata_ops = { + .inherits = &ata_bmdma_port_ops, }; -static const struct ata_port_operations piix_vmw_ops = { - .set_piomode = piix_set_piomode, - .set_dmamode = piix_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = piix_vmw_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = piix_pata_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static const struct ata_port_operations piix_sidpr_sata_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - +static struct ata_port_operations piix_sidpr_sata_ops = { + .inherits = &piix_sata_ops, .scr_read = piix_sidpr_scr_read, .scr_write = piix_sidpr_scr_write, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = piix_sidpr_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static const struct piix_map_db ich5_map_db = { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 394edf937cf2..32fa9ee397b6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,6 +74,56 @@ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; +const struct ata_port_operations ata_base_port_ops = { + .irq_clear = ata_noop_irq_clear, +}; + +const struct ata_port_operations sata_port_ops = { + .inherits = &ata_base_port_ops, + + .qc_defer = ata_std_qc_defer, + .dev_select = ata_noop_dev_select, +}; + +const struct ata_port_operations sata_pmp_port_ops = { + .inherits = &sata_port_ops, +}; + +const struct ata_port_operations ata_sff_port_ops = { + .inherits = &ata_base_port_ops, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .dev_select = ata_std_dev_select, + .check_status = ata_check_status, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .data_xfer = ata_data_xfer, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, + .irq_handler = ata_interrupt, +}; + +const struct ata_port_operations ata_bmdma_port_ops = { + .inherits = &ata_sff_port_ops, + + .mode_filter = ata_pci_default_filter, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .irq_clear = ata_bmdma_irq_clear, +}; + static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -6971,6 +7021,56 @@ static void ata_host_stop(struct device *gendev, void *res) host->ops->host_stop(host); } +/** + * ata_finalize_port_ops - finalize ata_port_operations + * @ops: ata_port_operations to finalize + * + * An ata_port_operations can inherit from another ops and that + * ops can again inherit from another. This can go on as many + * times as necessary as long as there is no loop in the + * inheritance chain. + * + * Ops tables are finalized when the host is started. NULL or + * unspecified entries are inherited from the closet ancestor + * which has the method and the entry is populated with it. + * After finalization, the ops table directly points to all the + * methods and ->inherits is no longer necessary and cleared. + * + * Using ATA_OP_NULL, inheriting ops can force a method to NULL. + * + * LOCKING: + * None. + */ +static void ata_finalize_port_ops(struct ata_port_operations *ops) +{ + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + const struct ata_port_operations *cur; + void **begin = (void **)ops; + void **end = (void **)&ops->inherits; + void **pp; + + if (!ops || !ops->inherits) + return; + + spin_lock(&lock); + + for (cur = ops->inherits; cur; cur = cur->inherits) { + void **inherit = (void **)cur; + + for (pp = begin; pp < end; pp++, inherit++) + if (!*pp) + *pp = *inherit; + } + + for (pp = begin; pp < end; pp++) + if (IS_ERR(*pp)) + *pp = NULL; + + ops->inherits = NULL; + + spin_unlock(&lock); +} + /** * ata_host_start - start and freeze ports of an ATA host * @host: ATA host to start ports for @@ -6996,9 +7096,13 @@ int ata_host_start(struct ata_host *host) if (host->flags & ATA_HOST_STARTED) return 0; + ata_finalize_port_ops(host->ops); + for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + ata_finalize_port_ops(ap->ops); + if (!host->ops && !ata_port_is_dummy(ap)) host->ops = ap->ops; @@ -7060,7 +7164,7 @@ int ata_host_start(struct ata_host *host) */ /* KILLME - the only user left is ipr */ void ata_host_init(struct ata_host *host, struct device *dev, - unsigned long flags, const struct ata_port_operations *ops) + unsigned long flags, struct ata_port_operations *ops) { spin_lock_init(&host->lock); host->dev = dev; @@ -7749,7 +7853,7 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) return AC_ERR_SYSTEM; } -const struct ata_port_operations ata_dummy_port_ops = { +struct ata_port_operations ata_dummy_port_ops = { .check_status = ata_dummy_check_status, .check_altstatus = ata_dummy_check_status, .dev_select = ata_noop_dev_select, @@ -7777,6 +7881,11 @@ const struct ata_port_info ata_dummy_port_info = { EXPORT_SYMBOL_GPL(sata_deb_timing_normal); EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_long); +EXPORT_SYMBOL_GPL(ata_base_port_ops); +EXPORT_SYMBOL_GPL(sata_port_ops); +EXPORT_SYMBOL_GPL(sata_pmp_port_ops); +EXPORT_SYMBOL_GPL(ata_sff_port_ops); +EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_std_bios_param); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 187545c0898a..35ad488db6ed 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -235,39 +235,14 @@ static struct scsi_host_template pacpi_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations pacpi_ops = { +static struct ata_port_operations pacpi_ops = { + .inherits = &ata_bmdma_port_ops, + .qc_issue = pacpi_qc_issue_prot, + .cable_detect = pacpi_cable_detect, + .mode_filter = pacpi_mode_filter, .set_piomode = pacpi_set_piomode, .set_dmamode = pacpi_set_dmamode, - .mode_filter = pacpi_mode_filter, - - /* Task file is PCI ATA format, use helpers */ - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = pacpi_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pacpi_cable_detect, - - /* BMDMA handling is PCI ATA format, use helpers */ - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = pacpi_qc_issue_prot, - .data_xfer = ata_data_xfer, - - /* Timeout handling */ - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - /* Generic PATA PCI ATA helpers */ .port_start = pacpi_port_start, }; diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index f3d6d9b345ba..b00a9cf72c31 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -347,29 +347,15 @@ static struct scsi_host_template ali_sht = { */ static struct ata_port_operations ali_early_port_ops = { - .set_piomode = ali_set_piomode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, + .set_piomode = ali_set_piomode, +}; - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, +static const struct ata_port_operations ali_dma_base_ops = { + .inherits = &ata_bmdma_port_ops, + .set_piomode = ali_set_piomode, + .set_dmamode = ali_set_dmamode, }; /* @@ -377,115 +363,31 @@ static struct ata_port_operations ali_early_port_ops = { * detect */ static struct ata_port_operations ali_20_port_ops = { - .set_piomode = ali_set_piomode, - .set_dmamode = ali_set_dmamode, + .inherits = &ali_dma_base_ops, + .cable_detect = ata_cable_40wire, .mode_filter = ali_20_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, .check_atapi_dma = ali_check_atapi_dma, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, .dev_config = ali_lock_sectors, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* * Port operations for DMA capable ALi with cable detect */ static struct ata_port_operations ali_c2_port_ops = { - .set_piomode = ali_set_piomode, - .set_dmamode = ali_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, + .inherits = &ali_dma_base_ops, .check_atapi_dma = ali_check_atapi_dma, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - .dev_config = ali_lock_sectors, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ali_c2_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .dev_config = ali_lock_sectors, }; /* * Port operations for DMA capable ALi with cable detect and LBA48 */ static struct ata_port_operations ali_c5_port_ops = { - .set_piomode = ali_set_piomode, - .set_dmamode = ali_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, + .inherits = &ali_dma_base_ops, .check_atapi_dma = ali_check_atapi_dma, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, .dev_config = ali_warn_atapi_dma, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ali_c2_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 90d786dfbec3..b0cb4eaf273c 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -356,204 +356,57 @@ static struct scsi_host_template amd_sht = { ATA_BMDMA_SHT(DRV_NAME), }; +static const struct ata_port_operations amd_base_port_ops = { + .inherits = &ata_bmdma_port_ops, + .error_handler = amd_error_handler, +}; + static struct ata_port_operations amd33_port_ops = { + .inherits = &amd_base_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = amd33_set_piomode, .set_dmamode = amd33_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations amd66_port_ops = { + .inherits = &amd_base_port_ops, + .cable_detect = ata_cable_unknown, .set_piomode = amd66_set_piomode, .set_dmamode = amd66_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations amd100_port_ops = { + .inherits = &amd_base_port_ops, + .cable_detect = ata_cable_unknown, .set_piomode = amd100_set_piomode, .set_dmamode = amd100_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations amd133_port_ops = { + .inherits = &amd_base_port_ops, + .cable_detect = amd_cable_detect, .set_piomode = amd133_set_piomode, .set_dmamode = amd133_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = amd_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, +}; - .port_start = ata_sff_port_start, +static const struct ata_port_operations nv_base_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_ignore, + .mode_filter = nv_mode_filter, + .error_handler = nv_error_handler, + .host_stop = nv_host_stop, }; static struct ata_port_operations nv100_port_ops = { + .inherits = &nv_base_port_ops, .set_piomode = nv100_set_piomode, .set_dmamode = nv100_set_dmamode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = nv_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_ignore, - .mode_filter = nv_mode_filter, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, - .host_stop = nv_host_stop, }; static struct ata_port_operations nv133_port_ops = { + .inherits = &nv_base_port_ops, .set_piomode = nv133_set_piomode, .set_dmamode = nv133_set_dmamode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = nv_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_ignore, - .mode_filter = nv_mode_filter, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, - .host_stop = nv_host_stop, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 7bfb7e8bdca2..0101e5aef3e0 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -317,69 +317,20 @@ static struct scsi_host_template artop_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations artop6210_ops = { +static struct ata_port_operations artop6210_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = artop6210_set_piomode, .set_dmamode = artop6210_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = artop6210_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations artop6260_ops = { +static struct ata_port_operations artop6260_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = artop6260_cable_detect, .set_piomode = artop6260_set_piomode, .set_dmamode = artop6260_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = artop6260_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = artop6260_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c index d7b7b7fde362..528315587532 100644 --- a/drivers/ata/pata_at32.c +++ b/drivers/ata/pata_at32.c @@ -171,28 +171,9 @@ static struct scsi_host_template at32_sht = { }; static struct ata_port_operations at32_port_ops = { - .set_piomode = pata_at32_set_piomode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_piomode = pata_at32_set_piomode, }; static int __init pata_at32_init_one(struct device *dev, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 645c47271ff5..2655f6a17ad3 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -226,36 +226,16 @@ static struct scsi_host_template atiixp_sht = { }; static struct ata_port_operations atiixp_port_ops = { - .set_piomode = atiixp_set_piomode, - .set_dmamode = atiixp_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = atiixp_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = atiixp_cable_detect, + .inherits = &ata_bmdma_port_ops, - .bmdma_setup = ata_bmdma_setup, + .qc_prep = ata_dumb_qc_prep, .bmdma_start = atiixp_bmdma_start, .bmdma_stop = atiixp_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_dumb_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = atiixp_cable_detect, + .set_piomode = atiixp_set_piomode, + .set_dmamode = atiixp_set_dmamode, + .error_handler = atiixp_error_handler, }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 6c75fcac3cf4..7a22ef483061 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1363,6 +1363,8 @@ static struct scsi_host_template bfin_sht = { }; static const struct ata_port_operations bfin_pata_ops = { + .inherits = &ata_sff_port_ops, + .set_piomode = bfin_set_piomode, .set_dmamode = bfin_set_dmamode, @@ -1380,14 +1382,12 @@ static const struct ata_port_operations bfin_pata_ops = { .data_xfer = bfin_data_xfer, .qc_prep = ata_noop_qc_prep, - .qc_issue = ata_qc_issue_prot, .freeze = bfin_bmdma_freeze, .thaw = bfin_bmdma_thaw, .error_handler = bfin_error_handler, .post_internal_cmd = bfin_bmdma_stop, - .irq_handler = ata_interrupt, .irq_clear = bfin_irq_clear, .irq_on = bfin_irq_on, diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 26562b814400..061c891c8a66 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -170,35 +170,12 @@ static struct scsi_host_template cmd640_sht = { }; static struct ata_port_operations cmd640_port_ops = { - .set_piomode = cmd640_set_piomode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = cmd640_qc_issue_prot, - - /* In theory this is not needed once we kill the prefetcher */ + .inherits = &ata_bmdma_port_ops, + /* In theory xfer_noirq is not needed once we kill the prefetcher */ .data_xfer = ata_data_xfer_noirq, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - + .qc_issue = cmd640_qc_issue_prot, + .cable_detect = ata_cable_40wire, + .set_piomode = cmd640_set_piomode, .port_start = cmd640_port_start, }; diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 6aea05cc0940..1ac8ecfb97e2 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -269,103 +269,27 @@ static struct scsi_host_template cmd64x_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static struct ata_port_operations cmd64x_port_ops = { +static const struct ata_port_operations cmd64x_base_ops = { + .inherits = &ata_bmdma_port_ops, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static struct ata_port_operations cmd646r1_port_ops = { - .set_piomode = cmd64x_set_piomode, - .set_dmamode = cmd64x_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, +static struct ata_port_operations cmd64x_port_ops = { + .inherits = &cmd64x_base_ops, .cable_detect = ata_cable_40wire, +}; - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, +static struct ata_port_operations cmd646r1_port_ops = { + .inherits = &cmd64x_base_ops, .bmdma_stop = cmd646r1_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, }; static struct ata_port_operations cmd648_port_ops = { - .set_piomode = cmd64x_set_piomode, - .set_dmamode = cmd64x_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = cmd648_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, + .inherits = &cmd64x_base_ops, .bmdma_stop = cmd648_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = cmd648_cable_detect, }; static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 7e643099a444..46d0ce32ee5a 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -145,34 +145,11 @@ static struct scsi_host_template cs5520_sht = { }; static struct ata_port_operations cs5520_port_ops = { + .inherits = &ata_bmdma_port_ops, + .qc_prep = ata_dumb_qc_prep, + .cable_detect = ata_cable_40wire, .set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_dumb_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 0bb03dabcf18..e4a16a578cac 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -166,37 +166,14 @@ static struct scsi_host_template cs5530_sht = { }; static struct ata_port_operations cs5530_port_ops = { - .set_piomode = cs5530_set_piomode, - .set_dmamode = cs5530_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, + .inherits = &ata_bmdma_port_ops, .qc_prep = ata_dumb_qc_prep, .qc_issue = cs5530_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = cs5530_set_piomode, + .set_dmamode = cs5530_set_dmamode, }; static const struct dmi_system_id palmax_dmi_table[] = { diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 48a18349c1d8..f910a8aa7437 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -162,37 +162,10 @@ static struct scsi_host_template cs5535_sht = { }; static struct ata_port_operations cs5535_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = cs5535_cable_detect, .set_piomode = cs5535_set_piomode, .set_dmamode = cs5535_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = cs5535_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index f02d9107ef3b..075ee6a7be39 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -225,37 +225,10 @@ static struct scsi_host_template cs5536_sht = { }; static struct ata_port_operations cs5536_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = cs5536_cable_detect, .set_piomode = cs5536_set_piomode, .set_dmamode = cs5536_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = cs5536_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 07fa1ab36315..c459553e7d1e 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -114,37 +114,10 @@ static struct scsi_host_template cy82c693_sht = { }; static struct ata_port_operations cy82c693_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = cy82c693_set_piomode, .set_dmamode = cy82c693_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 8700d9dcd8c9..ef62fc642c17 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -236,36 +236,12 @@ static struct scsi_host_template efar_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations efar_ops = { +static struct ata_port_operations efar_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = efar_cable_detect, .set_piomode = efar_set_piomode, .set_dmamode = efar_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = efar_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = efar_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index a30028de41c0..788955f57ff8 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -298,37 +298,11 @@ static struct scsi_host_template hpt36x_sht = { */ static struct ata_port_operations hpt366_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = hpt36x_cable_detect, + .mode_filter = hpt366_filter, .set_piomode = hpt366_set_piomode, .set_dmamode = hpt366_set_dmamode, - .mode_filter = hpt366_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = hpt36x_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 7d6fac43e2f9..c42eec70d297 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -627,36 +627,15 @@ static struct scsi_host_template hpt37x_sht = { */ static struct ata_port_operations hpt370_port_ops = { - .set_piomode = hpt370_set_piomode, - .set_dmamode = hpt370_set_dmamode, - .mode_filter = hpt370_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = hpt37x_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_bmdma_port_ops, - .bmdma_setup = ata_bmdma_setup, .bmdma_start = hpt370_bmdma_start, .bmdma_stop = hpt370_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .mode_filter = hpt370_filter, + .set_piomode = hpt370_set_piomode, + .set_dmamode = hpt370_set_dmamode, + .error_handler = hpt37x_error_handler, }; /* @@ -664,36 +643,8 @@ static struct ata_port_operations hpt370_port_ops = { */ static struct ata_port_operations hpt370a_port_ops = { - .set_piomode = hpt370_set_piomode, - .set_dmamode = hpt370_set_dmamode, + .inherits = &hpt370_port_ops, .mode_filter = hpt370a_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = hpt37x_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = hpt370_bmdma_start, - .bmdma_stop = hpt370_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* @@ -702,36 +653,13 @@ static struct ata_port_operations hpt370a_port_ops = { */ static struct ata_port_operations hpt372_port_ops = { - .set_piomode = hpt372_set_piomode, - .set_dmamode = hpt372_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = hpt37x_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_bmdma_port_ops, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, .bmdma_stop = hpt37x_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_piomode = hpt372_set_piomode, + .set_dmamode = hpt372_set_dmamode, + .error_handler = hpt37x_error_handler, }; /* @@ -740,36 +668,8 @@ static struct ata_port_operations hpt372_port_ops = { */ static struct ata_port_operations hpt374_port_ops = { - .set_piomode = hpt372_set_piomode, - .set_dmamode = hpt372_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, + .inherits = &hpt372_port_ops, .error_handler = hpt374_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = hpt37x_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index aa380c46b168..b77b1279d757 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -347,37 +347,15 @@ static struct scsi_host_template hpt3x2n_sht = { */ static struct ata_port_operations hpt3x2n_port_ops = { - .set_piomode = hpt3x2n_set_piomode, - .set_dmamode = hpt3x2n_set_dmamode, - .mode_filter = ata_pci_default_filter, + .inherits = &ata_bmdma_port_ops, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = hpt3x2n_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = hpt3x2n_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, .bmdma_stop = hpt3x2n_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, .qc_issue = hpt3x2n_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = hpt3x2n_cable_detect, + .set_piomode = hpt3x2n_set_piomode, + .set_dmamode = hpt3x2n_set_dmamode, + .error_handler = hpt3x2n_error_handler, }; /** diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 9837ab0181e8..8857d029ac2e 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -106,40 +106,13 @@ static struct scsi_host_template hpt3x3_sht = { }; static struct ata_port_operations hpt3x3_port_ops = { + .inherits = &ata_bmdma_port_ops, + .check_atapi_dma= hpt3x3_atapi_dma, + .cable_detect = ata_cable_40wire, .set_piomode = hpt3x3_set_piomode, #if defined(CONFIG_PATA_HPT3X3_DMA) .set_dmamode = hpt3x3_set_dmamode, #endif - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .check_atapi_dma= hpt3x3_atapi_dma, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 88a1c7ae0a4d..ff16b0eaa2c2 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -339,35 +339,19 @@ static void pata_icside_error_handler(struct ata_port *ap) } static struct ata_port_operations pata_icside_port_ops = { - .set_dmamode = pata_icside_set_dmamode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - - .cable_detect = ata_cable_40wire, - - .bmdma_setup = pata_icside_bmdma_setup, - .bmdma_start = pata_icside_bmdma_start, - - .data_xfer = ata_data_xfer_noirq, - + .inherits = &ata_sff_port_ops, /* no need to build any PRD tables for DMA */ .qc_prep = ata_noop_qc_prep, - .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer_noirq, + .bmdma_setup = pata_icside_bmdma_setup, + .bmdma_start = pata_icside_bmdma_start, + .bmdma_stop = pata_icside_bmdma_stop, + .bmdma_status = pata_icside_bmdma_status, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, + .cable_detect = ata_cable_40wire, + .set_dmamode = pata_icside_set_dmamode, .error_handler = pata_icside_error_handler, .post_internal_cmd = pata_icside_bmdma_stop, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .bmdma_stop = pata_icside_bmdma_stop, - .bmdma_status = pata_icside_bmdma_status, }; static void __devinit diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 91ca4d50db04..085913ec6f68 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -24,27 +24,8 @@ static struct scsi_host_template isapnp_sht = { }; static struct ata_port_operations isapnp_port_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 678a05b304d8..9ce89522e764 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -246,36 +246,13 @@ static struct scsi_host_template it8213_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations it8213_ops = { + +static struct ata_port_operations it8213_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = it8213_cable_detect, .set_piomode = it8213_set_piomode, .set_dmamode = it8213_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = it8213_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = it8213_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 7d969c911731..669d224d30ca 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -636,71 +636,30 @@ static struct scsi_host_template it821x_sht = { }; static struct ata_port_operations it821x_smart_port_ops = { - .set_mode = it821x_smart_set_mode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .mode_filter = ata_pci_default_filter, + .inherits = &ata_bmdma_port_ops, - .check_status = ata_check_status, .check_atapi_dma= it821x_check_atapi_dma, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - .dev_config = it821x_dev_config, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = it821x_ident_hack, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, .qc_issue = it821x_smart_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, + .cable_detect = it821x_ident_hack, + .set_mode = it821x_smart_set_mode, + .dev_config = it821x_dev_config, .port_start = it821x_port_start, }; static struct ata_port_operations it821x_passthru_port_ops = { - .set_piomode = it821x_passthru_set_piomode, - .set_dmamode = it821x_passthru_set_dmamode, - .mode_filter = ata_pci_default_filter, + .inherits = &ata_bmdma_port_ops, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, .check_atapi_dma= it821x_check_atapi_dma, .dev_select = it821x_passthru_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, - - .bmdma_setup = ata_bmdma_setup, .bmdma_start = it821x_passthru_bmdma_start, .bmdma_stop = it821x_passthru_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, .qc_issue = it821x_passthru_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_clear = ata_bmdma_irq_clear, - .irq_handler = ata_interrupt, - .irq_on = ata_irq_on, + .cable_detect = ata_cable_unknown, + .set_piomode = it821x_passthru_set_piomode, + .set_dmamode = it821x_passthru_set_dmamode, .port_start = it821x_port_start, }; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index b7e8e825a869..d02629aa20da 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -92,29 +92,10 @@ static struct scsi_host_template ixp4xx_sht = { }; static struct ata_port_operations ixp4xx_port_ops = { - .set_mode = ixp4xx_set_mode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, + .inherits = &ata_sff_port_ops, .data_xfer = ixp4xx_mmio_data_xfer, .cable_detect = ata_cable_40wire, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_mode = ixp4xx_set_mode, }; static void ixp4xx_setup_port(struct ata_port *ap, diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 69781af7b1bb..61ff5c6b4568 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -125,36 +125,9 @@ static struct scsi_host_template jmicron_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations jmicron_ops = { - /* Task file is PCI ATA format, use helpers */ - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, +static struct ata_port_operations jmicron_ops = { + .inherits = &ata_bmdma_port_ops, .error_handler = jmicron_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - /* BMDMA handling is PCI ATA format, use helpers */ - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - /* IRQ-related hooks */ - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - /* Generic PATA PCI ATA helpers */ - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 5329b954c5f2..2474068596f4 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -211,6 +211,11 @@ static struct scsi_host_template legacy_sht = { ATA_PIO_SHT(DRV_NAME), }; +static const struct ata_port_operations legacy_base_port_ops = { + .inherits = &ata_sff_port_ops, + .cable_detect = ata_cable_40wire, +}; + /* * These ops are used if the user indicates the hardware * snoops the commands to decide on the mode and handles the @@ -220,55 +225,14 @@ static struct scsi_host_template legacy_sht = { */ static struct ata_port_operations simple_port_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &legacy_base_port_ops, .data_xfer = ata_data_xfer_noirq, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations legacy_port_ops = { - .set_mode = legacy_set_mode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - .cable_detect = ata_cable_40wire, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &legacy_base_port_ops, .data_xfer = ata_data_xfer_noirq, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_mode = legacy_set_mode, }; /* @@ -359,30 +323,9 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, } static struct ata_port_operations pdc20230_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = pdc20230_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = pdc_data_xfer_vlb, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* @@ -413,30 +356,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) } static struct ata_port_operations ht6560a_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = ht6560a_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, /* Check vlb/noirq */ - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* @@ -478,30 +399,8 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) } static struct ata_port_operations ht6560b_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = ht6560b_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* @@ -599,30 +498,8 @@ static void opti82c611a_set_piomode(struct ata_port *ap, static struct ata_port_operations opti82c611a_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = opti82c611a_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /* @@ -731,30 +608,9 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) } static struct ata_port_operations opti82c46x_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = opti82c46x_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, .qc_issue = opti82c46x_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -916,84 +772,22 @@ static int qdi_port(struct platform_device *dev, } static struct ata_port_operations qdi6500_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = qdi6500_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, .qc_issue = qdi_qc_issue_prot, - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations qdi6580_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = qdi6580_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations qdi6580dp_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = qdi6580dp_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = qdi_qc_issue_prot, - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static DEFINE_SPINLOCK(winbond_lock); @@ -1062,29 +856,9 @@ static int winbond_port(struct platform_device *dev, } static struct ata_port_operations winbond_port_ops = { + .inherits = &legacy_base_port_ops, .set_piomode = winbond_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = vlb32_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct legacy_controller controllers[] = { diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 9de6e429d0d1..286310fc5910 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -95,37 +95,10 @@ static struct scsi_host_template marvell_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations marvell_ops = { - /* Task file is PCI ATA format, use helpers */ - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = marvell_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, +static struct ata_port_operations marvell_ops = { + .inherits = &ata_bmdma_port_ops, .cable_detect = marvell_cable_detect, - - /* BMDMA handling is PCI ATA format, use helpers */ - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - /* Timeout handling */ - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - /* Generic PATA PCI ATA helpers */ - .port_start = ata_sff_port_start, + .error_handler = marvell_error_handler, }; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 4117b618a9d9..ac7c0822b1a7 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -269,22 +269,12 @@ static struct scsi_host_template mpc52xx_ata_sht = { }; static struct ata_port_operations mpc52xx_ata_port_ops = { - .set_piomode = mpc52xx_ata_set_piomode, + .inherits = &ata_sff_port_ops, .dev_select = mpc52xx_ata_dev_select, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = mpc52xx_ata_error_handler, .cable_detect = ata_cable_40wire, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .set_piomode = mpc52xx_ata_set_piomode, + .error_handler = mpc52xx_ata_error_handler, + .post_internal_cmd = ATA_OP_NULL, }; static int __devinit diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index e8e6837110b4..dab54f8a272d 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -155,28 +155,11 @@ static struct scsi_host_template mpiix_sht = { }; static struct ata_port_operations mpiix_port_ops = { + .inherits = &ata_sff_port_ops, + .qc_issue = mpiix_qc_issue_prot, + .cable_detect = ata_cable_40wire, .set_piomode = mpiix_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = mpiix_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = mpiix_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 11f200a2a156..65389d1837b3 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -24,37 +24,9 @@ static struct scsi_host_template netcell_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations netcell_ops = { - /* Task file is PCI ATA format, use helpers */ - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, +static struct ata_port_operations netcell_ops = { + .inherits = &ata_bmdma_port_ops, .cable_detect = ata_cable_80wire, - - /* BMDMA handling is PCI ATA format, use helpers */ - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - /* IRQ-related hooks */ - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - /* Generic PATA PCI ATA helpers */ - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index ce3b07cab8bc..8213d081f313 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -83,36 +83,10 @@ static struct scsi_host_template ninja32_sht = { }; static struct ata_port_operations ninja32_port_ops = { - .set_piomode = ninja32_set_piomode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, + .inherits = &ata_bmdma_port_ops, .dev_select = ninja32_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_piomode = ninja32_set_piomode, }; static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index d2f85f107d15..5b1982fa0be1 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -148,30 +148,11 @@ static struct scsi_host_template ns87410_sht = { }; static struct ata_port_operations ns87410_port_ops = { + .inherits = &ata_sff_port_ops, + .qc_issue = ns87410_qc_issue_prot, + .cable_detect = ata_cable_40wire, .set_piomode = ns87410_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = ns87410_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ns87410_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 78d634423cbf..38d86a262dbb 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -297,73 +297,29 @@ static u8 ns87560_bmdma_status(struct ata_port *ap) { return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } +#endif /* 87560 SuperIO Support */ -static const struct ata_port_operations ns87560_pata_ops = { - .set_piomode = ns87415_set_piomode, - .mode_filter = ata_pci_default_filter, +static struct ata_port_operations ns87415_pata_ops = { + .inherits = &ata_bmdma_port_ops, - .tf_load = ata_tf_load, - .tf_read = ns87560_tf_read, - .check_status = ns87560_check_status, .check_atapi_dma = ns87415_check_atapi_dma, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - .bmdma_setup = ns87415_bmdma_setup, .bmdma_start = ns87415_bmdma_start, .bmdma_stop = ns87415_bmdma_stop, - .bmdma_status = ns87560_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, .irq_clear = ns87415_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -#endif /* 87560 SuperIO Support */ - - -static const struct ata_port_operations ns87415_pata_ops = { - .set_piomode = ns87415_set_piomode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .check_atapi_dma = ns87415_check_atapi_dma, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, + .set_piomode = ns87415_set_piomode, +}; - .bmdma_setup = ns87415_bmdma_setup, - .bmdma_start = ns87415_bmdma_start, - .bmdma_stop = ns87415_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ns87415_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, +#if defined(CONFIG_SUPERIO) +static struct ata_port_operations ns87560_pata_ops = { + .inherits = &ns87415_pata_ops, + .tf_read = ns87560_tf_read, + .check_status = ns87560_check_status, + .bmdma_status = ns87560_bmdma_status, }; +#endif static struct scsi_host_template ns87415_sht = { ATA_BMDMA_SHT(DRV_NAME), diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 45f9b3eb5b45..f6062b37310d 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -223,36 +223,13 @@ static struct scsi_host_template oldpiix_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations oldpiix_pata_ops = { +static struct ata_port_operations oldpiix_pata_ops = { + .inherits = &ata_bmdma_port_ops, + .qc_issue = oldpiix_qc_issue_prot, + .cable_detect = ata_cable_40wire, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = oldpiix_pata_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = oldpiix_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 1deacfa0be07..c4a0795c3ff4 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -169,29 +169,10 @@ static struct scsi_host_template opti_sht = { }; static struct ata_port_operations opti_port_ops = { + .inherits = &ata_sff_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = opti_set_piomode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = opti_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 7495758a86fe..eb4b08190e3a 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -354,73 +354,18 @@ static struct scsi_host_template optidma_sht = { }; static struct ata_port_operations optidma_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_40wire, .set_piomode = optidma_set_pio_mode, .set_dmamode = optidma_set_dma_mode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .error_handler = optidma_error_handler, .set_mode = optidma_set_mode, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .error_handler = optidma_error_handler, }; static struct ata_port_operations optiplus_port_ops = { + .inherits = &optidma_port_ops, .set_piomode = optiplus_set_pio_mode, .set_dmamode = optiplus_set_dma_mode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .error_handler = optidma_error_handler, - .set_mode = optidma_set_mode, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index c05b36c94d51..57efbf05c95f 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -132,53 +132,17 @@ static struct scsi_host_template pcmcia_sht = { }; static struct ata_port_operations pcmcia_port_ops = { - .set_mode = pcmcia_set_mode, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &ata_sff_port_ops, .data_xfer = ata_data_xfer_noirq, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_mode = pcmcia_set_mode, }; static struct ata_port_operations pcmcia_8bit_port_ops = { - .set_mode = pcmcia_set_mode_8bit, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &ata_sff_port_ops, .data_xfer = ata_data_xfer_8bit, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_mode = pcmcia_set_mode_8bit, }; #define CS_CHECK(fn, ret) \ diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 229d9acd934a..f619c20dd192 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -133,66 +133,18 @@ static struct scsi_host_template pdc2027x_sht = { }; static struct ata_port_operations pdc2027x_pata100_ops = { - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - + .inherits = &ata_bmdma_port_ops, .check_atapi_dma = pdc2027x_check_atapi_dma, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = pdc2027x_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = pdc2027x_cable_detect, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .error_handler = pdc2027x_error_handler, }; static struct ata_port_operations pdc2027x_pata133_ops = { + .inherits = &pdc2027x_pata100_ops, + .mode_filter = pdc2027x_mode_filter, .set_piomode = pdc2027x_set_piomode, .set_dmamode = pdc2027x_set_dmamode, .set_mode = pdc2027x_set_mode, - .mode_filter = pdc2027x_mode_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .check_atapi_dma = pdc2027x_check_atapi_dma, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = pdc2027x_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pdc2027x_cable_detect, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_info pdc2027x_port_info[] = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 564ee0798ec1..4daac20df0bc 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -266,69 +266,24 @@ static struct scsi_host_template pdc202xx_sht = { }; static struct ata_port_operations pdc2024x_port_ops = { - .set_piomode = pdc202xx_set_piomode, - .set_dmamode = pdc202xx_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .inherits = &ata_bmdma_port_ops, + + .cable_detect = ata_cable_40wire, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, }; static struct ata_port_operations pdc2026x_port_ops = { - .set_piomode = pdc202xx_set_piomode, - .set_dmamode = pdc202xx_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - .dev_config = pdc2026x_dev_config, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pdc2026x_cable_detect, - - .check_atapi_dma= pdc2026x_check_atapi_dma, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = pdc2026x_bmdma_start, - .bmdma_stop = pdc2026x_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = pdc2026x_port_start, + .inherits = &pdc2024x_port_ops, + + .check_atapi_dma = pdc2026x_check_atapi_dma, + .bmdma_start = pdc2026x_bmdma_start, + .bmdma_stop = pdc2026x_bmdma_stop, + + .cable_detect = pdc2026x_cable_detect, + .dev_config = pdc2026x_dev_config, + + .port_start = pdc2026x_port_start, }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index cd2d03a4591a..0588c9b7e73e 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -51,27 +51,11 @@ static struct scsi_host_template pata_platform_sht = { }; static struct ata_port_operations pata_platform_port_ops = { - .set_mode = pata_platform_set_mode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &ata_sff_port_ops, .data_xfer = ata_data_xfer_noirq, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, + .cable_detect = ata_cable_unknown, + .set_mode = pata_platform_set_mode, + .port_start = ATA_OP_NULL, }; static void pata_platform_setup_port(struct ata_ioports *ioaddr, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index ccb8682300b8..d16b343d2a62 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -158,55 +158,16 @@ static struct scsi_host_template qdi_sht = { }; static struct ata_port_operations qdi6500_port_ops = { - .set_piomode = qdi6500_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, + .inherits = &ata_sff_port_ops, .qc_issue = qdi_qc_issue_prot, - .data_xfer = qdi_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = qdi6500_set_piomode, }; static struct ata_port_operations qdi6580_port_ops = { + .inherits = &qdi6500_port_ops, .set_piomode = qdi6580_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = qdi_qc_issue_prot, - - .data_xfer = qdi_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 3981bf84d093..94e60b3a1ec6 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -188,36 +188,12 @@ static struct scsi_host_template radisys_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations radisys_pata_ops = { +static struct ata_port_operations radisys_pata_ops = { + .inherits = &ata_bmdma_port_ops, + .qc_issue = radisys_qc_issue_prot, + .cable_detect = ata_cable_unknown, .set_piomode = radisys_set_piomode, .set_dmamode = radisys_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = radisys_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c index 4543c980342c..7affceec1c29 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb500_cf.c @@ -118,25 +118,11 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) } static struct ata_port_operations rb500_pata_port_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - + .inherits = &ata_sff_port_ops, .exec_command = rb500_pata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .data_xfer = rb500_pata_data_xfer, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .freeze = rb500_pata_freeze, .thaw = rb500_pata_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, }; /* ------------------------------------------------------------------------ */ diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 80909a607d36..a2aef7328bfc 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -57,30 +57,9 @@ static struct scsi_host_template rz1000_sht = { }; static struct ata_port_operations rz1000_port_ops = { - .set_mode = rz1000_set_mode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, + .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, - - .irq_handler = ata_interrupt, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .set_mode = rz1000_set_mode, }; static int rz1000_fifo_disable(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 38ce6e12ee3d..362b7f829d8e 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -184,37 +184,12 @@ static struct scsi_host_template sc1200_sht = { }; static struct ata_port_operations sc1200_port_ops = { - .set_piomode = sc1200_set_piomode, - .set_dmamode = sc1200_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - + .inherits = &ata_bmdma_port_ops, .qc_prep = ata_dumb_qc_prep, .qc_issue = sc1200_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = sc1200_set_piomode, + .set_dmamode = sc1200_set_dmamode, }; /** diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 1833e9ef522e..033d1f3a82de 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -972,6 +972,8 @@ static struct scsi_host_template scc_sht = { }; static const struct ata_port_operations scc_pata_ops = { + .inherits = &ata_bmdma_port_ops, + .set_piomode = scc_set_piomode, .set_dmamode = scc_set_dmamode, .mode_filter = scc_mode_filter, @@ -989,12 +991,7 @@ static const struct ata_port_operations scc_pata_ops = { .bmdma_status = scc_bmdma_status, .data_xfer = scc_data_xfer, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .freeze = scc_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = scc_error_handler, .post_internal_cmd = scc_bmdma_stop, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 318a36988900..627abcf85c6e 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -302,71 +302,16 @@ static struct scsi_host_template serverworks_sht = { }; static struct ata_port_operations serverworks_osb4_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = serverworks_cable_detect, + .mode_filter = serverworks_osb4_filter, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, - .mode_filter = serverworks_osb4_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = serverworks_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations serverworks_csb_port_ops = { - .set_piomode = serverworks_set_piomode, - .set_dmamode = serverworks_set_dmamode, + .inherits = &serverworks_osb4_port_ops, .mode_filter = serverworks_csb_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = serverworks_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static int serverworks_fixup_osb4(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 7812815a34c3..0936f534d9c7 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -196,36 +196,10 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = sil680_cable_detect, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = sil680_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index dcd8457a8377..3ed628670cd7 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -517,196 +517,51 @@ static struct scsi_host_template sis_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations sis_133_ops = { +static struct ata_port_operations sis_133_for_sata_ops = { + .inherits = &ata_bmdma_port_ops, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = sis_133_cable_detect, +}; - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, +static struct ata_port_operations sis_base_ops = { + .inherits = &ata_bmdma_port_ops, + .error_handler = sis_error_handler, }; -static const struct ata_port_operations sis_133_for_sata_ops = { +static struct ata_port_operations sis_133_ops = { + .inherits = &sis_base_ops, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = sis_133_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations sis_133_early_ops = { +static struct ata_port_operations sis_133_early_ops = { + .inherits = &sis_base_ops, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_133_early_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = sis_66_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations sis_100_ops = { +static struct ata_port_operations sis_100_ops = { + .inherits = &sis_base_ops, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_100_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = sis_66_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations sis_66_ops = { +static struct ata_port_operations sis_66_ops = { + .inherits = &sis_base_ops, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_66_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, .cable_detect = sis_66_cable_detect, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations sis_old_ops = { +static struct ata_port_operations sis_old_ops = { + .inherits = &sis_base_ops, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_old_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static const struct ata_port_info sis_info = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index ece366bced0c..0dd8e2f69558 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -239,37 +239,13 @@ static struct scsi_host_template sl82c105_sht = { }; static struct ata_port_operations sl82c105_port_ops = { - .set_piomode = sl82c105_set_piomode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = sl82c105_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, + .inherits = &ata_bmdma_port_ops, + .qc_defer = sl82c105_qc_defer, .bmdma_start = sl82c105_bmdma_start, .bmdma_stop = sl82c105_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_defer = sl82c105_qc_defer, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = sl82c105_set_piomode, + .error_handler = sl82c105_error_handler, }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 510569957d10..bc4956ef0931 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -184,36 +184,12 @@ static struct scsi_host_template triflex_sht = { }; static struct ata_port_operations triflex_port_ops = { - .set_piomode = triflex_set_piomode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = triflex_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, + .inherits = &ata_bmdma_port_ops, .bmdma_start = triflex_bmdma_start, .bmdma_stop = triflex_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = triflex_set_piomode, + .error_handler = triflex_error_handler, }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index a7bc860e1310..d1edb1b27480 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -339,71 +339,16 @@ static struct scsi_host_template via_sht = { }; static struct ata_port_operations via_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = via_cable_detect, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, .error_handler = via_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = via_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; static struct ata_port_operations via_port_ops_noirq = { - .set_piomode = via_set_piomode, - .set_dmamode = via_set_dmamode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = via_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = via_cable_detect, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &via_port_ops, .data_xfer = ata_data_xfer_noirq, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 9bafae9d5fe0..f235bb0d6139 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -126,29 +126,10 @@ static struct scsi_host_template winbond_sht = { }; static struct ata_port_operations winbond_port_ops = { - .set_piomode = winbond_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - + .inherits = &ata_sff_port_ops, .data_xfer = winbond_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, + .cable_detect = ata_cable_40wire, + .set_piomode = winbond_set_piomode, }; /** diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index fdf62de57cfc..a5706149af6b 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -148,26 +148,29 @@ static struct scsi_host_template adma_ata_sht = { .dma_boundary = ADMA_DMA_BOUNDARY, }; -static const struct ata_port_operations adma_ata_ops = { +static struct ata_port_operations adma_ata_ops = { + .inherits = &ata_base_port_ops, + + .dev_select = ata_std_dev_select, .tf_load = ata_tf_load, .tf_read = ata_tf_read, - .exec_command = ata_exec_command, .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .check_atapi_dma = adma_check_atapi_dma, + .exec_command = ata_exec_command, .data_xfer = ata_data_xfer, + .check_atapi_dma = adma_check_atapi_dma, + .bmdma_stop = adma_bmdma_stop, + .bmdma_status = adma_bmdma_status, .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, + .irq_on = ata_irq_on, + .freeze = adma_freeze, .thaw = adma_thaw, .error_handler = adma_error_handler, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, + .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[] = { diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index f50381b4ba06..865030ae8f8a 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1198,16 +1198,15 @@ static struct scsi_host_template sata_fsl_sht = { }; static const struct ata_port_operations sata_fsl_ops = { + .inherits = &sata_port_ops, + .check_status = sata_fsl_check_status, .check_altstatus = sata_fsl_check_status, - .dev_select = ata_noop_dev_select, .tf_read = sata_fsl_tf_read, - .qc_defer = ata_std_qc_defer, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, - .irq_clear = ata_noop_irq_clear, .scr_read = sata_fsl_scr_read, .scr_write = sata_fsl_scr_write, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index bb853df865da..047f80f5825c 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -522,26 +522,13 @@ static int inic_port_start(struct ata_port *ap) } static struct ata_port_operations inic_port_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .scr_read = inic_scr_read, - .scr_write = inic_scr_write, + .inherits = &ata_sff_port_ops, .bmdma_setup = inic_bmdma_setup, .bmdma_start = inic_bmdma_start, .bmdma_stop = inic_bmdma_stop, .bmdma_status = inic_bmdma_status, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, - .data_xfer = ata_data_xfer, .freeze = inic_freeze, .thaw = inic_thaw, @@ -549,8 +536,10 @@ static struct ata_port_operations inic_port_ops = { .post_internal_cmd = inic_post_internal_cmd, .dev_config = inic_dev_config, - .port_resume = inic_port_resume, + .scr_read = inic_scr_read, + .scr_write = inic_scr_write, + .port_resume = inic_port_resume, .port_start = inic_port_start, }; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 52d41edadb72..f341a82d27bf 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -526,23 +526,16 @@ static struct scsi_host_template mv6_sht = { .dma_boundary = MV_DMA_BOUNDARY, }; -static const struct ata_port_operations mv5_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, +static struct ata_port_operations mv5_ops = { + .inherits = &ata_sff_port_ops, .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, - .data_xfer = ata_data_xfer, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .error_handler = mv_error_handler, .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, + .error_handler = mv_error_handler, + .post_internal_cmd = ATA_OP_NULL, .scr_read = mv5_scr_read, .scr_write = mv5_scr_write, @@ -551,57 +544,18 @@ static const struct ata_port_operations mv5_ops = { .port_stop = mv_port_stop, }; -static const struct ata_port_operations mv6_ops = { - .dev_config = mv6_dev_config, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .qc_prep = mv_qc_prep, - .qc_issue = mv_qc_issue, - .data_xfer = ata_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .error_handler = mv_error_handler, - .freeze = mv_eh_freeze, - .thaw = mv_eh_thaw, +static struct ata_port_operations mv6_ops = { + .inherits = &mv5_ops, .qc_defer = ata_std_qc_defer, - + .dev_config = mv6_dev_config, .scr_read = mv_scr_read, .scr_write = mv_scr_write, - - .port_start = mv_port_start, - .port_stop = mv_port_stop, }; -static const struct ata_port_operations mv_iie_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - +static struct ata_port_operations mv_iie_ops = { + .inherits = &mv6_ops, + .dev_config = ATA_OP_NULL, .qc_prep = mv_qc_prep_iie, - .qc_issue = mv_qc_issue, - .data_xfer = ata_data_xfer, - - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, - - .error_handler = mv_error_handler, - .freeze = mv_eh_freeze, - .thaw = mv_eh_thaw, - .qc_defer = ata_std_qc_defer, - - .scr_read = mv_scr_read, - .scr_write = mv_scr_write, - - .port_start = mv_port_start, - .port_stop = mv_port_stop, }; static const struct ata_port_info mv_port_info[] = { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 9e2b4cef48f2..7b7ba0e26903 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -404,106 +404,41 @@ static struct scsi_host_template nv_swncq_sht = { .slave_configure = nv_swncq_slave_config, }; -static const struct ata_port_operations nv_generic_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, +static struct ata_port_operations nv_generic_ops = { + .inherits = &ata_bmdma_port_ops, .error_handler = nv_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, .scr_read = nv_scr_read, .scr_write = nv_scr_write, - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations nv_nf2_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .mode_filter = ata_pci_default_filter, +static struct ata_port_operations nv_nf2_ops = { + .inherits = &nv_generic_ops, .freeze = nv_nf2_freeze, .thaw = nv_nf2_thaw, - .error_handler = nv_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - .scr_read = nv_scr_read, - .scr_write = nv_scr_write, - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations nv_ck804_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .mode_filter = ata_pci_default_filter, +static struct ata_port_operations nv_ck804_ops = { + .inherits = &nv_generic_ops, .freeze = nv_ck804_freeze, .thaw = nv_ck804_thaw, - .error_handler = nv_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - .scr_read = nv_scr_read, - .scr_write = nv_scr_write, - .port_start = ata_sff_port_start, .host_stop = nv_ck804_host_stop, }; -static const struct ata_port_operations nv_adma_ops = { - .tf_load = ata_tf_load, - .tf_read = nv_adma_tf_read, +static struct ata_port_operations nv_adma_ops = { + .inherits = &nv_generic_ops, + .check_atapi_dma = nv_adma_check_atapi_dma, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, + .tf_read = nv_adma_tf_read, .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, - .mode_filter = ata_pci_default_filter, + .irq_clear = nv_adma_irq_clear, + .freeze = nv_adma_freeze, .thaw = nv_adma_thaw, .error_handler = nv_adma_error_handler, .post_internal_cmd = nv_adma_post_internal_cmd, - .data_xfer = ata_data_xfer, - .irq_clear = nv_adma_irq_clear, - .irq_on = ata_irq_on, - .scr_read = nv_scr_read, - .scr_write = nv_scr_write, + .port_start = nv_adma_port_start, .port_stop = nv_adma_port_stop, #ifdef CONFIG_PM @@ -513,29 +448,17 @@ static const struct ata_port_operations nv_adma_ops = { .host_stop = nv_adma_host_stop, }; -static const struct ata_port_operations nv_swncq_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, +static struct ata_port_operations nv_swncq_ops = { + .inherits = &nv_generic_ops, + .qc_defer = ata_std_qc_defer, .qc_prep = nv_swncq_qc_prep, .qc_issue = nv_swncq_qc_issue, - .mode_filter = ata_pci_default_filter, + .freeze = nv_mcp55_freeze, .thaw = nv_mcp55_thaw, .error_handler = nv_swncq_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_data_xfer, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - .scr_read = nv_scr_read, - .scr_write = nv_scr_write, + #ifdef CONFIG_PM .port_suspend = nv_swncq_port_suspend, .port_resume = nv_swncq_port_resume, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 37c32ab3b23b..e09b975c973d 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -160,74 +160,42 @@ static struct scsi_host_template pdc_ata_sht = { .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations pdc_sata_ops = { +static const struct ata_port_operations pdc_common_ops = { + .inherits = &ata_sff_port_ops, + .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, .check_atapi_dma = pdc_check_atapi_dma, - .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, - .freeze = pdc_sata_freeze, - .thaw = pdc_sata_thaw, - .error_handler = pdc_sata_error_handler, - .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, - .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, - .scr_read = pdc_sata_scr_read, - .scr_write = pdc_sata_scr_write, - .port_start = pdc_sata_port_start, + .post_internal_cmd = pdc_post_internal_cmd, }; -/* First-generation chips need a more restrictive ->check_atapi_dma op */ -static const struct ata_port_operations pdc_old_sata_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, - .check_atapi_dma = pdc_old_sata_check_atapi_dma, - - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, +static struct ata_port_operations pdc_sata_ops = { + .inherits = &pdc_common_ops, + .cable_detect = pdc_sata_cable_detect, .freeze = pdc_sata_freeze, .thaw = pdc_sata_thaw, .error_handler = pdc_sata_error_handler, - .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, - .data_xfer = ata_data_xfer, - .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, - .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_sata_port_start, }; -static const struct ata_port_operations pdc_pata_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, - .check_atapi_dma = pdc_check_atapi_dma, +/* First-generation chips need a more restrictive ->check_atapi_dma op */ +static struct ata_port_operations pdc_old_sata_ops = { + .inherits = &pdc_sata_ops, + .check_atapi_dma = pdc_old_sata_check_atapi_dma, +}; - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, +static struct ata_port_operations pdc_pata_ops = { + .inherits = &pdc_common_ops, + .cable_detect = pdc_pata_cable_detect, .freeze = pdc_freeze, .thaw = pdc_thaw, .error_handler = pdc_pata_error_handler, - .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_pata_cable_detect, - .data_xfer = ata_data_xfer, - .irq_clear = pdc_irq_clear, - .irq_on = ata_irq_on, - .port_start = pdc_common_port_start, }; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 2566d0926aab..107ef09814de 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -131,27 +131,25 @@ static struct scsi_host_template qs_ata_sht = { .dma_boundary = QS_DMA_BOUNDARY, }; -static const struct ata_port_operations qs_ata_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, +static struct ata_port_operations qs_ata_ops = { + .inherits = &ata_sff_port_ops, + .check_atapi_dma = qs_check_atapi_dma, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, + .bmdma_stop = qs_bmdma_stop, + .bmdma_status = qs_bmdma_status, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, - .data_xfer = ata_data_xfer, + .freeze = qs_freeze, .thaw = qs_thaw, .error_handler = qs_error_handler, - .irq_clear = ata_noop_irq_clear, - .irq_on = ata_irq_on, + .post_internal_cmd = ATA_OP_NULL, + .scr_read = qs_scr_read, .scr_write = qs_scr_write, + .port_start = qs_port_start, .host_stop = qs_host_stop, - .bmdma_stop = qs_bmdma_stop, - .bmdma_status = qs_bmdma_status, }; static const struct ata_port_info qs_port_info[] = { diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 738c1a8ae3b6..eac7ca73cfa0 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -170,31 +170,14 @@ static struct scsi_host_template sil_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations sil_ops = { +static struct ata_port_operations sil_ops = { + .inherits = &ata_bmdma_port_ops, .dev_config = sil_dev_config, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, .set_mode = sil_set_mode, - .mode_filter = ata_pci_default_filter, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, .freeze = sil_freeze, .thaw = sil_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, .scr_read = sil_scr_read, .scr_write = sil_scr_write, - .port_start = ata_sff_port_start, }; static const struct ata_port_info sil_port_info[] = { diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 7fa63950d81a..363fb90e1047 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -390,34 +390,28 @@ static struct scsi_host_template sil24_sht = { .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations sil24_ops = { - .dev_config = sil24_dev_config, +static struct ata_port_operations sil24_ops = { + .inherits = &sata_pmp_port_ops, .check_status = sil24_check_status, .check_altstatus = sil24_check_status, - .dev_select = ata_noop_dev_select, - .tf_read = sil24_tf_read, - .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, - .irq_clear = ata_noop_irq_clear, + .freeze = sil24_freeze, + .thaw = sil24_thaw, + .error_handler = sil24_error_handler, + .post_internal_cmd = sil24_post_internal_cmd, + .dev_config = sil24_dev_config, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, - .pmp_attach = sil24_pmp_attach, .pmp_detach = sil24_pmp_detach, - .freeze = sil24_freeze, - .thaw = sil24_thaw, - .error_handler = sil24_error_handler, - .post_internal_cmd = sil24_post_internal_cmd, - .port_start = sil24_port_start, - #ifdef CONFIG_PM .port_resume = sil24_port_resume, #endif diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 4becb7fde5e7..9089c7ab5000 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -89,29 +89,10 @@ static struct scsi_host_template sis_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations sis_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, +static struct ata_port_operations sis_ops = { + .inherits = &ata_bmdma_port_ops, .scr_read = sis_scr_read, .scr_write = sis_scr_write, - .port_start = ata_sff_port_start, }; static const struct ata_port_info sis_port_info = { diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index c8768396e006..8636f164256e 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -334,30 +334,16 @@ static struct scsi_host_template k2_sata_sht = { }; -static const struct ata_port_operations k2_sata_ops = { +static struct ata_port_operations k2_sata_ops = { + .inherits = &ata_bmdma_port_ops, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, .check_atapi_dma = k2_sata_check_atapi_dma, .bmdma_setup = k2_bmdma_setup_mmio, .bmdma_start = k2_bmdma_start_mmio, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, - .port_start = ata_sff_port_start, }; static const struct ata_port_info k2_port_info[] = { diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 1802f92180e4..8138cda86a66 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -241,7 +241,8 @@ static struct scsi_host_template pdc_sata_sht = { .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations pdc_20621_ops = { +/* TODO: inherit from base port_ops after converting to new EH */ +static struct ata_port_operations pdc_20621_ops = { .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 764d7064fa59..6ecd13fefa1a 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -79,34 +79,10 @@ static struct scsi_host_template uli_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations uli_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .mode_filter = ata_pci_default_filter, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - +static struct ata_port_operations uli_ops = { + .inherits = &ata_bmdma_port_ops, .scr_read = uli_scr_read, .scr_write = uli_scr_write, - - .port_start = ata_sff_port_start, }; static const struct ata_port_info uli_port_info = { diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 9be877cb7f57..6326bcf8ea5d 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -103,97 +103,23 @@ static struct scsi_host_template svia_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static const struct ata_port_operations vt6420_sata_ops = { - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - +static struct ata_port_operations vt6420_sata_ops = { + .inherits = &ata_bmdma_port_ops, .freeze = svia_noop_freeze, - .thaw = ata_bmdma_thaw, .error_handler = vt6420_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations vt6421_pata_ops = { +static struct ata_port_operations vt6421_pata_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = vt6421_pata_cable_detect, .set_piomode = vt6421_set_pio_mode, .set_dmamode = vt6421_set_dma_mode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = vt6421_pata_cable_detect, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, }; -static const struct ata_port_operations vt6421_sata_ops = { - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - +static struct ata_port_operations vt6421_sata_ops = { + .inherits = &ata_bmdma_port_ops, .scr_read = svia_scr_read, .scr_write = svia_scr_write, - - .port_start = ata_sff_port_start, }; static const struct ata_port_info vt6420_port_info = { diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index fd6855f0bf48..8045a72dc559 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -304,29 +304,14 @@ static struct scsi_host_template vsc_sata_sht = { }; -static const struct ata_port_operations vsc_sata_ops = { +static struct ata_port_operations vsc_sata_ops = { + .inherits = &ata_bmdma_port_ops, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, - .exec_command = ata_exec_command, - .check_status = ata_check_status, - .dev_select = ata_std_dev_select, - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - .mode_filter = ata_pci_default_filter, .freeze = vsc_freeze, .thaw = vsc_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, - .port_start = ata_sff_port_start, }; static void __devinit vsc_sata_setup_port(struct ata_ioports *port, diff --git a/include/linux/libata.h b/include/linux/libata.h index eccc38e17568..46aa4ab64891 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -433,7 +433,7 @@ struct ata_host { void __iomem * const *iomap; unsigned int n_ports; void *private_data; - const struct ata_port_operations *ops; + struct ata_port_operations *ops; unsigned long flags; #ifdef CONFIG_ATA_ACPI acpi_handle acpi_handle; @@ -602,7 +602,7 @@ struct ata_link { struct ata_port { struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ - const struct ata_port_operations *ops; + struct ata_port_operations *ops; spinlock_t *lock; unsigned long flags; /* ATA_FLAG_xxx */ unsigned int pflags; /* ATA_PFLAG_xxx */ @@ -664,6 +664,13 @@ struct ata_port { u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ }; +/* The following initializer overrides a method to NULL whether one of + * its parent has the method defined or not. This is equivalent to + * ERR_PTR(-ENOENT). Unfortunately, ERR_PTR doesn't render a constant + * expression and thus can't be used as an initializer. + */ +#define ATA_OP_NULL (void *)(unsigned long)(-ENOENT) + struct ata_port_operations { /* * Command execution @@ -733,6 +740,12 @@ struct ata_port_operations { void (*phy_reset)(struct ata_port *ap); void (*eng_timeout)(struct ata_port *ap); irq_handler_t irq_handler; + + /* + * ->inherits must be the last field and all the preceding + * fields must be pointers. + */ + const struct ata_port_operations *inherits; }; struct ata_port_info { @@ -742,7 +755,7 @@ struct ata_port_info { unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; - const struct ata_port_operations *port_ops; + struct ata_port_operations *port_ops; irq_handler_t irq_handler; void *private_data; }; @@ -765,7 +778,7 @@ extern const unsigned long sata_deb_timing_normal[]; extern const unsigned long sata_deb_timing_hotplug[]; extern const unsigned long sata_deb_timing_long[]; -extern const struct ata_port_operations ata_dummy_port_ops; +extern struct ata_port_operations ata_dummy_port_ops; extern const struct ata_port_info ata_dummy_port_info; static inline const unsigned long * @@ -812,7 +825,7 @@ extern int ata_host_activate(struct ata_host *host, int irq, struct scsi_host_template *sht); extern void ata_host_detach(struct ata_host *host); extern void ata_host_init(struct ata_host *, struct device *, - unsigned long, const struct ata_port_operations *); + unsigned long, struct ata_port_operations *); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -- cgit v1.2.3 From 1bd5b715a305f6f13455e89becbd839010dd14b5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:49 +0900 Subject: libata: make ata_pci_init_one() not use ops->irq_handler and pi->sht ata_pci_init_one() is the only function which uses ops->irq_handler and pi->sht. Other initialization functions take the same information as arguments. This causes confusion and duplicate unused entries in structures. Make ata_pci_init_one() take sht as an argument and use ata_interrupt implicitly. All current users use ata_interrupt and if different irq handler is necessary open coding ata_pci_init_one() using ata_prepare_sff_host() and ata_activate_sff_host can be done under ten lines including error handling and driver which requires custom interrupt handler is likely to require custom initialization anyway. As ata_pci_init_one() was the last user of ops->irq_handler, this patch also kills the field. Signed-off-by: Tejun Heo --- drivers/ata/ata_generic.c | 3 +-- drivers/ata/libata-core.c | 1 - drivers/ata/libata-sff.c | 7 ++++--- drivers/ata/pata_acpi.c | 3 +-- drivers/ata/pata_ali.c | 9 +-------- drivers/ata/pata_amd.c | 12 +----------- drivers/ata/pata_artop.c | 6 +----- drivers/ata/pata_atiixp.c | 3 +-- drivers/ata/pata_cmd640.c | 3 +-- drivers/ata/pata_cmd64x.c | 8 +------- drivers/ata/pata_cs5530.c | 4 +--- drivers/ata/pata_cs5535.c | 3 +-- drivers/ata/pata_cs5536.c | 3 +-- drivers/ata/pata_cypress.c | 3 +-- drivers/ata/pata_efar.c | 3 +-- drivers/ata/pata_hpt366.c | 3 +-- drivers/ata/pata_hpt37x.c | 8 +------- drivers/ata/pata_hpt3x2n.c | 3 +-- drivers/ata/pata_it8213.c | 3 +-- drivers/ata/pata_it821x.c | 4 +--- drivers/ata/pata_jmicron.c | 3 +-- drivers/ata/pata_marvell.c | 4 +--- drivers/ata/pata_netcell.c | 3 +-- drivers/ata/pata_ns87410.c | 3 +-- drivers/ata/pata_ns87415.c | 4 +--- drivers/ata/pata_oldpiix.c | 3 +-- drivers/ata/pata_opti.c | 3 +-- drivers/ata/pata_optidma.c | 4 +--- drivers/ata/pata_pdc202xx_old.c | 5 +---- drivers/ata/pata_radisys.c | 3 +-- drivers/ata/pata_rz1000.c | 3 +-- drivers/ata/pata_sc1200.c | 3 +-- drivers/ata/pata_serverworks.c | 6 +----- drivers/ata/pata_sil680.c | 4 +--- drivers/ata/pata_sis.c | 10 +--------- drivers/ata/pata_sl82c105.c | 4 +--- drivers/ata/pata_triflex.c | 3 +-- drivers/ata/pata_via.c | 8 +------- include/linux/libata.h | 4 ++-- 39 files changed, 42 insertions(+), 130 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 0b5b515ae159..a912ee01a47c 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -120,7 +120,6 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id { u16 command; static const struct ata_port_info info = { - .sht = &generic_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -153,7 +152,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id if (dev->vendor == PCI_VENDOR_ID_AL) ata_pci_clear_simplex(dev); - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &generic_sht); } static struct pci_device_id ata_generic[] = { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 32fa9ee397b6..abbe3229480c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -109,7 +109,6 @@ const struct ata_port_operations ata_sff_port_ops = { .irq_on = ata_irq_on, .port_start = ata_sff_port_start, - .irq_handler = ata_interrupt, }; const struct ata_port_operations ata_bmdma_port_ops = { diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 1cf03d41aa33..a9d5898cbbc4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -826,6 +826,7 @@ int ata_pci_activate_sff_host(struct ata_host *host, * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized * @ppi: array of port_info, must be enough for two ports + * @sht: scsi_host_template to use when registering the host * * This is a helper function which can be called from a driver's * xxx_init_one() probe function if the hardware uses traditional @@ -846,7 +847,8 @@ int ata_pci_activate_sff_host(struct ata_host *host, * Zero on success, negative on errno-based value on error. */ int ata_pci_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi) + const struct ata_port_info * const * ppi, + struct scsi_host_template *sht) { struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; @@ -882,8 +884,7 @@ int ata_pci_init_one(struct pci_dev *pdev, goto out; pci_set_master(pdev); - rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler, - pi->sht); + rc = ata_pci_activate_sff_host(host, ata_interrupt, sht); out: if (rc == 0) devres_remove_group(&pdev->dev, NULL); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 35ad488db6ed..3edde51750da 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -264,7 +264,6 @@ static struct ata_port_operations pacpi_ops = { static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &pacpi_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, @@ -274,7 +273,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &pacpi_ops, }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &pacpi_sht); } static const struct pci_device_id pacpi_pci_tbl[] = { diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index b00a9cf72c31..f2924996f6e3 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -463,14 +463,12 @@ static void ali_init_chipset(struct pci_dev *pdev) static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info_early = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &ali_early_port_ops }; /* Revision 0x20 added DMA */ static const struct ata_port_info info_20 = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -478,7 +476,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Revision 0x20 with support logic added UDMA */ static const struct ata_port_info info_20_udma = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -487,7 +484,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Revision 0xC2 adds UDMA66 */ static const struct ata_port_info info_c2 = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -496,7 +492,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Revision 0xC3 is UDMA66 for now */ static const struct ata_port_info info_c3 = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -505,7 +500,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Revision 0xC4 is UDMA100 */ static const struct ata_port_info info_c4 = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -514,7 +508,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Revision 0xC5 is UDMA133 with LBA48 DMA */ static const struct ata_port_info info_c5 = { - .sht = &ali_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -559,7 +552,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[0] = &info_20_udma; pci_dev_put(isa_bridge); } - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &ali_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index b0cb4eaf273c..644702cac6ee 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -413,7 +413,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info[10] = { { /* 0: AMD 7401 */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, /* No SWDMA */ @@ -421,7 +420,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd33_port_ops }, { /* 1: Early AMD7409 - no swdma */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -429,7 +427,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd66_port_ops }, { /* 2: AMD 7409, no swdma errata */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -437,7 +434,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd66_port_ops }, { /* 3: AMD 7411 */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -445,7 +441,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd100_port_ops }, { /* 4: AMD 7441 */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -453,7 +448,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd100_port_ops }, { /* 5: AMD 8111*/ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -461,7 +455,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd133_port_ops }, { /* 6: AMD 8111 UDMA 100 (Serenade) */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -469,7 +462,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd133_port_ops }, { /* 7: Nvidia Nforce */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -477,7 +469,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &nv100_port_ops }, { /* 8: Nvidia Nforce2 and later */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -485,7 +476,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &nv133_port_ops }, { /* 9: AMD CS5536 (Geode companion) */ - .sht = &amd_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -544,7 +534,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* And fire it up */ - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &amd_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 0101e5aef3e0..698a53c96111 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -352,7 +352,6 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { static int printed_version; static const struct ata_port_info info_6210 = { - .sht = &artop_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -360,7 +359,6 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &artop6210_ops, }; static const struct ata_port_info info_626x = { - .sht = &artop_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -368,7 +366,6 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &artop6260_ops, }; static const struct ata_port_info info_628x = { - .sht = &artop_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -376,7 +373,6 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &artop6260_ops, }; static const struct ata_port_info info_628x_fast = { - .sht = &artop_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -434,7 +430,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) BUG_ON(ppi[0] == NULL); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &artop_sht); } static const struct pci_device_id artop_pci_tbl[] = { diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 2655f6a17ad3..6fe433ba62bd 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -241,7 +241,6 @@ static struct ata_port_operations atiixp_port_ops = { static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &atiixp_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x06, /* No MWDMA0 support */ @@ -249,7 +248,7 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &atiixp_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &atiixp_sht); } static const struct pci_device_id atiixp[] = { diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 061c891c8a66..efd2bb5747b4 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -211,7 +211,6 @@ static void cmd640_hardware_init(struct pci_dev *pdev) static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &cmd640_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &cmd640_port_ops @@ -225,7 +224,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) cmd640_hardware_init(pdev); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &cmd640_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 1ac8ecfb97e2..bfd72ef9cd31 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -298,21 +298,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static const struct ata_port_info cmd_info[6] = { { /* CMD 643 - no UDMA */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &cmd64x_port_ops }, { /* CMD 646 with broken UDMA */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &cmd64x_port_ops }, { /* CMD 646 with working UDMA */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -320,14 +317,12 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &cmd64x_port_ops }, { /* CMD 646 rev 1 */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &cmd646r1_port_ops }, { /* CMD 648 */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -335,7 +330,6 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &cmd648_port_ops }, { /* CMD 649 */ - .sht = &cmd64x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -379,7 +373,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_write_config_byte(pdev, UDIDETCR0, 0xF0); #endif - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &cmd64x_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index e4a16a578cac..c632ce499d33 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -298,7 +298,6 @@ fail_put: static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &cs5530_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -307,7 +306,6 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* The docking connector doesn't do UDMA, and it seems not MWDMA */ static const struct ata_port_info info_palmax_secondary = { - .sht = &cs5530_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &cs5530_port_ops @@ -327,7 +325,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[1] = &info_palmax_secondary; /* Now kick off ATA set up */ - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &cs5530_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index f910a8aa7437..d78cf95cbe45 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -181,7 +181,6 @@ static struct ata_port_operations cs5535_port_ops = { static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &cs5535_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -200,7 +199,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) rdmsr(ATAC_CH0D1_PIO, timings, dummy); if (CS5535_BAD_PIO(timings)) wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0); - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &cs5535_sht); } static const struct pci_device_id cs5535[] = { diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 075ee6a7be39..f7c0e4e319ed 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -241,7 +241,6 @@ static struct ata_port_operations cs5536_port_ops = { static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &cs5536_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -262,7 +261,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &cs5536_sht); } static const struct pci_device_id cs5536[] = { diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index c459553e7d1e..cbd6670ea0de 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -123,7 +123,6 @@ static struct ata_port_operations cy82c693_port_ops = { static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &cy82c693_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -137,7 +136,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i if (PCI_FUNC(pdev->devfn) != 1) return -ENODEV; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &cy82c693_sht); } static const struct pci_device_id cy82c693[] = { diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index ef62fc642c17..0260edac2370 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -263,7 +263,6 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; static const struct ata_port_info info = { - .sht = &efar_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma1-2 */ @@ -276,7 +275,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &efar_sht); } static const struct pci_device_id efar_pci_tbl[] = { diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 788955f57ff8..b62d398ed84b 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -350,7 +350,6 @@ static void hpt36x_init_chipset(struct pci_dev *dev) static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info_hpt366 = { - .sht = &hpt36x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -394,7 +393,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &hpt36x_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c42eec70d297..a43c19753669 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -783,7 +783,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* HPT370 - UDMA100 */ static const struct ata_port_info info_hpt370 = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -792,7 +791,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; /* HPT370A - UDMA100 */ static const struct ata_port_info info_hpt370a = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -801,7 +799,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; /* HPT370 - UDMA100 */ static const struct ata_port_info info_hpt370_33 = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -810,7 +807,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; /* HPT370A - UDMA100 */ static const struct ata_port_info info_hpt370a_33 = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -819,7 +815,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; /* HPT371, 372 and friends - UDMA133 */ static const struct ata_port_info info_hpt372 = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -828,7 +823,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; /* HPT374 - UDMA100 */ static const struct ata_port_info info_hpt374 = { - .sht = &hpt37x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -1051,7 +1045,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) port_info = *port; port_info.private_data = private_data; - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &hpt37x_sht); } static const struct pci_device_id hpt37x[] = { diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index b77b1279d757..2c178c30116c 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -452,7 +452,6 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* HPT372N and friends - UDMA133 */ static const struct ata_port_info info = { - .sht = &hpt3x2n_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -568,7 +567,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &hpt3x2n_sht); } static const struct pci_device_id hpt3x2n[] = { diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 9ce89522e764..291a0d6e2434 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -274,7 +274,6 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en { static int printed_version; static const struct ata_port_info info = { - .sht = &it8213_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -288,7 +287,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &it8213_sht); } static const struct pci_device_id it8213_pci_tbl[] = { diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 669d224d30ca..63c5cf0d1fee 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -687,14 +687,12 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) u8 conf; static const struct ata_port_info info_smart = { - .sht = &it821x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &it821x_smart_port_ops }; static const struct ata_port_info info_passthru = { - .sht = &it821x_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -724,7 +722,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) else ppi[0] = &info_smart; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &it821x_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 61ff5c6b4568..859e47a600cc 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -148,7 +148,6 @@ static struct ata_port_operations jmicron_ops = { static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &jmicron_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, @@ -159,7 +158,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &jmicron_sht); } static const struct pci_device_id jmicron_pci_tbl[] = { diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 286310fc5910..d8da4f344c0a 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -119,7 +119,6 @@ static struct ata_port_operations marvell_ops = { static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &marvell_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, @@ -129,7 +128,6 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i .port_ops = &marvell_ops, }; static const struct ata_port_info info_sata = { - .sht = &marvell_sht, /* Slave possible as its magically mapped not real */ .flags = ATA_FLAG_SLAVE_POSS, @@ -144,7 +142,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i if (pdev->device == 0x6101) ppi[1] = &ata_dummy_port_info; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &marvell_sht); } static const struct pci_device_id marvell_pci_tbl[] = { diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 65389d1837b3..ae50a5e85cf1 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -48,7 +48,6 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e { static int printed_version; static const struct ata_port_info info = { - .sht = &netcell_sht, .flags = ATA_FLAG_SLAVE_POSS, /* Actually we don't really care about these as the firmware deals with it */ @@ -72,7 +71,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e ata_pci_clear_simplex(pdev); /* And let the library code do the work */ - return ata_pci_init_one(pdev, port_info); + return ata_pci_init_one(pdev, port_info, &netcell_sht); } static const struct pci_device_id netcell_pci_tbl[] = { diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 5b1982fa0be1..1bdca8f1e767 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -158,13 +158,12 @@ static struct ata_port_operations ns87410_port_ops = { static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &ns87410_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x0F, .port_ops = &ns87410_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &ns87410_sht); } static const struct pci_device_id ns87410[] = { diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 38d86a262dbb..42508940e4a9 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -345,7 +345,6 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e { static int printed_version; static const struct ata_port_info info = { - .sht = &ns87415_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -355,7 +354,6 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e int rc; #if defined(CONFIG_SUPERIO) static const struct ata_port_info info87560 = { - .sht = &ns87415_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -377,7 +375,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e pci_write_config_byte(pdev, 0x55, 0xEE); /* Select PIO0 8bit clocking */ pci_write_config_byte(pdev, 0x54, 0xB7); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &ns87415_sht); } static const struct pci_device_id ns87415_pci_tbl[] = { diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index f6062b37310d..9e3afadbd04a 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -252,7 +252,6 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e { static int printed_version; static const struct ata_port_info info = { - .sht = &oldpiix_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma1-2 */ @@ -264,7 +263,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &oldpiix_sht); } static const struct pci_device_id oldpiix_pci_tbl[] = { diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index c4a0795c3ff4..8601d9c3cb39 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -178,7 +178,6 @@ static struct ata_port_operations opti_port_ops = { static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &opti_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &opti_port_ops @@ -189,7 +188,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &opti_sht); } static const struct pci_device_id opti[] = { diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index eb4b08190e3a..c376f9ef77c8 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -414,14 +414,12 @@ done_nomsg: /* Wrong chip revision */ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info_82c700 = { - .sht = &optidma_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &optidma_port_ops }; static const struct ata_port_info info_82c700_udma = { - .sht = &optidma_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -447,7 +445,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (optiplus_with_udma(dev)) ppi[0] = &info_82c700_udma; - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &optidma_sht); } static const struct pci_device_id optidma[] = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 4daac20df0bc..5545fbab6a7e 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -290,7 +290,6 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id { static const struct ata_port_info info[3] = { { - .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -298,7 +297,6 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id .port_ops = &pdc2024x_port_ops }, { - .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -306,7 +304,6 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id .port_ops = &pdc2026x_port_ops }, { - .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -327,7 +324,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id return -ENODEV; } } - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &pdc202xx_sht); } static const struct pci_device_id pdc202xx[] = { diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 94e60b3a1ec6..145d5ba92795 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -216,7 +216,6 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e { static int printed_version; static const struct ata_port_info info = { - .sht = &radisys_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma1-2 */ @@ -229,7 +228,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &radisys_sht); } static const struct pci_device_id radisys_pci_tbl[] = { diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index a2aef7328bfc..04be6aee4354 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -89,7 +89,6 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en { static int printed_version; static const struct ata_port_info info = { - .sht = &rz1000_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &rz1000_port_ops @@ -100,7 +99,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &rz1000_sht); printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); /* Not safe to use so skip */ diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 362b7f829d8e..38c7fb0bebe9 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -204,7 +204,6 @@ static struct ata_port_operations sc1200_port_ops = { static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &sc1200_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -214,7 +213,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* Can't enable port 2 yet, see top comments */ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &sc1200_sht); } static const struct pci_device_id sc1200[] = { diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 627abcf85c6e..515b5b70a555 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -399,28 +399,24 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id { static const struct ata_port_info info[4] = { { /* OSB4 */ - .sht = &serverworks_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x07, .port_ops = &serverworks_osb4_port_ops }, { /* OSB4 no UDMA */ - .sht = &serverworks_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x00, .port_ops = &serverworks_osb4_port_ops }, { /* CSB5 */ - .sht = &serverworks_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA4, .port_ops = &serverworks_csb_port_ops }, { /* CSB5 - later revisions*/ - .sht = &serverworks_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -465,7 +461,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ata_pci_clear_simplex(pdev); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &serverworks_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 0936f534d9c7..5313deeffa6d 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -282,7 +282,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &sil680_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -290,7 +289,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, .port_ops = &sil680_port_ops }; static const struct ata_port_info info_slow = { - .sht = &sil680_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -364,7 +362,7 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, &sil680_sht); use_ioports: - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &sil680_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 3ed628670cd7..32be13ba5f06 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -565,7 +565,6 @@ static struct ata_port_operations sis_old_ops = { }; static const struct ata_port_info sis_info = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, @@ -573,7 +572,6 @@ static const struct ata_port_info sis_info = { .port_ops = &sis_old_ops, }; static const struct ata_port_info sis_info33 = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, @@ -581,42 +579,36 @@ static const struct ata_port_info sis_info33 = { .port_ops = &sis_old_ops, }; static const struct ata_port_info sis_info66 = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA4, /* UDMA 66 */ .port_ops = &sis_66_ops, }; static const struct ata_port_info sis_info100 = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA5, .port_ops = &sis_100_ops, }; static const struct ata_port_info sis_info100_early = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .udma_mask = ATA_UDMA5, .pio_mask = 0x1f, /* pio0-4 */ .port_ops = &sis_66_ops, }; static const struct ata_port_info sis_info133 = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &sis_133_ops, }; const struct ata_port_info sis_info133_for_sata = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &sis_133_for_sata_ops, }; static const struct ata_port_info sis_info133_early = { - .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -844,7 +836,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) sis_fixup(pdev, chipset); - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &sis_sht); } static const struct pci_device_id sis_pci_tbl[] = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 0dd8e2f69558..2d14b2505c7d 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -289,14 +289,12 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev) static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info_dma = { - .sht = &sl82c105_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &sl82c105_port_ops }; static const struct ata_port_info info_early = { - .sht = &sl82c105_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &sl82c105_port_ops @@ -325,7 +323,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; pci_write_config_dword(dev, 0x40, val); - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &sl82c105_sht); } static const struct pci_device_id sl82c105[] = { diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bc4956ef0931..86dc66c37389 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -195,7 +195,6 @@ static struct ata_port_operations triflex_port_ops = { static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static const struct ata_port_info info = { - .sht = &triflex_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -207,7 +206,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi); + return ata_pci_init_one(dev, ppi, &triflex_sht); } static const struct pci_device_id triflex[] = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index d1edb1b27480..e66bb85ad3d1 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -398,7 +398,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { /* Early VIA without UDMA support */ static const struct ata_port_info via_mwdma_info = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -406,7 +405,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* Ditto with IRQ masking required */ static const struct ata_port_info via_mwdma_info_borked = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -414,7 +412,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* VIA UDMA 33 devices (and borked 66) */ static const struct ata_port_info via_udma33_info = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -423,7 +420,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* VIA UDMA 66 devices */ static const struct ata_port_info via_udma66_info = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -432,7 +428,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* VIA UDMA 100 devices */ static const struct ata_port_info via_udma100_info = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -441,7 +436,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; /* UDMA133 with bad AST (All current 133) */ static const struct ata_port_info via_udma133_info = { - .sht = &via_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -532,7 +526,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* We have established the device type, now fire it up */ type.private_data = (void *)config; - return ata_pci_init_one(pdev, ppi); + return ata_pci_init_one(pdev, ppi, &via_sht); } #ifdef CONFIG_PM diff --git a/include/linux/libata.h b/include/linux/libata.h index 46aa4ab64891..5494119854de 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -739,7 +739,6 @@ struct ata_port_operations { */ void (*phy_reset)(struct ata_port *ap); void (*eng_timeout)(struct ata_port *ap); - irq_handler_t irq_handler; /* * ->inherits must be the last field and all the preceding @@ -1020,7 +1019,8 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap, struct pci_dev; extern int ata_pci_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi); + const struct ata_port_info * const * ppi, + struct scsi_host_template *sht); extern void ata_pci_remove_one(struct pci_dev *pdev); #ifdef CONFIG_PM extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -- cgit v1.2.3 From 887125e3740283be25564bfc6fb5d24974b651ab Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:49 +0900 Subject: libata: stop overloading port_info->private_data port_info->private_data is currently used for two purposes - to record private data about the port_info or to specify host->private_data to use when allocating ata_host. This overloading is confusing and counter-intuitive in that port_info->private_data becomes host->private_data instead of port->private_data. In addition, port_info and host don't correspond to each other 1-to-1. Currently, the first non-NULL port_info->private_data is used. This patch makes port_info->private_data just be what it is - private_data for the port_info where LLD can jot down extra info. libata no longer sets host->private_data to the first non-NULL port_info->private_data, @host_priv argument is added to ata_pci_init_one() instead. LLDs which use ata_pci_init_one() can use this argument to pass in pointer to host private data. LLDs which don't should use init-register model anyway and can initialize host->private_data directly. Adding @host_priv instead of using init-register model for LLDs which use ata_pci_init_one() is suggested by Alan Cox. Signed-off-by: Tejun Heo Cc: Alan Cox --- drivers/ata/ata_generic.c | 2 +- drivers/ata/libata-core.c | 2 -- drivers/ata/libata-sff.c | 4 +++- drivers/ata/pata_acpi.c | 18 ++---------------- drivers/ata/pata_ali.c | 2 +- drivers/ata/pata_amd.c | 27 +++++++-------------------- drivers/ata/pata_artop.c | 2 +- drivers/ata/pata_atiixp.c | 2 +- drivers/ata/pata_cmd640.c | 2 +- drivers/ata/pata_cmd64x.c | 2 +- drivers/ata/pata_cs5530.c | 2 +- drivers/ata/pata_cs5535.c | 2 +- drivers/ata/pata_cs5536.c | 2 +- drivers/ata/pata_cypress.c | 2 +- drivers/ata/pata_efar.c | 2 +- drivers/ata/pata_hpt366.c | 12 ++++++------ drivers/ata/pata_hpt37x.c | 33 ++++++++++++++------------------- drivers/ata/pata_hpt3x2n.c | 9 ++++----- drivers/ata/pata_it8213.c | 2 +- drivers/ata/pata_it821x.c | 2 +- drivers/ata/pata_jmicron.c | 18 ++---------------- drivers/ata/pata_marvell.c | 18 ++---------------- drivers/ata/pata_netcell.c | 2 +- drivers/ata/pata_ns87410.c | 2 +- drivers/ata/pata_ns87415.c | 2 +- drivers/ata/pata_oldpiix.c | 2 +- drivers/ata/pata_opti.c | 2 +- drivers/ata/pata_optidma.c | 2 +- drivers/ata/pata_pdc202xx_old.c | 2 +- drivers/ata/pata_radisys.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_sc1200.c | 2 +- drivers/ata/pata_serverworks.c | 2 +- drivers/ata/pata_sil680.c | 2 +- drivers/ata/pata_sis.c | 8 +++----- drivers/ata/pata_sl82c105.c | 2 +- drivers/ata/pata_triflex.c | 2 +- drivers/ata/pata_via.c | 19 ++++++++----------- include/linux/libata.h | 2 +- 39 files changed, 79 insertions(+), 145 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index a912ee01a47c..b23e2a1099c5 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -152,7 +152,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id if (dev->vendor == PCI_VENDOR_ID_AL) ata_pci_clear_simplex(dev); - return ata_pci_init_one(dev, ppi, &generic_sht); + return ata_pci_init_one(dev, ppi, &generic_sht, NULL); } static struct pci_device_id ata_generic[] = { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index abbe3229480c..aa6bcd79d60a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6995,8 +6995,6 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) host->ops = pi->port_ops; - if (!host->private_data && pi->private_data) - host->private_data = pi->private_data; } return host; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index a9d5898cbbc4..6223ec042c80 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -827,6 +827,7 @@ int ata_pci_activate_sff_host(struct ata_host *host, * @pdev: Controller to be initialized * @ppi: array of port_info, must be enough for two ports * @sht: scsi_host_template to use when registering the host + * @host_priv: host private_data * * This is a helper function which can be called from a driver's * xxx_init_one() probe function if the hardware uses traditional @@ -848,7 +849,7 @@ int ata_pci_activate_sff_host(struct ata_host *host, */ int ata_pci_init_one(struct pci_dev *pdev, const struct ata_port_info * const * ppi, - struct scsi_host_template *sht) + struct scsi_host_template *sht, void *host_priv) { struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; @@ -882,6 +883,7 @@ int ata_pci_init_one(struct pci_dev *pdev, rc = ata_pci_prepare_sff_host(pdev, ppi, &host); if (rc) goto out; + host->private_data = host_priv; pci_set_master(pdev); rc = ata_pci_activate_sff_host(host, ata_interrupt, sht); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 3edde51750da..d337f3209caf 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -67,20 +67,6 @@ static int pacpi_cable_detect(struct ata_port *ap) return ATA_CBL_PATA40; } -/** - * pacpi_error_handler - Setup and error handler - * @ap: Port to handle - * - * LOCKING: - * None (inherited from caller). - */ - -static void pacpi_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, NULL, - ata_std_postreset); -} - /** * pacpi_discover_modes - filter non ACPI modes * @adev: ATA device @@ -242,7 +228,7 @@ static struct ata_port_operations pacpi_ops = { .mode_filter = pacpi_mode_filter, .set_piomode = pacpi_set_piomode, .set_dmamode = pacpi_set_dmamode, - .error_handler = pacpi_error_handler, + .prereset = pacpi_pre_reset, .port_start = pacpi_port_start, }; @@ -273,7 +259,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &pacpi_ops, }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi, &pacpi_sht); + return ata_pci_init_one(pdev, ppi, &pacpi_sht, NULL); } static const struct pci_device_id pacpi_pci_tbl[] = { diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index f2924996f6e3..43c558f20f92 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -552,7 +552,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[0] = &info_20_udma; pci_dev_put(isa_bridge); } - return ata_pci_init_one(pdev, ppi, &ali_sht); + return ata_pci_init_one(pdev, ppi, &ali_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 644702cac6ee..09c8286b6890 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -144,12 +144,6 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -static void amd_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, amd_pre_reset, ata_std_softreset, NULL, - ata_std_postreset); -} - static int amd_cable_detect(struct ata_port *ap) { static const u32 bitmask[2] = {0x03, 0x0C}; @@ -300,13 +294,6 @@ static int nv_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -static void nv_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, nv_pre_reset, - ata_std_softreset, NULL, - ata_std_postreset); -} - /** * nv100_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -358,7 +345,7 @@ static struct scsi_host_template amd_sht = { static const struct ata_port_operations amd_base_port_ops = { .inherits = &ata_bmdma_port_ops, - .error_handler = amd_error_handler, + .prereset = amd_pre_reset, }; static struct ata_port_operations amd33_port_ops = { @@ -393,7 +380,7 @@ static const struct ata_port_operations nv_base_port_ops = { .inherits = &ata_bmdma_port_ops, .cable_detect = ata_cable_ignore, .mode_filter = nv_mode_filter, - .error_handler = nv_error_handler, + .prereset = nv_pre_reset, .host_stop = nv_host_stop, }; @@ -483,10 +470,10 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd100_port_ops } }; - struct ata_port_info pi; - const struct ata_port_info *ppi[] = { &pi, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; static int printed_version; int type = id->driver_data; + void *hpriv = NULL; u8 fifo; int rc; @@ -511,7 +498,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* * Okay, type is determined now. Apply type-specific workarounds. */ - pi = info[type]; + ppi[0] = &info[type]; if (type < 3) ata_pci_clear_simplex(pdev); @@ -530,11 +517,11 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) u32 udma; pci_read_config_dword(pdev, 0x60, &udma); - pi.private_data = (void *)(unsigned long)udma; + hpriv = (void *)(unsigned long)udma; } /* And fire it up */ - return ata_pci_init_one(pdev, ppi, &amd_sht); + return ata_pci_init_one(pdev, ppi, &amd_sht, hpriv); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 698a53c96111..ebd15cadf15f 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -430,7 +430,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) BUG_ON(ppi[0] == NULL); - return ata_pci_init_one(pdev, ppi, &artop_sht); + return ata_pci_init_one(pdev, ppi, &artop_sht, NULL); } static const struct pci_device_id artop_pci_tbl[] = { diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 6fe433ba62bd..0bea7e75d2d6 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -248,7 +248,7 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &atiixp_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi, &atiixp_sht); + return ata_pci_init_one(dev, ppi, &atiixp_sht, NULL); } static const struct pci_device_id atiixp[] = { diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index efd2bb5747b4..27219b00edf4 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -224,7 +224,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) cmd640_hardware_init(pdev); - return ata_pci_init_one(pdev, ppi, &cmd640_sht); + return ata_pci_init_one(pdev, ppi, &cmd640_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index bfd72ef9cd31..f0e566623614 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -373,7 +373,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_write_config_byte(pdev, UDIDETCR0, 0xF0); #endif - return ata_pci_init_one(pdev, ppi, &cmd64x_sht); + return ata_pci_init_one(pdev, ppi, &cmd64x_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index c632ce499d33..ac3ad55d7c3c 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -325,7 +325,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[1] = &info_palmax_secondary; /* Now kick off ATA set up */ - return ata_pci_init_one(pdev, ppi, &cs5530_sht); + return ata_pci_init_one(pdev, ppi, &cs5530_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index d78cf95cbe45..5c0762ebf58c 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -199,7 +199,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) rdmsr(ATAC_CH0D1_PIO, timings, dummy); if (CS5535_BAD_PIO(timings)) wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0); - return ata_pci_init_one(dev, ppi, &cs5535_sht); + return ata_pci_init_one(dev, ppi, &cs5535_sht, NULL); } static const struct pci_device_id cs5535[] = { diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index f7c0e4e319ed..2d34b9145dcb 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -261,7 +261,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - return ata_pci_init_one(dev, ppi, &cs5536_sht); + return ata_pci_init_one(dev, ppi, &cs5536_sht, NULL); } static const struct pci_device_id cs5536[] = { diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index cbd6670ea0de..ae14969e1dfe 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -136,7 +136,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i if (PCI_FUNC(pdev->devfn) != 1) return -ENODEV; - return ata_pci_init_one(pdev, ppi, &cy82c693_sht); + return ata_pci_init_one(pdev, ppi, &cy82c693_sht, NULL); } static const struct pci_device_id cy82c693[] = { diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 0260edac2370..2f5b4848456a 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -275,7 +275,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &efar_sht); + return ata_pci_init_one(pdev, ppi, &efar_sht, NULL); } static const struct pci_device_id efar_pci_tbl[] = { diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index b62d398ed84b..c2d4923d4db7 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -356,9 +356,9 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA4, .port_ops = &hpt366_port_ops }; - struct ata_port_info info = info_hpt366; - const struct ata_port_info *ppi[] = { &info, NULL }; + const struct ata_port_info *ppi[] = { &info_hpt366, NULL }; + void *hpriv = NULL; u32 class_rev; u32 reg1; int rc; @@ -383,17 +383,17 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* info_hpt366 is safe against re-entry so we can scribble on it */ switch((reg1 & 0x700) >> 8) { case 5: - info.private_data = &hpt366_40; + hpriv = &hpt366_40; break; case 9: - info.private_data = &hpt366_25; + hpriv = &hpt366_25; break; default: - info.private_data = &hpt366_33; + hpriv = &hpt366_33; break; } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi, &hpt36x_sht); + return ata_pci_init_one(dev, ppi, &hpt36x_sht, hpriv); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index a43c19753669..fb37e3a161fc 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -831,10 +831,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; static const int MHz[4] = { 33, 40, 50, 66 }; - const struct ata_port_info *port; void *private_data = NULL; - struct ata_port_info port_info; - const struct ata_port_info *ppi[] = { &port_info, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; u8 irqmask; u32 class_rev; @@ -866,17 +864,17 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) switch(class_rev) { case 3: - port = &info_hpt370; + ppi[0] = &info_hpt370; chip_table = &hpt370; prefer_dpll = 0; break; case 4: - port = &info_hpt370a; + ppi[0] = &info_hpt370a; chip_table = &hpt370a; prefer_dpll = 0; break; case 5: - port = &info_hpt372; + ppi[0] = &info_hpt372; chip_table = &hpt372; break; default: @@ -889,21 +887,21 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* 372N if rev >= 2*/ if (class_rev >= 2) return -ENODEV; - port = &info_hpt372; + ppi[0] = &info_hpt372; chip_table = &hpt372a; break; case PCI_DEVICE_ID_TTI_HPT302: /* 302N if rev > 1 */ if (class_rev > 1) return -ENODEV; - port = &info_hpt372; + ppi[0] = &info_hpt372; /* Check this */ chip_table = &hpt302; break; case PCI_DEVICE_ID_TTI_HPT371: if (class_rev > 1) return -ENODEV; - port = &info_hpt372; + ppi[0] = &info_hpt372; chip_table = &hpt371; /* Single channel device, master is not present but the BIOS (or us for non x86) must mark it @@ -914,7 +912,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; case PCI_DEVICE_ID_TTI_HPT374: chip_table = &hpt374; - port = &info_hpt374; + ppi[0] = &info_hpt374; break; default: printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device); @@ -993,7 +991,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) int dpll, adjust; /* Compute DPLL */ - dpll = (port->udma_mask & 0xC0) ? 3 : 2; + dpll = (ppi[0]->udma_mask & 0xC0) ? 3 : 2; f_low = (MHz[clock_slot] * 48) / MHz[dpll]; f_high = f_low + 2; @@ -1033,19 +1031,16 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) * about lack of UDMA133 support on lower clocks */ - if (clock_slot < 2 && port == &info_hpt370) - port = &info_hpt370_33; - if (clock_slot < 2 && port == &info_hpt370a) - port = &info_hpt370a_33; + if (clock_slot < 2 && ppi[0] == &info_hpt370) + ppi[0] = &info_hpt370_33; + if (clock_slot < 2 && ppi[0] == &info_hpt370a) + ppi[0] = &info_hpt370a_33; printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n", chip_table->name, MHz[clock_slot]); } /* Now kick off ATA set up */ - port_info = *port; - port_info.private_data = private_data; - - return ata_pci_init_one(dev, ppi, &hpt37x_sht); + return ata_pci_init_one(dev, ppi, &hpt37x_sht, private_data); } static const struct pci_device_id hpt37x[] = { diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 2c178c30116c..c774be93ae04 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -458,8 +458,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, .port_ops = &hpt3x2n_port_ops }; - struct ata_port_info port = info; - const struct ata_port_info *ppi[] = { &port, NULL }; + const struct ata_port_info *ppi[] = { &info, NULL }; u8 irqmask; u32 class_rev; @@ -468,6 +467,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) unsigned int f_low, f_high; int adjust; unsigned long iobase = pci_resource_start(dev, 4); + void *hpriv = NULL; int rc; rc = pcim_enable_device(dev); @@ -554,9 +554,8 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_mhz); /* Set our private data up. We only need a few flags so we use it directly */ - port.private_data = NULL; if (pci_mhz > 60) { - port.private_data = (void *)PCI66; + hpriv = (void *)PCI66; /* * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in * the MISC. register to stretch the UltraDMA Tss timing. @@ -567,7 +566,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi, &hpt3x2n_sht); + return ata_pci_init_one(dev, ppi, &hpt3x2n_sht, hpriv); } static const struct pci_device_id hpt3x2n[] = { diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 291a0d6e2434..d23a46b75028 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -287,7 +287,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &it8213_sht); + return ata_pci_init_one(pdev, ppi, &it8213_sht, NULL); } static const struct pci_device_id it8213_pci_tbl[] = { diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 63c5cf0d1fee..6a8a4ddf5bfe 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -722,7 +722,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) else ppi[0] = &info_smart; - return ata_pci_init_one(pdev, ppi, &it821x_sht); + return ata_pci_init_one(pdev, ppi, &it821x_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 859e47a600cc..317f3474e0ba 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -105,20 +105,6 @@ static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * jmicron_error_handler - Setup and error handler - * @ap: Port to handle - * - * LOCKING: - * None (inherited from caller). - */ - -static void jmicron_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, - ata_std_postreset); -} - /* No PIO or DMA methods needed for this device */ static struct scsi_host_template jmicron_sht = { @@ -127,7 +113,7 @@ static struct scsi_host_template jmicron_sht = { static struct ata_port_operations jmicron_ops = { .inherits = &ata_bmdma_port_ops, - .error_handler = jmicron_error_handler, + .prereset = jmicron_pre_reset, }; @@ -158,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi, &jmicron_sht); + return ata_pci_init_one(pdev, ppi, &jmicron_sht, NULL); } static const struct pci_device_id jmicron_pci_tbl[] = { diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index d8da4f344c0a..d38e64cd6097 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -75,20 +75,6 @@ static int marvell_cable_detect(struct ata_port *ap) return 0; /* Our BUG macro needs the right markup */ } -/** - * marvell_error_handler - Setup and error handler - * @ap: Port to handle - * - * LOCKING: - * None (inherited from caller). - */ - -static void marvell_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, NULL, - ata_std_postreset); -} - /* No PIO or DMA methods needed for this device */ static struct scsi_host_template marvell_sht = { @@ -98,7 +84,7 @@ static struct scsi_host_template marvell_sht = { static struct ata_port_operations marvell_ops = { .inherits = &ata_bmdma_port_ops, .cable_detect = marvell_cable_detect, - .error_handler = marvell_error_handler, + .prereset = marvell_pre_reset, }; @@ -142,7 +128,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i if (pdev->device == 0x6101) ppi[1] = &ata_dummy_port_info; - return ata_pci_init_one(pdev, ppi, &marvell_sht); + return ata_pci_init_one(pdev, ppi, &marvell_sht, NULL); } static const struct pci_device_id marvell_pci_tbl[] = { diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index ae50a5e85cf1..349182840d24 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -71,7 +71,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e ata_pci_clear_simplex(pdev); /* And let the library code do the work */ - return ata_pci_init_one(pdev, port_info, &netcell_sht); + return ata_pci_init_one(pdev, port_info, &netcell_sht, NULL); } static const struct pci_device_id netcell_pci_tbl[] = { diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 1bdca8f1e767..5a043e426480 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -163,7 +163,7 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &ns87410_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi, &ns87410_sht); + return ata_pci_init_one(dev, ppi, &ns87410_sht, NULL); } static const struct pci_device_id ns87410[] = { diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 42508940e4a9..cdd79d6fc0ee 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -375,7 +375,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e pci_write_config_byte(pdev, 0x55, 0xEE); /* Select PIO0 8bit clocking */ pci_write_config_byte(pdev, 0x54, 0xB7); - return ata_pci_init_one(pdev, ppi, &ns87415_sht); + return ata_pci_init_one(pdev, ppi, &ns87415_sht, NULL); } static const struct pci_device_id ns87415_pci_tbl[] = { diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 9e3afadbd04a..7001b756819e 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -263,7 +263,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &oldpiix_sht); + return ata_pci_init_one(pdev, ppi, &oldpiix_sht, NULL); } static const struct pci_device_id oldpiix_pci_tbl[] = { diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 8601d9c3cb39..5a5f20e03fc0 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -188,7 +188,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi, &opti_sht); + return ata_pci_init_one(dev, ppi, &opti_sht, NULL); } static const struct pci_device_id opti[] = { diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index c376f9ef77c8..ba2819ff964b 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -445,7 +445,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (optiplus_with_udma(dev)) ppi[0] = &info_82c700_udma; - return ata_pci_init_one(dev, ppi, &optidma_sht); + return ata_pci_init_one(dev, ppi, &optidma_sht, NULL); } static const struct pci_device_id optidma[] = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 5545fbab6a7e..8214100e3ac1 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -324,7 +324,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id return -ENODEV; } } - return ata_pci_init_one(dev, ppi, &pdc202xx_sht); + return ata_pci_init_one(dev, ppi, &pdc202xx_sht, NULL); } static const struct pci_device_id pdc202xx[] = { diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 145d5ba92795..9ab84fc3798d 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -228,7 +228,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &radisys_sht); + return ata_pci_init_one(pdev, ppi, &radisys_sht, NULL); } static const struct pci_device_id radisys_pci_tbl[] = { diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 04be6aee4354..462b72a31280 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) - return ata_pci_init_one(pdev, ppi, &rz1000_sht); + return ata_pci_init_one(pdev, ppi, &rz1000_sht, NULL); printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); /* Not safe to use so skip */ diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 38c7fb0bebe9..42efacf73c79 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -213,7 +213,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* Can't enable port 2 yet, see top comments */ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; - return ata_pci_init_one(dev, ppi, &sc1200_sht); + return ata_pci_init_one(dev, ppi, &sc1200_sht, NULL); } static const struct pci_device_id sc1200[] = { diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 515b5b70a555..2f4f9b0f89de 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -461,7 +461,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ata_pci_clear_simplex(pdev); - return ata_pci_init_one(pdev, ppi, &serverworks_sht); + return ata_pci_init_one(pdev, ppi, &serverworks_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 5313deeffa6d..63fafc6d6da3 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -362,7 +362,7 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, &sil680_sht); use_ioports: - return ata_pci_init_one(pdev, ppi, &sil680_sht); + return ata_pci_init_one(pdev, ppi, &sil680_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 32be13ba5f06..28abfc26e7a4 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -690,8 +690,7 @@ static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis) static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info port; - const struct ata_port_info *ppi[] = { &port, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; struct pci_dev *host = NULL; struct sis_chipset *chipset = NULL; struct sis_chipset *sets; @@ -831,12 +830,11 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (chipset == NULL) return -ENODEV; - port = *chipset->info; - port.private_data = chipset; + ppi[0] = chipset->info; sis_fixup(pdev, chipset); - return ata_pci_init_one(pdev, ppi, &sis_sht); + return ata_pci_init_one(pdev, ppi, &sis_sht, chipset); } static const struct pci_device_id sis_pci_tbl[] = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 2d14b2505c7d..1d97f920bd2b 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -323,7 +323,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; pci_write_config_dword(dev, 0x40, val); - return ata_pci_init_one(dev, ppi, &sl82c105_sht); + return ata_pci_init_one(dev, ppi, &sl82c105_sht, NULL); } static const struct pci_device_id sl82c105[] = { diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 86dc66c37389..f07b0e5df222 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -206,7 +206,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi, &triflex_sht); + return ata_pci_init_one(dev, ppi, &triflex_sht, NULL); } static const struct pci_device_id triflex[] = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index e66bb85ad3d1..f4092cbd566f 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -442,8 +442,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, /* FIXME: should check north bridge */ .port_ops = &via_port_ops }; - struct ata_port_info type; - const struct ata_port_info *ppi[] = { &type, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; struct pci_dev *isa = NULL; const struct via_isa_bridge *config; static int printed_version; @@ -491,25 +490,25 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: if (config->flags & VIA_NO_UNMASK) - type = via_mwdma_info_borked; + ppi[0] = &via_mwdma_info_borked; else - type = via_mwdma_info; + ppi[0] = &via_mwdma_info; break; case VIA_UDMA_33: - type = via_udma33_info; + ppi[0] = &via_udma33_info; break; case VIA_UDMA_66: - type = via_udma66_info; + ppi[0] = &via_udma66_info; /* The 66 MHz devices require we enable the clock */ pci_read_config_dword(pdev, 0x50, &timing); timing |= 0x80008; pci_write_config_dword(pdev, 0x50, timing); break; case VIA_UDMA_100: - type = via_udma100_info; + ppi[0] = &via_udma100_info; break; case VIA_UDMA_133: - type = via_udma133_info; + ppi[0] = &via_udma133_info; break; default: WARN_ON(1); @@ -524,9 +523,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* We have established the device type, now fire it up */ - type.private_data = (void *)config; - - return ata_pci_init_one(pdev, ppi, &via_sht); + return ata_pci_init_one(pdev, ppi, &via_sht, (void *)config); } #ifdef CONFIG_PM diff --git a/include/linux/libata.h b/include/linux/libata.h index 5494119854de..e7f10a88efe1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1020,7 +1020,7 @@ struct pci_dev; extern int ata_pci_init_one(struct pci_dev *pdev, const struct ata_port_info * const * ppi, - struct scsi_host_template *sht); + struct scsi_host_template *sht, void *host_priv); extern void ata_pci_remove_one(struct pci_dev *pdev); #ifdef CONFIG_PM extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -- cgit v1.2.3 From 959471936241bd83da7d0a76411cef6772140fe6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:49 +0900 Subject: libata: kill port_info->sht and ->irq_handler libata core layer doesn't care about sht or ->irq_handler. Those are only of interest to the LLD during initialization. This is confusing and has caused several drivers to have duplicate unused initializers for these fields. Currently only sata_nv uses these fields. Make sata_nv use ->private_data, which is supposed to carry LLD-specific information, instead and kill ->sht and ->irq_handler. nv_pi_priv structure is defined and struct literals are used to initialize private_data. Notational overhead is negligible. Signed-off-by: Tejun Heo --- drivers/ata/sata_nv.c | 29 +++++++++++++++++------------ include/linux/libata.h | 2 -- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 7b7ba0e26903..5637b082bc85 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -466,58 +466,61 @@ static struct ata_port_operations nv_swncq_ops = { .port_start = nv_swncq_port_start, }; +struct nv_pi_priv { + irq_handler_t irq_handler; + struct scsi_host_template *sht; +}; + +#define NV_PI_PRIV(_irq_handler, _sht) \ + &(struct nv_pi_priv){ .irq_handler = _irq_handler, .sht = _sht } + static const struct ata_port_info nv_port_info[] = { /* generic */ { - .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_generic_ops, - .irq_handler = nv_generic_interrupt, + .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), }, /* nforce2/3 */ { - .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_nf2_ops, - .irq_handler = nv_nf2_interrupt, + .private_data = NV_PI_PRIV(nv_nf2_interrupt, &nv_sht), }, /* ck804 */ { - .sht = &nv_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_ck804_ops, - .irq_handler = nv_ck804_interrupt, + .private_data = NV_PI_PRIV(nv_ck804_interrupt, &nv_sht), }, /* ADMA */ { - .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_NCQ, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_adma_ops, - .irq_handler = nv_adma_interrupt, + .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), }, /* SWNCQ */ { - .sht = &nv_swncq_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_NCQ, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_swncq_ops, - .irq_handler = nv_swncq_interrupt, + .private_data = NV_PI_PRIV(nv_swncq_interrupt, &nv_swncq_sht), }, }; @@ -2316,6 +2319,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; const struct ata_port_info *ppi[] = { NULL, NULL }; + struct nv_pi_priv *ipriv; struct ata_host *host; struct nv_host_priv *hpriv; int rc; @@ -2352,6 +2356,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } ppi[0] = &nv_port_info[type]; + ipriv = ppi[0]->private_data; rc = ata_pci_prepare_sff_host(pdev, ppi, &host); if (rc) return rc; @@ -2390,8 +2395,8 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) nv_swncq_host_init(host); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler, - IRQF_SHARED, ppi[0]->sht); + return ata_host_activate(host, pdev->irq, ipriv->irq_handler, + IRQF_SHARED, ipriv->sht); } #ifdef CONFIG_PM diff --git a/include/linux/libata.h b/include/linux/libata.h index e7f10a88efe1..88c6fa84ed74 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -748,14 +748,12 @@ struct ata_port_operations { }; struct ata_port_info { - struct scsi_host_template *sht; unsigned long flags; unsigned long link_flags; unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; struct ata_port_operations *port_ops; - irq_handler_t irq_handler; void *private_data; }; -- cgit v1.2.3 From a1efdaba2dbd6fb89e23a87b66d3f4dd92c9f5af Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 12:22:50 +0900 Subject: libata: make reset related methods proper port operations Currently reset methods are not specified directly in the ata_port_operations table. If a LLD wants to use custom reset methods, it should construct and use a error_handler which uses those reset methods. It's done this way for two reasons. First, the ops table already contained too many methods and adding four more of them would noticeably increase the amount of necessary boilerplate code all over low level drivers. Second, as ->error_handler uses those reset methods, it can get confusing. ie. By overriding ->error_handler, those reset ops can be made useless making layering a bit hazy. Now that ops table uses inheritance, the first problem doesn't exist anymore. The second isn't completely solved but is relieved by providing default values - most drivers can just override what it has implemented and don't have to concern itself about higher level callbacks. In fact, there currently is no driver which actually modifies error handling behavior. Drivers which override ->error_handler just wraps the standard error handler only to prepare the controller for EH. I don't think making ops layering strict has any noticeable benefit. This patch makes ->prereset, ->softreset, ->hardreset, ->postreset and their PMP counterparts propoer ops. Default ops are provided in the base ops tables and drivers are converted to override individual reset methods instead of creating custom error_handler. * ata_std_error_handler() doesn't use sata_std_hardreset() if SCRs aren't accessible. sata_promise doesn't need to use separate error_handlers for PATA and SATA anymore. * softreset is broken for sata_inic162x and sata_sx4. As libata now always prefers hardreset, this doesn't really matter but the ops are forced to NULL using ATA_OP_NULL for documentation purpose. * pata_hpt374 needs to use different prereset for the first and second PCI functions. This used to be done by branching from hpt374_error_handler(). The proper way to do this is to use separate ops and port_info tables for each function. Converted. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 53 +++++++++++++-------------------------- drivers/ata/ata_piix.c | 21 ++++------------ drivers/ata/libata-core.c | 14 +++++++++-- drivers/ata/libata-eh.c | 25 +++++++++++++++++++ drivers/ata/libata-pmp.c | 47 ++++++++-------------------------- drivers/ata/libata-sff.c | 49 ++++++++++++------------------------ drivers/ata/pata_artop.c | 34 ++----------------------- drivers/ata/pata_atiixp.c | 7 +----- drivers/ata/pata_bf54x.c | 14 ++--------- drivers/ata/pata_efar.c | 15 +---------- drivers/ata/pata_hpt37x.c | 61 +++++++++++++++------------------------------ drivers/ata/pata_hpt3x2n.c | 16 ++---------- drivers/ata/pata_icside.c | 8 +----- drivers/ata/pata_it8213.c | 15 +---------- drivers/ata/pata_mpc52xx.c | 10 -------- drivers/ata/pata_mpiix.c | 16 +----------- drivers/ata/pata_ns87410.c | 16 +----------- drivers/ata/pata_oldpiix.c | 16 +----------- drivers/ata/pata_opti.c | 17 +------------ drivers/ata/pata_optidma.c | 17 +------------ drivers/ata/pata_pdc2027x.c | 19 ++------------ drivers/ata/pata_scc.c | 15 +++-------- drivers/ata/pata_sis.c | 15 +---------- drivers/ata/pata_sl82c105.c | 8 +----- drivers/ata/pata_triflex.c | 7 +----- drivers/ata/pata_via.c | 14 +---------- drivers/ata/pdc_adma.c | 11 +++----- drivers/ata/sata_fsl.c | 12 +-------- drivers/ata/sata_inic162x.c | 5 ++-- drivers/ata/sata_mv.c | 16 ++++++------ drivers/ata/sata_nv.c | 17 ++++--------- drivers/ata/sata_promise.c | 22 +++------------- drivers/ata/sata_qstor.c | 6 +++-- drivers/ata/sata_sil24.c | 18 +++++++++---- drivers/ata/sata_via.c | 10 ++------ drivers/scsi/ipr.c | 3 ++- include/linux/libata.h | 19 +++++++------- 37 files changed, 186 insertions(+), 502 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dacb3ef0c3e6..3efa9904f7a0 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -252,9 +252,18 @@ static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); +static int ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int ahci_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static void ahci_postreset(struct ata_link *link, unsigned int *class); +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void ahci_error_handler(struct ata_port *ap); -static void ahci_vt8251_error_handler(struct ata_port *ap); -static void ahci_p5wdh_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_resume(struct ata_port *ap); static void ahci_dev_config(struct ata_device *dev); @@ -293,6 +302,10 @@ static struct ata_port_operations ahci_ops = { .freeze = ahci_freeze, .thaw = ahci_thaw, + .softreset = ahci_softreset, + .hardreset = ahci_hardreset, + .postreset = ahci_postreset, + .pmp_softreset = ahci_pmp_softreset, .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, .dev_config = ahci_dev_config, @@ -314,12 +327,12 @@ static struct ata_port_operations ahci_ops = { static struct ata_port_operations ahci_vt8251_ops = { .inherits = &ahci_ops, - .error_handler = ahci_vt8251_error_handler, + .hardreset = ahci_vt8251_hardreset, }; static struct ata_port_operations ahci_p5wdh_ops = { .inherits = &ahci_ops, - .error_handler = ahci_p5wdh_error_handler, + .hardreset = ahci_p5wdh_hardreset, }; #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) @@ -1796,37 +1809,7 @@ static void ahci_error_handler(struct ata_port *ap) ahci_start_engine(ap); } - /* perform recovery */ - sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, - ahci_hardreset, ahci_postreset, - sata_pmp_std_prereset, ahci_pmp_softreset, - sata_pmp_std_hardreset, sata_pmp_std_postreset); -} - -static void ahci_vt8251_error_handler(struct ata_port *ap) -{ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - /* restart engine */ - ahci_stop_engine(ap); - ahci_start_engine(ap); - } - - /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, - ahci_postreset); -} - -static void ahci_p5wdh_error_handler(struct ata_port *ap) -{ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - /* restart engine */ - ahci_stop_engine(ap); - ahci_start_engine(ap); - } - - /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset, - ahci_postreset); + sata_pmp_error_handler(ap); } static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index bb46b61a7c6b..eafb984313f6 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -162,15 +162,16 @@ struct piix_host_priv { static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void piix_pata_error_handler(struct ata_port *ap); +static int piix_pata_prereset(struct ata_link *link, unsigned long deadline); static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev); static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int ich_pata_cable_detect(struct ata_port *ap); static u8 piix_vmw_bmdma_status(struct ata_port *ap); +static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); -static void piix_sidpr_error_handler(struct ata_port *ap); #ifdef CONFIG_PM static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_resume(struct pci_dev *pdev); @@ -299,7 +300,7 @@ static struct ata_port_operations piix_pata_ops = { .cable_detect = ata_cable_40wire, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, - .error_handler = piix_pata_error_handler, + .prereset = piix_pata_prereset, }; static struct ata_port_operations piix_vmw_ops = { @@ -319,9 +320,9 @@ static struct ata_port_operations piix_sata_ops = { static struct ata_port_operations piix_sidpr_sata_ops = { .inherits = &piix_sata_ops, + .hardreset = piix_sidpr_hardreset, .scr_read = piix_sidpr_scr_read, .scr_write = piix_sidpr_scr_write, - .error_handler = piix_sidpr_error_handler, }; static const struct piix_map_db ich5_map_db = { @@ -645,12 +646,6 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -static void piix_pata_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL, - ata_std_postreset); -} - /** * piix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring @@ -1057,12 +1052,6 @@ static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, return -EAGAIN; } -static void piix_sidpr_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, - piix_sidpr_hardreset, ata_std_postreset); -} - #ifdef CONFIG_PM static int piix_broken_suspend(void) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index aa6bcd79d60a..345f4a6865a8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -76,6 +76,10 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { .irq_clear = ata_noop_irq_clear, + .prereset = ata_std_prereset, + .hardreset = sata_std_hardreset, + .postreset = ata_std_postreset, + .error_handler = ata_std_error_handler, }; const struct ata_port_operations sata_port_ops = { @@ -87,6 +91,11 @@ const struct ata_port_operations sata_port_ops = { const struct ata_port_operations sata_pmp_port_ops = { .inherits = &sata_port_ops, + + .pmp_prereset = sata_pmp_std_prereset, + .pmp_hardreset = sata_pmp_std_hardreset, + .pmp_postreset = sata_pmp_std_postreset, + .error_handler = sata_pmp_error_handler, }; const struct ata_port_operations ata_sff_port_ops = { @@ -97,6 +106,7 @@ const struct ata_port_operations ata_sff_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, + .softreset = ata_std_softreset, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, @@ -7935,7 +7945,6 @@ EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_bmdma_freeze); EXPORT_SYMBOL_GPL(ata_bmdma_thaw); -EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); @@ -8005,7 +8014,7 @@ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); -EXPORT_SYMBOL_GPL(sata_pmp_do_eh); +EXPORT_SYMBOL_GPL(sata_pmp_error_handler); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); @@ -8024,6 +8033,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); +EXPORT_SYMBOL_GPL(ata_std_error_handler); EXPORT_SYMBOL_GPL(ata_irq_on); EXPORT_SYMBOL_GPL(ata_dev_try_classify); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0d0a2c0ab9e7..ec32082356cb 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2814,6 +2814,7 @@ void ata_eh_finish(struct ata_port *ap) /** * ata_do_eh - do standard error handling * @ap: host port to handle error for + * * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) @@ -2844,6 +2845,30 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_eh_finish(ap); } +/** + * ata_std_error_handler - standard error handler + * @ap: host port to handle error for + * + * Standard error handler + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_std_error_handler(struct ata_port *ap) +{ + struct ata_port_operations *ops = ap->ops; + ata_reset_fn_t hardreset = ops->hardreset; + + /* sata_std_hardreset is inherited to all drivers from + * ata_base_port_ops. Ignore it if SCR access is not + * available. + */ + if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link)) + hardreset = NULL; + + ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset); +} + #ifdef CONFIG_PM /** * ata_eh_handle_port_suspend - perform port suspend operation diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 39e036c8a2bc..a7cb1498c9b2 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -962,14 +962,6 @@ static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) /** * sata_pmp_eh_recover - recover PMP-enabled port * @ap: ATA port to recover - * @prereset: prereset method (can be NULL) - * @softreset: softreset method - * @hardreset: hardreset method - * @postreset: postreset method (can be NULL) - * @pmp_prereset: PMP prereset method (can be NULL) - * @pmp_softreset: PMP softreset method (can be NULL) - * @pmp_hardreset: PMP hardreset method (can be NULL) - * @pmp_postreset: PMP postreset method (can be NULL) * * Drive EH recovery operation for PMP enabled port @ap. This * function recovers host and PMP ports with proper retrials and @@ -982,12 +974,9 @@ static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) * RETURNS: * 0 on success, -errno on failure. */ -static int sata_pmp_eh_recover(struct ata_port *ap, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, - ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, - ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +static int sata_pmp_eh_recover(struct ata_port *ap) { + struct ata_port_operations *ops = ap->ops; int pmp_tries, link_tries[SATA_PMP_MAX_PORTS]; struct ata_link *pmp_link = &ap->link; struct ata_device *pmp_dev = pmp_link->device; @@ -1005,8 +994,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap, retry: /* PMP attached? */ if (!ap->nr_pmp_links) { - rc = ata_eh_recover(ap, prereset, softreset, hardreset, - postreset, NULL); + rc = ata_eh_recover(ap, ops->prereset, ops->softreset, + ops->hardreset, ops->postreset, NULL); if (rc) { ata_link_for_each_dev(dev, &ap->link) ata_dev_disable(dev); @@ -1024,8 +1013,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap, } /* recover pmp */ - rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset, - postreset); + rc = sata_pmp_eh_recover_pmp(ap, ops->prereset, ops->softreset, + ops->hardreset, ops->postreset); if (rc) goto pmp_fail; @@ -1035,8 +1024,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap, goto pmp_fail; /* recover links */ - rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset, - pmp_postreset, &link); + rc = ata_eh_recover(ap, ops->pmp_prereset, ops->pmp_softreset, + ops->pmp_hardreset, ops->pmp_postreset, &link); if (rc) goto link_fail; @@ -1132,16 +1121,8 @@ static int sata_pmp_eh_recover(struct ata_port *ap, } /** - * sata_pmp_do_eh - do standard error handling for PMP-enabled host + * sata_pmp_error_handler - do standard error handling for PMP-enabled host * @ap: host port to handle error for - * @prereset: prereset method (can be NULL) - * @softreset: softreset method - * @hardreset: hardreset method - * @postreset: postreset method (can be NULL) - * @pmp_prereset: PMP prereset method (can be NULL) - * @pmp_softreset: PMP softreset method (can be NULL) - * @pmp_hardreset: PMP hardreset method (can be NULL) - * @pmp_postreset: PMP postreset method (can be NULL) * * Perform standard error handling sequence for PMP-enabled host * @ap. @@ -1149,16 +1130,10 @@ static int sata_pmp_eh_recover(struct ata_port *ap, * LOCKING: * Kernel thread context (may sleep). */ -void sata_pmp_do_eh(struct ata_port *ap, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, - ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, - ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +void sata_pmp_error_handler(struct ata_port *ap) { ata_eh_autopsy(ap); ata_eh_report(ap); - sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset, - pmp_prereset, pmp_softreset, pmp_hardreset, - pmp_postreset); + sata_pmp_eh_recover(ap); ata_eh_finish(ap); } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 6223ec042c80..2a229a1d3211 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -396,28 +396,21 @@ void ata_bmdma_thaw(struct ata_port *ap) } /** - * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller + * ata_bmdma_error_handler - Stock error handler for BMDMA controller * @ap: port to handle error for - * @prereset: prereset method (can be NULL) - * @softreset: softreset method (can be NULL) - * @hardreset: hardreset method (can be NULL) - * @postreset: postreset method (can be NULL) * - * Handle error for ATA BMDMA controller. It can handle both + * Stock error handler for BMDMA controller. It can handle both * PATA and SATA controllers. Many controllers should be able to * use this EH as-is or with some added handling before and * after. * - * This function is intended to be used for constructing - * ->error_handler callback by low level drivers. - * * LOCKING: * Kernel thread context (may sleep) */ -void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset) +void ata_bmdma_error_handler(struct ata_port *ap) { + ata_reset_fn_t softreset = ap->ops->softreset; + ata_reset_fn_t hardreset = ap->ops->hardreset; struct ata_queued_cmd *qc; unsigned long flags; int thaw = 0; @@ -460,29 +453,19 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_eh_thaw_port(ap); /* PIO and DMA engines have been stopped, perform recovery */ - ata_do_eh(ap, prereset, softreset, hardreset, postreset); -} - -/** - * ata_bmdma_error_handler - Stock error handler for BMDMA controller - * @ap: port to handle error for - * - * Stock error handler for BMDMA controller. - * - * LOCKING: - * Kernel thread context (may sleep) - */ -void ata_bmdma_error_handler(struct ata_port *ap) -{ - ata_reset_fn_t softreset = NULL, hardreset = NULL; - if (ap->ioaddr.ctl_addr) - softreset = ata_std_softreset; - if (sata_scr_valid(&ap->link)) - hardreset = sata_std_hardreset; + /* ata_std_softreset and sata_std_hardreset are inherited to + * all SFF drivers from ata_sff_port_ops. Ignore softreset if + * ctl isn't accessible. Ignore hardreset if SCR access isn't + * available. + */ + if (softreset == ata_std_softreset && !ap->ioaddr.ctl_addr) + softreset = NULL; + if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link)) + hardreset = NULL; - ata_bmdma_drive_eh(ap, ata_std_prereset, softreset, hardreset, - ata_std_postreset); + ata_do_eh(ap, ap->ops->prereset, softreset, hardreset, + ap->ops->postreset); } /** diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index ebd15cadf15f..b6d8c4d0e6c2 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -55,21 +55,6 @@ static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * artop6210_error_handler - Probe specified port on PATA host controller - * @ap: Port to probe - * - * LOCKING: - * None (inherited from caller). - */ - -static void artop6210_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, artop6210_pre_reset, - ata_std_softreset, NULL, - ata_std_postreset); -} - /** * artop6260_pre_reset - check for 40/80 pin * @link: link @@ -113,21 +98,6 @@ static int artop6260_cable_detect(struct ata_port *ap) return ATA_CBL_PATA80; } -/** - * artop6260_error_handler - Probe specified port on PATA host controller - * @ap: Port to probe - * - * LOCKING: - * None (inherited from caller). - */ - -static void artop6260_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, artop6260_pre_reset, - ata_std_softreset, NULL, - ata_std_postreset); -} - /** * artop6210_load_piomode - Load a set of PATA PIO timings * @ap: Port whose timings we are configuring @@ -322,7 +292,7 @@ static struct ata_port_operations artop6210_ops = { .cable_detect = ata_cable_40wire, .set_piomode = artop6210_set_piomode, .set_dmamode = artop6210_set_dmamode, - .error_handler = artop6210_error_handler, + .prereset = artop6210_pre_reset, }; static struct ata_port_operations artop6260_ops = { @@ -330,7 +300,7 @@ static struct ata_port_operations artop6260_ops = { .cable_detect = artop6260_cable_detect, .set_piomode = artop6260_set_piomode, .set_dmamode = artop6260_set_dmamode, - .error_handler = artop6260_error_handler, + .prereset = artop6260_pre_reset, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 0bea7e75d2d6..56a65baddd4a 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -48,11 +48,6 @@ static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -static void atiixp_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - static int atiixp_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); @@ -235,7 +230,7 @@ static struct ata_port_operations atiixp_port_ops = { .cable_detect = atiixp_cable_detect, .set_piomode = atiixp_set_piomode, .set_dmamode = atiixp_set_dmamode, - .error_handler = atiixp_error_handler, + .prereset = atiixp_pre_reset, }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 7a22ef483061..eea275acb2a8 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1314,17 +1314,6 @@ static void bfin_std_postreset(struct ata_link *link, unsigned int *classes) write_atapi_register(base, ATA_REG_CTRL, ap->ctl); } -/** - * bfin_error_handler - Stock error handler for DMA controller - * @ap: port to handle error for - */ - -static void bfin_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL, - bfin_std_postreset); -} - static void bfin_port_stop(struct ata_port *ap) { dev_dbg(ap->dev, "in atapi port stop\n"); @@ -1385,7 +1374,8 @@ static const struct ata_port_operations bfin_pata_ops = { .freeze = bfin_bmdma_freeze, .thaw = bfin_bmdma_thaw, - .error_handler = bfin_error_handler, + .softreset = bfin_std_softreset, + .postreset = bfin_std_postreset, .post_internal_cmd = bfin_bmdma_stop, .irq_clear = bfin_irq_clear, diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 2f5b4848456a..1d839a57068e 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -48,19 +48,6 @@ static int efar_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * efar_probe_reset - Probe specified port on PATA host controller - * @ap: Port to probe - * - * LOCKING: - * None (inherited from caller). - */ - -static void efar_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * efar_cable_detect - check for 40/80 pin * @ap: Port @@ -241,7 +228,7 @@ static struct ata_port_operations efar_ops = { .cable_detect = efar_cable_detect, .set_piomode = efar_set_piomode, .set_dmamode = efar_set_dmamode, - .error_handler = efar_error_handler, + .prereset = efar_pre_reset, }; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index fb37e3a161fc..c10fcd31418d 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -341,19 +341,7 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * hpt37x_error_handler - reset the hpt374 - * @ap: ATA port to reset - * - * Perform probe for HPT37x, except for HPT374 channel 2 - */ - -static void hpt37x_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - -static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline) +static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -389,25 +377,6 @@ static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * hpt374_error_handler - reset the hpt374 - * @classes: - * - * The 374 cable detect is a little different due to the extra - * channels. The function 0 channels work like usual but function 1 - * is special - */ - -static void hpt374_error_handler(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - - if (!(PCI_FUNC(pdev->devfn) & 1)) - hpt37x_error_handler(ap); - else - ata_bmdma_drive_eh(ap, hpt374_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * hpt370_set_piomode - PIO setup * @ap: ATA interface @@ -635,7 +604,7 @@ static struct ata_port_operations hpt370_port_ops = { .mode_filter = hpt370_filter, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, - .error_handler = hpt37x_error_handler, + .prereset = hpt37x_pre_reset, }; /* @@ -659,17 +628,17 @@ static struct ata_port_operations hpt372_port_ops = { .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, - .error_handler = hpt37x_error_handler, + .prereset = hpt37x_pre_reset, }; /* * Configuration for HPT374. Mode setting works like 372 and friends - * but we have a different cable detection procedure. + * but we have a different cable detection procedure for function 1. */ -static struct ata_port_operations hpt374_port_ops = { +static struct ata_port_operations hpt374_fn1_port_ops = { .inherits = &hpt372_port_ops, - .error_handler = hpt374_error_handler, + .prereset = hpt374_fn1_pre_reset, }; /** @@ -821,13 +790,20 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, .port_ops = &hpt372_port_ops }; - /* HPT374 - UDMA100 */ - static const struct ata_port_info info_hpt374 = { + /* HPT374 - UDMA100, function 1 uses different prereset method */ + static const struct ata_port_info info_hpt374_fn0 = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = ATA_UDMA5, + .port_ops = &hpt372_port_ops + }; + static const struct ata_port_info info_hpt374_fn1 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA5, - .port_ops = &hpt374_port_ops + .port_ops = &hpt374_fn1_port_ops }; static const int MHz[4] = { 33, 40, 50, 66 }; @@ -912,7 +888,10 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; case PCI_DEVICE_ID_TTI_HPT374: chip_table = &hpt374; - ppi[0] = &info_hpt374; + if (!(PCI_FUNC(dev->devfn) & 1)) + *ppi = &info_hpt374_fn0; + else + *ppi = &info_hpt374_fn1; break; default: printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device); diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index c774be93ae04..cd44ee3d3cc1 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -148,7 +148,7 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) * Reset the hardware and state machine, */ -static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline) +static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); @@ -159,18 +159,6 @@ static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * hpt3x2n_error_handler - probe the hpt3x2n bus - * @ap: ATA port to reset - * - * Perform the probe reset handling for the 3x2N - */ - -static void hpt3x2n_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, hpt3xn_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * hpt3x2n_set_piomode - PIO setup * @ap: ATA interface @@ -355,7 +343,7 @@ static struct ata_port_operations hpt3x2n_port_ops = { .cable_detect = hpt3x2n_cable_detect, .set_piomode = hpt3x2n_set_piomode, .set_dmamode = hpt3x2n_set_dmamode, - .error_handler = hpt3x2n_error_handler, + .prereset = hpt3x2n_pre_reset, }; /** diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index ff16b0eaa2c2..13d43e9dd279 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -332,12 +332,6 @@ static void pata_icside_postreset(struct ata_link *link, unsigned int *classes) } } -static void pata_icside_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, - pata_icside_postreset); -} - static struct ata_port_operations pata_icside_port_ops = { .inherits = &ata_sff_port_ops, /* no need to build any PRD tables for DMA */ @@ -350,7 +344,7 @@ static struct ata_port_operations pata_icside_port_ops = { .cable_detect = ata_cable_40wire, .set_dmamode = pata_icside_set_dmamode, - .error_handler = pata_icside_error_handler, + .postreset = pata_icside_postreset, .post_internal_cmd = pata_icside_bmdma_stop, }; diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index d23a46b75028..84ab89e8a247 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -43,19 +43,6 @@ static int it8213_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * it8213_error_handler - Probe specified port on PATA host controller - * @ap: Port to probe - * - * LOCKING: - * None (inherited from caller). - */ - -static void it8213_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * it8213_cable_detect - check for 40/80 pin * @ap: Port @@ -252,7 +239,7 @@ static struct ata_port_operations it8213_ops = { .cable_detect = it8213_cable_detect, .set_piomode = it8213_set_piomode, .set_dmamode = it8213_set_dmamode, - .error_handler = it8213_error_handler, + .prereset = it8213_pre_reset, }; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index ac7c0822b1a7..fec93196710e 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -255,15 +255,6 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) ata_std_dev_select(ap,device); } -static void -mpc52xx_ata_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, - ata_std_postreset); -} - - - static struct scsi_host_template mpc52xx_ata_sht = { ATA_PIO_SHT(DRV_NAME), }; @@ -273,7 +264,6 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .dev_select = mpc52xx_ata_dev_select, .cable_detect = ata_cable_40wire, .set_piomode = mpc52xx_ata_set_piomode, - .error_handler = mpc52xx_ata_error_handler, .post_internal_cmd = ATA_OP_NULL, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index dab54f8a272d..1b9d0d412ebf 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -58,20 +58,6 @@ static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * mpiix_error_handler - probe reset - * @ap: ATA port - * - * Perform the ATA probe and bus reset sequence plus specific handling - * for this hardware. The MPIIX has the enable bits in a different place - * to PIIX4 and friends. As a pure PIO device it has no cable detect - */ - -static void mpiix_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, mpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * mpiix_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -159,7 +145,7 @@ static struct ata_port_operations mpiix_port_ops = { .qc_issue = mpiix_qc_issue_prot, .cable_detect = ata_cable_40wire, .set_piomode = mpiix_set_piomode, - .error_handler = mpiix_error_handler, + .prereset = mpiix_pre_reset, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 5a043e426480..4d2eefee7387 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -53,20 +53,6 @@ static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * ns87410_error_handler - probe reset - * @ap: ATA port - * - * Perform the ATA probe and bus reset sequence plus specific handling - * for this hardware. The MPIIX has the enable bits in a different place - * to PIIX4 and friends. As a pure PIO device it has no cable detect - */ - -static void ns87410_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ns87410_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * ns87410_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -152,7 +138,7 @@ static struct ata_port_operations ns87410_port_ops = { .qc_issue = ns87410_qc_issue_prot, .cable_detect = ata_cable_40wire, .set_piomode = ns87410_set_piomode, - .error_handler = ns87410_error_handler, + .prereset = ns87410_pre_reset, }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 7001b756819e..c1da79a76439 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -50,20 +50,6 @@ static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * oldpiix_pata_error_handler - Probe specified port on PATA host controller - * @ap: Port to probe - * @classes: - * - * LOCKING: - * None (inherited from caller). - */ - -static void oldpiix_pata_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, oldpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * oldpiix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring @@ -229,7 +215,7 @@ static struct ata_port_operations oldpiix_pata_ops = { .cable_detect = ata_cable_40wire, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, - .error_handler = oldpiix_pata_error_handler, + .prereset = oldpiix_pre_reset, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 5a5f20e03fc0..4ddd03a67775 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -67,21 +67,6 @@ static int opti_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * opti_probe_reset - probe reset - * @ap: ATA port - * - * Perform the ATA probe and bus reset sequence plus specific handling - * for this hardware. The Opti needs little handling - we have no UDMA66 - * capability that needs cable detection. All we must do is check the port - * is enabled. - */ - -static void opti_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, opti_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * opti_write_reg - control register setup * @ap: ATA port @@ -172,7 +157,7 @@ static struct ata_port_operations opti_port_ops = { .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = opti_set_piomode, - .error_handler = opti_error_handler, + .prereset = opti_pre_reset, }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index ba2819ff964b..36ac147de178 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -67,21 +67,6 @@ static int optidma_pre_reset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * optidma_probe_reset - probe reset - * @ap: ATA port - * - * Perform the ATA probe and bus reset sequence plus specific handling - * for this hardware. The Opti needs little handling - we have no UDMA66 - * capability that needs cable detection. All we must do is check the port - * is enabled. - */ - -static void optidma_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, optidma_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * optidma_unlock - unlock control registers * @ap: ATA port @@ -359,7 +344,7 @@ static struct ata_port_operations optidma_port_ops = { .set_piomode = optidma_set_pio_mode, .set_dmamode = optidma_set_dma_mode, .set_mode = optidma_set_mode, - .error_handler = optidma_error_handler, + .prereset = optidma_pre_reset, }; static struct ata_port_operations optiplus_port_ops = { diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index f619c20dd192..d235c9f92d09 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -63,7 +63,7 @@ enum { }; static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc2027x_error_handler(struct ata_port *ap); +static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline); static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); @@ -136,7 +136,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .inherits = &ata_bmdma_port_ops, .check_atapi_dma = pdc2027x_check_atapi_dma, .cable_detect = pdc2027x_cable_detect, - .error_handler = pdc2027x_error_handler, + .prereset = pdc2027x_prereset, }; static struct ata_port_operations pdc2027x_pata133_ops = { @@ -251,21 +251,6 @@ static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -/** - * pdc2027x_error_handler - Perform reset on PATA port and classify - * @ap: Port to reset - * - * Reset PATA phy and classify attached devices. - * - * LOCKING: - * None (inherited from caller). - */ - -static void pdc2027x_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * pdc2720x_mode_filter - mode selection filter * @adev: ATA device diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 033d1f3a82de..07f2d7a6f1a8 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -904,17 +904,6 @@ static void scc_std_postreset(struct ata_link *link, unsigned int *classes) DPRINTK("EXIT\n"); } -/** - * scc_error_handler - Stock error handler for BMDMA controller - * @ap: port to handle error for - */ - -static void scc_error_handler (struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, scc_pata_prereset, scc_std_softreset, NULL, - scc_std_postreset); -} - /** * scc_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. * @ap: Port associated with this ATA transaction. @@ -992,7 +981,9 @@ static const struct ata_port_operations scc_pata_ops = { .data_xfer = scc_data_xfer, .freeze = scc_bmdma_freeze, - .error_handler = scc_error_handler, + .prereset = scc_pata_prereset, + .softreset = scc_std_softreset, + .postreset = scc_std_postreset, .post_internal_cmd = scc_bmdma_stop, .irq_clear = scc_bmdma_irq_clear, diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 28abfc26e7a4..793e6714df8c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -160,19 +160,6 @@ static int sis_pre_reset(struct ata_link *link, unsigned long deadline) } -/** - * sis_error_handler - Probe specified port on PATA host controller - * @ap: Port to probe - * - * LOCKING: - * None (inherited from caller). - */ - -static void sis_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, sis_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * sis_set_fifo - Set RWP fifo bits for this device * @ap: Port @@ -526,7 +513,7 @@ static struct ata_port_operations sis_133_for_sata_ops = { static struct ata_port_operations sis_base_ops = { .inherits = &ata_bmdma_port_ops, - .error_handler = sis_error_handler, + .prereset = sis_pre_reset, }; static struct ata_port_operations sis_133_ops = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 1d97f920bd2b..bee11ca8f55a 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -64,12 +64,6 @@ static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline) } -static void sl82c105_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, sl82c105_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - - /** * sl82c105_configure_piomode - set chip PIO timing * @ap: ATA interface @@ -245,7 +239,7 @@ static struct ata_port_operations sl82c105_port_ops = { .bmdma_stop = sl82c105_bmdma_stop, .cable_detect = ata_cable_40wire, .set_piomode = sl82c105_set_piomode, - .error_handler = sl82c105_error_handler, + .prereset = sl82c105_pre_reset, }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index f07b0e5df222..bd546a389ce1 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -71,11 +71,6 @@ static int triflex_prereset(struct ata_link *link, unsigned long deadline) -static void triflex_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, triflex_prereset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * triflex_load_timing - timing configuration * @ap: ATA interface @@ -189,7 +184,7 @@ static struct ata_port_operations triflex_port_ops = { .bmdma_stop = triflex_bmdma_stop, .cable_detect = ata_cable_40wire, .set_piomode = triflex_set_piomode, - .error_handler = triflex_error_handler, + .prereset = triflex_prereset, }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f4092cbd566f..2928fa173132 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -214,18 +214,6 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline) } -/** - * via_error_handler - reset for VIA chips - * @ap: ATA port - * - * Handle the reset callback for the later chips with cable detect - */ - -static void via_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, via_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - /** * via_do_set_mode - set initial PIO mode data * @ap: ATA interface @@ -343,7 +331,7 @@ static struct ata_port_operations via_port_ops = { .cable_detect = via_cable_detect, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, - .error_handler = via_error_handler, + .prereset = via_pre_reset, }; static struct ata_port_operations via_port_ops_noirq = { diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index a5706149af6b..5ed065d0ab4c 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -140,7 +140,7 @@ static void adma_bmdma_stop(struct ata_queued_cmd *qc); static u8 adma_bmdma_status(struct ata_port *ap); static void adma_freeze(struct ata_port *ap); static void adma_thaw(struct ata_port *ap); -static void adma_error_handler(struct ata_port *ap); +static int adma_prereset(struct ata_link *link, unsigned long deadline); static struct scsi_host_template adma_ata_sht = { ATA_BASE_SHT(DRV_NAME), @@ -166,7 +166,8 @@ static struct ata_port_operations adma_ata_ops = { .freeze = adma_freeze, .thaw = adma_thaw, - .error_handler = adma_error_handler, + .prereset = adma_prereset, + .softreset = ata_std_softreset, .port_start = adma_port_start, .port_stop = adma_port_stop, @@ -292,12 +293,6 @@ static int adma_prereset(struct ata_link *link, unsigned long deadline) return ata_std_prereset(link, deadline); } -static void adma_error_handler(struct ata_port *ap) -{ - ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, - ata_std_postreset); -} - static int adma_fill_sg(struct ata_queued_cmd *qc) { struct scatterlist *sg; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 865030ae8f8a..676302fdaa97 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -912,16 +912,6 @@ err: return -EIO; } -static void sata_fsl_error_handler(struct ata_port *ap) -{ - - DPRINTK("in xx_error_handler\n"); - - /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, sata_fsl_softreset, sata_std_hardreset, - ata_std_postreset); -} - static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) { if (qc->flags & ATA_QCFLAG_FAILED) @@ -1213,7 +1203,7 @@ static const struct ata_port_operations sata_fsl_ops = { .freeze = sata_fsl_freeze, .thaw = sata_fsl_thaw, - .error_handler = sata_fsl_error_handler, + .softreset = sata_fsl_softreset, .post_internal_cmd = sata_fsl_post_internal_cmd, .port_start = sata_fsl_port_start, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 047f80f5825c..ba1c09953517 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -452,8 +452,7 @@ static void inic_error_handler(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); /* PIO and DMA engines have been stopped, perform recovery */ - ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset, - ata_std_postreset); + ata_std_error_handler(ap); } static void inic_post_internal_cmd(struct ata_queued_cmd *qc) @@ -532,6 +531,8 @@ static struct ata_port_operations inic_port_ops = { .freeze = inic_freeze, .thaw = inic_thaw, + .softreset = ATA_OP_NULL, /* softreset is broken */ + .hardreset = inic_hardreset, .error_handler = inic_error_handler, .post_internal_cmd = inic_post_internal_cmd, .dev_config = inic_dev_config, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index f341a82d27bf..9a89390531b1 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -470,7 +470,10 @@ static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); static void mv_qc_prep_iie(struct ata_queued_cmd *qc); static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); -static void mv_error_handler(struct ata_port *ap); +static int mv_prereset(struct ata_link *link, unsigned long deadline); +static int mv_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static void mv_postreset(struct ata_link *link, unsigned int *classes); static void mv_eh_freeze(struct ata_port *ap); static void mv_eh_thaw(struct ata_port *ap); static void mv6_dev_config(struct ata_device *dev); @@ -534,7 +537,10 @@ static struct ata_port_operations mv5_ops = { .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, - .error_handler = mv_error_handler, + .prereset = mv_prereset, + .hardreset = mv_hardreset, + .postreset = mv_postreset, + .error_handler = ata_std_error_handler, /* avoid SFF EH */ .post_internal_cmd = ATA_OP_NULL, .scr_read = mv5_scr_read, @@ -2415,12 +2421,6 @@ static void mv_postreset(struct ata_link *link, unsigned int *classes) iowrite8(ap->ctl, ap->ioaddr.ctl_addr); } -static void mv_error_handler(struct ata_port *ap) -{ - ata_do_eh(ap, mv_prereset, ata_std_softreset, - mv_hardreset, mv_postreset); -} - static void mv_eh_freeze(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 5637b082bc85..b2eb5724cf85 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -309,7 +309,8 @@ static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); -static void nv_error_handler(struct ata_port *ap); +static int nv_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static int nv_adma_slave_config(struct scsi_device *sdev); static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc); static void nv_adma_qc_prep(struct ata_queued_cmd *qc); @@ -406,7 +407,7 @@ static struct scsi_host_template nv_swncq_sht = { static struct ata_port_operations nv_generic_ops = { .inherits = &ata_bmdma_port_ops, - .error_handler = nv_error_handler, + .hardreset = nv_hardreset, .scr_read = nv_scr_read, .scr_write = nv_scr_write, }; @@ -1599,12 +1600,6 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, return sata_std_hardreset(link, &dummy, deadline); } -static void nv_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, - nv_hardreset, ata_std_postreset); -} - static void nv_adma_error_handler(struct ata_port *ap) { struct nv_adma_port_priv *pp = ap->private_data; @@ -1658,8 +1653,7 @@ static void nv_adma_error_handler(struct ata_port *ap) readw(mmio + NV_ADMA_CTL); /* flush posted write */ } - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, - nv_hardreset, ata_std_postreset); + ata_bmdma_error_handler(ap); } static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc) @@ -1785,8 +1779,7 @@ static void nv_swncq_error_handler(struct ata_port *ap) ehc->i.action |= ATA_EH_RESET; } - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, - nv_hardreset, ata_std_postreset); + ata_bmdma_error_handler(ap); } #ifdef CONFIG_PM diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index e09b975c973d..91659dc15caf 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -148,8 +148,7 @@ static void pdc_freeze(struct ata_port *ap); static void pdc_sata_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); static void pdc_sata_thaw(struct ata_port *ap); -static void pdc_pata_error_handler(struct ata_port *ap); -static void pdc_sata_error_handler(struct ata_port *ap); +static void pdc_error_handler(struct ata_port *ap); static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); static int pdc_pata_cable_detect(struct ata_port *ap); static int pdc_sata_cable_detect(struct ata_port *ap); @@ -171,6 +170,7 @@ static const struct ata_port_operations pdc_common_ops = { .irq_clear = pdc_irq_clear, .post_internal_cmd = pdc_post_internal_cmd, + .error_handler = pdc_error_handler, }; static struct ata_port_operations pdc_sata_ops = { @@ -178,7 +178,6 @@ static struct ata_port_operations pdc_sata_ops = { .cable_detect = pdc_sata_cable_detect, .freeze = pdc_sata_freeze, .thaw = pdc_sata_thaw, - .error_handler = pdc_sata_error_handler, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_sata_port_start, @@ -195,7 +194,6 @@ static struct ata_port_operations pdc_pata_ops = { .cable_detect = pdc_pata_cable_detect, .freeze = pdc_freeze, .thaw = pdc_thaw, - .error_handler = pdc_pata_error_handler, .port_start = pdc_common_port_start, }; @@ -694,24 +692,12 @@ static void pdc_sata_thaw(struct ata_port *ap) readl(host_mmio + hotplug_offset); /* flush */ } -static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) +static void pdc_error_handler(struct ata_port *ap) { if (!(ap->pflags & ATA_PFLAG_FROZEN)) pdc_reset_port(ap); - /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, - ata_std_postreset); -} - -static void pdc_pata_error_handler(struct ata_port *ap) -{ - pdc_common_error_handler(ap, NULL); -} - -static void pdc_sata_error_handler(struct ata_port *ap) -{ - pdc_common_error_handler(ap, sata_std_hardreset); + ata_std_error_handler(ap); } static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 107ef09814de..2ceb0990bcd8 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -123,6 +123,7 @@ static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_freeze(struct ata_port *ap); static void qs_thaw(struct ata_port *ap); +static int qs_prereset(struct ata_link *link, unsigned long deadline); static void qs_error_handler(struct ata_port *ap); static struct scsi_host_template qs_ata_sht = { @@ -142,6 +143,8 @@ static struct ata_port_operations qs_ata_ops = { .freeze = qs_freeze, .thaw = qs_thaw, + .prereset = qs_prereset, + .softreset = ATA_OP_NULL, .error_handler = qs_error_handler, .post_internal_cmd = ATA_OP_NULL, @@ -250,8 +253,7 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static void qs_error_handler(struct ata_port *ap) { qs_enter_reg_mode(ap); - ata_do_eh(ap, qs_prereset, NULL, sata_std_hardreset, - ata_std_postreset); + ata_std_error_handler(ap); } static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 363fb90e1047..67df1d753305 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -352,6 +352,14 @@ static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); +static int sil24_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int sil24_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void sil24_error_handler(struct ata_port *ap); static void sil24_post_internal_cmd(struct ata_queued_cmd *qc); static int sil24_port_start(struct ata_port *ap); @@ -402,6 +410,10 @@ static struct ata_port_operations sil24_ops = { .freeze = sil24_freeze, .thaw = sil24_thaw, + .softreset = sil24_softreset, + .hardreset = sil24_hardreset, + .pmp_softreset = sil24_pmp_softreset, + .pmp_hardreset = sil24_pmp_hardreset, .error_handler = sil24_error_handler, .post_internal_cmd = sil24_post_internal_cmd, .dev_config = sil24_dev_config, @@ -1181,11 +1193,7 @@ static void sil24_error_handler(struct ata_port *ap) if (sil24_init_port(ap)) ata_eh_freeze_port(ap); - /* perform recovery */ - sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, - ata_std_postreset, sata_pmp_std_prereset, - sil24_pmp_softreset, sil24_pmp_hardreset, - sata_pmp_std_postreset); + sata_pmp_error_handler(ap); pp->do_port_rst = 0; } diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 6326bcf8ea5d..402fd7333d48 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -71,7 +71,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static void svia_noop_freeze(struct ata_port *ap); -static void vt6420_error_handler(struct ata_port *ap); +static int vt6420_prereset(struct ata_link *link, unsigned long deadline); static int vt6421_pata_cable_detect(struct ata_port *ap); static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); @@ -106,7 +106,7 @@ static struct scsi_host_template svia_sht = { static struct ata_port_operations vt6420_sata_ops = { .inherits = &ata_bmdma_port_ops, .freeze = svia_noop_freeze, - .error_handler = vt6420_error_handler, + .prereset = vt6420_prereset, }; static struct ata_port_operations vt6421_pata_ops = { @@ -247,12 +247,6 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) return 0; } -static void vt6420_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, NULL, - ata_std_postreset); -} - static int vt6421_pata_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index c72014a3e7d4..79fd2436bd70 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3937,7 +3937,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) if (ipr_is_gata(res) && res->sata_port) { ap = res->sata_port->ap; spin_unlock_irq(scsi_cmd->device->host->host_lock); - ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL); + ata_std_error_handler(ap); spin_lock_irq(scsi_cmd->device->host->host_lock); list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { @@ -5275,6 +5275,7 @@ static struct ata_port_operations ipr_sata_ops = { .check_altstatus = ipr_ata_check_altstatus, .dev_select = ata_noop_dev_select, .phy_reset = ipr_ata_phy_reset, + .hardreset = ipr_sata_reset, .post_internal_cmd = ipr_ata_post_internal, .tf_read = ipr_tf_read, .qc_prep = ata_noop_qc_prep, diff --git a/include/linux/libata.h b/include/linux/libata.h index 88c6fa84ed74..01c233303aee 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -693,6 +693,14 @@ struct ata_port_operations { void (*freeze)(struct ata_port *ap); void (*thaw)(struct ata_port *ap); + ata_prereset_fn_t prereset; + ata_reset_fn_t softreset; + ata_reset_fn_t hardreset; + ata_postreset_fn_t postreset; + ata_prereset_fn_t pmp_prereset; + ata_reset_fn_t pmp_softreset; + ata_reset_fn_t pmp_hardreset; + ata_postreset_fn_t pmp_postreset; void (*error_handler)(struct ata_port *ap); void (*post_internal_cmd)(struct ata_queued_cmd *qc); @@ -909,10 +917,6 @@ extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_noop_irq_clear(struct ata_port *ap); extern void ata_bmdma_freeze(struct ata_port *ap); extern void ata_bmdma_thaw(struct ata_port *ap); -extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, - ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset); extern void ata_bmdma_error_handler(struct ata_port *ap); extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, @@ -1056,11 +1060,7 @@ extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class); -extern void sata_pmp_do_eh(struct ata_port *ap, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, - ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, - ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset); +extern void sata_pmp_error_handler(struct ata_port *ap); /* * EH @@ -1080,6 +1080,7 @@ extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern void ata_std_error_handler(struct ata_port *ap); /* * Base operations to inherit from and initializers for sht -- cgit v1.2.3 From 624d5c514eed18d5a93062e9d86d67065175f30a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 22:16:41 +0900 Subject: libata: reorganize SFF related stuff * Move SFF related functions from libata-core.c to libata-sff.c. ata_[bmdma_]sff_port_ops, ata_devchk(), ata_dev_try_classify(), ata_std_dev_select(), ata_tf_to_host(), ata_busy_sleep(), ata_wait_after_reset(), ata_wait_ready(), ata_bus_post_reset(), ata_bus_softreset(), ata_bus_reset(), ata_std_softreset(), sata_std_hardreset(), ata_fill_sg(), ata_fill_sg_dumb(), ata_qc_prep(), ata_dump_qc_prep(), ata_data_xfer(), ata_data_xfer_noirq(), ata_pio_sector(), ata_pio_sectors(), atapi_send_cdb(), __atapi_pio_bytes(), atapi_pio_bytes(), ata_hsm_ok_in_wq(), ata_hsm_qc_complete(), ata_hsm_move(), ata_pio_task(), ata_qc_issue_prot(), ata_host_intr(), ata_interrupt(), ata_std_ports() * Make ata_pio_queue_task() global as it's now called from libata-sff.c. * Move SFF related stuff in include/linux/libata.h and drivers/ata/libata.h into one place. While at it, move timing constants into the global enum definition and fortify comments a bit. This patch strictly moves stuff around and as such doesn't cause any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2114 +++----------------------------------------- drivers/ata/libata-sff.c | 2151 +++++++++++++++++++++++++++++++++++++++++---- drivers/ata/libata.h | 8 +- include/linux/libata.h | 379 ++++---- 4 files changed, 2321 insertions(+), 2331 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7860d9f60ae4..34c068f18350 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -98,41 +97,6 @@ const struct ata_port_operations sata_pmp_port_ops = { .error_handler = sata_pmp_error_handler, }; -const struct ata_port_operations ata_sff_port_ops = { - .inherits = &ata_base_port_ops, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .softreset = ata_std_softreset, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .dev_select = ata_std_dev_select, - .check_status = ata_check_status, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .data_xfer = ata_data_xfer, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -const struct ata_port_operations ata_bmdma_port_ops = { - .inherits = &ata_sff_port_ops, - - .mode_filter = ata_pci_default_filter, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .irq_clear = ata_bmdma_irq_clear, -}; - static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -422,6 +386,14 @@ int atapi_cmd_type(u8 opcode) } } +/** + * ata_noop_irq_clear - Noop placeholder for irq_clear + * @ap: Port associated with this ATA transaction. + */ +void ata_noop_irq_clear(struct ata_port *ap) +{ +} + /** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert @@ -1102,50 +1074,6 @@ static void ata_lpm_disable(struct ata_host *host) } #endif /* CONFIG_PM */ - -/** - * ata_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * This technique was originally described in - * Hale Landis's ATADRVR (www.ata-atapi.com), and - * later found its way into the ATA/ATAPI spec. - * - * Write a pattern to the ATA shadow registers, - * and if a device is present, it will respond by - * correctly storing and echoing back the - * ATA shadow register contents. - * - * LOCKING: - * caller. - */ - -static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 nsect, lbal; - - ap->ops->dev_select(ap, device); - - iowrite8(0x55, ioaddr->nsect_addr); - iowrite8(0xaa, ioaddr->lbal_addr); - - iowrite8(0xaa, ioaddr->nsect_addr); - iowrite8(0x55, ioaddr->lbal_addr); - - iowrite8(0x55, ioaddr->nsect_addr); - iowrite8(0xaa, ioaddr->lbal_addr); - - nsect = ioread8(ioaddr->nsect_addr); - lbal = ioread8(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - - return 0; /* nothing found */ -} - /** * ata_dev_classify - determine device type based on ATA-spec signature * @tf: ATA taskfile register set for device to be identified @@ -1205,75 +1133,6 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) return ATA_DEV_UNKNOWN; } -/** - * ata_dev_try_classify - Parse returned ATA device signature - * @dev: ATA device to classify (starting at zero) - * @present: device seems present - * @r_err: Value of error register on completion - * - * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, - * an ATA/ATAPI-defined set of values is placed in the ATA - * shadow registers, indicating the results of device detection - * and diagnostics. - * - * Select the ATA device, and read the values from the ATA shadow - * registers. Then parse according to the Error register value, - * and the spec-defined values examined by ata_dev_classify(). - * - * LOCKING: - * caller. - * - * RETURNS: - * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. - */ -unsigned int ata_dev_try_classify(struct ata_device *dev, int present, - u8 *r_err) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - unsigned int class; - u8 err; - - ap->ops->dev_select(ap, dev->devno); - - memset(&tf, 0, sizeof(tf)); - - ap->ops->tf_read(ap, &tf); - err = tf.feature; - if (r_err) - *r_err = err; - - /* see if device passed diags: continue and warn later */ - if (err == 0) - /* diagnostic fail : do nothing _YET_ */ - dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; - else if (err == 1) - /* do nothing */ ; - else if ((dev->devno == 0) && (err == 0x81)) - /* do nothing */ ; - else - return ATA_DEV_NONE; - - /* determine if device is ATA or ATAPI */ - class = ata_dev_classify(&tf); - - if (class == ATA_DEV_UNKNOWN) { - /* If the device failed diagnostic, it's likely to - * have reported incorrect device signature too. - * Assume ATA device if the device seems present but - * device signature is invalid with diagnostic - * failure. - */ - if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC)) - class = ATA_DEV_ATA; - else - class = ATA_DEV_NONE; - } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) - class = ATA_DEV_NONE; - - return class; -} - /** * ata_id_string - Convert IDENTIFY DEVICE page into string * @id: IDENTIFY DEVICE results we will examine @@ -1597,73 +1456,6 @@ void ata_noop_dev_select(struct ata_port *ap, unsigned int device) { } - -/** - * ata_std_dev_select - Select device 0/1 on ATA bus - * @ap: ATA channel to manipulate - * @device: ATA device (numbered from zero) to select - * - * Use the method defined in the ATA specification to - * make either device 0, or device 1, active on the - * ATA channel. Works with both PIO and MMIO. - * - * May be used as the dev_select() entry in ata_port_operations. - * - * LOCKING: - * caller. - */ - -void ata_std_dev_select(struct ata_port *ap, unsigned int device) -{ - u8 tmp; - - if (device == 0) - tmp = ATA_DEVICE_OBS; - else - tmp = ATA_DEVICE_OBS | ATA_DEV1; - - iowrite8(tmp, ap->ioaddr.device_addr); - ata_pause(ap); /* needed; also flushes, for mmio */ -} - -/** - * ata_dev_select - Select device 0/1 on ATA bus - * @ap: ATA channel to manipulate - * @device: ATA device (numbered from zero) to select - * @wait: non-zero to wait for Status register BSY bit to clear - * @can_sleep: non-zero if context allows sleeping - * - * Use the method defined in the ATA specification to - * make either device 0, or device 1, active on the - * ATA channel. - * - * This is a high-level version of ata_std_dev_select(), - * which additionally provides the services of inserting - * the proper pauses and status polling, where needed. - * - * LOCKING: - * caller. - */ - -void ata_dev_select(struct ata_port *ap, unsigned int device, - unsigned int wait, unsigned int can_sleep) -{ - if (ata_msg_probe(ap)) - ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, " - "device %u, wait %u\n", device, wait); - - if (wait) - ata_wait_idle(ap); - - ap->ops->dev_select(ap, device); - - if (wait) { - if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) - msleep(150); - ata_wait_idle(ap); - } -} - /** * ata_dump_id - IDENTIFY DEVICE info debugging output * @id: IDENTIFY DEVICE page to dump @@ -1791,8 +1583,7 @@ unsigned long ata_id_xfermask(const u16 *id) * LOCKING: * Inherited from caller. */ -static void ata_pio_queue_task(struct ata_port *ap, void *data, - unsigned long delay) +void ata_pio_queue_task(struct ata_port *ap, void *data, unsigned long delay) { ap->port_task_data = data; @@ -3531,353 +3322,6 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) return rc; } -/** - * ata_tf_to_host - issue ATA taskfile to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues ATA taskfile register set to ATA host controller, - * with proper synchronization with interrupt handler and - * other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static inline void ata_tf_to_host(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - ap->ops->tf_load(ap, tf); - ap->ops->exec_command(ap, tf); -} - -/** - * ata_busy_sleep - sleep until BSY clears, or timeout - * @ap: port containing status register to be polled - * @tmout_pat: impatience timeout - * @tmout: overall timeout - * - * Sleep until ATA Status register bit BSY clears, - * or a timeout occurs. - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_busy_sleep(struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) -{ - unsigned long timer_start, timeout; - u8 status; - - status = ata_busy_wait(ap, ATA_BUSY, 300); - timer_start = jiffies; - timeout = timer_start + tmout_pat; - while (status != 0xff && (status & ATA_BUSY) && - time_before(jiffies, timeout)) { - msleep(50); - status = ata_busy_wait(ap, ATA_BUSY, 3); - } - - if (status != 0xff && (status & ATA_BUSY)) - ata_port_printk(ap, KERN_WARNING, - "port is slow to respond, please be patient " - "(Status 0x%x)\n", status); - - timeout = timer_start + tmout; - while (status != 0xff && (status & ATA_BUSY) && - time_before(jiffies, timeout)) { - msleep(50); - status = ata_chk_status(ap); - } - - if (status == 0xff) - return -ENODEV; - - if (status & ATA_BUSY) { - ata_port_printk(ap, KERN_ERR, "port failed to respond " - "(%lu secs, Status 0x%x)\n", - tmout / HZ, status); - return -EBUSY; - } - - return 0; -} - -/** - * ata_wait_after_reset - wait before checking status after reset - * @ap: port containing status register to be polled - * @deadline: deadline jiffies for the operation - * - * After reset, we need to pause a while before reading status. - * Also, certain combination of controller and device report 0xff - * for some duration (e.g. until SATA PHY is up and running) - * which is interpreted as empty port in ATA world. This - * function also waits for such devices to get out of 0xff - * status. - * - * LOCKING: - * Kernel thread context (may sleep). - */ -void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) -{ - unsigned long until = jiffies + ATA_TMOUT_FF_WAIT; - - if (time_before(until, deadline)) - deadline = until; - - /* Spec mandates ">= 2ms" before checking status. We wait - * 150ms, because that was the magic delay used for ATAPI - * devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready. - */ - msleep(150); - - /* Wait for 0xff to clear. Some SATA devices take a long time - * to clear 0xff after reset. For example, HHD424020F7SV00 - * iVDR needs >= 800ms while. Quantum GoVault needs even more - * than that. - * - * Note that some PATA controllers (pata_ali) explode if - * status register is read more than once when there's no - * device attached. - */ - if (ap->flags & ATA_FLAG_SATA) { - while (1) { - u8 status = ata_chk_status(ap); - - if (status != 0xff || time_after(jiffies, deadline)) - return; - - msleep(50); - } - } -} - -/** - * ata_wait_ready - sleep until BSY clears, or timeout - * @ap: port containing status register to be polled - * @deadline: deadline jiffies for the operation - * - * Sleep until ATA Status register bit BSY clears, or timeout - * occurs. - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_wait_ready(struct ata_port *ap, unsigned long deadline) -{ - unsigned long start = jiffies; - int warned = 0; - - while (1) { - u8 status = ata_chk_status(ap); - unsigned long now = jiffies; - - if (!(status & ATA_BUSY)) - return 0; - if (!ata_link_online(&ap->link) && status == 0xff) - return -ENODEV; - if (time_after(now, deadline)) - return -EBUSY; - - if (!warned && time_after(now, start + 5 * HZ) && - (deadline - now > 3 * HZ)) { - ata_port_printk(ap, KERN_WARNING, - "port is slow to respond, please be patient " - "(Status 0x%x)\n", status); - warned = 1; - } - - msleep(50); - } -} - -static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, - unsigned long deadline) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int dev0 = devmask & (1 << 0); - unsigned int dev1 = devmask & (1 << 1); - int rc, ret = 0; - - /* if device 0 was found in ata_devchk, wait for its - * BSY bit to clear - */ - if (dev0) { - rc = ata_wait_ready(ap, deadline); - if (rc) { - if (rc != -ENODEV) - return rc; - ret = rc; - } - } - - /* if device 1 was found in ata_devchk, wait for register - * access briefly, then wait for BSY to clear. - */ - if (dev1) { - int i; - - ap->ops->dev_select(ap, 1); - - /* Wait for register access. Some ATAPI devices fail - * to set nsect/lbal after reset, so don't waste too - * much time on it. We're gonna wait for !BSY anyway. - */ - for (i = 0; i < 2; i++) { - u8 nsect, lbal; - - nsect = ioread8(ioaddr->nsect_addr); - lbal = ioread8(ioaddr->lbal_addr); - if ((nsect == 1) && (lbal == 1)) - break; - msleep(50); /* give drive a breather */ - } - - rc = ata_wait_ready(ap, deadline); - if (rc) { - if (rc != -ENODEV) - return rc; - ret = rc; - } - } - - /* is all this really necessary? */ - ap->ops->dev_select(ap, 0); - if (dev1) - ap->ops->dev_select(ap, 1); - if (dev0) - ap->ops->dev_select(ap, 0); - - return ret; -} - -static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, - unsigned long deadline) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); - - /* software reset. causes dev0 to be selected */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - - /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); - - /* Before we perform post reset processing we want to see if - * the bus shows 0xFF because the odd clown forgets the D7 - * pulldown resistor. - */ - if (ata_chk_status(ap) == 0xFF) - return -ENODEV; - - return ata_bus_post_reset(ap, devmask, deadline); -} - -/** - * ata_bus_reset - reset host port and associated ATA channel - * @ap: port to reset - * - * This is typically the first time we actually start issuing - * commands to the ATA channel. We wait for BSY to clear, then - * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its - * result. Determine what devices, if any, are on the channel - * by looking at the device 0/1 error register. Look at the signature - * stored in each device's taskfile registers, to determine if - * the device is ATA or ATAPI. - * - * LOCKING: - * PCI/etc. bus probe sem. - * Obtains host lock. - * - * SIDE EFFECTS: - * Sets ATA_FLAG_DISABLED if bus reset fails. - */ - -void ata_bus_reset(struct ata_port *ap) -{ - struct ata_device *device = ap->link.device; - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - u8 err; - unsigned int dev0, dev1 = 0, devmask = 0; - int rc; - - DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); - - /* determine if device 0/1 are present */ - if (ap->flags & ATA_FLAG_SATA_RESET) - dev0 = 1; - else { - dev0 = ata_devchk(ap, 0); - if (slave_possible) - dev1 = ata_devchk(ap, 1); - } - - if (dev0) - devmask |= (1 << 0); - if (dev1) - devmask |= (1 << 1); - - /* select device 0 again */ - ap->ops->dev_select(ap, 0); - - /* issue bus reset */ - if (ap->flags & ATA_FLAG_SRST) { - rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ); - if (rc && rc != -ENODEV) - goto err_out; - } - - /* - * determine by signature whether we have ATA or ATAPI devices - */ - device[0].class = ata_dev_try_classify(&device[0], dev0, &err); - if ((slave_possible) && (err != 0x81)) - device[1].class = ata_dev_try_classify(&device[1], dev1, &err); - - /* is double-select really necessary? */ - if (device[1].class != ATA_DEV_NONE) - ap->ops->dev_select(ap, 1); - if (device[0].class != ATA_DEV_NONE) - ap->ops->dev_select(ap, 0); - - /* if no devices were detected, disable this port */ - if ((device[0].class == ATA_DEV_NONE) && - (device[1].class == ATA_DEV_NONE)) - goto err_out; - - if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { - /* set up device control for ATA_FLAG_SATA_RESET */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - } - - DPRINTK("EXIT\n"); - return; - -err_out: - ata_port_printk(ap, KERN_ERR, "disabling port\n"); - ata_port_disable(ap); - - DPRINTK("EXIT\n"); -} - /** * sata_link_debounce - debounce SATA phy status * @link: ATA link to debounce SATA phy status for @@ -4034,12 +3478,12 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) } /** - * ata_std_softreset - reset host port via ATA SRST - * @link: ATA link to reset - * @classes: resulting classes of attached devices + * sata_link_hardreset - reset link via SATA phy reset + * @link: link to reset + * @timing: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Reset host port using ATA SRST. + * SATA phy-reset @link using DET bits of SControl register. * * LOCKING: * Kernel thread context (may sleep) @@ -4047,70 +3491,10 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) +int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, + unsigned long deadline) { - struct ata_port *ap = link->ap; - unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - unsigned int devmask = 0; - int rc; - u8 err; - - DPRINTK("ENTER\n"); - - if (ata_link_offline(link)) { - classes[0] = ATA_DEV_NONE; - goto out; - } - - /* determine if device 0/1 are present */ - if (ata_devchk(ap, 0)) - devmask |= (1 << 0); - if (slave_possible && ata_devchk(ap, 1)) - devmask |= (1 << 1); - - /* select device 0 again */ - ap->ops->dev_select(ap, 0); - - /* issue bus reset */ - DPRINTK("about to softreset, devmask=%x\n", devmask); - rc = ata_bus_softreset(ap, devmask, deadline); - /* if link is occupied, -ENODEV too is an error */ - if (rc && (rc != -ENODEV || sata_scr_valid(link))) { - ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); - return rc; - } - - /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(&link->device[0], - devmask & (1 << 0), &err); - if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(&link->device[1], - devmask & (1 << 1), &err); - - out: - DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); - return 0; -} - -/** - * sata_link_hardreset - reset link via SATA phy reset - * @link: link to reset - * @timing: timing parameters { interval, duratinon, timeout } in msec - * @deadline: deadline jiffies for the operation - * - * SATA phy-reset @link using DET bits of SControl register. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, - unsigned long deadline) -{ - u32 scontrol; + u32 scontrol; int rc; DPRINTK("ENTER\n"); @@ -4153,74 +3537,6 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, return rc; } -/** - * sata_std_hardreset - reset host port via SATA phy reset - * @link: link to reset - * @class: resulting class of attached device - * @deadline: deadline jiffies for the operation - * - * SATA phy-reset host port using DET bits of SControl register, - * wait for !BSY and classify the attached device. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int sata_std_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - struct ata_port *ap = link->ap; - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); - int rc; - - DPRINTK("ENTER\n"); - - /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline); - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_link_offline(link)) { - *class = ATA_DEV_NONE; - DPRINTK("EXIT, link offline\n"); - return 0; - } - - /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); - - /* If PMP is supported, we have to do follow-up SRST. Note - * that some PMPs don't send D2H Reg FIS after hardreset at - * all if the first port is empty. Wait for it just for a - * second and request follow-up SRST. - */ - if (ap->flags & ATA_FLAG_PMP) { - ata_wait_ready(ap, jiffies + HZ); - return -EAGAIN; - } - - rc = ata_wait_ready(ap, deadline); - /* link occupied, -ENODEV too is an error */ - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - ap->ops->dev_select(ap, 0); /* probably unnecessary */ - - *class = ata_dev_try_classify(link->device, 1, NULL); - - DPRINTK("EXIT, class=%u\n", *class); - return 0; -} - /** * ata_std_postreset - standard postreset callback * @link: the target ata_link @@ -4803,112 +4119,6 @@ void ata_sg_clean(struct ata_queued_cmd *qc) qc->sg = NULL; } -/** - * ata_fill_sg - Fill PCI IDE PRD table - * @qc: Metadata associated with taskfile to be transferred - * - * Fill PCI IDE PRD (scatter-gather) table with segments - * associated with the current disk command. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - */ -static void ata_fill_sg(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct scatterlist *sg; - unsigned int si, pi; - - pi = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { - u32 addr, offset; - u32 sg_len, len; - - /* determine if physical DMA addr spans 64K boundary. - * Note h/w doesn't support 64-bit, so we unconditionally - * truncate dma_addr_t to u32. - */ - addr = (u32) sg_dma_address(sg); - sg_len = sg_dma_len(sg); - - while (sg_len) { - offset = addr & 0xffff; - len = sg_len; - if ((offset + sg_len) > 0x10000) - len = 0x10000 - offset; - - ap->prd[pi].addr = cpu_to_le32(addr); - ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); - - pi++; - sg_len -= len; - addr += len; - } - } - - ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); -} - -/** - * ata_fill_sg_dumb - Fill PCI IDE PRD table - * @qc: Metadata associated with taskfile to be transferred - * - * Fill PCI IDE PRD (scatter-gather) table with segments - * associated with the current disk command. Perform the fill - * so that we avoid writing any length 64K records for - * controllers that don't follow the spec. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - */ -static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct scatterlist *sg; - unsigned int si, pi; - - pi = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { - u32 addr, offset; - u32 sg_len, len, blen; - - /* determine if physical DMA addr spans 64K boundary. - * Note h/w doesn't support 64-bit, so we unconditionally - * truncate dma_addr_t to u32. - */ - addr = (u32) sg_dma_address(sg); - sg_len = sg_dma_len(sg); - - while (sg_len) { - offset = addr & 0xffff; - len = sg_len; - if ((offset + sg_len) > 0x10000) - len = 0x10000 - offset; - - blen = len & 0xffff; - ap->prd[pi].addr = cpu_to_le32(addr); - if (blen == 0) { - /* Some PATA chipsets like the CS5530 can't - cope with 0x0000 meaning 64K as the spec says */ - ap->prd[pi].flags_len = cpu_to_le32(0x8000); - blen = 0x8000; - ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000); - } - ap->prd[pi].flags_len = cpu_to_le32(blen); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); - - pi++; - sg_len -= len; - addr += len; - } - } - - ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); -} - /** * ata_check_atapi_dma - Check whether ATAPI DMA can be supported * @qc: Metadata associated with taskfile to check @@ -4918,858 +4128,132 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) * supplied PACKET command. * * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: 0 when ATAPI DMA can be used - * nonzero otherwise - */ -int ata_check_atapi_dma(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - /* Don't allow DMA if it isn't multiple of 16 bytes. Quite a - * few ATAPI devices choke on such DMA requests. - */ - if (unlikely(qc->nbytes & 15)) - return 1; - - if (ap->ops->check_atapi_dma) - return ap->ops->check_atapi_dma(qc); - - return 0; -} - -/** - * ata_std_qc_defer - Check whether a qc needs to be deferred - * @qc: ATA command in question - * - * Non-NCQ commands cannot run with any other command, NCQ or - * not. As upper layer only knows the queue depth, we are - * responsible for maintaining exclusion. This function checks - * whether a new command @qc can be issued. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * ATA_DEFER_* if deferring is needed, 0 otherwise. - */ -int ata_std_qc_defer(struct ata_queued_cmd *qc) -{ - struct ata_link *link = qc->dev->link; - - if (qc->tf.protocol == ATA_PROT_NCQ) { - if (!ata_tag_valid(link->active_tag)) - return 0; - } else { - if (!ata_tag_valid(link->active_tag) && !link->sactive) - return 0; - } - - return ATA_DEFER_LINK; -} - -/** - * ata_qc_prep - Prepare taskfile for submission - * @qc: Metadata associated with taskfile to be prepared - * - * Prepare ATA taskfile for submission. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_qc_prep(struct ata_queued_cmd *qc) -{ - if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; - - ata_fill_sg(qc); -} - -/** - * ata_dumb_qc_prep - Prepare taskfile for submission - * @qc: Metadata associated with taskfile to be prepared - * - * Prepare ATA taskfile for submission. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_dumb_qc_prep(struct ata_queued_cmd *qc) -{ - if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; - - ata_fill_sg_dumb(qc); -} - -void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } - -/** - * ata_sg_init - Associate command with scatter-gather table. - * @qc: Command to be associated - * @sg: Scatter-gather table. - * @n_elem: Number of elements in s/g table. - * - * Initialize the data-related elements of queued_cmd @qc - * to point to a scatter-gather table @sg, containing @n_elem - * elements. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, - unsigned int n_elem) -{ - qc->sg = sg; - qc->n_elem = n_elem; - qc->cursg = qc->sg; -} - -/** - * ata_sg_setup - DMA-map the scatter-gather table associated with a command. - * @qc: Command with scatter-gather table to be mapped. - * - * DMA-map the scatter-gather table associated with queued_cmd @qc. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Zero on success, negative on error. - * - */ -static int ata_sg_setup(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int n_elem; - - VPRINTK("ENTER, ata%u\n", ap->print_id); - - n_elem = dma_map_sg(ap->dev, qc->sg, qc->n_elem, qc->dma_dir); - if (n_elem < 1) - return -1; - - DPRINTK("%d sg elements mapped\n", n_elem); - - qc->n_elem = n_elem; - qc->flags |= ATA_QCFLAG_DMAMAP; - - return 0; -} - -/** - * swap_buf_le16 - swap halves of 16-bit words in place - * @buf: Buffer to swap - * @buf_words: Number of 16-bit words in buffer. - * - * Swap halves of 16-bit words if needed to convert from - * little-endian byte order to native cpu byte order, or - * vice-versa. - * - * LOCKING: - * Inherited from caller. - */ -void swap_buf_le16(u16 *buf, unsigned int buf_words) -{ -#ifdef __BIG_ENDIAN - unsigned int i; - - for (i = 0; i < buf_words; i++) - buf[i] = le16_to_cpu(buf[i]); -#endif /* __BIG_ENDIAN */ -} - -/** - * ata_data_xfer - Transfer data by PIO - * @dev: device to target - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Transfer data from/to the device data register by PIO. - * - * LOCKING: - * Inherited from caller. - * - * RETURNS: - * Bytes consumed. - */ -unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) -{ - struct ata_port *ap = dev->link->ap; - void __iomem *data_addr = ap->ioaddr.data_addr; - unsigned int words = buflen >> 1; - - /* Transfer multiple of 2 bytes */ - if (rw == READ) - ioread16_rep(data_addr, buf, words); - else - iowrite16_rep(data_addr, buf, words); - - /* Transfer trailing 1 byte, if any. */ - if (unlikely(buflen & 0x01)) { - __le16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (rw == READ) { - align_buf[0] = cpu_to_le16(ioread16(data_addr)); - memcpy(trailing_buf, align_buf, 1); - } else { - memcpy(align_buf, trailing_buf, 1); - iowrite16(le16_to_cpu(align_buf[0]), data_addr); - } - words++; - } - - return words << 1; -} - -/** - * ata_data_xfer_noirq - Transfer data by PIO - * @dev: device to target - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Transfer data from/to the device data register by PIO. Do the - * transfer with interrupts disabled. - * - * LOCKING: - * Inherited from caller. - * - * RETURNS: - * Bytes consumed. - */ -unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) -{ - unsigned long flags; - unsigned int consumed; - - local_irq_save(flags); - consumed = ata_data_xfer(dev, buf, buflen, rw); - local_irq_restore(flags); - - return consumed; -} - - -/** - * ata_pio_sector - Transfer a sector of data. - * @qc: Command on going - * - * Transfer qc->sect_size bytes of data from/to the ATA device. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_pio_sector(struct ata_queued_cmd *qc) -{ - int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct ata_port *ap = qc->ap; - struct page *page; - unsigned int offset; - unsigned char *buf; - - if (qc->curbytes == qc->nbytes - qc->sect_size) - ap->hsm_task_state = HSM_ST_LAST; - - page = sg_page(qc->cursg); - offset = qc->cursg->offset + qc->cursg_ofs; - - /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); - offset %= PAGE_SIZE; - - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - - if (PageHighMem(page)) { - unsigned long flags; - - /* FIXME: use a bounce buffer */ - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); - - /* do the actual data transfer */ - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); - - kunmap_atomic(buf, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(page); - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); - } - - qc->curbytes += qc->sect_size; - qc->cursg_ofs += qc->sect_size; - - if (qc->cursg_ofs == qc->cursg->length) { - qc->cursg = sg_next(qc->cursg); - qc->cursg_ofs = 0; - } -} - -/** - * ata_pio_sectors - Transfer one or many sectors. - * @qc: Command on going - * - * Transfer one or many sectors of data from/to the - * ATA device for the DRQ request. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_pio_sectors(struct ata_queued_cmd *qc) -{ - if (is_multi_taskfile(&qc->tf)) { - /* READ/WRITE MULTIPLE */ - unsigned int nsect; - - WARN_ON(qc->dev->multi_count == 0); - - nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, - qc->dev->multi_count); - while (nsect--) - ata_pio_sector(qc); - } else - ata_pio_sector(qc); - - ata_altstatus(qc->ap); /* flush */ -} - -/** - * atapi_send_cdb - Write CDB bytes to hardware - * @ap: Port to which ATAPI device is attached. - * @qc: Taskfile currently active - * - * When device has indicated its readiness to accept - * a CDB, this function is called. Send the CDB. - * - * LOCKING: - * caller. - */ - -static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) -{ - /* send SCSI cdb */ - DPRINTK("send cdb\n"); - WARN_ON(qc->dev->cdb_len < 12); - - ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); - ata_altstatus(ap); /* flush */ - - switch (qc->tf.protocol) { - case ATAPI_PROT_PIO: - ap->hsm_task_state = HSM_ST; - break; - case ATAPI_PROT_NODATA: - ap->hsm_task_state = HSM_ST_LAST; - break; - case ATAPI_PROT_DMA: - ap->hsm_task_state = HSM_ST_LAST; - /* initiate bmdma */ - ap->ops->bmdma_start(qc); - break; - } -} - -/** - * __atapi_pio_bytes - Transfer data from/to the ATAPI device. - * @qc: Command on going - * @bytes: number of bytes - * - * Transfer Transfer data from/to the ATAPI device. - * - * LOCKING: - * Inherited from caller. - * - */ -static int __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) -{ - int rw = (qc->tf.flags & ATA_TFLAG_WRITE) ? WRITE : READ; - struct ata_port *ap = qc->ap; - struct ata_device *dev = qc->dev; - struct ata_eh_info *ehi = &dev->link->eh_info; - struct scatterlist *sg; - struct page *page; - unsigned char *buf; - unsigned int offset, count, consumed; - -next_sg: - sg = qc->cursg; - if (unlikely(!sg)) { - ata_ehi_push_desc(ehi, "unexpected or too much trailing data " - "buf=%u cur=%u bytes=%u", - qc->nbytes, qc->curbytes, bytes); - return -1; - } - - page = sg_page(sg); - offset = sg->offset + qc->cursg_ofs; - - /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); - offset %= PAGE_SIZE; - - /* don't overrun current sg */ - count = min(sg->length - qc->cursg_ofs, bytes); - - /* don't cross page boundaries */ - count = min(count, (unsigned int)PAGE_SIZE - offset); - - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - - if (PageHighMem(page)) { - unsigned long flags; - - /* FIXME: use bounce buffer */ - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); - - /* do the actual data transfer */ - consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); - - kunmap_atomic(buf, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(page); - consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); - } - - bytes -= min(bytes, consumed); - qc->curbytes += count; - qc->cursg_ofs += count; - - if (qc->cursg_ofs == sg->length) { - qc->cursg = sg_next(qc->cursg); - qc->cursg_ofs = 0; - } - - /* consumed can be larger than count only for the last transfer */ - WARN_ON(qc->cursg && count != consumed); - - if (bytes) - goto next_sg; - return 0; -} - -/** - * atapi_pio_bytes - Transfer data from/to the ATAPI device. - * @qc: Command on going - * - * Transfer Transfer data from/to the ATAPI device. - * - * LOCKING: - * Inherited from caller. - */ - -static void atapi_pio_bytes(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_device *dev = qc->dev; - struct ata_eh_info *ehi = &dev->link->eh_info; - unsigned int ireason, bc_lo, bc_hi, bytes; - int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0; - - /* Abuse qc->result_tf for temp storage of intermediate TF - * here to save some kernel stack usage. - * For normal completion, qc->result_tf is not relevant. For - * error, qc->result_tf is later overwritten by ata_qc_complete(). - * So, the correctness of qc->result_tf is not affected. - */ - ap->ops->tf_read(ap, &qc->result_tf); - ireason = qc->result_tf.nsect; - bc_lo = qc->result_tf.lbam; - bc_hi = qc->result_tf.lbah; - bytes = (bc_hi << 8) | bc_lo; - - /* shall be cleared to zero, indicating xfer of data */ - if (unlikely(ireason & (1 << 0))) - goto atapi_check; - - /* make sure transfer direction matches expected */ - i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; - if (unlikely(do_write != i_write)) - goto atapi_check; - - if (unlikely(!bytes)) - goto atapi_check; - - VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); - - if (unlikely(__atapi_pio_bytes(qc, bytes))) - goto err_out; - ata_altstatus(ap); /* flush */ - - return; - - atapi_check: - ata_ehi_push_desc(ehi, "ATAPI check failed (ireason=0x%x bytes=%u)", - ireason, bytes); - err_out: - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; -} - -/** - * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue. - * @ap: the target ata_port - * @qc: qc on going - * - * RETURNS: - * 1 if ok in workqueue, 0 otherwise. - */ - -static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) -{ - if (qc->tf.flags & ATA_TFLAG_POLLING) - return 1; - - if (ap->hsm_task_state == HSM_ST_FIRST) { - if (qc->tf.protocol == ATA_PROT_PIO && - (qc->tf.flags & ATA_TFLAG_WRITE)) - return 1; - - if (ata_is_atapi(qc->tf.protocol) && - !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; - } - - return 0; -} - -/** - * ata_hsm_qc_complete - finish a qc running on standard HSM - * @qc: Command to complete - * @in_wq: 1 if called from workqueue, 0 otherwise - * - * Finish @qc which is running on standard HSM. - * - * LOCKING: - * If @in_wq is zero, spin_lock_irqsave(host lock). - * Otherwise, none on entry and grabs host lock. - */ -static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) -{ - struct ata_port *ap = qc->ap; - unsigned long flags; - - if (ap->ops->error_handler) { - if (in_wq) { - spin_lock_irqsave(ap->lock, flags); - - /* EH might have kicked in while host lock is - * released. - */ - qc = ata_qc_from_tag(ap, qc->tag); - if (qc) { - if (likely(!(qc->err_mask & AC_ERR_HSM))) { - ap->ops->irq_on(ap); - ata_qc_complete(qc); - } else - ata_port_freeze(ap); - } - - spin_unlock_irqrestore(ap->lock, flags); - } else { - if (likely(!(qc->err_mask & AC_ERR_HSM))) - ata_qc_complete(qc); - else - ata_port_freeze(ap); - } - } else { - if (in_wq) { - spin_lock_irqsave(ap->lock, flags); - ap->ops->irq_on(ap); - ata_qc_complete(qc); - spin_unlock_irqrestore(ap->lock, flags); - } else - ata_qc_complete(qc); - } -} - -/** - * ata_hsm_move - move the HSM to the next state. - * @ap: the target ata_port - * @qc: qc on going - * @status: current device status - * @in_wq: 1 if called from workqueue, 0 otherwise - * - * RETURNS: - * 1 when poll next status needed, 0 otherwise. - */ -int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq) -{ - unsigned long flags = 0; - int poll_next; - - WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); - - /* Make sure ata_qc_issue_prot() does not throw things - * like DMA polling into the workqueue. Notice that - * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). - */ - WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); - -fsm_start: - DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", - ap->print_id, qc->tf.protocol, ap->hsm_task_state, status); - - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - /* Send first data block or PACKET CDB */ - - /* If polling, we will stay in the work queue after - * sending the data. Otherwise, interrupt handler - * takes over after sending the data. - */ - poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); - - /* check device status */ - if (unlikely((status & ATA_DRQ) == 0)) { - /* handle BSY=0, DRQ=0 as error */ - if (likely(status & (ATA_ERR | ATA_DF))) - /* device stops HSM for abort/error */ - qc->err_mask |= AC_ERR_DEV; - else - /* HSM violation. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; - - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - /* Device should not ask for data transfer (DRQ=1) - * when it finds something wrong. - * We ignore DRQ here and stop the HSM by - * changing hsm_task_state to HSM_ST_ERR and - * let the EH abort the command or reset the device. - */ - if (unlikely(status & (ATA_ERR | ATA_DF))) { - /* Some ATAPI tape drives forget to clear the ERR bit - * when doing the next command (mostly request sense). - * We ignore ERR here to workaround and proceed sending - * the CDB. - */ - if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { - ata_port_printk(ap, KERN_WARNING, - "DRQ=1 with device error, " - "dev_stat 0x%X\n", status); - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - } - - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - if (in_wq) - spin_lock_irqsave(ap->lock, flags); - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - - /* ata_pio_sectors() might change the state - * to HSM_ST_LAST. so, the state is changed here - * before ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sectors(qc); - } else - /* send CDB */ - atapi_send_cdb(ap, qc); - - if (in_wq) - spin_unlock_irqrestore(ap->lock, flags); - - /* if polling, ata_pio_task() handles the rest. - * otherwise, interrupt handler takes over from here. - */ - break; - - case HSM_ST: - /* complete command or read/write the data register */ - if (qc->tf.protocol == ATAPI_PROT_PIO) { - /* ATAPI PIO protocol */ - if ((status & ATA_DRQ) == 0) { - /* No more data to transfer or device error. - * Device error will be tagged in HSM_ST_LAST. - */ - ap->hsm_task_state = HSM_ST_LAST; - goto fsm_start; - } - - /* Device should not ask for data transfer (DRQ=1) - * when it finds something wrong. - * We ignore DRQ here and stop the HSM by - * changing hsm_task_state to HSM_ST_ERR and - * let the EH abort the command or reset the device. - */ - if (unlikely(status & (ATA_ERR | ATA_DF))) { - ata_port_printk(ap, KERN_WARNING, "DRQ=1 with " - "device error, dev_stat 0x%X\n", - status); - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - atapi_pio_bytes(qc); - - if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) - /* bad ireason reported by device */ - goto fsm_start; - - } else { - /* ATA PIO protocol */ - if (unlikely((status & ATA_DRQ) == 0)) { - /* handle BSY=0, DRQ=0 as error */ - if (likely(status & (ATA_ERR | ATA_DF))) - /* device stops HSM for abort/error */ - qc->err_mask |= AC_ERR_DEV; - else - /* HSM violation. Let EH handle this. - * Phantom devices also trigger this - * condition. Mark hint. - */ - qc->err_mask |= AC_ERR_HSM | - AC_ERR_NODEV_HINT; - - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - /* For PIO reads, some devices may ask for - * data transfer (DRQ=1) alone with ERR=1. - * We respect DRQ here and transfer one - * block of junk data before changing the - * hsm_task_state to HSM_ST_ERR. - * - * For PIO writes, ERR=1 DRQ=1 doesn't make - * sense since the data block has been - * transferred to the device. - */ - if (unlikely(status & (ATA_ERR | ATA_DF))) { - /* data might be corrputed */ - qc->err_mask |= AC_ERR_DEV; - - if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { - ata_pio_sectors(qc); - status = ata_wait_idle(ap); - } - - if (status & (ATA_BUSY | ATA_DRQ)) - qc->err_mask |= AC_ERR_HSM; - - /* ata_pio_sectors() might change the - * state to HSM_ST_LAST. so, the state - * is changed after ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } + * spin_lock_irqsave(host lock) + * + * RETURNS: 0 when ATAPI DMA can be used + * nonzero otherwise + */ +int ata_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; - ata_pio_sectors(qc); + /* Don't allow DMA if it isn't multiple of 16 bytes. Quite a + * few ATAPI devices choke on such DMA requests. + */ + if (unlikely(qc->nbytes & 15)) + return 1; - if (ap->hsm_task_state == HSM_ST_LAST && - (!(qc->tf.flags & ATA_TFLAG_WRITE))) { - /* all data read */ - status = ata_wait_idle(ap); - goto fsm_start; - } - } + if (ap->ops->check_atapi_dma) + return ap->ops->check_atapi_dma(qc); - poll_next = 1; - break; + return 0; +} - case HSM_ST_LAST: - if (unlikely(!ata_ok(status))) { - qc->err_mask |= __ac_err_mask(status); - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } +/** + * ata_std_qc_defer - Check whether a qc needs to be deferred + * @qc: ATA command in question + * + * Non-NCQ commands cannot run with any other command, NCQ or + * not. As upper layer only knows the queue depth, we are + * responsible for maintaining exclusion. This function checks + * whether a new command @qc can be issued. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int ata_std_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; - /* no more data to transfer */ - DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", - ap->print_id, qc->dev->devno, status); + if (qc->tf.protocol == ATA_PROT_NCQ) { + if (!ata_tag_valid(link->active_tag)) + return 0; + } else { + if (!ata_tag_valid(link->active_tag) && !link->sactive) + return 0; + } - WARN_ON(qc->err_mask); + return ATA_DEFER_LINK; +} - ap->hsm_task_state = HSM_ST_IDLE; +void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } - /* complete taskfile transaction */ - ata_hsm_qc_complete(qc, in_wq); +/** + * ata_sg_init - Associate command with scatter-gather table. + * @qc: Command to be associated + * @sg: Scatter-gather table. + * @n_elem: Number of elements in s/g table. + * + * Initialize the data-related elements of queued_cmd @qc + * to point to a scatter-gather table @sg, containing @n_elem + * elements. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, + unsigned int n_elem) +{ + qc->sg = sg; + qc->n_elem = n_elem; + qc->cursg = qc->sg; +} - poll_next = 0; - break; +/** + * ata_sg_setup - DMA-map the scatter-gather table associated with a command. + * @qc: Command with scatter-gather table to be mapped. + * + * DMA-map the scatter-gather table associated with queued_cmd @qc. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Zero on success, negative on error. + * + */ +static int ata_sg_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int n_elem; - case HSM_ST_ERR: - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - WARN_ON(qc->err_mask == 0); + VPRINTK("ENTER, ata%u\n", ap->print_id); - ap->hsm_task_state = HSM_ST_IDLE; + n_elem = dma_map_sg(ap->dev, qc->sg, qc->n_elem, qc->dma_dir); + if (n_elem < 1) + return -1; - /* complete taskfile transaction */ - ata_hsm_qc_complete(qc, in_wq); + DPRINTK("%d sg elements mapped\n", n_elem); - poll_next = 0; - break; - default: - poll_next = 0; - BUG(); - } + qc->n_elem = n_elem; + qc->flags |= ATA_QCFLAG_DMAMAP; - return poll_next; + return 0; } -static void ata_pio_task(struct work_struct *work) +/** + * swap_buf_le16 - swap halves of 16-bit words in place + * @buf: Buffer to swap + * @buf_words: Number of 16-bit words in buffer. + * + * Swap halves of 16-bit words if needed to convert from + * little-endian byte order to native cpu byte order, or + * vice-versa. + * + * LOCKING: + * Inherited from caller. + */ +void swap_buf_le16(u16 *buf, unsigned int buf_words) { - struct ata_port *ap = - container_of(work, struct ata_port, port_task.work); - struct ata_queued_cmd *qc = ap->port_task_data; - u8 status; - int poll_next; - -fsm_start: - WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); - - /* - * 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, queue delayed work. - */ - 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) { - ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); - return; - } - } - - /* move the HSM */ - poll_next = ata_hsm_move(ap, qc, status, 1); +#ifdef __BIG_ENDIAN + unsigned int i; - /* another command or interrupt handler - * may be running at this point. - */ - if (poll_next) - goto fsm_start; + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +#endif /* __BIG_ENDIAN */ } /** @@ -6121,285 +4605,6 @@ err: ata_qc_complete(qc); } -/** - * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner - * @qc: command to issue to device - * - * Using various libata functions and hooks, this function - * starts an ATA command. ATA commands are grouped into - * classes called "protocols", and issuing each type of protocol - * is slightly different. - * - * May be used as the qc_issue() entry in ata_port_operations. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Zero on success, AC_ERR_* mask on failure - */ - -unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - /* Use polling pio if the LLD doesn't handle - * interrupt driven pio and atapi CDB interrupt. - */ - if (ap->flags & ATA_FLAG_PIO_POLLING) { - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - case ATA_PROT_NODATA: - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - qc->tf.flags |= ATA_TFLAG_POLLING; - break; - case ATAPI_PROT_DMA: - if (qc->dev->flags & ATA_DFLAG_CDB_INTR) - /* see ata_dma_blacklisted() */ - BUG(); - break; - default: - break; - } - } - - /* select the device */ - ata_dev_select(ap, qc->dev->devno, 1, 0); - - /* start the command */ - switch (qc->tf.protocol) { - case ATA_PROT_NODATA: - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_qc_set_polling(qc); - - ata_tf_to_host(ap, &qc->tf); - ap->hsm_task_state = HSM_ST_LAST; - - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); - - break; - - case ATA_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); - - ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ - ap->ops->bmdma_setup(qc); /* set up bmdma */ - ap->ops->bmdma_start(qc); /* initiate bmdma */ - ap->hsm_task_state = HSM_ST_LAST; - break; - - case ATA_PROT_PIO: - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_qc_set_polling(qc); - - ata_tf_to_host(ap, &qc->tf); - - if (qc->tf.flags & ATA_TFLAG_WRITE) { - /* PIO data out protocol */ - ap->hsm_task_state = HSM_ST_FIRST; - ata_pio_queue_task(ap, qc, 0); - - /* always send first data block using - * the ata_pio_task() codepath. - */ - } else { - /* PIO data in protocol */ - ap->hsm_task_state = HSM_ST; - - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); - - /* if polling, ata_pio_task() handles the rest. - * otherwise, interrupt handler takes over from here. - */ - } - - break; - - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_qc_set_polling(qc); - - ata_tf_to_host(ap, &qc->tf); - - ap->hsm_task_state = HSM_ST_FIRST; - - /* send cdb by polling if no cdb interrupt */ - if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || - (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_pio_queue_task(ap, qc, 0); - break; - - case ATAPI_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); - - ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ - ap->ops->bmdma_setup(qc); /* set up bmdma */ - ap->hsm_task_state = HSM_ST_FIRST; - - /* send cdb by polling if no cdb interrupt */ - if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_pio_queue_task(ap, qc, 0); - break; - - default: - WARN_ON(1); - return AC_ERR_SYSTEM; - } - - return 0; -} - -/** - * ata_host_intr - Handle host interrupt for given (port, task) - * @ap: Port on which interrupt arrived (possibly...) - * @qc: Taskfile currently active in engine - * - * Handle host interrupt for given queued command. Currently, - * only DMA interrupts are handled. All other commands are - * handled via polling with interrupts disabled (nIEN bit). - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * One if interrupt was handled, zero if not (shared irq). - */ - -inline unsigned int ata_host_intr(struct ata_port *ap, - struct ata_queued_cmd *qc) -{ - struct ata_eh_info *ehi = &ap->link.eh_info; - u8 status, host_stat = 0; - - VPRINTK("ata%u: protocol %d task_state %d\n", - ap->print_id, qc->tf.protocol, ap->hsm_task_state); - - /* Check whether we are expecting interrupt in this state */ - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - /* Some pre-ATAPI-4 devices assert INTRQ - * at this state when ready to receive CDB. - */ - - /* Check the ATA_DFLAG_CDB_INTR flag is enough here. - * The flag was turned on only for atapi devices. No - * need to check ata_is_atapi(qc->tf.protocol) again. - */ - if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - goto idle_irq; - break; - case HSM_ST_LAST: - if (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATAPI_PROT_DMA) { - /* check status of DMA engine */ - host_stat = ap->ops->bmdma_status(ap); - VPRINTK("ata%u: host_stat 0x%X\n", - ap->print_id, host_stat); - - /* if it's not our irq... */ - if (!(host_stat & ATA_DMA_INTR)) - goto idle_irq; - - /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(qc); - - if (unlikely(host_stat & ATA_DMA_ERR)) { - /* error when transfering data to/from memory */ - qc->err_mask |= AC_ERR_HOST_BUS; - ap->hsm_task_state = HSM_ST_ERR; - } - } - break; - case HSM_ST: - break; - default: - goto idle_irq; - } - - /* check altstatus */ - status = ata_altstatus(ap); - if (status & ATA_BUSY) - goto idle_irq; - - /* check main status, clearing INTRQ */ - status = ata_chk_status(ap); - if (unlikely(status & ATA_BUSY)) - goto idle_irq; - - /* ack bmdma irq events */ - ap->ops->irq_clear(ap); - - ata_hsm_move(ap, qc, status, 0); - - if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATAPI_PROT_DMA)) - ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); - - return 1; /* irq handled */ - -idle_irq: - ap->stats.idle_irq++; - -#ifdef ATA_IRQ_TRAP - if ((ap->stats.idle_irq % 1000) == 0) { - ata_chk_status(ap); - ap->ops->irq_clear(ap); - ata_port_printk(ap, KERN_WARNING, "irq trap\n"); - return 1; - } -#endif - return 0; /* irq not handled */ -} - -/** - * ata_interrupt - Default ATA host interrupt handler - * @irq: irq line (unused) - * @dev_instance: pointer to our ata_host information structure - * - * Default interrupt handler for PCI IDE devices. Calls - * ata_host_intr() for each port that is not disabled. - * - * LOCKING: - * Obtains host lock during operation. - * - * RETURNS: - * IRQ_NONE or IRQ_HANDLED. - */ - -irqreturn_t ata_interrupt(int irq, void *dev_instance) -{ - struct ata_host *host = dev_instance; - unsigned int i; - unsigned int handled = 0; - unsigned long flags; - - /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ - spin_lock_irqsave(&host->lock, flags); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap; - - ap = host->ports[i]; - if (ap && - !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_queued_cmd *qc; - - qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && - (qc->flags & ATA_QCFLAG_ACTIVE)) - handled |= ata_host_intr(ap, qc); - } - } - - spin_unlock_irqrestore(&host->lock, flags); - - return IRQ_RETVAL(handled); -} - /** * sata_scr_valid - test whether SCRs are accessible * @link: ATA link to test SCR accessibility for @@ -7432,33 +5637,6 @@ void ata_host_detach(struct ata_host *host) ata_acpi_dissociate(host); } -/** - * ata_std_ports - initialize ioaddr with standard port offsets. - * @ioaddr: IO address structure to be initialized - * - * Utility function which initializes data_addr, error_addr, - * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr, - * device_addr, status_addr, and command_addr to standard offsets - * relative to cmd_addr. - * - * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr. - */ - -void ata_std_ports(struct ata_ioports *ioaddr) -{ - ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; - ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR; - ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE; - ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT; - ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL; - ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM; - ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH; - ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE; - ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS; - ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; -} - - #ifdef CONFIG_PCI /** @@ -7890,12 +6068,9 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_long); EXPORT_SYMBOL_GPL(ata_base_port_ops); EXPORT_SYMBOL_GPL(sata_port_ops); EXPORT_SYMBOL_GPL(sata_pmp_port_ops); -EXPORT_SYMBOL_GPL(ata_sff_port_ops); -EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_std_bios_param); -EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_alloc); EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); @@ -7904,14 +6079,9 @@ EXPORT_SYMBOL_GPL(ata_host_register); EXPORT_SYMBOL_GPL(ata_host_activate); EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); -EXPORT_SYMBOL_GPL(ata_hsm_move); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); -EXPORT_SYMBOL_GPL(ata_qc_issue_prot); -EXPORT_SYMBOL_GPL(ata_tf_load); -EXPORT_SYMBOL_GPL(ata_tf_read); EXPORT_SYMBOL_GPL(ata_noop_dev_select); -EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(sata_print_link_status); EXPORT_SYMBOL_GPL(atapi_cmd_type); EXPORT_SYMBOL_GPL(ata_tf_to_fis); @@ -7923,54 +6093,27 @@ EXPORT_SYMBOL_GPL(ata_xfer_mode2mask); EXPORT_SYMBOL_GPL(ata_xfer_mode2shift); EXPORT_SYMBOL_GPL(ata_mode_string); EXPORT_SYMBOL_GPL(ata_id_xfermask); -EXPORT_SYMBOL_GPL(ata_check_status); -EXPORT_SYMBOL_GPL(ata_altstatus); -EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); -EXPORT_SYMBOL_GPL(ata_sff_port_start); -EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_do_set_mode); -EXPORT_SYMBOL_GPL(ata_data_xfer); -EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_std_qc_defer); -EXPORT_SYMBOL_GPL(ata_qc_prep); -EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); -EXPORT_SYMBOL_GPL(ata_bmdma_setup); -EXPORT_SYMBOL_GPL(ata_bmdma_start); -EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_noop_irq_clear); -EXPORT_SYMBOL_GPL(ata_bmdma_status); -EXPORT_SYMBOL_GPL(ata_bmdma_stop); -EXPORT_SYMBOL_GPL(ata_bmdma_freeze); -EXPORT_SYMBOL_GPL(ata_bmdma_thaw); -EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); -EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); -EXPORT_SYMBOL_GPL(ata_bus_reset); -EXPORT_SYMBOL_GPL(ata_std_prereset); -EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_link_hardreset); -EXPORT_SYMBOL_GPL(sata_std_hardreset); -EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_wait_register); -EXPORT_SYMBOL_GPL(ata_busy_sleep); -EXPORT_SYMBOL_GPL(ata_wait_after_reset); -EXPORT_SYMBOL_GPL(ata_wait_ready); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); -EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); EXPORT_SYMBOL_GPL(sata_scr_write); @@ -7993,11 +6136,6 @@ EXPORT_SYMBOL_GPL(ata_timing_cycle2mode); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); -EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); -EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend); @@ -8005,8 +6143,6 @@ EXPORT_SYMBOL_GPL(ata_pci_device_do_resume); EXPORT_SYMBOL_GPL(ata_pci_device_suspend); EXPORT_SYMBOL_GPL(ata_pci_device_resume); #endif /* CONFIG_PM */ -EXPORT_SYMBOL_GPL(ata_pci_default_filter); -EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); @@ -8033,8 +6169,6 @@ EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); EXPORT_SYMBOL_GPL(ata_std_error_handler); -EXPORT_SYMBOL_GPL(ata_irq_on); -EXPORT_SYMBOL_GPL(ata_dev_try_classify); EXPORT_SYMBOL_GPL(ata_cable_40wire); EXPORT_SYMBOL_GPL(ata_cable_80wire); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 40645ed125b1..840ae6da59bc 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -35,9 +35,185 @@ #include #include #include +#include #include "libata.h" +const struct ata_port_operations ata_sff_port_ops = { + .inherits = &ata_base_port_ops, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .softreset = ata_std_softreset, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .dev_select = ata_std_dev_select, + .check_status = ata_check_status, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .data_xfer = ata_data_xfer, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +const struct ata_port_operations ata_bmdma_port_ops = { + .inherits = &ata_sff_port_ops, + + .mode_filter = ata_pci_default_filter, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .irq_clear = ata_bmdma_irq_clear, +}; + +/** + * ata_fill_sg - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred + * + * Fill PCI IDE PRD (scatter-gather) table with segments + * associated with the current disk command. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + */ +static void ata_fill_sg(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + unsigned int si, pi; + + pi = 0; + for_each_sg(qc->sg, sg, qc->n_elem, si) { + u32 addr, offset; + u32 sg_len, len; + + /* determine if physical DMA addr spans 64K boundary. + * Note h/w doesn't support 64-bit, so we unconditionally + * truncate dma_addr_t to u32. + */ + addr = (u32) sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + while (sg_len) { + offset = addr & 0xffff; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; + + ap->prd[pi].addr = cpu_to_le32(addr); + ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); + + pi++; + sg_len -= len; + addr += len; + } + } + + ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); +} + +/** + * ata_fill_sg_dumb - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred + * + * Fill PCI IDE PRD (scatter-gather) table with segments + * associated with the current disk command. Perform the fill + * so that we avoid writing any length 64K records for + * controllers that don't follow the spec. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + */ +static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + unsigned int si, pi; + + pi = 0; + for_each_sg(qc->sg, sg, qc->n_elem, si) { + u32 addr, offset; + u32 sg_len, len, blen; + + /* determine if physical DMA addr spans 64K boundary. + * Note h/w doesn't support 64-bit, so we unconditionally + * truncate dma_addr_t to u32. + */ + addr = (u32) sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + while (sg_len) { + offset = addr & 0xffff; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; + + blen = len & 0xffff; + ap->prd[pi].addr = cpu_to_le32(addr); + if (blen == 0) { + /* Some PATA chipsets like the CS5530 can't + cope with 0x0000 meaning 64K as the spec says */ + ap->prd[pi].flags_len = cpu_to_le32(0x8000); + blen = 0x8000; + ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000); + } + ap->prd[pi].flags_len = cpu_to_le32(blen); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); + + pi++; + sg_len -= len; + addr += len; + } + } + + ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); +} + +/** + * ata_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * Prepare ATA taskfile for submission. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + ata_fill_sg(qc); +} + +/** + * ata_dumb_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * Prepare ATA taskfile for submission. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_dumb_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + ata_fill_sg_dumb(qc); +} + /** * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is @@ -67,223 +243,1746 @@ u8 ata_check_status(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -u8 ata_altstatus(struct ata_port *ap) +u8 ata_altstatus(struct ata_port *ap) +{ + if (ap->ops->check_altstatus) + return ap->ops->check_altstatus(ap); + + return ioread8(ap->ioaddr.altstatus_addr); +} + +/** + * ata_busy_sleep - sleep until BSY clears, or timeout + * @ap: port containing status register to be polled + * @tmout_pat: impatience timeout + * @tmout: overall timeout + * + * Sleep until ATA Status register bit BSY clears, + * or a timeout occurs. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) +{ + unsigned long timer_start, timeout; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300); + timer_start = jiffies; + timeout = timer_start + tmout_pat; + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { + msleep(50); + status = ata_busy_wait(ap, ATA_BUSY, 3); + } + + if (status != 0xff && (status & ATA_BUSY)) + ata_port_printk(ap, KERN_WARNING, + "port is slow to respond, please be patient " + "(Status 0x%x)\n", status); + + timeout = timer_start + tmout; + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { + msleep(50); + status = ata_chk_status(ap); + } + + if (status == 0xff) + return -ENODEV; + + if (status & ATA_BUSY) { + ata_port_printk(ap, KERN_ERR, "port failed to respond " + "(%lu secs, Status 0x%x)\n", + tmout / HZ, status); + return -EBUSY; + } + + return 0; +} + +/** + * ata_wait_ready - sleep until BSY clears, or timeout + * @ap: port containing status register to be polled + * @deadline: deadline jiffies for the operation + * + * Sleep until ATA Status register bit BSY clears, or timeout + * occurs. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_wait_ready(struct ata_port *ap, unsigned long deadline) +{ + unsigned long start = jiffies; + int warned = 0; + + while (1) { + u8 status = ata_chk_status(ap); + unsigned long now = jiffies; + + if (!(status & ATA_BUSY)) + return 0; + if (!ata_link_online(&ap->link) && status == 0xff) + return -ENODEV; + if (time_after(now, deadline)) + return -EBUSY; + + if (!warned && time_after(now, start + 5 * HZ) && + (deadline - now > 3 * HZ)) { + ata_port_printk(ap, KERN_WARNING, + "port is slow to respond, please be patient " + "(Status 0x%x)\n", status); + warned = 1; + } + + msleep(50); + } +} + +/** + * ata_std_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * + * Use the method defined in the ATA specification to + * make either device 0, or device 1, active on the + * ATA channel. Works with both PIO and MMIO. + * + * May be used as the dev_select() entry in ata_port_operations. + * + * LOCKING: + * caller. + */ +void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + iowrite8(tmp, ap->ioaddr.device_addr); + ata_pause(ap); /* needed; also flushes, for mmio */ +} + +/** + * ata_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * @wait: non-zero to wait for Status register BSY bit to clear + * @can_sleep: non-zero if context allows sleeping + * + * Use the method defined in the ATA specification to + * make either device 0, or device 1, active on the + * ATA channel. + * + * This is a high-level version of ata_std_dev_select(), + * which additionally provides the services of inserting + * the proper pauses and status polling, where needed. + * + * LOCKING: + * caller. + */ +void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, " + "device %u, wait %u\n", device, wait); + + if (wait) + ata_wait_idle(ap); + + ap->ops->dev_select(ap, device); + + if (wait) { + if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) + msleep(150); + ata_wait_idle(ap); + } +} + +/** + * ata_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Enable interrupts on a legacy IDE device using MMIO or PIO, + * wait for idle, clear any pending interrupts. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + +/** + * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. + * @ap: Port associated with this ATA transaction. + * + * Clear interrupt and error flags in DMA status register. + * + * May be used as the irq_clear() entry in ata_port_operations. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_bmdma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + + iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); +} + +/** + * ata_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Outputs ATA taskfile to standard ATA host controller. + * + * LOCKING: + * Inherited from caller. + */ +void ata_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; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + WARN_ON(!ioaddr->ctl_addr); + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + iowrite8(tf->device, ioaddr->device_addr); + VPRINTK("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + +/** + * ata_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Reads ATA taskfile registers for currently-selected device + * into @tf. Assumes the device has a fully SFF compliant task file + * layout and behaviour. If you device does not (eg has a different + * status method) then you will need to provide a replacement tf_read + * + * LOCKING: + * Inherited from caller. + */ +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ioread8(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (likely(ioaddr->ctl_addr)) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else + WARN_ON(1); + } +} + +/** + * ata_exec_command - issue ATA command to host controller + * @ap: port to which command is being issued + * @tf: ATA taskfile register set + * + * Issues ATA command, with proper synchronization with interrupt + * handler / other threads. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +{ + DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + + iowrite8(tf->command, ap->ioaddr.command_addr); + ata_pause(ap); +} + +/** + * ata_tf_to_host - issue ATA taskfile to host controller + * @ap: port to which command is being issued + * @tf: ATA taskfile register set + * + * Issues ATA taskfile register set to ATA host controller, + * with proper synchronization with interrupt handler and + * other threads. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static inline void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ap->ops->tf_load(ap, tf); + ap->ops->exec_command(ap, tf); +} + +/** + * ata_data_xfer - Transfer data by PIO + * @dev: device to target + * @buf: data buffer + * @buflen: buffer length + * @rw: read/write + * + * Transfer data from/to the device data register by PIO. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * Bytes consumed. + */ +unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_port *ap = dev->link->ap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + + /* Transfer multiple of 2 bytes */ + if (rw == READ) + ioread16_rep(data_addr, buf, words); + else + iowrite16_rep(data_addr, buf, words); + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (rw == READ) { + align_buf[0] = cpu_to_le16(ioread16(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } else { + memcpy(align_buf, trailing_buf, 1); + iowrite16(le16_to_cpu(align_buf[0]), data_addr); + } + words++; + } + + return words << 1; +} + +/** + * ata_data_xfer_noirq - Transfer data by PIO + * @dev: device to target + * @buf: data buffer + * @buflen: buffer length + * @rw: read/write + * + * Transfer data from/to the device data register by PIO. Do the + * transfer with interrupts disabled. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * Bytes consumed. + */ +unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) +{ + unsigned long flags; + unsigned int consumed; + + local_irq_save(flags); + consumed = ata_data_xfer(dev, buf, buflen, rw); + local_irq_restore(flags); + + return consumed; +} + +/** + * ata_pio_sector - Transfer a sector of data. + * @qc: Command on going + * + * Transfer qc->sect_size bytes of data from/to the ATA device. + * + * LOCKING: + * Inherited from caller. + */ +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + struct page *page; + unsigned int offset; + unsigned char *buf; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + page = sg_page(qc->cursg); + offset = qc->cursg->offset + qc->cursg_ofs; + + /* get the current page and offset */ + page = nth_page(page, (offset >> PAGE_SHIFT)); + offset %= PAGE_SIZE; + + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + if (PageHighMem(page)) { + unsigned long flags; + + /* FIXME: use a bounce buffer */ + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); + + /* do the actual data transfer */ + ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + + kunmap_atomic(buf, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(page); + ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + } + + qc->curbytes += qc->sect_size; + qc->cursg_ofs += qc->sect_size; + + if (qc->cursg_ofs == qc->cursg->length) { + qc->cursg = sg_next(qc->cursg); + qc->cursg_ofs = 0; + } +} + +/** + * ata_pio_sectors - Transfer one or many sectors. + * @qc: Command on going + * + * Transfer one or many sectors of data from/to the + * ATA device for the DRQ request. + * + * LOCKING: + * Inherited from caller. + */ +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + WARN_ON(qc->dev->multi_count == 0); + + nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, + qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else + ata_pio_sector(qc); + + ata_altstatus(qc->ap); /* flush */ +} + +/** + * atapi_send_cdb - Write CDB bytes to hardware + * @ap: Port to which ATAPI device is attached. + * @qc: Taskfile currently active + * + * When device has indicated its readiness to accept + * a CDB, this function is called. Send the CDB. + * + * LOCKING: + * caller. + */ +static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + /* send SCSI cdb */ + DPRINTK("send cdb\n"); + WARN_ON(qc->dev->cdb_len < 12); + + ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); + ata_altstatus(ap); /* flush */ + + switch (qc->tf.protocol) { + case ATAPI_PROT_PIO: + ap->hsm_task_state = HSM_ST; + break; + case ATAPI_PROT_NODATA: + ap->hsm_task_state = HSM_ST_LAST; + break; + case ATAPI_PROT_DMA: + ap->hsm_task_state = HSM_ST_LAST; + /* initiate bmdma */ + ap->ops->bmdma_start(qc); + break; + } +} + +/** + * __atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * @bytes: number of bytes + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + * + */ +static int __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) +{ + int rw = (qc->tf.flags & ATA_TFLAG_WRITE) ? WRITE : READ; + struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + struct ata_eh_info *ehi = &dev->link->eh_info; + struct scatterlist *sg; + struct page *page; + unsigned char *buf; + unsigned int offset, count, consumed; + +next_sg: + sg = qc->cursg; + if (unlikely(!sg)) { + ata_ehi_push_desc(ehi, "unexpected or too much trailing data " + "buf=%u cur=%u bytes=%u", + qc->nbytes, qc->curbytes, bytes); + return -1; + } + + page = sg_page(sg); + offset = sg->offset + qc->cursg_ofs; + + /* get the current page and offset */ + page = nth_page(page, (offset >> PAGE_SHIFT)); + offset %= PAGE_SIZE; + + /* don't overrun current sg */ + count = min(sg->length - qc->cursg_ofs, bytes); + + /* don't cross page boundaries */ + count = min(count, (unsigned int)PAGE_SIZE - offset); + + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + if (PageHighMem(page)) { + unsigned long flags; + + /* FIXME: use bounce buffer */ + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); + + /* do the actual data transfer */ + consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); + + kunmap_atomic(buf, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(page); + consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); + } + + bytes -= min(bytes, consumed); + qc->curbytes += count; + qc->cursg_ofs += count; + + if (qc->cursg_ofs == sg->length) { + qc->cursg = sg_next(qc->cursg); + qc->cursg_ofs = 0; + } + + /* consumed can be larger than count only for the last transfer */ + WARN_ON(qc->cursg && count != consumed); + + if (bytes) + goto next_sg; + return 0; +} + +/** + * atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + */ +static void atapi_pio_bytes(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + struct ata_eh_info *ehi = &dev->link->eh_info; + unsigned int ireason, bc_lo, bc_hi, bytes; + int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0; + + /* Abuse qc->result_tf for temp storage of intermediate TF + * here to save some kernel stack usage. + * For normal completion, qc->result_tf is not relevant. For + * error, qc->result_tf is later overwritten by ata_qc_complete(). + * So, the correctness of qc->result_tf is not affected. + */ + ap->ops->tf_read(ap, &qc->result_tf); + ireason = qc->result_tf.nsect; + bc_lo = qc->result_tf.lbam; + bc_hi = qc->result_tf.lbah; + bytes = (bc_hi << 8) | bc_lo; + + /* shall be cleared to zero, indicating xfer of data */ + if (unlikely(ireason & (1 << 0))) + goto atapi_check; + + /* make sure transfer direction matches expected */ + i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; + if (unlikely(do_write != i_write)) + goto atapi_check; + + if (unlikely(!bytes)) + goto atapi_check; + + VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); + + if (unlikely(__atapi_pio_bytes(qc, bytes))) + goto err_out; + ata_altstatus(ap); /* flush */ + + return; + + atapi_check: + ata_ehi_push_desc(ehi, "ATAPI check failed (ireason=0x%x bytes=%u)", + ireason, bytes); + err_out: + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; +} + +/** + * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue. + * @ap: the target ata_port + * @qc: qc on going + * + * RETURNS: + * 1 if ok in workqueue, 0 otherwise. + */ +static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; + + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (qc->tf.protocol == ATA_PROT_PIO && + (qc->tf.flags & ATA_TFLAG_WRITE)) + return 1; + + if (ata_is_atapi(qc->tf.protocol) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + } + + return 0; +} + +/** + * ata_hsm_qc_complete - finish a qc running on standard HSM + * @qc: Command to complete + * @in_wq: 1 if called from workqueue, 0 otherwise + * + * Finish @qc which is running on standard HSM. + * + * LOCKING: + * If @in_wq is zero, spin_lock_irqsave(host lock). + * Otherwise, none on entry and grabs host lock. + */ +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + unsigned long flags; + + if (ap->ops->error_handler) { + if (in_wq) { + spin_lock_irqsave(ap->lock, flags); + + /* EH might have kicked in while host lock is + * released. + */ + qc = ata_qc_from_tag(ap, qc->tag); + if (qc) { + if (likely(!(qc->err_mask & AC_ERR_HSM))) { + ap->ops->irq_on(ap); + ata_qc_complete(qc); + } else + ata_port_freeze(ap); + } + + spin_unlock_irqrestore(ap->lock, flags); + } else { + if (likely(!(qc->err_mask & AC_ERR_HSM))) + ata_qc_complete(qc); + else + ata_port_freeze(ap); + } + } else { + if (in_wq) { + spin_lock_irqsave(ap->lock, flags); + ap->ops->irq_on(ap); + ata_qc_complete(qc); + spin_unlock_irqrestore(ap->lock, flags); + } else + ata_qc_complete(qc); + } +} + +/** + * ata_hsm_move - move the HSM to the next state. + * @ap: the target ata_port + * @qc: qc on going + * @status: current device status + * @in_wq: 1 if called from workqueue, 0 otherwise + * + * RETURNS: + * 1 when poll next status needed, 0 otherwise. + */ +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + unsigned long flags = 0; + int poll_next; + + WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + + /* Make sure ata_qc_issue_prot() does not throw things + * like DMA polling into the workqueue. Notice that + * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). + */ + WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); + +fsm_start: + DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", + ap->print_id, qc->tf.protocol, ap->hsm_task_state, status); + + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Send first data block or PACKET CDB */ + + /* If polling, we will stay in the work queue after + * sending the data. Otherwise, interrupt handler + * takes over after sending the data. + */ + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + /* check device status */ + if (unlikely((status & ATA_DRQ) == 0)) { + /* handle BSY=0, DRQ=0 as error */ + if (likely(status & (ATA_ERR | ATA_DF))) + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + else + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + /* Some ATAPI tape drives forget to clear the ERR bit + * when doing the next command (mostly request sense). + * We ignore ERR here to workaround and proceed sending + * the CDB. + */ + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + ata_port_printk(ap, KERN_WARNING, + "DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + /* Send the CDB (atapi) or the first data block (ata pio out). + * During the state transition, interrupt handler shouldn't + * be invoked before the data transfer is complete and + * hsm_task_state is changed. Hence, the following locking. + */ + if (in_wq) + spin_lock_irqsave(ap->lock, flags); + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else + /* send CDB */ + atapi_send_cdb(ap, qc); + + if (in_wq) + spin_unlock_irqrestore(ap->lock, flags); + + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ + break; + + case HSM_ST: + /* complete command or read/write the data register */ + if (qc->tf.protocol == ATAPI_PROT_PIO) { + /* ATAPI PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* No more data to transfer or device error. + * Device error will be tagged in HSM_ST_LAST. + */ + ap->hsm_task_state = HSM_ST_LAST; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + ata_port_printk(ap, KERN_WARNING, "DRQ=1 with " + "device error, dev_stat 0x%X\n", + status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + atapi_pio_bytes(qc); + + if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) + /* bad ireason reported by device */ + goto fsm_start; + + } else { + /* ATA PIO protocol */ + if (unlikely((status & ATA_DRQ) == 0)) { + /* handle BSY=0, DRQ=0 as error */ + if (likely(status & (ATA_ERR | ATA_DF))) + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + else + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | + AC_ERR_NODEV_HINT; + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + /* data might be corrputed */ + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + status = ata_wait_idle(ap); + goto fsm_start; + } + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (unlikely(!ata_ok(status))) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", + ap->print_id, qc->dev->devno, status); + + WARN_ON(qc->err_mask); + + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + WARN_ON(qc->err_mask == 0); + + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + BUG(); + } + + return poll_next; +} + +void ata_pio_task(struct work_struct *work) +{ + struct ata_port *ap = + container_of(work, struct ata_port, port_task.work); + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); + + /* + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + /* move the HSM */ + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +/** + * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner + * @qc: command to issue to device + * + * Using various libata functions and hooks, this function + * starts an ATA command. ATA commands are grouped into + * classes called "protocols", and issuing each type of protocol + * is slightly different. + * + * May be used as the qc_issue() entry in ata_port_operations. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Zero on success, AC_ERR_* mask on failure + */ +unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* Use polling pio if the LLD doesn't handle + * interrupt driven pio and atapi CDB interrupt. + */ + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + case ATAPI_PROT_DMA: + if (qc->dev->flags & ATA_DFLAG_CDB_INTR) + /* see ata_dma_blacklisted() */ + BUG(); + break; + default: + break; + } + } + + /* select the device */ + ata_dev_select(ap, qc->dev->devno, 1, 0); + + /* start the command */ + switch (qc->tf.protocol) { + case ATA_PROT_NODATA: + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + + ata_tf_to_host(ap, &qc->tf); + ap->hsm_task_state = HSM_ST_LAST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + case ATA_PROT_DMA: + WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + + ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->bmdma_setup(qc); /* set up bmdma */ + ap->ops->bmdma_start(qc); /* initiate bmdma */ + ap->hsm_task_state = HSM_ST_LAST; + break; + + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + + ata_tf_to_host(ap, &qc->tf); + + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* PIO data out protocol */ + ap->hsm_task_state = HSM_ST_FIRST; + ata_pio_queue_task(ap, qc, 0); + + /* always send first data block using + * the ata_pio_task() codepath. + */ + } else { + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ + } + + break; + + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST_FIRST; + + /* send cdb by polling if no cdb interrupt */ + if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || + (qc->tf.flags & ATA_TFLAG_POLLING)) + ata_pio_queue_task(ap, qc, 0); + break; + + case ATAPI_PROT_DMA: + WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + + ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->bmdma_setup(qc); /* set up bmdma */ + ap->hsm_task_state = HSM_ST_FIRST; + + /* send cdb by polling if no cdb interrupt */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + ata_pio_queue_task(ap, qc, 0); + break; + + default: + WARN_ON(1); + return AC_ERR_SYSTEM; + } + + return 0; +} + +/** + * ata_host_intr - Handle host interrupt for given (port, task) + * @ap: Port on which interrupt arrived (possibly...) + * @qc: Taskfile currently active in engine + * + * Handle host interrupt for given queued command. Currently, + * only DMA interrupts are handled. All other commands are + * handled via polling with interrupts disabled (nIEN bit). + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * One if interrupt was handled, zero if not (shared irq). + */ +inline unsigned int ata_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) +{ + struct ata_eh_info *ehi = &ap->link.eh_info; + u8 status, host_stat = 0; + + VPRINTK("ata%u: protocol %d task_state %d\n", + ap->print_id, qc->tf.protocol, ap->hsm_task_state); + + /* Check whether we are expecting interrupt in this state */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. + * The flag was turned on only for atapi devices. No + * need to check ata_is_atapi(qc->tf.protocol) again. + */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + goto idle_irq; + break; + case HSM_ST_LAST: + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA) { + /* check status of DMA engine */ + host_stat = ap->ops->bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", + ap->print_id, host_stat); + + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + qc->err_mask |= AC_ERR_HOST_BUS; + ap->hsm_task_state = HSM_ST_ERR; + } + } + break; + case HSM_ST: + break; + default: + goto idle_irq; + } + + /* check altstatus */ + status = ata_altstatus(ap); + if (status & ATA_BUSY) + goto idle_irq; + + /* check main status, clearing INTRQ */ + status = ata_chk_status(ap); + if (unlikely(status & ATA_BUSY)) + goto idle_irq; + + /* ack bmdma irq events */ + ap->ops->irq_clear(ap); + + ata_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ap->stats.idle_irq % 1000) == 0) { + ata_chk_status(ap); + ap->ops->irq_clear(ap); + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); + return 1; + } +#endif + return 0; /* irq not handled */ +} + +/** + * ata_interrupt - Default ATA host interrupt handler + * @irq: irq line (unused) + * @dev_instance: pointer to our ata_host information structure + * + * Default interrupt handler for PCI IDE devices. Calls + * ata_host_intr() for each port that is not disabled. + * + * LOCKING: + * Obtains host lock during operation. + * + * RETURNS: + * IRQ_NONE or IRQ_HANDLED. + */ +irqreturn_t ata_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + ap = host->ports[i]; + if (ap && + !(ap->flags & ATA_FLAG_DISABLED)) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->link.active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && + (qc->flags & ATA_QCFLAG_ACTIVE)) + handled |= ata_host_intr(ap, qc); + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + +/** + * ata_bmdma_freeze - Freeze BMDMA controller port + * @ap: port to freeze + * + * Freeze BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_freeze(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + ap->ops->irq_clear(ap); +} + +/** + * ata_bmdma_thaw - Thaw BMDMA controller port + * @ap: port to thaw + * + * Thaw BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_thaw(struct ata_port *ap) { - if (ap->ops->check_altstatus) - return ap->ops->check_altstatus(ap); - - return ioread8(ap->ioaddr.altstatus_addr); + /* clear & re-enable interrupts */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); + ap->ops->irq_on(ap); } /** - * ata_irq_on - Enable interrupts on a port. - * @ap: Port on which interrupts are enabled. + * ata_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) * - * Enable interrupts on a legacy IDE device using MMIO or PIO, - * wait for idle, clear any pending interrupts. + * This technique was originally described in + * Hale Landis's ATADRVR (www.ata-atapi.com), and + * later found its way into the ATA/ATAPI spec. + * + * Write a pattern to the ATA shadow registers, + * and if a device is present, it will respond by + * correctly storing and echoing back the + * ATA shadow register contents. * * LOCKING: - * Inherited from caller. + * caller. */ -u8 ata_irq_on(struct ata_port *ap) +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; + u8 nsect, lbal; - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; + ap->ops->dev_select(ap, device); - if (ioaddr->ctl_addr) - iowrite8(ap->ctl, ioaddr->ctl_addr); - tmp = ata_wait_idle(ap); + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); - ap->ops->irq_clear(ap); + iowrite8(0xaa, ioaddr->nsect_addr); + iowrite8(0x55, ioaddr->lbal_addr); - return tmp; + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); + + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ } /** - * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. - * @ap: Port associated with this ATA transaction. + * ata_dev_try_classify - Parse returned ATA device signature + * @dev: ATA device to classify (starting at zero) + * @present: device seems present + * @r_err: Value of error register on completion * - * Clear interrupt and error flags in DMA status register. + * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, + * an ATA/ATAPI-defined set of values is placed in the ATA + * shadow registers, indicating the results of device detection + * and diagnostics. * - * May be used as the irq_clear() entry in ata_port_operations. + * Select the ATA device, and read the values from the ATA shadow + * registers. Then parse according to the Error register value, + * and the spec-defined values examined by ata_dev_classify(). * * LOCKING: - * spin_lock_irqsave(host lock) + * caller. + * + * RETURNS: + * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ -void ata_bmdma_irq_clear(struct ata_port *ap) +unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err) { - void __iomem *mmio = ap->ioaddr.bmdma_addr; + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + unsigned int class; + u8 err; + + ap->ops->dev_select(ap, dev->devno); + + memset(&tf, 0, sizeof(tf)); + + ap->ops->tf_read(ap, &tf); + err = tf.feature; + if (r_err) + *r_err = err; + + /* see if device passed diags: continue and warn later */ + if (err == 0) + /* diagnostic fail : do nothing _YET_ */ + dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; + else if (err == 1) + /* do nothing */ ; + else if ((dev->devno == 0) && (err == 0x81)) + /* do nothing */ ; + else + return ATA_DEV_NONE; - if (!mmio) - return; + /* determine if device is ATA or ATAPI */ + class = ata_dev_classify(&tf); - iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); + if (class == ATA_DEV_UNKNOWN) { + /* If the device failed diagnostic, it's likely to + * have reported incorrect device signature too. + * Assume ATA device if the device seems present but + * device signature is invalid with diagnostic + * failure. + */ + if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC)) + class = ATA_DEV_ATA; + else + class = ATA_DEV_NONE; + } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) + class = ATA_DEV_NONE; + + return class; } -/** - * ata_tf_load - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set - * - * Outputs ATA taskfile to standard ATA host controller. - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, + unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + unsigned int dev0 = devmask & (1 << 0); + unsigned int dev1 = devmask & (1 << 1); + int rc, ret = 0; - if (tf->ctl != ap->last_ctl) { - if (ioaddr->ctl_addr) - iowrite8(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); + /* if device 0 was found in ata_devchk, wait for its + * BSY bit to clear + */ + if (dev0) { + rc = ata_wait_ready(ap, deadline); + if (rc) { + if (rc != -ENODEV) + return rc; + ret = rc; + } } - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - WARN_ON(!ioaddr->ctl_addr); - iowrite8(tf->hob_feature, ioaddr->feature_addr); - iowrite8(tf->hob_nsect, ioaddr->nsect_addr); - iowrite8(tf->hob_lbal, ioaddr->lbal_addr); - iowrite8(tf->hob_lbam, ioaddr->lbam_addr); - iowrite8(tf->hob_lbah, ioaddr->lbah_addr); - VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", - tf->hob_feature, - tf->hob_nsect, - tf->hob_lbal, - tf->hob_lbam, - tf->hob_lbah); - } + /* if device 1 was found in ata_devchk, wait for register + * access briefly, then wait for BSY to clear. + */ + if (dev1) { + int i; - if (is_addr) { - iowrite8(tf->feature, ioaddr->feature_addr); - iowrite8(tf->nsect, ioaddr->nsect_addr); - iowrite8(tf->lbal, ioaddr->lbal_addr); - iowrite8(tf->lbam, ioaddr->lbam_addr); - iowrite8(tf->lbah, ioaddr->lbah_addr); - VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", - tf->feature, - tf->nsect, - tf->lbal, - tf->lbam, - tf->lbah); - } + ap->ops->dev_select(ap, 1); - if (tf->flags & ATA_TFLAG_DEVICE) { - iowrite8(tf->device, ioaddr->device_addr); - VPRINTK("device 0x%X\n", tf->device); + /* Wait for register access. Some ATAPI devices fail + * to set nsect/lbal after reset, so don't waste too + * much time on it. We're gonna wait for !BSY anyway. + */ + for (i = 0; i < 2; i++) { + u8 nsect, lbal; + + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); + if ((nsect == 1) && (lbal == 1)) + break; + msleep(50); /* give drive a breather */ + } + + rc = ata_wait_ready(ap, deadline); + if (rc) { + if (rc != -ENODEV) + return rc; + ret = rc; + } } - ata_wait_idle(ap); + /* is all this really necessary? */ + ap->ops->dev_select(ap, 0); + if (dev1) + ap->ops->dev_select(ap, 1); + if (dev0) + ap->ops->dev_select(ap, 0); + + return ret; } /** - * ata_tf_read - input device's ATA taskfile shadow registers - * @ap: Port from which input is read - * @tf: ATA taskfile register set for storing input + * ata_wait_after_reset - wait before checking status after reset + * @ap: port containing status register to be polled + * @deadline: deadline jiffies for the operation * - * Reads ATA taskfile registers for currently-selected device - * into @tf. Assumes the device has a fully SFF compliant task file - * layout and behaviour. If you device does not (eg has a different - * status method) then you will need to provide a replacement tf_read + * After reset, we need to pause a while before reading status. + * Also, certain combination of controller and device report 0xff + * for some duration (e.g. until SATA PHY is up and running) + * which is interpreted as empty port in ATA world. This + * function also waits for such devices to get out of 0xff + * status. * * LOCKING: - * Inherited from caller. + * Kernel thread context (may sleep). */ -void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) { - struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned long until = jiffies + ATA_TMOUT_FF_WAIT; + + if (time_before(until, deadline)) + deadline = until; + + /* Spec mandates ">= 2ms" before checking status. We wait + * 150ms, because that was the magic delay used for ATAPI + * devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready. + */ + msleep(150); - tf->command = ata_check_status(ap); - tf->feature = ioread8(ioaddr->error_addr); - tf->nsect = ioread8(ioaddr->nsect_addr); - tf->lbal = ioread8(ioaddr->lbal_addr); - tf->lbam = ioread8(ioaddr->lbam_addr); - tf->lbah = ioread8(ioaddr->lbah_addr); - tf->device = ioread8(ioaddr->device_addr); + /* Wait for 0xff to clear. Some SATA devices take a long time + * to clear 0xff after reset. For example, HHD424020F7SV00 + * iVDR needs >= 800ms while. Quantum GoVault needs even more + * than that. + * + * Note that some PATA controllers (pata_ali) explode if + * status register is read more than once when there's no + * device attached. + */ + if (ap->flags & ATA_FLAG_SATA) { + while (1) { + u8 status = ata_chk_status(ap); - if (tf->flags & ATA_TFLAG_LBA48) { - if (likely(ioaddr->ctl_addr)) { - iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = ioread8(ioaddr->error_addr); - tf->hob_nsect = ioread8(ioaddr->nsect_addr); - tf->hob_lbal = ioread8(ioaddr->lbal_addr); - tf->hob_lbam = ioread8(ioaddr->lbam_addr); - tf->hob_lbah = ioread8(ioaddr->lbah_addr); - iowrite8(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - } else - WARN_ON(1); + if (status != 0xff || time_after(jiffies, deadline)) + return; + + msleep(50); + } } } -/** - * ata_exec_command - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues ATA command, with proper synchronization with interrupt - * handler / other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, + unsigned long deadline) { - DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + struct ata_ioports *ioaddr = &ap->ioaddr; - iowrite8(tf->command, ap->ioaddr.command_addr); - ata_pause(ap); + DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); + + /* software reset. causes dev0 to be selected */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); + + /* Before we perform post reset processing we want to see if + * the bus shows 0xFF because the odd clown forgets the D7 + * pulldown resistor. + */ + if (ata_chk_status(ap) == 0xFF) + return -ENODEV; + + return ata_bus_post_reset(ap, devmask, deadline); } /** - * ata_bmdma_freeze - Freeze BMDMA controller port - * @ap: port to freeze + * ata_std_softreset - reset host port via ATA SRST + * @link: ATA link to reset + * @classes: resulting classes of attached devices + * @deadline: deadline jiffies for the operation * - * Freeze BMDMA controller port. + * Reset host port using ATA SRST. * * LOCKING: - * Inherited from caller. + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. */ -void ata_bmdma_freeze(struct ata_port *ap) +int ata_std_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { - struct ata_ioports *ioaddr = &ap->ioaddr; + struct ata_port *ap = link->ap; + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + unsigned int devmask = 0; + int rc; + u8 err; - ap->ctl |= ATA_NIEN; - ap->last_ctl = ap->ctl; + DPRINTK("ENTER\n"); - if (ioaddr->ctl_addr) - iowrite8(ap->ctl, ioaddr->ctl_addr); + if (ata_link_offline(link)) { + classes[0] = ATA_DEV_NONE; + goto out; + } - /* Under certain circumstances, some controllers raise IRQ on - * ATA_NIEN manipulation. Also, many controllers fail to mask - * previously pending IRQ on ATA_NIEN assertion. Clear it. - */ - ata_chk_status(ap); + /* determine if device 0/1 are present */ + if (ata_devchk(ap, 0)) + devmask |= (1 << 0); + if (slave_possible && ata_devchk(ap, 1)) + devmask |= (1 << 1); + + /* select device 0 again */ + ap->ops->dev_select(ap, 0); + + /* issue bus reset */ + DPRINTK("about to softreset, devmask=%x\n", devmask); + rc = ata_bus_softreset(ap, devmask, deadline); + /* if link is occupied, -ENODEV too is an error */ + if (rc && (rc != -ENODEV || sata_scr_valid(link))) { + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); + return rc; + } - ap->ops->irq_clear(ap); + /* determine by signature whether we have ATA or ATAPI devices */ + classes[0] = ata_dev_try_classify(&link->device[0], + devmask & (1 << 0), &err); + if (slave_possible && err != 0x81) + classes[1] = ata_dev_try_classify(&link->device[1], + devmask & (1 << 1), &err); + + out: + DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); + return 0; } /** - * ata_bmdma_thaw - Thaw BMDMA controller port - * @ap: port to thaw + * sata_std_hardreset - reset host port via SATA phy reset + * @link: link to reset + * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation * - * Thaw BMDMA controller port. + * SATA phy-reset host port using DET bits of SControl register, + * wait for !BSY and classify the attached device. * * LOCKING: - * Inherited from caller. + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. */ -void ata_bmdma_thaw(struct ata_port *ap) +int sata_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { - /* clear & re-enable interrupts */ - ata_chk_status(ap); - ap->ops->irq_clear(ap); - ap->ops->irq_on(ap); + struct ata_port *ap = link->ap; + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } + + /* TODO: phy layer with polling, timeouts, etc. */ + if (ata_link_offline(link)) { + *class = ATA_DEV_NONE; + DPRINTK("EXIT, link offline\n"); + return 0; + } + + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); + + /* If PMP is supported, we have to do follow-up SRST. Note + * that some PMPs don't send D2H Reg FIS after hardreset at + * all if the first port is empty. Wait for it just for a + * second and request follow-up SRST. + */ + if (ap->flags & ATA_FLAG_PMP) { + ata_wait_ready(ap, jiffies + HZ); + return -EAGAIN; + } + + rc = ata_wait_ready(ap, deadline); + /* link occupied, -ENODEV too is an error */ + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } + + ap->ops->dev_select(ap, 0); /* probably unnecessary */ + + *class = ata_dev_try_classify(link->device, 1, NULL); + + DPRINTK("EXIT, class=%u\n", *class); + return 0; } /** @@ -393,6 +2092,31 @@ int ata_sff_port_start(struct ata_port *ap) return 0; } +/** + * ata_std_ports - initialize ioaddr with standard port offsets. + * @ioaddr: IO address structure to be initialized + * + * Utility function which initializes data_addr, error_addr, + * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr, + * device_addr, status_addr, and command_addr to standard offsets + * relative to cmd_addr. + * + * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr. + */ +void ata_std_ports(struct ata_ioports *ioaddr) +{ + ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; + ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR; + ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE; + ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT; + ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL; + ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM; + ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH; + ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE; + ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS; + ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; +} + /** * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. @@ -494,11 +2218,94 @@ u8 ata_bmdma_status(struct ata_port *ap) } /** - * ata_noop_irq_clear - Noop placeholder for irq_clear - * @ap: Port associated with this ATA transaction. + * ata_bus_reset - reset host port and associated ATA channel + * @ap: port to reset + * + * This is typically the first time we actually start issuing + * commands to the ATA channel. We wait for BSY to clear, then + * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its + * result. Determine what devices, if any, are on the channel + * by looking at the device 0/1 error register. Look at the signature + * stored in each device's taskfile registers, to determine if + * the device is ATA or ATAPI. + * + * LOCKING: + * PCI/etc. bus probe sem. + * Obtains host lock. + * + * SIDE EFFECTS: + * Sets ATA_FLAG_DISABLED if bus reset fails. + * + * DEPRECATED: + * This function is only for drivers which still use old EH and + * will be removed soon. */ -void ata_noop_irq_clear(struct ata_port *ap) +void ata_bus_reset(struct ata_port *ap) { + struct ata_device *device = ap->link.device; + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + u8 err; + unsigned int dev0, dev1 = 0, devmask = 0; + int rc; + + DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); + + /* determine if device 0/1 are present */ + if (ap->flags & ATA_FLAG_SATA_RESET) + dev0 = 1; + else { + dev0 = ata_devchk(ap, 0); + if (slave_possible) + dev1 = ata_devchk(ap, 1); + } + + if (dev0) + devmask |= (1 << 0); + if (dev1) + devmask |= (1 << 1); + + /* select device 0 again */ + ap->ops->dev_select(ap, 0); + + /* issue bus reset */ + if (ap->flags & ATA_FLAG_SRST) { + rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ); + if (rc && rc != -ENODEV) + goto err_out; + } + + /* + * determine by signature whether we have ATA or ATAPI devices + */ + device[0].class = ata_dev_try_classify(&device[0], dev0, &err); + if ((slave_possible) && (err != 0x81)) + device[1].class = ata_dev_try_classify(&device[1], dev1, &err); + + /* is double-select really necessary? */ + if (device[1].class != ATA_DEV_NONE) + ap->ops->dev_select(ap, 1); + if (device[0].class != ATA_DEV_NONE) + ap->ops->dev_select(ap, 0); + + /* if no devices were detected, disable this port */ + if ((device[0].class == ATA_DEV_NONE) && + (device[1].class == ATA_DEV_NONE)) + goto err_out; + + if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { + /* set up device control for ATA_FLAG_SATA_RESET */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + } + + DPRINTK("EXIT\n"); + return; + +err_out: + ata_port_printk(ap, KERN_ERR, "disabling port\n"); + ata_port_disable(ap); + + DPRINTK("EXIT\n"); } #ifdef CONFIG_PCI @@ -914,3 +2721,49 @@ int ata_pci_init_one(struct pci_dev *pdev, #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(ata_sff_port_ops); +EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); +EXPORT_SYMBOL_GPL(ata_qc_prep); +EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); +EXPORT_SYMBOL_GPL(ata_std_dev_select); +EXPORT_SYMBOL_GPL(ata_check_status); +EXPORT_SYMBOL_GPL(ata_altstatus); +EXPORT_SYMBOL_GPL(ata_busy_sleep); +EXPORT_SYMBOL_GPL(ata_wait_ready); +EXPORT_SYMBOL_GPL(ata_tf_load); +EXPORT_SYMBOL_GPL(ata_tf_read); +EXPORT_SYMBOL_GPL(ata_exec_command); +EXPORT_SYMBOL_GPL(ata_data_xfer); +EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_irq_on); +EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); +EXPORT_SYMBOL_GPL(ata_hsm_move); +EXPORT_SYMBOL_GPL(ata_qc_issue_prot); +EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(ata_interrupt); +EXPORT_SYMBOL_GPL(ata_bmdma_freeze); +EXPORT_SYMBOL_GPL(ata_bmdma_thaw); +EXPORT_SYMBOL_GPL(ata_std_prereset); +EXPORT_SYMBOL_GPL(ata_dev_try_classify); +EXPORT_SYMBOL_GPL(ata_wait_after_reset); +EXPORT_SYMBOL_GPL(ata_std_softreset); +EXPORT_SYMBOL_GPL(sata_std_hardreset); +EXPORT_SYMBOL_GPL(ata_std_postreset); +EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); +EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); +EXPORT_SYMBOL_GPL(ata_sff_port_start); +EXPORT_SYMBOL_GPL(ata_std_ports); +EXPORT_SYMBOL_GPL(ata_bmdma_setup); +EXPORT_SYMBOL_GPL(ata_bmdma_start); +EXPORT_SYMBOL_GPL(ata_bmdma_stop); +EXPORT_SYMBOL_GPL(ata_bmdma_status); +EXPORT_SYMBOL_GPL(ata_bus_reset); +#ifdef CONFIG_PCI +EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); +EXPORT_SYMBOL_GPL(ata_pci_default_filter); +EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); +EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); +EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); +EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); +EXPORT_SYMBOL_GPL(ata_pci_init_one); +#endif /* CONFIG_PCI */ diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index aa884f71a12a..a69f663c7402 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -67,6 +67,8 @@ extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, unsigned int tag); extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); extern void ata_dev_disable(struct ata_device *dev); +extern void ata_pio_queue_task(struct ata_port *ap, void *data, + unsigned long delay); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, @@ -91,8 +93,6 @@ extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern void __ata_qc_complete(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 swap_buf_le16(u16 *buf, unsigned int buf_words); extern int ata_flush_cache(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev); @@ -194,7 +194,9 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, extern void ata_eh_finish(struct ata_port *ap); /* libata-sff.c */ +extern void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); extern u8 ata_irq_on(struct ata_port *ap); - +extern void ata_pio_task(struct work_struct *work); #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 01c233303aee..673f34b256ba 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -349,6 +349,22 @@ enum { ATAPI_READ_CD = 2, /* READ CD [MSF] */ ATAPI_PASS_THRU = 3, /* SAT pass-thru */ ATAPI_MISC = 4, /* the rest */ + + /* Timing constants */ + ATA_TIMING_SETUP = (1 << 0), + ATA_TIMING_ACT8B = (1 << 1), + ATA_TIMING_REC8B = (1 << 2), + ATA_TIMING_CYC8B = (1 << 3), + ATA_TIMING_8BIT = ATA_TIMING_ACT8B | ATA_TIMING_REC8B | + ATA_TIMING_CYC8B, + ATA_TIMING_ACTIVE = (1 << 4), + ATA_TIMING_RECOVER = (1 << 5), + ATA_TIMING_CYCLE = (1 << 6), + ATA_TIMING_UDMA = (1 << 7), + ATA_TIMING_ALL = ATA_TIMING_SETUP | ATA_TIMING_ACT8B | + ATA_TIMING_REC8B | ATA_TIMING_CYC8B | + ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER | + ATA_TIMING_CYCLE | ATA_TIMING_UDMA, }; enum ata_xfer_mask { @@ -779,6 +795,9 @@ struct ata_timing { #define FIT(v, vmin, vmax) max_t(short, min_t(short, v, vmax), vmin) +/* + * Core layer - drivers/ata/libata-core.c + */ extern const unsigned long sata_deb_timing_normal[]; extern const unsigned long sata_deb_timing_hotplug[]; extern const unsigned long sata_deb_timing_long[]; @@ -802,22 +821,14 @@ static inline int ata_port_is_dummy(struct ata_port *ap) extern void sata_print_link_status(struct ata_link *link); extern void ata_port_probe(struct ata_port *); -extern void ata_bus_reset(struct ata_port *ap); extern int sata_set_spd(struct ata_link *link); extern int sata_link_debounce(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); -extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); -extern int ata_std_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline); extern int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline); -extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); -extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); -extern void ata_std_ports(struct ata_ioports *ioaddr); extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, @@ -843,7 +854,6 @@ extern void ata_sas_port_stop(struct ata_port *ap); extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), struct ata_port *ap); -extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern int sata_scr_valid(struct ata_link *link); extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_scr_write(struct ata_link *link, int reg, u32 val); @@ -855,21 +865,9 @@ extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); #endif extern int ata_ratelimit(void); -extern int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, unsigned long timeout); -extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline); -extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, unsigned long timeout_msec); -extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present, - u8 *r_err); - -/* - * Default driver ops implementations - */ -extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); -extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern int atapi_cmd_type(u8 opcode); extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis); @@ -885,22 +883,9 @@ extern int ata_xfer_mode2shift(unsigned long xfer_mode); extern const char *ata_mode_string(unsigned long xfer_mask); extern unsigned long ata_id_xfermask(const u16 *id); extern void ata_noop_dev_select(struct ata_port *ap, unsigned int device); -extern void ata_std_dev_select(struct ata_port *ap, unsigned int device); -extern u8 ata_check_status(struct ata_port *ap); -extern u8 ata_altstatus(struct ata_port *ap); -extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern int ata_port_start(struct ata_port *ap); -extern int ata_sff_port_start(struct ata_port *ap); -extern irqreturn_t ata_interrupt(int irq, void *dev_instance); -extern unsigned int ata_data_xfer(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw); -extern unsigned int ata_data_xfer_noirq(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw); extern int ata_std_qc_defer(struct ata_queued_cmd *qc); -extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); -extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); -extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem); extern unsigned int ata_dev_classify(const struct ata_taskfile *tf); @@ -909,18 +894,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); -extern void ata_bmdma_setup(struct ata_queued_cmd *qc); -extern void ata_bmdma_start(struct ata_queued_cmd *qc); -extern void ata_bmdma_stop(struct ata_queued_cmd *qc); -extern u8 ata_bmdma_status(struct ata_port *ap); -extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_noop_irq_clear(struct ata_port *ap); -extern void ata_bmdma_freeze(struct ata_port *ap); -extern void ata_bmdma_thaw(struct ata_port *ap); -extern void ata_bmdma_error_handler(struct ata_port *ap); -extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); -extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq); extern void ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, void (*finish_qc)(struct ata_queued_cmd *)); @@ -935,7 +909,6 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); -extern u8 ata_irq_on(struct ata_port *ap); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); @@ -943,10 +916,7 @@ extern int ata_cable_sata(struct ata_port *ap); extern int ata_cable_ignore(struct ata_port *ap); extern int ata_cable_unknown(struct ata_port *ap); -/* - * Timing helpers - */ - +/* Timing helpers */ extern unsigned int ata_pio_need_iordy(const struct ata_device *); extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode); extern int ata_timing_compute(struct ata_device *, unsigned short, @@ -956,24 +926,31 @@ extern void ata_timing_merge(const struct ata_timing *, unsigned int); extern u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle); -enum { - ATA_TIMING_SETUP = (1 << 0), - ATA_TIMING_ACT8B = (1 << 1), - ATA_TIMING_REC8B = (1 << 2), - ATA_TIMING_CYC8B = (1 << 3), - ATA_TIMING_8BIT = ATA_TIMING_ACT8B | ATA_TIMING_REC8B | - ATA_TIMING_CYC8B, - ATA_TIMING_ACTIVE = (1 << 4), - ATA_TIMING_RECOVER = (1 << 5), - ATA_TIMING_CYCLE = (1 << 6), - ATA_TIMING_UDMA = (1 << 7), - ATA_TIMING_ALL = ATA_TIMING_SETUP | ATA_TIMING_ACT8B | - ATA_TIMING_REC8B | ATA_TIMING_CYC8B | - ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER | - ATA_TIMING_CYCLE | ATA_TIMING_UDMA, +/* PCI */ +#ifdef CONFIG_PCI +struct pci_dev; + +struct pci_bits { + unsigned int reg; /* PCI config register to read */ + unsigned int width; /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */ + unsigned long mask; + unsigned long val; }; -/* libata-acpi.c */ +extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); +extern void ata_pci_remove_one(struct pci_dev *pdev); + +#ifdef CONFIG_PM +extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); +extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int ata_pci_device_resume(struct pci_dev *pdev); +#endif /* CONFIG_PM */ +#endif /* CONFIG_PCI */ + +/* + * ACPI - drivers/ata/libata-acpi.c + */ #ifdef CONFIG_ATA_ACPI static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) { @@ -1017,43 +994,8 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap, } #endif -#ifdef CONFIG_PCI -struct pci_dev; - -extern int ata_pci_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, - struct scsi_host_template *sht, void *host_priv); -extern void ata_pci_remove_one(struct pci_dev *pdev); -#ifdef CONFIG_PM -extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); -extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int ata_pci_device_resume(struct pci_dev *pdev); -#endif -extern int ata_pci_clear_simplex(struct pci_dev *pdev); - -struct pci_bits { - unsigned int reg; /* PCI config register to read */ - unsigned int width; /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */ - unsigned long mask; - unsigned long val; -}; - -extern int ata_pci_init_sff_host(struct ata_host *host); -extern int ata_pci_init_bmdma(struct ata_host *host); -extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, - struct ata_host **r_host); -extern int ata_pci_activate_sff_host(struct ata_host *host, - irq_handler_t irq_handler, - struct scsi_host_template *sht); -extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); -extern unsigned long ata_pci_default_filter(struct ata_device *dev, - unsigned long xfer_mask); -#endif /* CONFIG_PCI */ - /* - * PMP + * PMP - drivers/ata/libata-pmp.c */ extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); @@ -1063,7 +1005,7 @@ extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class); extern void sata_pmp_error_handler(struct ata_port *ap); /* - * EH + * EH - drivers/ata/libata-eh.c */ extern void ata_port_schedule_eh(struct ata_port *ap); extern int ata_link_abort(struct ata_link *link); @@ -1106,8 +1048,6 @@ extern void ata_std_error_handler(struct ata_port *ap); extern const struct ata_port_operations ata_base_port_ops; extern const struct ata_port_operations sata_port_ops; extern const struct ata_port_operations sata_pmp_port_ops; -extern const struct ata_port_operations ata_sff_port_ops; -extern const struct ata_port_operations ata_bmdma_port_ops; #define ATA_BASE_SHT(drv_name) \ .module = THIS_MODULE, \ @@ -1124,17 +1064,6 @@ extern const struct ata_port_operations ata_bmdma_port_ops; .slave_destroy = ata_scsi_slave_destroy, \ .bios_param = ata_std_bios_param -/* PIO only, sg_tablesize and dma_boundary limits can be removed */ -#define ATA_PIO_SHT(drv_name) \ - ATA_BASE_SHT(drv_name), \ - .sg_tablesize = LIBATA_MAX_PRD, \ - .dma_boundary = ATA_DMA_BOUNDARY - -#define ATA_BMDMA_SHT(drv_name) \ - ATA_BASE_SHT(drv_name), \ - .sg_tablesize = LIBATA_MAX_PRD, \ - .dma_boundary = ATA_DMA_BOUNDARY - #define ATA_NCQ_SHT(drv_name) \ ATA_BASE_SHT(drv_name), \ .change_queue_depth = ata_scsi_change_queue_depth @@ -1287,11 +1216,6 @@ static inline struct ata_link *ata_port_next_link(struct ata_link *link) for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \ (dev) >= (link)->device || ((dev) = NULL); (dev)--) -static inline u8 ata_chk_status(struct ata_port *ap) -{ - return ap->ops->check_status(ap); -} - /** * ata_ncq_enabled - Test whether NCQ is enabled * @dev: ATA device to test for @@ -1308,74 +1232,6 @@ static inline int ata_ncq_enabled(struct ata_device *dev) ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ; } -/** - * ata_pause - Flush writes and pause 400 nanoseconds. - * @ap: Port to wait for. - * - * LOCKING: - * Inherited from caller. - */ - -static inline void ata_pause(struct ata_port *ap) -{ - ata_altstatus(ap); - ndelay(400); -} - - -/** - * ata_busy_wait - Wait for a port status register - * @ap: Port to wait for. - * @bits: bits that must be clear - * @max: number of 10uS waits to perform - * - * Waits up to max*10 microseconds for the selected bits in the port's - * status register to be cleared. - * Returns final value of status register. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, - unsigned int max) -{ - u8 status; - - do { - udelay(10); - status = ata_chk_status(ap); - max--; - } while (status != 0xff && (status & bits) && (max > 0)); - - return status; -} - - -/** - * ata_wait_idle - Wait for a port to be idle. - * @ap: Port to wait for. - * - * Waits up to 10ms for port's BUSY and DRQ signals to clear. - * Returns final value of status register. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_wait_idle(struct ata_port *ap) -{ - u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - -#ifdef ATA_DEBUG - if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) - ata_port_printk(ap, KERN_DEBUG, "abnormal Status 0x%X\n", - status); -#endif - - return status; -} - static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) { qc->tf.ctl |= ATA_NIEN; @@ -1468,4 +1324,149 @@ static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) return *(struct ata_port **)&host->hostdata[0]; } +/************************************************************************** + * SFF - drivers/ata/libata-sff.c + */ +extern const struct ata_port_operations ata_sff_port_ops; +extern const struct ata_port_operations ata_bmdma_port_ops; + +/* PIO only, sg_tablesize and dma_boundary limits can be removed */ +#define ATA_PIO_SHT(drv_name) \ + ATA_BASE_SHT(drv_name), \ + .sg_tablesize = LIBATA_MAX_PRD, \ + .dma_boundary = ATA_DMA_BOUNDARY + +#define ATA_BMDMA_SHT(drv_name) \ + ATA_BASE_SHT(drv_name), \ + .sg_tablesize = LIBATA_MAX_PRD, \ + .dma_boundary = ATA_DMA_BOUNDARY + +extern void ata_qc_prep(struct ata_queued_cmd *qc); +extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); +extern void ata_std_dev_select(struct ata_port *ap, unsigned int device); +extern u8 ata_check_status(struct ata_port *ap); +extern u8 ata_altstatus(struct ata_port *ap); +extern int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); +extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline); +extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); +extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); +extern unsigned int ata_data_xfer(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw); +extern unsigned int ata_data_xfer_noirq(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw); +extern u8 ata_irq_on(struct ata_port *ap); +extern void ata_bmdma_irq_clear(struct ata_port *ap); +extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); +extern irqreturn_t ata_interrupt(int irq, void *dev_instance); +extern void ata_bmdma_freeze(struct ata_port *ap); +extern void ata_bmdma_thaw(struct ata_port *ap); +extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); +extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err); +extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline); +extern int ata_std_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline); +extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); +extern void ata_bmdma_error_handler(struct ata_port *ap); +extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); +extern int ata_sff_port_start(struct ata_port *ap); +extern void ata_std_ports(struct ata_ioports *ioaddr); +extern void ata_bmdma_setup(struct ata_queued_cmd *qc); +extern void ata_bmdma_start(struct ata_queued_cmd *qc); +extern void ata_bmdma_stop(struct ata_queued_cmd *qc); +extern u8 ata_bmdma_status(struct ata_port *ap); +extern void ata_bus_reset(struct ata_port *ap); + +#ifdef CONFIG_PCI +extern int ata_pci_clear_simplex(struct pci_dev *pdev); +extern unsigned long ata_pci_default_filter(struct ata_device *dev, + unsigned long xfer_mask); +extern int ata_pci_init_bmdma(struct ata_host *host); +extern int ata_pci_init_sff_host(struct ata_host *host); +extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, + const struct ata_port_info * const * ppi, + struct ata_host **r_host); +extern int ata_pci_activate_sff_host(struct ata_host *host, + irq_handler_t irq_handler, + struct scsi_host_template *sht); +extern int ata_pci_init_one(struct pci_dev *pdev, + const struct ata_port_info * const * ppi, + struct scsi_host_template *sht, void *host_priv); +#endif /* CONFIG_PCI */ + +static inline u8 ata_chk_status(struct ata_port *ap) +{ + return ap->ops->check_status(ap); +} + +/** + * ata_pause - Flush writes and pause 400 nanoseconds. + * @ap: Port to wait for. + * + * LOCKING: + * Inherited from caller. + */ +static inline void ata_pause(struct ata_port *ap) +{ + ata_altstatus(ap); + ndelay(400); +} + +/** + * ata_busy_wait - Wait for a port status register + * @ap: Port to wait for. + * @bits: bits that must be clear + * @max: number of 10uS waits to perform + * + * Waits up to max*10 microseconds for the selected bits in the port's + * status register to be cleared. + * Returns final value of status register. + * + * LOCKING: + * Inherited from caller. + */ +static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, + unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_chk_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +/** + * ata_wait_idle - Wait for a port to be idle. + * @ap: Port to wait for. + * + * Waits up to 10ms for port's BUSY and DRQ signals to clear. + * Returns final value of status register. + * + * LOCKING: + * Inherited from caller. + */ +static inline u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + +#ifdef ATA_DEBUG + if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) + ata_port_printk(ap, KERN_DEBUG, "abnormal Status 0x%X\n", + status); +#endif + + return status; +} + #endif /* __LINUX_LIBATA_H__ */ -- cgit v1.2.3 From 071ce34d57924edb76b76f7de460eb4991463959 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 22:16:42 +0900 Subject: libata: move ata_pci_default_filter() out of CONFIG_PCI ata_pci_default_filter() doesn't really have anything to do with PCI. It's generally applicable to BMDMA controllers. Move it out of CONFIG_PCI. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 22 +++++++++++----------- include/linux/libata.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 840ae6da59bc..ebdd46bc13c4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2117,6 +2117,16 @@ void ata_std_ports(struct ata_ioports *ioaddr) ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } +unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask) +{ + /* Filter out DMA modes if the device has been configured by + the BIOS as PIO only */ + + if (adev->link->ap->ioaddr.bmdma_addr == NULL) + xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); + return xfer_mask; +} + /** * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. @@ -2335,16 +2345,6 @@ int ata_pci_clear_simplex(struct pci_dev *pdev) return 0; } -unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask) -{ - /* Filter out DMA modes if the device has been configured by - the BIOS as PIO only */ - - if (adev->link->ap->ioaddr.bmdma_addr == NULL) - xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - return xfer_mask; -} - /** * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host * @host: target ATA host @@ -2725,6 +2725,7 @@ EXPORT_SYMBOL_GPL(ata_sff_port_ops); EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); +EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); @@ -2760,7 +2761,6 @@ EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bus_reset); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); -EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); diff --git a/include/linux/libata.h b/include/linux/libata.h index 673f34b256ba..53b8db05a1fb 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1378,6 +1378,8 @@ extern void ata_bmdma_error_handler(struct ata_port *ap); extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); extern int ata_sff_port_start(struct ata_port *ap); extern void ata_std_ports(struct ata_ioports *ioaddr); +extern unsigned long ata_pci_default_filter(struct ata_device *dev, + unsigned long xfer_mask); extern void ata_bmdma_setup(struct ata_queued_cmd *qc); extern void ata_bmdma_start(struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); @@ -1386,8 +1388,6 @@ extern void ata_bus_reset(struct ata_port *ap); #ifdef CONFIG_PCI extern int ata_pci_clear_simplex(struct pci_dev *pdev); -extern unsigned long ata_pci_default_filter(struct ata_device *dev, - unsigned long xfer_mask); extern int ata_pci_init_bmdma(struct ata_host *host); extern int ata_pci_init_sff_host(struct ata_host *host); extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, -- cgit v1.2.3 From 6fd36390117f7844ad147377878ddb52088f583a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 25 Mar 2008 22:16:44 +0900 Subject: libata: kill ata_chk_status() ata_chk_status() just calls ops->check_status and it only adds confusion with other status functions. Kill it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 22 +++++++++++----------- drivers/ata/pata_bf54x.c | 2 +- drivers/ata/pata_scc.c | 2 +- drivers/ata/sata_inic162x.c | 10 +++++----- drivers/ata/sata_sil.c | 6 +++--- drivers/ata/sata_via.c | 2 +- drivers/ata/sata_vsc.c | 2 +- include/linux/libata.h | 7 +------ 8 files changed, 24 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index ebdd46bc13c4..c601dcef2925 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -290,7 +290,7 @@ int ata_busy_sleep(struct ata_port *ap, while (status != 0xff && (status & ATA_BUSY) && time_before(jiffies, timeout)) { msleep(50); - status = ata_chk_status(ap); + status = ap->ops->check_status(ap); } if (status == 0xff) @@ -326,7 +326,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) int warned = 0; while (1) { - u8 status = ata_chk_status(ap); + u8 status = ap->ops->check_status(ap); unsigned long now = jiffies; if (!(status & ATA_BUSY)) @@ -1486,7 +1486,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap, goto idle_irq; /* check main status, clearing INTRQ */ - status = ata_chk_status(ap); + status = ap->ops->check_status(ap); if (unlikely(status & ATA_BUSY)) goto idle_irq; @@ -1506,7 +1506,7 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ata_chk_status(ap); + ap->ops->check_status(ap); ap->ops->irq_clear(ap); ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; @@ -1582,7 +1582,7 @@ void ata_bmdma_freeze(struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ata_chk_status(ap); + ap->ops->check_status(ap); ap->ops->irq_clear(ap); } @@ -1599,7 +1599,7 @@ void ata_bmdma_freeze(struct ata_port *ap) void ata_bmdma_thaw(struct ata_port *ap) { /* clear & re-enable interrupts */ - ata_chk_status(ap); + ap->ops->check_status(ap); ap->ops->irq_clear(ap); ap->ops->irq_on(ap); } @@ -1709,7 +1709,7 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present, class = ATA_DEV_ATA; else class = ATA_DEV_NONE; - } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) + } else if ((class == ATA_DEV_ATA) && (ap->ops->check_status(ap) == 0)) class = ATA_DEV_NONE; return class; @@ -1820,7 +1820,7 @@ void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) */ if (ap->flags & ATA_FLAG_SATA) { while (1) { - u8 status = ata_chk_status(ap); + u8 status = ap->ops->check_status(ap); if (status != 0xff || time_after(jiffies, deadline)) return; @@ -1851,7 +1851,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ata_chk_status(ap) == 0xFF) + if (ap->ops->check_status(ap) == 0xFF) return -ENODEV; return ata_bus_post_reset(ap, devmask, deadline); @@ -2034,7 +2034,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) } ata_altstatus(ap); - ata_chk_status(ap); + ap->ops->check_status(ap); ap->ops->irq_clear(ap); spin_unlock_irqrestore(ap->lock, flags); @@ -2725,7 +2725,6 @@ EXPORT_SYMBOL_GPL(ata_sff_port_ops); EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); -EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); @@ -2754,6 +2753,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_sff_port_start); EXPORT_SYMBOL_GPL(ata_std_ports); +EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_stop); diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index eea275acb2a8..457ac800cd5e 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1264,7 +1264,7 @@ static void bfin_bmdma_freeze(struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ata_chk_status(ap); + ap->ops->check_status(ap); bfin_irq_clear(ap); } diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 07f2d7a6f1a8..85d33637dff9 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -854,7 +854,7 @@ static void scc_bmdma_freeze (struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ata_chk_status(ap); + ap->ops->check_status(ap); ap->ops->irq_clear(ap); } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index ba1c09953517..12fbf3868fe2 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -267,14 +267,14 @@ static void inic_host_intr(struct ata_port *ap) ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { - ata_chk_status(ap); /* clear ATA interrupt */ + ap->ops->check_status(ap); /* clear ATA interrupt */ return; } if (likely(ata_host_intr(ap, qc))) return; - ata_chk_status(ap); /* clear ATA interrupt */ + ap->ops->check_status(ap); /* clear ATA interrupt */ ata_port_printk(ap, KERN_WARNING, "unhandled " "interrupt, irq_stat=%x\n", irq_stat); return; @@ -351,7 +351,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) */ if (unlikely(qc->tf.command == ATA_CMD_ID_ATA || qc->tf.command == ATA_CMD_ID_ATAPI)) { - u8 stat = ata_chk_status(ap); + u8 stat = ap->ops->check_status(ap); if (stat == 0x7f || stat == 0xff) return AC_ERR_HSM; } @@ -365,7 +365,7 @@ static void inic_freeze(struct ata_port *ap) __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE); - ata_chk_status(ap); + ap->ops->check_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); readb(port_base + PORT_IRQ_STAT); /* flush */ @@ -375,7 +375,7 @@ static void inic_thaw(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); - ata_chk_status(ap); + ap->ops->check_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index eac7ca73cfa0..659dfcbdc1b2 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -369,7 +369,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { /* this sometimes happens, just clear IRQ */ - ata_chk_status(ap); + ap->ops->check_status(ap); return; } @@ -405,7 +405,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) } /* check main status, clearing INTRQ */ - status = ata_chk_status(ap); + status = ap->ops->check_status(ap); if (unlikely(status & ATA_BUSY)) goto err_hsm; @@ -480,7 +480,7 @@ static void sil_thaw(struct ata_port *ap) u32 tmp; /* clear IRQ */ - ata_chk_status(ap); + ap->ops->check_status(ap); ata_bmdma_irq_clear(ap); /* turn on SATA IRQ if supported */ diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 402fd7333d48..4bc6e849af2c 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -173,7 +173,7 @@ static void svia_noop_freeze(struct ata_port *ap) /* Some VIA controllers choke if ATA_NIEN is manipulated in * certain way. Leave it alone and just clear pending IRQ. */ - ata_chk_status(ap); + ap->ops->check_status(ap); ata_bmdma_irq_clear(ap); } diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 8045a72dc559..fb3a88722664 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -251,7 +251,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) * simply clear the interrupt */ if (unlikely(!handled)) - ata_chk_status(ap); + ap->ops->check_status(ap); } /* diff --git a/include/linux/libata.h b/include/linux/libata.h index 53b8db05a1fb..61a7f8d06971 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1401,11 +1401,6 @@ extern int ata_pci_init_one(struct pci_dev *pdev, struct scsi_host_template *sht, void *host_priv); #endif /* CONFIG_PCI */ -static inline u8 ata_chk_status(struct ata_port *ap) -{ - return ap->ops->check_status(ap); -} - /** * ata_pause - Flush writes and pause 400 nanoseconds. * @ap: Port to wait for. @@ -1439,7 +1434,7 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, do { udelay(10); - status = ata_chk_status(ap); + status = ap->ops->check_status(ap); max--; } while (status != 0xff && (status & bits) && (max > 0)); -- cgit v1.2.3 From 03faab7827e4e45823fd27c47b84c133e20a0cd0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 27 Mar 2008 19:14:24 +0900 Subject: libata: implement ATA_QCFLAG_RETRY Currently whether a command should be retried after failure is determined inside ata_eh_finish(). Add ATA_QCFLAG_RETRY and move the logic into ata_eh_autopsy(). This makes things clearer and helps extending retry determination logic. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 18 ++++++++---------- include/linux/libata.h | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ec32082356cb..cc8548e1572a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1785,6 +1785,11 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); + /* determine whether the command is worth retrying */ + if (!(qc->err_mask & AC_ERR_INVALID) && + ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV)) + qc->flags |= ATA_QCFLAG_RETRY; + /* accumulate error info */ ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; @@ -2783,18 +2788,11 @@ void ata_eh_finish(struct ata_port *ap) /* FIXME: Once EH migration is complete, * generate sense data in this function, * considering both err_mask and tf. - * - * There's no point in retrying invalid - * (detected by libata) and non-IO device - * errors (rejected by device). Finish them - * immediately. */ - if ((qc->err_mask & AC_ERR_INVALID) || - (!(qc->flags & ATA_QCFLAG_IO) && - qc->err_mask == AC_ERR_DEV)) - ata_eh_qc_complete(qc); - else + if (qc->flags & ATA_QCFLAG_RETRY) ata_eh_qc_retry(qc); + else + ata_eh_qc_complete(qc); } else { if (qc->flags & ATA_QCFLAG_SENSE_VALID) { ata_eh_qc_complete(qc); diff --git a/include/linux/libata.h b/include/linux/libata.h index 61a7f8d06971..b25ea6ab1be9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -224,6 +224,7 @@ enum { ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ + ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */ ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ -- cgit v1.2.3 From 83c063dd730cb56bf3fc89b70250ff9a398fec1e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 28 Feb 2008 21:43:13 +0900 Subject: use ATA_TAG_INTERNAL in ata_tag_internal() It should be ATA_TAG_INTERNAL. Signed-off-by: Yoichi Yuasa Signed-off-by: Jeff Garzik --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index b25ea6ab1be9..a05de2ba7a72 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1121,7 +1121,7 @@ static inline unsigned int ata_tag_valid(unsigned int tag) static inline unsigned int ata_tag_internal(unsigned int tag) { - return tag == ATA_MAX_QUEUE - 1; + return tag == ATA_TAG_INTERNAL; } /* -- cgit v1.2.3 From 9363c3825ea9ad76561eb48a395349dd29211ed6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:16 +0900 Subject: libata: rename SFF functions SFF functions have confusing names. Some have sff prefix, some have bmdma, some std, some pci and some none. Unify the naming by... * SFF functions which are common to both BMDMA and non-BMDMA are prefixed with ata_sff_. * SFF functions which are specific to BMDMA are prefixed with ata_bmdma_. * SFF functions which are specific to PCI but apply to both BMDMA and non-BMDMA are prefixed with ata_pci_sff_. * SFF functions which are specific to PCI and BMDMA are prefixed with ata_pci_bmdma_. * Drop generic prefixes from LLD specific routines. For example, bfin_std_dev_select -> bfin_dev_select. The following renames are noteworthy. ata_qc_issue_prot() -> ata_sff_qc_issue() ata_pci_default_filter() -> ata_bmdma_mode_filter() ata_dev_try_classify() -> ata_sff_dev_classify() This rename is in preparation of separating SFF support out of libata core layer. This patch strictly renames functions and doesn't introduce any behavior difference. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 10 +- drivers/ata/ata_generic.c | 4 +- drivers/ata/ata_piix.c | 6 +- drivers/ata/libata-core.c | 16 +- drivers/ata/libata-eh.c | 2 +- drivers/ata/libata-sff.c | 344 ++++++++++++++++++++-------------------- drivers/ata/pata_acpi.c | 16 +- drivers/ata/pata_ali.c | 6 +- drivers/ata/pata_amd.c | 10 +- drivers/ata/pata_artop.c | 6 +- drivers/ata/pata_at32.c | 2 +- drivers/ata/pata_atiixp.c | 6 +- drivers/ata/pata_bf54x.c | 84 +++++----- drivers/ata/pata_cmd640.c | 16 +- drivers/ata/pata_cmd64x.c | 4 +- drivers/ata/pata_cs5520.c | 8 +- drivers/ata/pata_cs5530.c | 12 +- drivers/ata/pata_cs5535.c | 2 +- drivers/ata/pata_cs5536.c | 2 +- drivers/ata/pata_cypress.c | 2 +- drivers/ata/pata_efar.c | 4 +- drivers/ata/pata_hpt366.c | 4 +- drivers/ata/pata_hpt37x.c | 10 +- drivers/ata/pata_hpt3x2n.c | 10 +- drivers/ata/pata_hpt3x3.c | 6 +- drivers/ata/pata_icside.c | 8 +- drivers/ata/pata_isapnp.c | 4 +- drivers/ata/pata_it8213.c | 4 +- drivers/ata/pata_it821x.c | 20 +-- drivers/ata/pata_ixp4xx_cf.c | 4 +- drivers/ata/pata_jmicron.c | 4 +- drivers/ata/pata_legacy.c | 32 ++-- drivers/ata/pata_marvell.c | 4 +- drivers/ata/pata_mpc52xx.c | 4 +- drivers/ata/pata_mpiix.c | 18 +-- drivers/ata/pata_netcell.c | 4 +- drivers/ata/pata_ninja32.c | 6 +- drivers/ata/pata_ns87410.c | 12 +- drivers/ata/pata_ns87415.c | 8 +- drivers/ata/pata_oldpiix.c | 12 +- drivers/ata/pata_opti.c | 4 +- drivers/ata/pata_optidma.c | 4 +- drivers/ata/pata_pcmcia.c | 6 +- drivers/ata/pata_pdc2027x.c | 10 +- drivers/ata/pata_pdc202xx_old.c | 2 +- drivers/ata/pata_platform.c | 4 +- drivers/ata/pata_qdi.c | 14 +- drivers/ata/pata_radisys.c | 10 +- drivers/ata/pata_rb500_cf.c | 6 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_sc1200.c | 12 +- drivers/ata/pata_scc.c | 80 +++++----- drivers/ata/pata_serverworks.c | 12 +- drivers/ata/pata_sil680.c | 10 +- drivers/ata/pata_sis.c | 4 +- drivers/ata/pata_sl82c105.c | 4 +- drivers/ata/pata_triflex.c | 4 +- drivers/ata/pata_via.c | 6 +- drivers/ata/pata_winbond.c | 6 +- drivers/ata/pdc_adma.c | 12 +- drivers/ata/sata_inic162x.c | 12 +- drivers/ata/sata_mv.c | 6 +- drivers/ata/sata_nv.c | 32 ++-- drivers/ata/sata_promise.c | 12 +- drivers/ata/sata_qstor.c | 10 +- drivers/ata/sata_sil.c | 8 +- drivers/ata/sata_sis.c | 6 +- drivers/ata/sata_svw.c | 4 +- drivers/ata/sata_sx4.c | 26 +-- drivers/ata/sata_uli.c | 12 +- drivers/ata/sata_via.c | 12 +- drivers/ata/sata_vsc.c | 4 +- include/linux/libata.h | 103 ++++++------ 73 files changed, 599 insertions(+), 596 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3efa9904f7a0..771509c9a3fb 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1303,9 +1303,9 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); + ata_sff_wait_after_reset(ap, deadline); - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { reason = "device not ready"; @@ -1350,7 +1350,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); - rc = sata_std_hardreset(link, class, deadline); + rc = sata_sff_hardreset(link, class, deadline); ahci_start_engine(ap); @@ -1431,7 +1431,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, * have to be reset again. For most cases, this should * suffice while making probing snappish enough. */ - rc = ata_wait_ready(ap, jiffies + 2 * HZ); + rc = ata_sff_wait_ready(ap, jiffies + 2 * HZ); if (rc) ahci_kick_engine(ap, 0); @@ -1444,7 +1444,7 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) void __iomem *port_mmio = ahci_port_base(ap); u32 new_tmp, tmp; - ata_std_postreset(link, class); + ata_sff_postreset(link, class); /* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp = readl(port_mmio + PORT_CMD); diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index b23e2a1099c5..47aeccd52fa9 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -150,9 +150,9 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id return -ENODEV; if (dev->vendor == PCI_VENDOR_ID_AL) - ata_pci_clear_simplex(dev); + ata_pci_bmdma_clear_simplex(dev); - return ata_pci_init_one(dev, ppi, &generic_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL); } static struct pci_device_id ata_generic[] = { diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index e113f2f80275..7ab76a413cdf 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -629,7 +629,7 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -1493,7 +1493,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, hpriv->map = piix_init_sata_map(pdev, port_info, piix_map_db_table[ent->driver_data]); - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) return rc; host->private_data = hpriv; @@ -1527,7 +1527,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } pci_set_master(pdev); - return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht); + return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); } static int __init piix_init(void) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fa205d7c5bea..cbdbfb5eaeaa 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -75,9 +75,9 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { .irq_clear = ata_noop_irq_clear, - .prereset = ata_std_prereset, - .hardreset = sata_std_hardreset, - .postreset = ata_std_postreset, + .prereset = ata_sff_prereset, + .hardreset = sata_sff_hardreset, + .postreset = ata_sff_postreset, .error_handler = ata_std_error_handler, }; @@ -3425,7 +3425,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, } /** - * ata_std_prereset - prepare for reset + * ata_sff_prereset - prepare for reset * @link: ATA link to be reset * @deadline: deadline jiffies for the operation * @@ -3441,7 +3441,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_prereset(struct ata_link *link, unsigned long deadline) +int ata_sff_prereset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -3463,7 +3463,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) /* wait for !BSY if we don't know that no device is attached */ if (!ata_link_offline(link)) { - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " "(errno=%d), forcing hardreset\n", rc); @@ -3535,7 +3535,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, } /** - * ata_std_postreset - standard postreset callback + * ata_sff_postreset - standard postreset callback * @link: the target ata_link * @classes: classes of attached devices * @@ -3546,7 +3546,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, * LOCKING: * Kernel thread context (may sleep) */ -void ata_std_postreset(struct ata_link *link, unsigned int *classes) +void ata_sff_postreset(struct ata_link *link, unsigned int *classes) { struct ata_port *ap = link->ap; u32 serror; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index cc8548e1572a..f4f9c2783821 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2861,7 +2861,7 @@ void ata_std_error_handler(struct ata_port *ap) * ata_base_port_ops. Ignore it if SCR access is not * available. */ - if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link)) + if (hardreset == sata_sff_hardreset && !sata_scr_valid(&ap->link)) hardreset = NULL; ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 5208ca21f634..8544321293d4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -42,22 +42,22 @@ const struct ata_port_operations ata_sff_port_ops = { .inherits = &ata_base_port_ops, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .softreset = ata_std_softreset, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .dev_select = ata_std_dev_select, - .check_status = ata_check_status, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .exec_command = ata_exec_command, - .data_xfer = ata_data_xfer, - .irq_on = ata_irq_on, + .qc_prep = ata_sff_qc_prep, + .qc_issue = ata_sff_qc_issue, + + .freeze = ata_sff_freeze, + .thaw = ata_sff_thaw, + .softreset = ata_sff_softreset, + .error_handler = ata_sff_error_handler, + .post_internal_cmd = ata_sff_post_internal_cmd, + + .dev_select = ata_sff_dev_select, + .check_status = ata_sff_check_status, + .tf_load = ata_sff_tf_load, + .tf_read = ata_sff_tf_read, + .exec_command = ata_sff_exec_command, + .data_xfer = ata_sff_data_xfer, + .irq_on = ata_sff_irq_on, .port_start = ata_sff_port_start, }; @@ -65,13 +65,13 @@ const struct ata_port_operations ata_sff_port_ops = { const struct ata_port_operations ata_bmdma_port_ops = { .inherits = &ata_sff_port_ops, - .mode_filter = ata_pci_default_filter, + .mode_filter = ata_bmdma_mode_filter, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, - .irq_clear = ata_bmdma_irq_clear, + .irq_clear = ata_sff_irq_clear, }; /** @@ -181,7 +181,7 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) } /** - * ata_qc_prep - Prepare taskfile for submission + * ata_sff_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared * * Prepare ATA taskfile for submission. @@ -189,7 +189,7 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_qc_prep(struct ata_queued_cmd *qc) +void ata_sff_qc_prep(struct ata_queued_cmd *qc) { if (!(qc->flags & ATA_QCFLAG_DMAMAP)) return; @@ -198,7 +198,7 @@ void ata_qc_prep(struct ata_queued_cmd *qc) } /** - * ata_dumb_qc_prep - Prepare taskfile for submission + * ata_sff_dumb_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared * * Prepare ATA taskfile for submission. @@ -206,7 +206,7 @@ void ata_qc_prep(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_dumb_qc_prep(struct ata_queued_cmd *qc) +void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc) { if (!(qc->flags & ATA_QCFLAG_DMAMAP)) return; @@ -215,7 +215,7 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc) } /** - * ata_check_status - Read device status reg & clear interrupt + * ata_sff_check_status - Read device status reg & clear interrupt * @ap: port where the device is * * Reads ATA taskfile status register for currently-selected device @@ -225,13 +225,13 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc) * LOCKING: * Inherited from caller. */ -u8 ata_check_status(struct ata_port *ap) +u8 ata_sff_check_status(struct ata_port *ap) { return ioread8(ap->ioaddr.status_addr); } /** - * ata_altstatus - Read device alternate status reg + * ata_sff_altstatus - Read device alternate status reg * @ap: port where the device is * * Reads ATA taskfile alternate status register for @@ -243,7 +243,7 @@ u8 ata_check_status(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -u8 ata_altstatus(struct ata_port *ap) +u8 ata_sff_altstatus(struct ata_port *ap) { if (ap->ops->check_altstatus) return ap->ops->check_altstatus(ap); @@ -252,7 +252,7 @@ u8 ata_altstatus(struct ata_port *ap) } /** - * ata_busy_sleep - sleep until BSY clears, or timeout + * ata_sff_busy_sleep - sleep until BSY clears, or timeout * @ap: port containing status register to be polled * @tmout_pat: impatience timeout * @tmout: overall timeout @@ -266,19 +266,19 @@ u8 ata_altstatus(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_busy_sleep(struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) +int ata_sff_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; - status = ata_busy_wait(ap, ATA_BUSY, 300); + status = ata_sff_busy_wait(ap, ATA_BUSY, 300); timer_start = jiffies; timeout = timer_start + tmout_pat; while (status != 0xff && (status & ATA_BUSY) && time_before(jiffies, timeout)) { msleep(50); - status = ata_busy_wait(ap, ATA_BUSY, 3); + status = ata_sff_busy_wait(ap, ATA_BUSY, 3); } if (status != 0xff && (status & ATA_BUSY)) @@ -307,7 +307,7 @@ int ata_busy_sleep(struct ata_port *ap, } /** - * ata_wait_ready - sleep until BSY clears, or timeout + * ata_sff_wait_ready - sleep until BSY clears, or timeout * @ap: port containing status register to be polled * @deadline: deadline jiffies for the operation * @@ -320,7 +320,7 @@ int ata_busy_sleep(struct ata_port *ap, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_wait_ready(struct ata_port *ap, unsigned long deadline) +int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline) { unsigned long start = jiffies; int warned = 0; @@ -349,7 +349,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) } /** - * ata_std_dev_select - Select device 0/1 on ATA bus + * ata_sff_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * @@ -362,7 +362,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) * LOCKING: * caller. */ -void ata_std_dev_select(struct ata_port *ap, unsigned int device) +void ata_sff_dev_select(struct ata_port *ap, unsigned int device) { u8 tmp; @@ -372,7 +372,7 @@ void ata_std_dev_select(struct ata_port *ap, unsigned int device) tmp = ATA_DEVICE_OBS | ATA_DEV1; iowrite8(tmp, ap->ioaddr.device_addr); - ata_pause(ap); /* needed; also flushes, for mmio */ + ata_sff_pause(ap); /* needed; also flushes, for mmio */ } /** @@ -386,9 +386,9 @@ void ata_std_dev_select(struct ata_port *ap, unsigned int device) * make either device 0, or device 1, active on the * ATA channel. * - * This is a high-level version of ata_std_dev_select(), - * which additionally provides the services of inserting - * the proper pauses and status polling, where needed. + * This is a high-level version of ata_sff_dev_select(), which + * additionally provides the services of inserting the proper + * pauses and status polling, where needed. * * LOCKING: * caller. @@ -413,7 +413,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, } /** - * ata_irq_on - Enable interrupts on a port. + * ata_sff_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. * * Enable interrupts on a legacy IDE device using MMIO or PIO, @@ -422,7 +422,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, * LOCKING: * Inherited from caller. */ -u8 ata_irq_on(struct ata_port *ap) +u8 ata_sff_irq_on(struct ata_port *ap) { struct ata_ioports *ioaddr = &ap->ioaddr; u8 tmp; @@ -440,7 +440,7 @@ u8 ata_irq_on(struct ata_port *ap) } /** - * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. + * ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt. * @ap: Port associated with this ATA transaction. * * Clear interrupt and error flags in DMA status register. @@ -450,7 +450,7 @@ u8 ata_irq_on(struct ata_port *ap) * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_bmdma_irq_clear(struct ata_port *ap) +void ata_sff_irq_clear(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.bmdma_addr; @@ -461,7 +461,7 @@ void ata_bmdma_irq_clear(struct ata_port *ap) } /** - * ata_tf_load - send taskfile registers to host controller + * ata_sff_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -470,7 +470,7 @@ void ata_bmdma_irq_clear(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_sff_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; @@ -520,7 +520,7 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) } /** - * ata_tf_read - input device's ATA taskfile shadow registers + * ata_sff_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * @@ -532,11 +532,11 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) * LOCKING: * Inherited from caller. */ -void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_check_status(ap); + tf->command = ata_sff_check_status(ap); tf->feature = ioread8(ioaddr->error_addr); tf->nsect = ioread8(ioaddr->nsect_addr); tf->lbal = ioread8(ioaddr->lbal_addr); @@ -560,7 +560,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) } /** - * ata_exec_command - issue ATA command to host controller + * ata_sff_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * @@ -570,12 +570,12 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); iowrite8(tf->command, ap->ioaddr.command_addr); - ata_pause(ap); + ata_sff_pause(ap); } /** @@ -598,7 +598,7 @@ static inline void ata_tf_to_host(struct ata_port *ap, } /** - * ata_data_xfer - Transfer data by PIO + * ata_sff_data_xfer - Transfer data by PIO * @dev: device to target * @buf: data buffer * @buflen: buffer length @@ -612,8 +612,8 @@ static inline void ata_tf_to_host(struct ata_port *ap, * RETURNS: * Bytes consumed. */ -unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { struct ata_port *ap = dev->link->ap; void __iomem *data_addr = ap->ioaddr.data_addr; @@ -644,7 +644,7 @@ unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, } /** - * ata_data_xfer_noirq - Transfer data by PIO + * ata_sff_data_xfer_noirq - Transfer data by PIO * @dev: device to target * @buf: data buffer * @buflen: buffer length @@ -659,14 +659,14 @@ unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, * RETURNS: * Bytes consumed. */ -unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { unsigned long flags; unsigned int consumed; local_irq_save(flags); - consumed = ata_data_xfer(dev, buf, buflen, rw); + consumed = ata_sff_data_xfer(dev, buf, buflen, rw); local_irq_restore(flags); return consumed; @@ -752,7 +752,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) } else ata_pio_sector(qc); - ata_altstatus(qc->ap); /* flush */ + ata_sff_altstatus(qc->ap); /* flush */ } /** @@ -773,7 +773,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) WARN_ON(qc->dev->cdb_len < 12); ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); - ata_altstatus(ap); /* flush */ + ata_sff_altstatus(ap); /* flush */ switch (qc->tf.protocol) { case ATAPI_PROT_PIO: @@ -915,7 +915,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) if (unlikely(__atapi_pio_bytes(qc, bytes))) goto err_out; - ata_altstatus(ap); /* flush */ + ata_sff_altstatus(ap); /* flush */ return; @@ -1004,7 +1004,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } /** - * ata_hsm_move - move the HSM to the next state. + * ata_sff_hsm_move - move the HSM to the next state. * @ap: the target ata_port * @qc: qc on going * @status: current device status @@ -1013,15 +1013,15 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) * RETURNS: * 1 when poll next status needed, 0 otherwise. */ -int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq) +int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) { unsigned long flags = 0; int poll_next; WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); - /* Make sure ata_qc_issue_prot() does not throw things + /* Make sure ata_sff_qc_issue() does not throw things * like DMA polling into the workqueue. Notice that * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). */ @@ -1263,10 +1263,10 @@ fsm_start: * or something. Snooze for a couple msecs, then * chk-status again. If still busy, queue delayed work. */ - status = ata_busy_wait(ap, ATA_BUSY, 5); + status = ata_sff_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { msleep(2); - status = ata_busy_wait(ap, ATA_BUSY, 10); + status = ata_sff_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); return; @@ -1274,7 +1274,7 @@ fsm_start: } /* move the HSM */ - poll_next = ata_hsm_move(ap, qc, status, 1); + poll_next = ata_sff_hsm_move(ap, qc, status, 1); /* another command or interrupt handler * may be running at this point. @@ -1284,7 +1284,7 @@ fsm_start: } /** - * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner + * ata_sff_qc_issue - issue taskfile to device in proto-dependent manner * @qc: command to issue to device * * Using various libata functions and hooks, this function @@ -1300,7 +1300,7 @@ fsm_start: * RETURNS: * Zero on success, AC_ERR_* mask on failure */ -unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -1415,7 +1415,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) } /** - * ata_host_intr - Handle host interrupt for given (port, task) + * ata_sff_host_intr - Handle host interrupt for given (port, task) * @ap: Port on which interrupt arrived (possibly...) * @qc: Taskfile currently active in engine * @@ -1429,8 +1429,8 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) * RETURNS: * One if interrupt was handled, zero if not (shared irq). */ -inline unsigned int ata_host_intr(struct ata_port *ap, - struct ata_queued_cmd *qc) +inline unsigned int ata_sff_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) { struct ata_eh_info *ehi = &ap->link.eh_info; u8 status, host_stat = 0; @@ -1481,7 +1481,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap, } /* check altstatus */ - status = ata_altstatus(ap); + status = ata_sff_altstatus(ap); if (status & ATA_BUSY) goto idle_irq; @@ -1493,7 +1493,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap, /* ack bmdma irq events */ ap->ops->irq_clear(ap); - ata_hsm_move(ap, qc, status, 0); + ata_sff_hsm_move(ap, qc, status, 0); if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || qc->tf.protocol == ATAPI_PROT_DMA)) @@ -1516,12 +1516,12 @@ idle_irq: } /** - * ata_interrupt - Default ATA host interrupt handler + * ata_sff_interrupt - Default ATA host interrupt handler * @irq: irq line (unused) * @dev_instance: pointer to our ata_host information structure * * Default interrupt handler for PCI IDE devices. Calls - * ata_host_intr() for each port that is not disabled. + * ata_sff_host_intr() for each port that is not disabled. * * LOCKING: * Obtains host lock during operation. @@ -1529,7 +1529,7 @@ idle_irq: * RETURNS: * IRQ_NONE or IRQ_HANDLED. */ -irqreturn_t ata_interrupt(int irq, void *dev_instance) +irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int i; @@ -1550,7 +1550,7 @@ irqreturn_t ata_interrupt(int irq, void *dev_instance) qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) - handled |= ata_host_intr(ap, qc); + handled |= ata_sff_host_intr(ap, qc); } } @@ -1560,7 +1560,7 @@ irqreturn_t ata_interrupt(int irq, void *dev_instance) } /** - * ata_bmdma_freeze - Freeze BMDMA controller port + * ata_sff_freeze - Freeze SFF controller port * @ap: port to freeze * * Freeze BMDMA controller port. @@ -1568,7 +1568,7 @@ irqreturn_t ata_interrupt(int irq, void *dev_instance) * LOCKING: * Inherited from caller. */ -void ata_bmdma_freeze(struct ata_port *ap) +void ata_sff_freeze(struct ata_port *ap) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -1588,15 +1588,15 @@ void ata_bmdma_freeze(struct ata_port *ap) } /** - * ata_bmdma_thaw - Thaw BMDMA controller port + * ata_sff_thaw - Thaw SFF controller port * @ap: port to thaw * - * Thaw BMDMA controller port. + * Thaw SFF controller port. * * LOCKING: * Inherited from caller. */ -void ata_bmdma_thaw(struct ata_port *ap) +void ata_sff_thaw(struct ata_port *ap) { /* clear & re-enable interrupts */ ap->ops->check_status(ap); @@ -1647,7 +1647,7 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) } /** - * ata_dev_try_classify - Parse returned ATA device signature + * ata_sff_dev_classify - Parse returned ATA device signature * @dev: ATA device to classify (starting at zero) * @present: device seems present * @r_err: Value of error register on completion @@ -1667,7 +1667,7 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) * RETURNS: * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ -unsigned int ata_dev_try_classify(struct ata_device *dev, int present, +unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, u8 *r_err) { struct ata_port *ap = dev->link->ap; @@ -1727,7 +1727,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, * BSY bit to clear */ if (dev0) { - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); if (rc) { if (rc != -ENODEV) return rc; @@ -1757,7 +1757,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, msleep(50); /* give drive a breather */ } - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); if (rc) { if (rc != -ENODEV) return rc; @@ -1776,7 +1776,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, } /** - * ata_wait_after_reset - wait before checking status after reset + * ata_sff_wait_after_reset - wait before checking status after reset * @ap: port containing status register to be polled * @deadline: deadline jiffies for the operation * @@ -1790,7 +1790,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, * LOCKING: * Kernel thread context (may sleep). */ -void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) +void ata_sff_wait_after_reset(struct ata_port *ap, unsigned long deadline) { unsigned long until = jiffies + ATA_TMOUT_FF_WAIT; @@ -1845,7 +1845,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, iowrite8(ap->ctl, ioaddr->ctl_addr); /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); + ata_sff_wait_after_reset(ap, deadline); /* Before we perform post reset processing we want to see if * the bus shows 0xFF because the odd clown forgets the D7 @@ -1858,7 +1858,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, } /** - * ata_std_softreset - reset host port via ATA SRST + * ata_sff_softreset - reset host port via ATA SRST * @link: ATA link to reset * @classes: resulting classes of attached devices * @deadline: deadline jiffies for the operation @@ -1871,7 +1871,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_link *link, unsigned int *classes, +int ata_sff_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { struct ata_port *ap = link->ap; @@ -1906,10 +1906,10 @@ int ata_std_softreset(struct ata_link *link, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(&link->device[0], + classes[0] = ata_sff_dev_classify(&link->device[0], devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(&link->device[1], + classes[1] = ata_sff_dev_classify(&link->device[1], devmask & (1 << 1), &err); out: @@ -1918,7 +1918,7 @@ int ata_std_softreset(struct ata_link *link, unsigned int *classes, } /** - * sata_std_hardreset - reset host port via SATA phy reset + * sata_sff_hardreset - reset host port via SATA phy reset * @link: link to reset * @class: resulting class of attached device * @deadline: deadline jiffies for the operation @@ -1932,7 +1932,7 @@ int ata_std_softreset(struct ata_link *link, unsigned int *classes, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_link *link, unsigned int *class, +int sata_sff_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_port *ap = link->ap; @@ -1957,7 +1957,7 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, } /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); + ata_sff_wait_after_reset(ap, deadline); /* If PMP is supported, we have to do follow-up SRST. Note * that some PMPs don't send D2H Reg FIS after hardreset at @@ -1965,11 +1965,11 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, * second and request follow-up SRST. */ if (ap->flags & ATA_FLAG_PMP) { - ata_wait_ready(ap, jiffies + HZ); + ata_sff_wait_ready(ap, jiffies + HZ); return -EAGAIN; } - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { ata_link_printk(link, KERN_ERR, @@ -1979,17 +1979,17 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, ap->ops->dev_select(ap, 0); /* probably unnecessary */ - *class = ata_dev_try_classify(link->device, 1, NULL); + *class = ata_sff_dev_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); return 0; } /** - * ata_bmdma_error_handler - Stock error handler for BMDMA controller + * ata_sff_error_handler - Stock error handler for BMDMA controller * @ap: port to handle error for * - * Stock error handler for BMDMA controller. It can handle both + * Stock error handler for SFF controller. It can handle both * PATA and SATA controllers. Many controllers should be able to * use this EH as-is or with some added handling before and * after. @@ -1997,7 +1997,7 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, * LOCKING: * Kernel thread context (may sleep) */ -void ata_bmdma_error_handler(struct ata_port *ap) +void ata_sff_error_handler(struct ata_port *ap) { ata_reset_fn_t softreset = ap->ops->softreset; ata_reset_fn_t hardreset = ap->ops->hardreset; @@ -2034,7 +2034,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) ap->ops->bmdma_stop(qc); } - ata_altstatus(ap); + ata_sff_altstatus(ap); ap->ops->check_status(ap); ap->ops->irq_clear(ap); @@ -2045,14 +2045,14 @@ void ata_bmdma_error_handler(struct ata_port *ap) /* PIO and DMA engines have been stopped, perform recovery */ - /* ata_std_softreset and sata_std_hardreset are inherited to + /* ata_sff_softreset and sata_sff_hardreset are inherited to * all SFF drivers from ata_sff_port_ops. Ignore softreset if * ctl isn't accessible. Ignore hardreset if SCR access isn't * available. */ - if (softreset == ata_std_softreset && !ap->ioaddr.ctl_addr) + if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr) softreset = NULL; - if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link)) + if (hardreset == sata_sff_hardreset && !sata_scr_valid(&ap->link)) hardreset = NULL; ata_do_eh(ap, ap->ops->prereset, softreset, hardreset, @@ -2060,14 +2060,13 @@ void ata_bmdma_error_handler(struct ata_port *ap) } /** - * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for - * BMDMA controller + * ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller * @qc: internal command to clean up * * LOCKING: * Kernel thread context (may sleep) */ -void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) +void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc) { if (qc->ap->ioaddr.bmdma_addr) ata_bmdma_stop(qc); @@ -2094,7 +2093,7 @@ int ata_sff_port_start(struct ata_port *ap) } /** - * ata_std_ports - initialize ioaddr with standard port offsets. + * ata_sff_std_ports - initialize ioaddr with standard port offsets. * @ioaddr: IO address structure to be initialized * * Utility function which initializes data_addr, error_addr, @@ -2104,7 +2103,7 @@ int ata_sff_port_start(struct ata_port *ap) * * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr. */ -void ata_std_ports(struct ata_ioports *ioaddr) +void ata_sff_std_ports(struct ata_ioports *ioaddr) { ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR; @@ -2118,7 +2117,8 @@ void ata_std_ports(struct ata_ioports *ioaddr) ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } -unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask) +unsigned long ata_bmdma_mode_filter(struct ata_device *adev, + unsigned long xfer_mask) { /* Filter out DMA modes if the device has been configured by the BIOS as PIO only */ @@ -2209,7 +2209,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) mmio + ATA_DMA_CMD); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ + ata_sff_altstatus(ap); /* dummy read */ } /** @@ -2289,9 +2289,9 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - device[0].class = ata_dev_try_classify(&device[0], dev0, &err); + device[0].class = ata_sff_dev_classify(&device[0], dev0, &err); if ((slave_possible) && (err != 0x81)) - device[1].class = ata_dev_try_classify(&device[1], dev1, &err); + device[1].class = ata_sff_dev_classify(&device[1], dev1, &err); /* is double-select really necessary? */ if (device[1].class != ATA_DEV_NONE) @@ -2322,7 +2322,7 @@ err_out: #ifdef CONFIG_PCI /** - * ata_pci_clear_simplex - attempt to kick device out of simplex + * ata_pci_bmdma_clear_simplex - attempt to kick device out of simplex * @pdev: PCI device * * Some PCI ATA devices report simplex mode but in fact can be told to @@ -2330,7 +2330,7 @@ err_out: * perform the task on such devices. Calling it on other devices will * have -undefined- behaviour. */ -int ata_pci_clear_simplex(struct pci_dev *pdev) +int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev) { unsigned long bmdma = pci_resource_start(pdev, 4); u8 simplex; @@ -2347,7 +2347,7 @@ int ata_pci_clear_simplex(struct pci_dev *pdev) } /** - * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host + * ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host * @host: target ATA host * * Acquire PCI BMDMA resources and initialize @host accordingly. @@ -2358,7 +2358,7 @@ int ata_pci_clear_simplex(struct pci_dev *pdev) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_pci_init_bmdma(struct ata_host *host) +int ata_pci_bmdma_init(struct ata_host *host) { struct device *gdev = host->dev; struct pci_dev *pdev = to_pci_dev(gdev); @@ -2418,7 +2418,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port) } /** - * ata_pci_init_sff_host - acquire native PCI ATA resources and init host + * ata_pci_sff_init_host - acquire native PCI ATA resources and init host * @host: target ATA host * * Acquire native PCI ATA resources for @host and initialize the @@ -2436,7 +2436,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port) * 0 if at least one port is initialized, -ENODEV if no port is * available. */ -int ata_pci_init_sff_host(struct ata_host *host) +int ata_pci_sff_init_host(struct ata_host *host) { struct device *gdev = host->dev; struct pci_dev *pdev = to_pci_dev(gdev); @@ -2478,7 +2478,7 @@ int ata_pci_init_sff_host(struct ata_host *host) ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr = (void __iomem *) ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS); - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", (unsigned long long)pci_resource_start(pdev, base), @@ -2496,7 +2496,7 @@ int ata_pci_init_sff_host(struct ata_host *host) } /** - * ata_pci_prepare_sff_host - helper to prepare native PCI ATA host + * ata_pci_sff_prepare_host - helper to prepare native PCI ATA host * @pdev: target PCI device * @ppi: array of port_info, must be enough for two ports * @r_host: out argument for the initialized ATA host @@ -2510,7 +2510,7 @@ int ata_pci_init_sff_host(struct ata_host *host) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_pci_prepare_sff_host(struct pci_dev *pdev, +int ata_pci_sff_prepare_host(struct pci_dev *pdev, const struct ata_port_info * const * ppi, struct ata_host **r_host) { @@ -2528,12 +2528,12 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, goto err_out; } - rc = ata_pci_init_sff_host(host); + rc = ata_pci_sff_init_host(host); if (rc) goto err_out; /* init DMA related stuff */ - rc = ata_pci_init_bmdma(host); + rc = ata_pci_bmdma_init(host); if (rc) goto err_bmdma; @@ -2554,7 +2554,7 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, } /** - * ata_pci_activate_sff_host - start SFF host, request IRQ and register it + * ata_pci_sff_activate_host - start SFF host, request IRQ and register it * @host: target SFF ATA host * @irq_handler: irq_handler used when requesting IRQ(s) * @sht: scsi_host_template to use when registering the host @@ -2569,7 +2569,7 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_pci_activate_sff_host(struct ata_host *host, +int ata_pci_sff_activate_host(struct ata_host *host, irq_handler_t irq_handler, struct scsi_host_template *sht) { @@ -2647,7 +2647,7 @@ int ata_pci_activate_sff_host(struct ata_host *host, } /** - * ata_pci_init_one - Initialize/register PCI IDE host controller + * ata_pci_sff_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized * @ppi: array of port_info, must be enough for two ports * @sht: scsi_host_template to use when registering the host @@ -2671,9 +2671,9 @@ int ata_pci_activate_sff_host(struct ata_host *host, * RETURNS: * Zero on success, negative on errno-based value on error. */ -int ata_pci_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, - struct scsi_host_template *sht, void *host_priv) +int ata_pci_sff_init_one(struct pci_dev *pdev, + const struct ata_port_info * const * ppi, + struct scsi_host_template *sht, void *host_priv) { struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; @@ -2704,13 +2704,13 @@ int ata_pci_init_one(struct pci_dev *pdev, goto out; /* prepare and activate SFF host */ - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) goto out; host->private_data = host_priv; pci_set_master(pdev); - rc = ata_pci_activate_sff_host(host, ata_interrupt, sht); + rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht); out: if (rc == 0) devres_remove_group(&pdev->dev, NULL); @@ -2724,47 +2724,47 @@ int ata_pci_init_one(struct pci_dev *pdev, EXPORT_SYMBOL_GPL(ata_sff_port_ops); EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); -EXPORT_SYMBOL_GPL(ata_qc_prep); -EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); -EXPORT_SYMBOL_GPL(ata_std_dev_select); -EXPORT_SYMBOL_GPL(ata_check_status); -EXPORT_SYMBOL_GPL(ata_altstatus); -EXPORT_SYMBOL_GPL(ata_busy_sleep); -EXPORT_SYMBOL_GPL(ata_wait_ready); -EXPORT_SYMBOL_GPL(ata_tf_load); -EXPORT_SYMBOL_GPL(ata_tf_read); -EXPORT_SYMBOL_GPL(ata_exec_command); -EXPORT_SYMBOL_GPL(ata_data_xfer); -EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); -EXPORT_SYMBOL_GPL(ata_irq_on); -EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); -EXPORT_SYMBOL_GPL(ata_hsm_move); -EXPORT_SYMBOL_GPL(ata_qc_issue_prot); -EXPORT_SYMBOL_GPL(ata_host_intr); -EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_bmdma_freeze); -EXPORT_SYMBOL_GPL(ata_bmdma_thaw); -EXPORT_SYMBOL_GPL(ata_std_prereset); -EXPORT_SYMBOL_GPL(ata_dev_try_classify); -EXPORT_SYMBOL_GPL(ata_wait_after_reset); -EXPORT_SYMBOL_GPL(ata_std_softreset); -EXPORT_SYMBOL_GPL(sata_std_hardreset); -EXPORT_SYMBOL_GPL(ata_std_postreset); -EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); -EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); +EXPORT_SYMBOL_GPL(ata_sff_qc_prep); +EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep); +EXPORT_SYMBOL_GPL(ata_sff_dev_select); +EXPORT_SYMBOL_GPL(ata_sff_check_status); +EXPORT_SYMBOL_GPL(ata_sff_altstatus); +EXPORT_SYMBOL_GPL(ata_sff_busy_sleep); +EXPORT_SYMBOL_GPL(ata_sff_wait_ready); +EXPORT_SYMBOL_GPL(ata_sff_tf_load); +EXPORT_SYMBOL_GPL(ata_sff_tf_read); +EXPORT_SYMBOL_GPL(ata_sff_exec_command); +EXPORT_SYMBOL_GPL(ata_sff_data_xfer); +EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_sff_irq_on); +EXPORT_SYMBOL_GPL(ata_sff_irq_clear); +EXPORT_SYMBOL_GPL(ata_sff_hsm_move); +EXPORT_SYMBOL_GPL(ata_sff_qc_issue); +EXPORT_SYMBOL_GPL(ata_sff_host_intr); +EXPORT_SYMBOL_GPL(ata_sff_interrupt); +EXPORT_SYMBOL_GPL(ata_sff_freeze); +EXPORT_SYMBOL_GPL(ata_sff_thaw); +EXPORT_SYMBOL_GPL(ata_sff_prereset); +EXPORT_SYMBOL_GPL(ata_sff_dev_classify); +EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset); +EXPORT_SYMBOL_GPL(ata_sff_softreset); +EXPORT_SYMBOL_GPL(sata_sff_hardreset); +EXPORT_SYMBOL_GPL(ata_sff_postreset); +EXPORT_SYMBOL_GPL(ata_sff_error_handler); +EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_sff_port_start); -EXPORT_SYMBOL_GPL(ata_std_ports); -EXPORT_SYMBOL_GPL(ata_pci_default_filter); +EXPORT_SYMBOL_GPL(ata_sff_std_ports); +EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter); EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bus_reset); #ifdef CONFIG_PCI -EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); -EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); -EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_init_one); +EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex); +EXPORT_SYMBOL_GPL(ata_pci_bmdma_init); +EXPORT_SYMBOL_GPL(ata_pci_sff_init_host); +EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host); +EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host); +EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); #endif /* CONFIG_PCI */ diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index d337f3209caf..c5f91e629945 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -47,7 +47,7 @@ static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) return -ENODEV; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -106,7 +106,7 @@ static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) { struct pata_acpi *acpi = adev->link->ap->private_data; - return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); + return ata_bmdma_mode_filter(adev, mask & acpi->mask[adev->devno]); } /** @@ -162,7 +162,7 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * pacpi_qc_issue_prot - command issue + * pacpi_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -170,14 +170,14 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) * neccessary. */ -static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int pacpi_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; struct pata_acpi *acpi = ap->private_data; if (acpi->gtm.flags & 0x10) - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); if (adev != acpi->last) { pacpi_set_piomode(ap, adev); @@ -185,7 +185,7 @@ static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) pacpi_set_dmamode(ap, adev); acpi->last = adev; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } /** @@ -223,7 +223,7 @@ static struct scsi_host_template pacpi_sht = { static struct ata_port_operations pacpi_ops = { .inherits = &ata_bmdma_port_ops, - .qc_issue = pacpi_qc_issue_prot, + .qc_issue = pacpi_qc_issue, .cable_detect = pacpi_cable_detect, .mode_filter = pacpi_mode_filter, .set_piomode = pacpi_set_piomode, @@ -259,7 +259,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &pacpi_ops, }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi, &pacpi_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL); } static const struct pci_device_id pacpi_pci_tbl[] = { diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 43c558f20f92..fcabe46f262b 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -121,7 +121,7 @@ static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask) ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strstr(model_num, "WDC")) return mask &= ~ATA_MASK_UDMA; - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -449,7 +449,7 @@ static void ali_init_chipset(struct pci_dev *pdev) } pci_dev_put(isa_bridge); pci_dev_put(north); - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); } /** * ali_init_one - discovery callback @@ -552,7 +552,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[0] = &info_20_udma; pci_dev_put(isa_bridge); } - return ata_pci_init_one(pdev, ppi, &ali_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 33074c34105c..26665c396485 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -143,7 +143,7 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int amd_cable_detect(struct ata_port *ap) @@ -293,7 +293,7 @@ static int nv_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -503,7 +503,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[0] = &info[type]; if (type < 3) - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); /* Check for AMD7411 */ if (type == 3) @@ -523,7 +523,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* And fire it up */ - return ata_pci_init_one(pdev, ppi, &amd_sht, hpriv); + return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv); } #ifdef CONFIG_PM @@ -546,7 +546,7 @@ static int amd_reinit_one(struct pci_dev *pdev) pci_write_config_byte(pdev, 0x41, fifo | 0xF0); if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 || pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401) - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); } ata_host_resume(host); diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index b6d8c4d0e6c2..0f513bc11193 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -52,7 +52,7 @@ static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -78,7 +78,7 @@ static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline) if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -400,7 +400,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) BUG_ON(ppi[0] == NULL); - return ata_pci_init_one(pdev, ppi, &artop_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL); } static const struct pci_device_id artop_pci_tbl[] = { diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c index 528315587532..3e8651d78952 100644 --- a/drivers/ata/pata_at32.c +++ b/drivers/ata/pata_at32.c @@ -223,7 +223,7 @@ static int __init pata_at32_init_one(struct device *dev, host->private_data = info; /* Register ATA device and return */ - return ata_host_activate(host, info->irq, ata_interrupt, + return ata_host_activate(host, info->irq, ata_sff_interrupt, IRQF_SHARED | IRQF_TRIGGER_RISING, &at32_sht); } diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 56a65baddd4a..78738fb4223b 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -45,7 +45,7 @@ static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int atiixp_cable_detect(struct ata_port *ap) @@ -223,7 +223,7 @@ static struct scsi_host_template atiixp_sht = { static struct ata_port_operations atiixp_port_ops = { .inherits = &ata_bmdma_port_ops, - .qc_prep = ata_dumb_qc_prep, + .qc_prep = ata_sff_dumb_qc_prep, .bmdma_start = atiixp_bmdma_start, .bmdma_stop = atiixp_bmdma_stop, @@ -243,7 +243,7 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &atiixp_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi, &atiixp_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &atiixp_sht, NULL); } static const struct pci_device_id atiixp[] = { diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 457ac800cd5e..c854e882d4a9 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -674,7 +674,7 @@ static void read_atapi_data(void __iomem *base, * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Note: Original code is ata_tf_load(). + * Note: Original code is ata_sff_tf_load(). */ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) @@ -745,7 +745,7 @@ static u8 bfin_check_status(struct ata_port *ap) * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * - * Note: Original code is ata_tf_read(). + * Note: Original code is ata_sff_tf_read(). */ static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf) @@ -775,7 +775,7 @@ static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf) * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Note: Original code is ata_exec_command(). + * Note: Original code is ata_sff_exec_command(). */ static void bfin_exec_command(struct ata_port *ap, @@ -785,7 +785,7 @@ static void bfin_exec_command(struct ata_port *ap, dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command); write_atapi_register(base, ATA_REG_CMD, tf->command); - ata_pause(ap); + ata_sff_pause(ap); } /** @@ -800,14 +800,14 @@ static u8 bfin_check_altstatus(struct ata_port *ap) } /** - * bfin_std_dev_select - Select device 0/1 on ATA bus + * bfin_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * - * Note: Original code is ata_std_dev_select(). + * Note: Original code is ata_sff_dev_select(). */ -static void bfin_std_dev_select(struct ata_port *ap, unsigned int device) +static void bfin_dev_select(struct ata_port *ap, unsigned int device) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; u8 tmp; @@ -818,7 +818,7 @@ static void bfin_std_dev_select(struct ata_port *ap, unsigned int device) tmp = ATA_DEVICE_OBS | ATA_DEV1; write_atapi_register(base, ATA_REG_DEVICE, tmp); - ata_pause(ap); + ata_sff_pause(ap); } /** @@ -977,7 +977,7 @@ static unsigned int bfin_devchk(struct ata_port *ap, void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; u8 nsect, lbal; - bfin_std_dev_select(ap, device); + bfin_dev_select(ap, device); write_atapi_register(base, ATA_REG_NSECT, 0x55); write_atapi_register(base, ATA_REG_LBAL, 0xaa); @@ -1014,7 +1014,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) * BSY bit to clear */ if (dev0) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); /* if device 1 was found in ata_devchk, wait for * register access, then wait for BSY to clear @@ -1023,7 +1023,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) while (dev1) { u8 nsect, lbal; - bfin_std_dev_select(ap, 1); + bfin_dev_select(ap, 1); nsect = read_atapi_register(base, ATA_REG_NSECT); lbal = read_atapi_register(base, ATA_REG_LBAL); if ((nsect == 1) && (lbal == 1)) @@ -1035,14 +1035,14 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) msleep(50); /* give drive a breather */ } if (dev1) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); /* is all this really necessary? */ - bfin_std_dev_select(ap, 0); + bfin_dev_select(ap, 0); if (dev1) - bfin_std_dev_select(ap, 1); + bfin_dev_select(ap, 1); if (dev0) - bfin_std_dev_select(ap, 0); + bfin_dev_select(ap, 0); } /** @@ -1088,15 +1088,15 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap, } /** - * bfin_std_softreset - reset host port via ATA SRST + * bfin_softreset - reset host port via ATA SRST * @ap: port to reset * @classes: resulting classes of attached devices * - * Note: Original code is ata_std_softreset(). + * Note: Original code is ata_sff_softreset(). */ -static int bfin_std_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) +static int bfin_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; @@ -1115,7 +1115,7 @@ static int bfin_std_softreset(struct ata_link *link, unsigned int *classes, devmask |= (1 << 1); /* select device 0 again */ - bfin_std_dev_select(ap, 0); + bfin_dev_select(ap, 0); /* issue bus reset */ err_mask = bfin_bus_softreset(ap, devmask); @@ -1126,10 +1126,10 @@ static int bfin_std_softreset(struct ata_link *link, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(&ap->link.device[0], + classes[0] = ata_sff_dev_classify(&ap->link.device[0], devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(&ap->link.device[1], + classes[1] = ata_sff_dev_classify(&ap->link.device[1], devmask & (1 << 1), &err); out: @@ -1167,7 +1167,7 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) * @buflen: buffer length * @write_data: read/write * - * Note: Original code is ata_data_xfer(). + * Note: Original code is ata_sff_data_xfer(). */ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf, @@ -1206,7 +1206,7 @@ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf, * bfin_irq_clear - Clear ATAPI interrupt. * @ap: Port associated with this ATA transaction. * - * Note: Original code is ata_bmdma_irq_clear(). + * Note: Original code is ata_sff_irq_clear(). */ static void bfin_irq_clear(struct ata_port *ap) @@ -1223,7 +1223,7 @@ static void bfin_irq_clear(struct ata_port *ap) * bfin_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. * - * Note: Original code is ata_irq_on(). + * Note: Original code is ata_sff_irq_on(). */ static unsigned char bfin_irq_on(struct ata_port *ap) @@ -1244,13 +1244,13 @@ static unsigned char bfin_irq_on(struct ata_port *ap) } /** - * bfin_bmdma_freeze - Freeze DMA controller port + * bfin_freeze - Freeze DMA controller port * @ap: port to freeze * - * Note: Original code is ata_bmdma_freeze(). + * Note: Original code is ata_sff_freeze(). */ -static void bfin_bmdma_freeze(struct ata_port *ap) +static void bfin_freeze(struct ata_port *ap) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; @@ -1270,13 +1270,13 @@ static void bfin_bmdma_freeze(struct ata_port *ap) } /** - * bfin_bmdma_thaw - Thaw DMA controller port + * bfin_thaw - Thaw DMA controller port * @ap: port to thaw * - * Note: Original code is ata_bmdma_thaw(). + * Note: Original code is ata_sff_thaw(). */ -void bfin_bmdma_thaw(struct ata_port *ap) +void bfin_thaw(struct ata_port *ap) { bfin_check_status(ap); bfin_irq_clear(ap); @@ -1284,14 +1284,14 @@ void bfin_bmdma_thaw(struct ata_port *ap) } /** - * bfin_std_postreset - standard postreset callback + * bfin_postreset - standard postreset callback * @ap: the target ata_port * @classes: classes of attached devices * - * Note: Original code is ata_std_postreset(). + * Note: Original code is ata_sff_postreset(). */ -static void bfin_std_postreset(struct ata_link *link, unsigned int *classes) +static void bfin_postreset(struct ata_link *link, unsigned int *classes) { struct ata_port *ap = link->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; @@ -1301,9 +1301,9 @@ static void bfin_std_postreset(struct ata_link *link, unsigned int *classes) /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) - bfin_std_dev_select(ap, 1); + bfin_dev_select(ap, 1); if (classes[1] != ATA_DEV_NONE) - bfin_std_dev_select(ap, 0); + bfin_dev_select(ap, 0); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { @@ -1362,7 +1362,7 @@ static const struct ata_port_operations bfin_pata_ops = { .exec_command = bfin_exec_command, .check_status = bfin_check_status, .check_altstatus = bfin_check_altstatus, - .dev_select = bfin_std_dev_select, + .dev_select = bfin_dev_select, .bmdma_setup = bfin_bmdma_setup, .bmdma_start = bfin_bmdma_start, @@ -1372,10 +1372,10 @@ static const struct ata_port_operations bfin_pata_ops = { .qc_prep = ata_noop_qc_prep, - .freeze = bfin_bmdma_freeze, - .thaw = bfin_bmdma_thaw, - .softreset = bfin_std_softreset, - .postreset = bfin_std_postreset, + .freeze = bfin_freeze, + .thaw = bfin_thaw, + .softreset = bfin_softreset, + .postreset = bfin_postreset, .post_internal_cmd = bfin_bmdma_stop, .irq_clear = bfin_irq_clear, @@ -1513,7 +1513,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) } if (ata_host_activate(host, platform_get_irq(pdev, 0), - ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); return -ENODEV; diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 27219b00edf4..a907cf478891 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -107,8 +107,8 @@ static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover); } else { /* Save the shared timings for channel, they will be loaded - by qc_issue_prot. Reloading the setup time is expensive - so we keep a merged one loaded */ + by qc_issue. Reloading the setup time is expensive so we + keep a merged one loaded */ pci_read_config_byte(pdev, ARTIM23, ®); reg &= 0x3F; reg |= t.setup; @@ -119,14 +119,14 @@ static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev) /** - * cmd640_qc_issue_prot - command preparation hook + * cmd640_qc_issue - command preparation hook * @qc: Command to be issued * * Channel 1 has shared timings. We must reprogram the * clock each drive 2/3 switch we do. */ -static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int cmd640_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -137,7 +137,7 @@ static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc) pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]); timing->last = adev->devno; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } /** @@ -172,8 +172,8 @@ static struct scsi_host_template cmd640_sht = { static struct ata_port_operations cmd640_port_ops = { .inherits = &ata_bmdma_port_ops, /* In theory xfer_noirq is not needed once we kill the prefetcher */ - .data_xfer = ata_data_xfer_noirq, - .qc_issue = cmd640_qc_issue_prot, + .data_xfer = ata_sff_data_xfer_noirq, + .qc_issue = cmd640_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = cmd640_set_piomode, .port_start = cmd640_port_start, @@ -224,7 +224,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) cmd640_hardware_init(pdev); - return ata_pci_init_one(pdev, ppi, &cmd640_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index f0e566623614..ddd09b7d98c9 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -349,7 +349,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) class_rev &= 0xFF; if (id->driver_data == 0) /* 643 */ - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); if (pdev->device == PCI_DEVICE_ID_CMD_646) { /* Does UDMA work ? */ @@ -373,7 +373,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_write_config_byte(pdev, UDIDETCR0, 0xF0); #endif - return ata_pci_init_one(pdev, ppi, &cmd64x_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 46d0ce32ee5a..1186bcd2781c 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -146,7 +146,7 @@ static struct scsi_host_template cs5520_sht = { static struct ata_port_operations cs5520_port_ops = { .inherits = &ata_bmdma_port_ops, - .qc_prep = ata_dumb_qc_prep, + .qc_prep = ata_sff_dumb_qc_prep, .cable_detect = ata_cable_40wire, .set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, @@ -227,7 +227,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->ctl_addr = iomap[1]; ioaddr->altstatus_addr = iomap[1]; ioaddr->bmdma_addr = iomap[4]; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_desc(host->ports[0], "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]); @@ -238,7 +238,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->ctl_addr = iomap[3]; ioaddr->altstatus_addr = iomap[3]; ioaddr->bmdma_addr = iomap[4] + 8; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_desc(host->ports[1], "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]); @@ -258,7 +258,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi continue; rc = devm_request_irq(&pdev->dev, irq[ap->port_no], - ata_interrupt, 0, DRV_NAME, host); + ata_sff_interrupt, 0, DRV_NAME, host); if (rc) return rc; diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index ac3ad55d7c3c..744beebaaf49 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -133,7 +133,7 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * cs5530_qc_issue_prot - command issue + * cs5530_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -142,7 +142,7 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) * one MWDMA/UDMA bit. */ -static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int cs5530_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -157,7 +157,7 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc) cs5530_set_dmamode(ap, adev); } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct scsi_host_template cs5530_sht = { @@ -168,8 +168,8 @@ static struct scsi_host_template cs5530_sht = { static struct ata_port_operations cs5530_port_ops = { .inherits = &ata_bmdma_port_ops, - .qc_prep = ata_dumb_qc_prep, - .qc_issue = cs5530_qc_issue_prot, + .qc_prep = ata_sff_dumb_qc_prep, + .qc_issue = cs5530_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = cs5530_set_piomode, @@ -325,7 +325,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ppi[1] = &info_palmax_secondary; /* Now kick off ATA set up */ - return ata_pci_init_one(pdev, ppi, &cs5530_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 5c0762ebf58c..f1b6556f0483 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -199,7 +199,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) rdmsr(ATAC_CH0D1_PIO, timings, dummy); if (CS5535_BAD_PIO(timings)) wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0); - return ata_pci_init_one(dev, ppi, &cs5535_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL); } static const struct pci_device_id cs5535[] = { diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 2d34b9145dcb..73f8332cb679 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -261,7 +261,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - return ata_pci_init_one(dev, ppi, &cs5536_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL); } static const struct pci_device_id cs5536[] = { diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index ae14969e1dfe..a9c3218e22fd 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -136,7 +136,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i if (PCI_FUNC(pdev->devfn) != 1) return -ENODEV; - return ata_pci_init_one(pdev, ppi, &cy82c693_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL); } static const struct pci_device_id cy82c693[] = { diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 1d839a57068e..9fba82976ba6 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -45,7 +45,7 @@ static int efar_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -262,7 +262,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &efar_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL); } static const struct pci_device_id efar_pci_tbl[] = { diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index c2d4923d4db7..f2b83eabc7c7 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -184,7 +184,7 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) mask &= ~(0xF0 << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -393,7 +393,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi, &hpt36x_sht, hpriv); + return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c10fcd31418d..42163998de9a 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -283,7 +283,7 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) mask &= ~(0xE0 << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -299,7 +299,7 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) mask &= ~(0xE0 << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -338,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline) @@ -374,7 +374,7 @@ static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -1019,7 +1019,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi, &hpt37x_sht, private_data); + return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data); } static const struct pci_device_id hpt37x[] = { diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index cd44ee3d3cc1..d5c9fd7b82bb 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -156,7 +156,7 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -308,7 +308,7 @@ static int hpt3x2n_use_dpll(struct ata_port *ap, int writing) return 0; } -static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &qc->tf; struct ata_port *ap = qc->ap; @@ -323,7 +323,7 @@ static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc) hpt3x2n_set_clock(ap, 0x23); } } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct scsi_host_template hpt3x2n_sht = { @@ -338,7 +338,7 @@ static struct ata_port_operations hpt3x2n_port_ops = { .inherits = &ata_bmdma_port_ops, .bmdma_stop = hpt3x2n_bmdma_stop, - .qc_issue = hpt3x2n_qc_issue_prot, + .qc_issue = hpt3x2n_qc_issue, .cable_detect = hpt3x2n_cable_detect, .set_piomode = hpt3x2n_set_piomode, @@ -554,7 +554,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) } /* Now kick off ATA set up */ - return ata_pci_init_one(dev, ppi, &hpt3x2n_sht, hpriv); + return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv); } static const struct pci_device_id hpt3x2n[] = { diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 8857d029ac2e..f11a320337c0 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -202,15 +202,15 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ioaddr->altstatus_addr = ioaddr->ctl_addr = base + offset_ctl[i]; ioaddr->scr_addr = NULL; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ioaddr->bmdma_addr = base + 8 * i; ata_port_pbar_desc(ap, 4, -1, "ioport"); ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd"); } pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &hpt3x3_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &hpt3x3_sht); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 13d43e9dd279..52de9f908fb0 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -270,7 +270,7 @@ static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc) disable_dma(state->dma); /* see ata_bmdma_stop */ - ata_altstatus(ap); + ata_sff_altstatus(ap); } static u8 pata_icside_bmdma_status(struct ata_port *ap) @@ -316,7 +316,7 @@ static void pata_icside_postreset(struct ata_link *link, unsigned int *classes) struct pata_icside_state *state = ap->host->private_data; if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE) - return ata_std_postreset(link, classes); + return ata_sff_postreset(link, classes); state->port[ap->port_no].disabled = 1; @@ -336,7 +336,7 @@ static struct ata_port_operations pata_icside_port_ops = { .inherits = &ata_sff_port_ops, /* no need to build any PRD tables for DMA */ .qc_prep = ata_noop_qc_prep, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, .bmdma_setup = pata_icside_bmdma_setup, .bmdma_start = pata_icside_bmdma_start, .bmdma_stop = pata_icside_bmdma_stop, @@ -481,7 +481,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info) pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]); } - return ata_host_activate(host, ec->irq, ata_interrupt, 0, + return ata_host_activate(host, ec->irq, ata_sff_interrupt, 0, &pata_icside_sht); } diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 085913ec6f68..6a111baab523 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -50,7 +50,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev if (pnp_irq_valid(idev, 0)) { irq = pnp_irq(idev, 0); - handler = ata_interrupt; + handler = ata_sff_interrupt; } /* allocate host */ @@ -78,7 +78,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev ap->ioaddr.ctl_addr = ctl_addr; } - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", (unsigned long long)pnp_port_start(idev, 0), diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 84ab89e8a247..c113d7c079c8 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -40,7 +40,7 @@ static int it8213_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -274,7 +274,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &it8213_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL); } static const struct pci_device_id it8213_pci_tbl[] = { diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 6a8a4ddf5bfe..88e37cfcfc4f 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -395,11 +395,11 @@ static void it821x_passthru_dev_select(struct ata_port *ap, it821x_program(ap, adev, itdev->pio[adev->devno]); itdev->last_device = device; } - ata_std_dev_select(ap, device); + ata_sff_dev_select(ap, device); } /** - * it821x_smart_qc_issue_prot - wrap qc issue prot + * it821x_smart_qc_issue - wrap qc issue prot * @qc: command * * Wrap the command issue sequence for the IT821x. We need to @@ -407,7 +407,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap, * usual happenings kick off */ -static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc) { switch(qc->tf.command) { @@ -427,14 +427,14 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc) case ATA_CMD_ID_ATA: /* Arguably should just no-op this one */ case ATA_CMD_SET_FEATURES: - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command); return AC_ERR_DEV; } /** - * it821x_passthru_qc_issue_prot - wrap qc issue prot + * it821x_passthru_qc_issue - wrap qc issue prot * @qc: command * * Wrap the command issue sequence for the IT821x. We need to @@ -442,10 +442,10 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc) * usual happenings kick off */ -static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int it821x_passthru_qc_issue(struct ata_queued_cmd *qc) { it821x_passthru_dev_select(qc->ap, qc->dev->devno); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } /** @@ -639,7 +639,7 @@ static struct ata_port_operations it821x_smart_port_ops = { .inherits = &ata_bmdma_port_ops, .check_atapi_dma= it821x_check_atapi_dma, - .qc_issue = it821x_smart_qc_issue_prot, + .qc_issue = it821x_smart_qc_issue, .cable_detect = it821x_ident_hack, .set_mode = it821x_smart_set_mode, @@ -655,7 +655,7 @@ static struct ata_port_operations it821x_passthru_port_ops = { .dev_select = it821x_passthru_dev_select, .bmdma_start = it821x_passthru_bmdma_start, .bmdma_stop = it821x_passthru_bmdma_stop, - .qc_issue = it821x_passthru_qc_issue_prot, + .qc_issue = it821x_passthru_qc_issue, .cable_detect = ata_cable_unknown, .set_piomode = it821x_passthru_set_piomode, @@ -722,7 +722,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) else ppi[0] = &info_smart; - return ata_pci_init_one(pdev, ppi, &it821x_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index d02629aa20da..283a8fba79b3 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -110,7 +110,7 @@ static void ixp4xx_setup_port(struct ata_port *ap, ioaddr->altstatus_addr = data->cs1 + 0x06; ioaddr->ctl_addr = data->cs1 + 0x06; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); #ifndef __ARMEB__ @@ -186,7 +186,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); /* activate host */ - return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht); + return ata_host_activate(host, irq, ata_sff_interrupt, 0, &ixp4xx_sht); } static __devexit int ixp4xx_pata_remove(struct platform_device *dev) diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 317f3474e0ba..73b7596816b4 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -102,7 +102,7 @@ static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) ap->cbl = ATA_CBL_SATA; break; } - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /* No PIO or DMA methods needed for this device */ @@ -144,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(pdev, ppi, &jmicron_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL); } static const struct pci_device_id jmicron_pci_tbl[] = { diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 2474068596f4..f13f10a55ef3 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -226,12 +226,12 @@ static const struct ata_port_operations legacy_base_port_ops = { static struct ata_port_operations simple_port_ops = { .inherits = &legacy_base_port_ops, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, }; static struct ata_port_operations legacy_port_ops = { .inherits = &legacy_base_port_ops, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, .set_mode = legacy_set_mode, }; @@ -317,7 +317,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, } local_irq_restore(flags); } else - buflen = ata_data_xfer_noirq(dev, buf, buflen, rw); + buflen = ata_sff_data_xfer_noirq(dev, buf, buflen, rw); return buflen; } @@ -579,7 +579,7 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** - * opt82c465mv_qc_issue_prot - command issue + * opt82c465mv_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -593,7 +593,7 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) * FIXME: dual channel needs ->serialize support */ -static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int opti82c46x_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -604,13 +604,13 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) && ap->host->private_data != NULL) opti82c46x_set_piomode(ap, adev); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct ata_port_operations opti82c46x_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = opti82c46x_set_piomode, - .qc_issue = opti82c46x_qc_issue_prot, + .qc_issue = opti82c46x_qc_issue, }; static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -644,7 +644,7 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) * @irq: interrupt line * * In dual channel mode the 6580 has one clock per channel and we have - * to software clockswitch in qc_issue_prot. + * to software clockswitch in qc_issue. */ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -710,14 +710,14 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** - * qdi_qc_issue_prot - command issue + * qdi_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap * this interface so that we can load the correct ATA timings. */ -static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -730,7 +730,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) 2 * ap->port_no); } } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, @@ -759,7 +759,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, } return (buflen + 3) & ~3; } else - return ata_data_xfer(adev, buf, buflen, rw); + return ata_sff_data_xfer(adev, buf, buflen, rw); } static int qdi_port(struct platform_device *dev, @@ -774,7 +774,7 @@ static int qdi_port(struct platform_device *dev, static struct ata_port_operations qdi6500_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = qdi6500_set_piomode, - .qc_issue = qdi_qc_issue_prot, + .qc_issue = qdi_qc_issue, .data_xfer = vlb32_data_xfer, }; @@ -1016,13 +1016,13 @@ static __init int legacy_init_one(struct legacy_probe *probe) ap->ioaddr.cmd_addr = io_addr; ap->ioaddr.altstatus_addr = ctrl_addr; ap->ioaddr.ctl_addr = ctrl_addr; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ap->host->private_data = ld; ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206); - ret = ata_host_activate(host, probe->irq, ata_interrupt, 0, - &legacy_sht); + ret = ata_host_activate(host, probe->irq, ata_sff_interrupt, 0, + &legacy_sht); if (ret) goto fail; ld->platform_dev = pdev; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index d38e64cd6097..24a011b25024 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -55,7 +55,7 @@ static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int marvell_cable_detect(struct ata_port *ap) @@ -128,7 +128,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i if (pdev->device == 0x6101) ppi[1] = &ata_dummy_port_info; - return ata_pci_init_one(pdev, ppi, &marvell_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL); } static const struct pci_device_id marvell_pci_tbl[] = { diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index fec93196710e..5d1d32a39c4d 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -252,7 +252,7 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) if (device != priv->csel) mpc52xx_ata_apply_timings(priv, device); - ata_std_dev_select(ap,device); + ata_sff_dev_select(ap,device); } static struct scsi_host_template mpc52xx_ata_sht = { @@ -305,7 +305,7 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); /* activate host */ - return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, + return ata_host_activate(host, priv->ata_irq, ata_sff_interrupt, 0, &mpc52xx_ata_sht); } diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 1b9d0d412ebf..7d7e3fdab71f 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -55,7 +55,7 @@ static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -69,8 +69,8 @@ static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline) * * This would get very ugly because we can only program timing for one * device at a time, the other gets PIO0. Fortunately libata calls - * our qc_issue_prot command before a command is issued so we can - * flip the timings back and forth to reduce the pain. + * our qc_issue command before a command is issued so we can flip the + * timings back and forth to reduce the pain. */ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -110,7 +110,7 @@ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** - * mpiix_qc_issue_prot - command issue + * mpiix_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -120,7 +120,7 @@ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev) * be made PIO0. */ -static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int mpiix_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -133,7 +133,7 @@ static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc) if (adev->pio_mode && adev != ap->private_data) mpiix_set_piomode(ap, adev); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct scsi_host_template mpiix_sht = { @@ -142,7 +142,7 @@ static struct scsi_host_template mpiix_sht = { static struct ata_port_operations mpiix_port_ops = { .inherits = &ata_sff_port_ops, - .qc_issue = mpiix_qc_issue_prot, + .qc_issue = mpiix_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = mpiix_set_piomode, .prereset = mpiix_pre_reset, @@ -207,10 +207,10 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) ap->ioaddr.altstatus_addr = ctl_addr; /* Let libata fill in the port details */ - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); /* activate host */ - return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED, + return ata_host_activate(host, irq, ata_sff_interrupt, IRQF_SHARED, &mpiix_sht); } diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 349182840d24..d9719c8b9dbe 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -68,10 +68,10 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e return rc; /* Any chip specific setup/optimisation/messages here */ - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); /* And let the library code do the work */ - return ata_pci_init_one(pdev, port_info, &netcell_sht, NULL); + return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL); } static const struct pci_device_id netcell_pci_tbl[] = { diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 8213d081f313..c9c0ea67c71a 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -73,7 +73,7 @@ static void ninja32_dev_select(struct ata_port *ap, unsigned int device) struct ata_device *adev = &ap->link.device[device]; if (ap->private_data != adev) { iowrite8(0xd6, ap->ioaddr.bmdma_addr + 0x1f); - ata_std_dev_select(ap, device); + ata_sff_dev_select(ap, device); ninja32_set_piomode(ap, adev); } } @@ -132,7 +132,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) ap->ioaddr.ctl_addr = base + 0x1E; ap->ioaddr.altstatus_addr = base + 0x1E; ap->ioaddr.bmdma_addr = base; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); iowrite8(0x05, base + 0x01); /* Enable interrupt lines */ iowrite8(0xBE, base + 0x02); /* Burst, ?? setup */ @@ -142,7 +142,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) iowrite8(0xa4, base + 0x1c); /* Unknown */ iowrite8(0x83, base + 0x1d); /* BMDMA control: WAIT0 */ /* FIXME: Should we disable them at remove ? */ - return ata_host_activate(host, dev->irq, ata_interrupt, + return ata_host_activate(host, dev->irq, ata_sff_interrupt, IRQF_SHARED, &ninja32_sht); } diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 4d2eefee7387..76d2455bc453 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -50,7 +50,7 @@ static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -105,7 +105,7 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** - * ns87410_qc_issue_prot - command issue + * ns87410_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -113,7 +113,7 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev) * necessary. */ -static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int ns87410_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -126,7 +126,7 @@ static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc) if (adev->pio_mode && adev != ap->private_data) ns87410_set_piomode(ap, adev); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct scsi_host_template ns87410_sht = { @@ -135,7 +135,7 @@ static struct scsi_host_template ns87410_sht = { static struct ata_port_operations ns87410_port_ops = { .inherits = &ata_sff_port_ops, - .qc_issue = ns87410_qc_issue_prot, + .qc_issue = ns87410_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = ns87410_set_piomode, .prereset = ns87410_pre_reset, @@ -149,7 +149,7 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &ns87410_port_ops }; const struct ata_port_info *ppi[] = { &info, NULL }; - return ata_pci_init_one(dev, ppi, &ns87410_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL); } static const struct pci_device_id ns87410[] = { diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index cdd79d6fc0ee..03a52cefc010 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -172,14 +172,14 @@ static void ns87415_bmdma_stop(struct ata_queued_cmd *qc) } /** - * ns87415_bmdma_irq_clear - Clear interrupt + * ns87415_irq_clear - Clear interrupt * @ap: Channel to clear * * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the * error bits) are reset by writing to register 00 or 08. */ -static void ns87415_bmdma_irq_clear(struct ata_port *ap) +static void ns87415_irq_clear(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.bmdma_addr; @@ -306,7 +306,7 @@ static struct ata_port_operations ns87415_pata_ops = { .bmdma_setup = ns87415_bmdma_setup, .bmdma_start = ns87415_bmdma_start, .bmdma_stop = ns87415_bmdma_stop, - .irq_clear = ns87415_bmdma_irq_clear, + .irq_clear = ns87415_irq_clear, .cable_detect = ata_cable_40wire, .set_piomode = ns87415_set_piomode, @@ -375,7 +375,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e pci_write_config_byte(pdev, 0x55, 0xEE); /* Select PIO0 8bit clocking */ pci_write_config_byte(pdev, 0x54, 0xB7); - return ata_pci_init_one(pdev, ppi, &ns87415_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL); } static const struct pci_device_id ns87415_pci_tbl[] = { diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index c1da79a76439..e678af383d13 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -47,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -181,7 +181,7 @@ static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev) } /** - * oldpiix_qc_issue_prot - command issue + * oldpiix_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -191,7 +191,7 @@ static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev) * be made PIO0. */ -static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int oldpiix_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -201,7 +201,7 @@ static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc) if (adev->dma_mode) oldpiix_set_dmamode(ap, adev); } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } @@ -211,7 +211,7 @@ static struct scsi_host_template oldpiix_sht = { static struct ata_port_operations oldpiix_pata_ops = { .inherits = &ata_bmdma_port_ops, - .qc_issue = oldpiix_qc_issue_prot, + .qc_issue = oldpiix_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, @@ -249,7 +249,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &oldpiix_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL); } static const struct pci_device_id oldpiix_pci_tbl[] = { diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 4ddd03a67775..fb2cf661b0e8 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -64,7 +64,7 @@ static int opti_pre_reset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -173,7 +173,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi, &opti_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL); } static const struct pci_device_id opti[] = { diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 36ac147de178..4cd744456313 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -64,7 +64,7 @@ static int optidma_pre_reset(struct ata_link *link, unsigned long deadline) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -430,7 +430,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (optiplus_with_udma(dev)) ppi[0] = &info_82c700_udma; - return ata_pci_init_one(dev, ppi, &optidma_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL); } static const struct pci_device_id optidma[] = { diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 57efbf05c95f..2e206c5f869a 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -133,7 +133,7 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, .cable_detect = ata_cable_40wire, .set_mode = pcmcia_set_mode, }; @@ -323,13 +323,13 @@ next_entry: ap->ioaddr.cmd_addr = io_addr + 0x10 * p; ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p; ap->ioaddr.ctl_addr = ctl_addr + 0x10 * p; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); } /* activate */ - ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, + ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_sff_interrupt, IRQF_SHARED, &pcmcia_sht); if (ret) goto failed; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index d235c9f92d09..0e1c2c1134d3 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -248,7 +248,7 @@ static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) /* Check whether port enabled */ if (!pdc2027x_port_enabled(link->ap)) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** @@ -265,7 +265,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long struct ata_device *pair = ata_dev_pair(adev); if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL) - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); /* Check for slave of a Maxtor at UDMA6 */ ata_id_c_string(pair->id, model_num, ATA_ID_PROD, @@ -274,7 +274,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6) mask &= ~ (1 << (6 + ATA_SHIFT_UDMA)); - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -759,8 +759,8 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de return -EIO; pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &pdc2027x_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &pdc2027x_sht); } /** diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 8214100e3ac1..d2673060bc8d 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -324,7 +324,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id return -ENODEV; } } - return ata_pci_init_one(dev, ppi, &pdc202xx_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL); } static const struct pci_device_id pdc202xx[] = { diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 0588c9b7e73e..1edfc13d05d2 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -52,7 +52,7 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, .cable_detect = ata_cable_unknown, .set_mode = pata_platform_set_mode, .port_start = ATA_OP_NULL, @@ -176,7 +176,7 @@ int __devinit __pata_platform_probe(struct device *dev, (unsigned long long)ctl_res->start); /* activate */ - return ata_host_activate(host, irq, irq ? ata_interrupt : NULL, + return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL, irq_flags, &pata_platform_sht); } EXPORT_SYMBOL_GPL(__pata_platform_probe); diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index d16b343d2a62..0d81dd5fdc38 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -102,14 +102,14 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** - * qdi_qc_issue_prot - command issue + * qdi_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap * this interface so that we can load the correct ATA timings. */ -static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -121,7 +121,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) outb(qdi->clock[adev->devno], qdi->timing); } } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, @@ -148,7 +148,7 @@ static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, buflen += 4 - slop; } } else - buflen = ata_data_xfer(dev, buf, buflen, rw); + buflen = ata_sff_data_xfer(dev, buf, buflen, rw); return buflen; } @@ -159,7 +159,7 @@ static struct scsi_host_template qdi_sht = { static struct ata_port_operations qdi6500_port_ops = { .inherits = &ata_sff_port_ops, - .qc_issue = qdi_qc_issue_prot, + .qc_issue = qdi_qc_issue, .data_xfer = qdi_data_xfer, .cable_detect = ata_cable_40wire, .set_piomode = qdi6500_set_piomode, @@ -223,7 +223,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ap->ioaddr.cmd_addr = io_addr; ap->ioaddr.altstatus_addr = ctl_addr; ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl); @@ -239,7 +239,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); /* activate */ - ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht); + ret = ata_host_activate(host, irq, ata_sff_interrupt, 0, &qdi_sht); if (ret) goto fail; diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 9ab84fc3798d..1c0d9fa7ee54 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -156,7 +156,7 @@ static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev) } /** - * radisys_qc_issue_prot - command issue + * radisys_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -166,7 +166,7 @@ static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev) * be made PIO0. */ -static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int radisys_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -180,7 +180,7 @@ static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc) radisys_set_piomode(ap, adev); } } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } @@ -190,7 +190,7 @@ static struct scsi_host_template radisys_sht = { static struct ata_port_operations radisys_pata_ops = { .inherits = &ata_bmdma_port_ops, - .qc_issue = radisys_qc_issue_prot, + .qc_issue = radisys_qc_issue, .cable_detect = ata_cable_unknown, .set_piomode = radisys_set_piomode, .set_dmamode = radisys_set_dmamode, @@ -228,7 +228,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(pdev, ppi, &radisys_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL); } static const struct pci_device_id radisys_pci_tbl[] = { diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c index 7affceec1c29..5b23d79bc92b 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb500_cf.c @@ -57,7 +57,7 @@ static inline void rb500_pata_finish_io(struct ata_port *ap) struct ata_host *ah = ap->host; struct rb500_cf_info *info = ah->private_data; - ata_altstatus(ap); + ata_sff_altstatus(ap); ndelay(RB500_CF_IO_DELAY); set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); @@ -109,7 +109,7 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) if (gpio_get_value(info->gpio_line)) { set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); if (!info->frozen) - ata_interrupt(info->irq, dev_instance); + ata_sff_interrupt(info->irq, dev_instance); } else { set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); } @@ -148,7 +148,7 @@ static void rb500_pata_setup_ports(struct ata_host *ah) ap->ioaddr.ctl_addr = info->iobase + RB500_CF_REG_CTRL; ap->ioaddr.altstatus_addr = info->iobase + RB500_CF_REG_CTRL; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA; } diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 462b72a31280..7dfd1f3f6f3a 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) - return ata_pci_init_one(pdev, ppi, &rz1000_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL); printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); /* Not safe to use so skip */ diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 42efacf73c79..cbab397e3db7 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -151,7 +151,7 @@ static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * sc1200_qc_issue_prot - command issue + * sc1200_qc_issue - command issue * @qc: command pending * * Called when the libata layer is about to issue a command. We wrap @@ -160,7 +160,7 @@ static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev) * one MWDMA/UDMA bit. */ -static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int sc1200_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_device *adev = qc->dev; @@ -175,7 +175,7 @@ static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc) sc1200_set_dmamode(ap, adev); } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static struct scsi_host_template sc1200_sht = { @@ -185,8 +185,8 @@ static struct scsi_host_template sc1200_sht = { static struct ata_port_operations sc1200_port_ops = { .inherits = &ata_bmdma_port_ops, - .qc_prep = ata_dumb_qc_prep, - .qc_issue = sc1200_qc_issue_prot, + .qc_prep = ata_sff_dumb_qc_prep, + .qc_issue = sc1200_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = sc1200_set_piomode, .set_dmamode = sc1200_set_dmamode, @@ -213,7 +213,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* Can't enable port 2 yet, see top comments */ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; - return ata_pci_init_one(dev, ppi, &sc1200_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL); } static const struct pci_device_id sc1200[] = { diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index fba5bed0a641..701d0addae73 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -266,7 +266,7 @@ unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask) printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME); mask &= ~(0xE0 << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -274,7 +274,7 @@ unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask) * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Note: Original code is ata_tf_load(). + * Note: Original code is ata_sff_tf_load(). */ static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf) @@ -341,7 +341,7 @@ static u8 scc_check_status (struct ata_port *ap) * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * - * Note: Original code is ata_tf_read(). + * Note: Original code is ata_sff_tf_read(). */ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf) @@ -373,7 +373,7 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf) * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Note: Original code is ata_exec_command(). + * Note: Original code is ata_sff_exec_command(). */ static void scc_exec_command (struct ata_port *ap, @@ -382,7 +382,7 @@ static void scc_exec_command (struct ata_port *ap, DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); out_be32(ap->ioaddr.command_addr, tf->command); - ata_pause(ap); + ata_sff_pause(ap); } /** @@ -396,14 +396,14 @@ static u8 scc_check_altstatus (struct ata_port *ap) } /** - * scc_std_dev_select - Select device 0/1 on ATA bus + * scc_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select * - * Note: Original code is ata_std_dev_select(). + * Note: Original code is ata_sff_dev_select(). */ -static void scc_std_dev_select (struct ata_port *ap, unsigned int device) +static void scc_dev_select (struct ata_port *ap, unsigned int device) { u8 tmp; @@ -413,7 +413,7 @@ static void scc_std_dev_select (struct ata_port *ap, unsigned int device) tmp = ATA_DEVICE_OBS | ATA_DEV1; out_be32(ap->ioaddr.device_addr, tmp); - ata_pause(ap); + ata_sff_pause(ap); } /** @@ -514,7 +514,7 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, * BSY bit to clear */ if (dev0) { - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); if (rc && rc != -ENODEV) return rc; } @@ -535,7 +535,7 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, msleep(50); /* give drive a breather */ } if (dev1) { - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); if (rc && rc != -ENODEV) return rc; } @@ -571,7 +571,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, out_be32(ioaddr->ctl_addr, ap->ctl); /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); + ata_sff_wait_after_reset(ap, deadline); /* Before we perform post reset processing we want to see if * the bus shows 0xFF because the odd clown forgets the D7 @@ -586,16 +586,16 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, } /** - * scc_std_softreset - reset host port via ATA SRST + * scc_softreset - reset host port via ATA SRST * @ap: port to reset * @classes: resulting classes of attached devices * @deadline: deadline jiffies for the operation * - * Note: Original code is ata_std_softreset(). + * Note: Original code is ata_sff_softreset(). */ -static int scc_std_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) +static int scc_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; @@ -628,10 +628,10 @@ static int scc_std_softreset(struct ata_link *link, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(&ap->link.device[0], + classes[0] = ata_sff_dev_classify(&ap->link.device[0], devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(&ap->link.device[1], + classes[1] = ata_sff_dev_classify(&ap->link.device[1], devmask & (1 << 1), &err); out: @@ -695,7 +695,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc) printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME); out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT); /* TBD: SW reset */ - scc_std_softreset(&ap->link, &classes, deadline); + scc_softreset(&ap->link, &classes, deadline); continue; } @@ -721,7 +721,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc) in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ + ata_sff_altstatus(ap); /* dummy read */ } /** @@ -742,7 +742,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) return host_stat; /* errata A252,A308 workaround: Step4 */ - if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ)) + if ((ata_sff_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ)) return (host_stat | ATA_DMA_INTR); /* errata A308 workaround Step5 */ @@ -773,7 +773,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) * @buflen: buffer length * @rw: read/write * - * Note: Original code is ata_data_xfer(). + * Note: Original code is ata_sff_data_xfer(). */ static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf, @@ -815,7 +815,7 @@ static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf, * scc_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. * - * Note: Original code is ata_irq_on(). + * Note: Original code is ata_sff_irq_on(). */ static u8 scc_irq_on (struct ata_port *ap) @@ -835,13 +835,13 @@ static u8 scc_irq_on (struct ata_port *ap) } /** - * scc_bmdma_freeze - Freeze BMDMA controller port + * scc_freeze - Freeze BMDMA controller port * @ap: port to freeze * - * Note: Original code is ata_bmdma_freeze(). + * Note: Original code is ata_sff_freeze(). */ -static void scc_bmdma_freeze (struct ata_port *ap) +static void scc_freeze (struct ata_port *ap) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -868,18 +868,18 @@ static void scc_bmdma_freeze (struct ata_port *ap) static int scc_pata_prereset(struct ata_link *link, unsigned long deadline) { link->ap->cbl = ATA_CBL_PATA80; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** - * scc_std_postreset - standard postreset callback + * scc_postreset - standard postreset callback * @ap: the target ata_port * @classes: classes of attached devices * - * Note: Original code is ata_std_postreset(). + * Note: Original code is ata_sff_postreset(). */ -static void scc_std_postreset(struct ata_link *link, unsigned int *classes) +static void scc_postreset(struct ata_link *link, unsigned int *classes) { struct ata_port *ap = link->ap; @@ -905,13 +905,13 @@ static void scc_std_postreset(struct ata_link *link, unsigned int *classes) } /** - * scc_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. + * scc_irq_clear - Clear PCI IDE BMDMA interrupt. * @ap: Port associated with this ATA transaction. * - * Note: Original code is ata_bmdma_irq_clear(). + * Note: Original code is ata_sff_irq_clear(). */ -static void scc_bmdma_irq_clear (struct ata_port *ap) +static void scc_irq_clear (struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.bmdma_addr; @@ -972,7 +972,7 @@ static struct ata_port_operations scc_pata_ops = { .exec_command = scc_exec_command, .check_status = scc_check_status, .check_altstatus = scc_check_altstatus, - .dev_select = scc_std_dev_select, + .dev_select = scc_dev_select, .bmdma_setup = scc_bmdma_setup, .bmdma_start = scc_bmdma_start, @@ -980,13 +980,13 @@ static struct ata_port_operations scc_pata_ops = { .bmdma_status = scc_bmdma_status, .data_xfer = scc_data_xfer, - .freeze = scc_bmdma_freeze, + .freeze = scc_freeze, .prereset = scc_pata_prereset, - .softreset = scc_std_softreset, - .postreset = scc_std_postreset, + .softreset = scc_softreset, + .postreset = scc_postreset, .post_internal_cmd = scc_bmdma_stop, - .irq_clear = scc_bmdma_irq_clear, + .irq_clear = scc_irq_clear, .irq_on = scc_irq_on, .port_start = scc_port_start, @@ -1140,8 +1140,8 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &scc_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &scc_sht); } static struct pci_driver scc_pci_driver = { diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 2f4f9b0f89de..ffd26d0dc50d 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -199,7 +199,7 @@ static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned l { if (adev->class == ATA_DEV_ATA) mask &= ~ATA_MASK_UDMA; - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } @@ -219,7 +219,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo /* Disk, UDMA */ if (adev->class != ATA_DEV_ATA) - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); /* Actually do need to check */ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); @@ -228,7 +228,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo if (!strcmp(p, model_num)) mask &= ~(0xE0 << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_bmdma_mode_filter(adev, mask); } /** @@ -459,9 +459,9 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id serverworks_fixup_ht1000(pdev); if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); - return ata_pci_init_one(pdev, ppi, &serverworks_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL); } #ifdef CONFIG_PM @@ -482,7 +482,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev) serverworks_fixup_osb4(pdev); break; case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - ata_pci_clear_simplex(pdev); + ata_pci_bmdma_clear_simplex(pdev); /* fall through */ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 63fafc6d6da3..720b8645f58a 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -350,19 +350,19 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80; host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a; host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a; - ata_std_ports(&host->ports[0]->ioaddr); + ata_sff_std_ports(&host->ports[0]->ioaddr); host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08; host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0; host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca; host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca; - ata_std_ports(&host->ports[1]->ioaddr); + ata_sff_std_ports(&host->ports[1]->ioaddr); /* Register & activate */ - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &sil680_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &sil680_sht); use_ioports: - return ata_pci_init_one(pdev, ppi, &sil680_sht, NULL); + return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 793e6714df8c..e82c66e8d31b 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -156,7 +156,7 @@ static int sis_pre_reset(struct ata_link *link, unsigned long deadline) /* Clear the FIFO settings. We can't enable the FIFO until we know we are poking at a disk */ pci_write_config_byte(pdev, 0x4B, 0); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } @@ -821,7 +821,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) sis_fixup(pdev, chipset); - return ata_pci_init_one(pdev, ppi, &sis_sht, chipset); + return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset); } static const struct pci_device_id sis_pci_tbl[] = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index bee11ca8f55a..70d94fb28a5f 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -60,7 +60,7 @@ static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline) if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } @@ -317,7 +317,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; pci_write_config_dword(dev, 0x40, val); - return ata_pci_init_one(dev, ppi, &sl82c105_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL); } static const struct pci_device_id sl82c105[] = { diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bd546a389ce1..b181261f2743 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -66,7 +66,7 @@ static int triflex_prereset(struct ata_link *link, unsigned long deadline) if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } @@ -201,7 +201,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - return ata_pci_init_one(dev, ppi, &triflex_sht, NULL); + return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL); } static const struct pci_device_id triflex[] = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 2928fa173132..4b85f84fbe76 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -210,7 +210,7 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline) return -ENOENT; } - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } @@ -336,7 +336,7 @@ static struct ata_port_operations via_port_ops = { static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, - .data_xfer = ata_data_xfer_noirq, + .data_xfer = ata_sff_data_xfer_noirq, }; /** @@ -511,7 +511,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* We have established the device type, now fire it up */ - return ata_pci_init_one(pdev, ppi, &via_sht, (void *)config); + return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config); } #ifdef CONFIG_PM diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index f235bb0d6139..cc18231e9334 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -116,7 +116,7 @@ static unsigned int winbond_data_xfer(struct ata_device *dev, buflen += 4 - slop; } } else - buflen = ata_data_xfer(dev, buf, buflen, rw); + buflen = ata_sff_data_xfer(dev, buf, buflen, rw); return buflen; } @@ -198,7 +198,7 @@ static __init int winbond_init_one(unsigned long port) ap->ioaddr.cmd_addr = cmd_addr; ap->ioaddr.altstatus_addr = ctl_addr; ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); + ata_sff_std_ports(&ap->ioaddr); /* hook in a private data structure per channel */ host->private_data = &winbond_data[nr_winbond_host]; @@ -206,7 +206,7 @@ static __init int winbond_init_one(unsigned long port) winbond_data[nr_winbond_host].platform_dev = pdev; /* activate */ - rc = ata_host_activate(host, 14 + i, ata_interrupt, 0, + rc = ata_host_activate(host, 14 + i, ata_sff_interrupt, 0, &winbond_sht); if (rc) goto err_unregister; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index c431bf36f9ba..be53545c9f64 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -208,7 +208,7 @@ static void adma_reinit_engine(struct ata_port *ap) /* mask/clear ATA interrupts */ writeb(ATA_NIEN, ap->ioaddr.ctl_addr); - ata_check_status(ap); + ata_sff_check_status(ap); /* reset the ADMA engine */ adma_reset_engine(ap); @@ -243,7 +243,7 @@ static void adma_freeze(struct ata_port *ap) /* mask/clear ATA interrupts */ writeb(ATA_NIEN, ap->ioaddr.ctl_addr); - ata_check_status(ap); + ata_sff_check_status(ap); /* reset ADMA to idle state */ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); @@ -266,7 +266,7 @@ static int adma_prereset(struct ata_link *link, unsigned long deadline) pp->state = adma_state_mmio; adma_reinit_engine(ap); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int adma_fill_sg(struct ata_queued_cmd *qc) @@ -322,7 +322,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc) adma_enter_reg_mode(qc->ap); if (qc->tf.protocol != ATA_PROT_DMA) { - ata_qc_prep(qc); + ata_sff_qc_prep(qc); return; } @@ -421,7 +421,7 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc) } pp->state = adma_state_mmio; - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static inline unsigned int adma_intr_pkt(struct ata_host *host) @@ -492,7 +492,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ - u8 status = ata_check_status(ap); + u8 status = ata_sff_check_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 12fbf3868fe2..6e6fca4c20b6 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -271,7 +271,7 @@ static void inic_host_intr(struct ata_port *ap) return; } - if (likely(ata_host_intr(ap, qc))) + if (likely(ata_sff_host_intr(ap, qc))) return; ap->ops->check_status(ap); /* clear ATA interrupt */ @@ -356,7 +356,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) return AC_ERR_HSM; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static void inic_freeze(struct ata_port *ap) @@ -418,9 +418,9 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, struct ata_taskfile tf; /* wait a while before checking status */ - ata_wait_after_reset(ap, deadline); + ata_sff_wait_after_reset(ap, deadline); - rc = ata_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { ata_link_printk(link, KERN_WARNING, "device not ready " @@ -428,7 +428,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, return rc; } - ata_tf_read(ap, &tf); + ata_sff_tf_read(ap, &tf); *class = ata_dev_classify(&tf); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; @@ -663,7 +663,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR; - ata_std_ports(port); + ata_sff_std_ports(port); ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio"); ata_port_pbar_desc(ap, MMIO_BAR, offset, "port"); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 16c15ed3536e..fa75df634c75 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1386,7 +1386,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) * shadow block, etc registers. */ mv_stop_edma(ap); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } mv_start_dma(ap, port_mmio, pp, qc->tf.protocol); @@ -2362,7 +2362,7 @@ comreset_retry: */ retry = 20; while (1) { - u8 drv_stat = ata_check_status(ap); + u8 drv_stat = ata_sff_check_status(ap); if ((drv_stat != 0x80) && (drv_stat != 0x7f)) break; msleep(500); @@ -2377,7 +2377,7 @@ comreset_retry: */ /* finally, read device signature from TF registers */ - *class = ata_dev_try_classify(ap->link.device, 1, NULL); + *class = ata_sff_dev_classify(ap->link.device, 1, NULL); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 95fd0cd28b49..63cc43765f04 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -730,7 +730,7 @@ static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf) ADMA mode could abort outstanding commands. */ nv_adma_register_mode(ap); - ata_tf_read(ap, tf); + ata_sff_tf_read(ap, tf); } static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) @@ -844,12 +844,12 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat) /* DEV interrupt w/ no active qc? */ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { - ata_check_status(ap); + ata_sff_check_status(ap); return 1; } /* handle interrupt */ - return ata_host_intr(ap, qc); + return ata_sff_host_intr(ap, qc); } static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) @@ -1028,7 +1028,7 @@ static void nv_adma_irq_clear(struct ata_port *ap) u32 notifier_clears[2]; if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) { - ata_bmdma_irq_clear(ap); + ata_sff_irq_clear(ap); return; } @@ -1059,7 +1059,7 @@ static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc) struct nv_adma_port_priv *pp = qc->ap->private_data; if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) - ata_bmdma_post_internal_cmd(qc); + ata_sff_post_internal_cmd(qc); } static int nv_adma_port_start(struct ata_port *ap) @@ -1336,7 +1336,7 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) && (qc->flags & ATA_QCFLAG_DMAMAP)); nv_adma_register_mode(qc->ap); - ata_qc_prep(qc); + ata_sff_qc_prep(qc); return; } @@ -1395,7 +1395,7 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) && (qc->flags & ATA_QCFLAG_DMAMAP)); nv_adma_register_mode(qc->ap); - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } else nv_adma_mode(qc->ap); @@ -1436,7 +1436,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) - handled += ata_host_intr(ap, qc); + handled += ata_sff_host_intr(ap, qc); else // No request pending? Clear interrupt status // anyway, in case there's one pending. @@ -1571,7 +1571,7 @@ static void nv_mcp55_freeze(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask &= ~(NV_INT_ALL_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_bmdma_freeze(ap); + ata_sff_freeze(ap); } static void nv_mcp55_thaw(struct ata_port *ap) @@ -1585,7 +1585,7 @@ static void nv_mcp55_thaw(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask |= (NV_INT_MASK_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_bmdma_thaw(ap); + ata_sff_thaw(ap); } static int nv_hardreset(struct ata_link *link, unsigned int *class, @@ -1597,7 +1597,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, * some controllers. Don't classify on hardreset. For more * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352 */ - return sata_std_hardreset(link, &dummy, deadline); + return sata_sff_hardreset(link, &dummy, deadline); } static void nv_adma_error_handler(struct ata_port *ap) @@ -1653,7 +1653,7 @@ static void nv_adma_error_handler(struct ata_port *ap) readw(mmio + NV_ADMA_CTL); /* flush posted write */ } - ata_bmdma_error_handler(ap); + ata_sff_error_handler(ap); } static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc) @@ -1779,7 +1779,7 @@ static void nv_swncq_error_handler(struct ata_port *ap) ehc->i.action |= ATA_EH_RESET; } - ata_bmdma_error_handler(ap); + ata_sff_error_handler(ap); } #ifdef CONFIG_PM @@ -1925,7 +1925,7 @@ static int nv_swncq_port_start(struct ata_port *ap) static void nv_swncq_qc_prep(struct ata_queued_cmd *qc) { if (qc->tf.protocol != ATA_PROT_NCQ) { - ata_qc_prep(qc); + ata_sff_qc_prep(qc); return; } @@ -2001,7 +2001,7 @@ static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc) struct nv_swncq_port_priv *pp = ap->private_data; if (qc->tf.protocol != ATA_PROT_NCQ) - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); DPRINTK("Enter\n"); @@ -2350,7 +2350,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ppi[0] = &nv_port_info[type]; ipriv = ppi[0]->private_data; - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) return rc; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 5a0a03a08abc..9923e860eae3 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -143,7 +143,7 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile static int pdc_check_atapi_dma(struct ata_queued_cmd *qc); static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc); static void pdc_irq_clear(struct ata_port *ap); -static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); +static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc); static void pdc_freeze(struct ata_port *ap); static void pdc_sata_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); @@ -166,7 +166,7 @@ static const struct ata_port_operations pdc_common_ops = { .exec_command = pdc_exec_command_mmio, .check_atapi_dma = pdc_check_atapi_dma, .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, + .qc_issue = pdc_qc_issue, .irq_clear = pdc_irq_clear, .post_internal_cmd = pdc_post_internal_cmd, @@ -894,7 +894,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } -static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { case ATAPI_PROT_NODATA: @@ -914,20 +914,20 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) break; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); - ata_tf_load(ap, tf); + ata_sff_tf_load(ap, 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 == ATAPI_PROT_DMA); - ata_exec_command(ap, tf); + ata_sff_exec_command(ap, tf); } static int pdc_check_atapi_dma(struct ata_queued_cmd *qc) diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 2ceb0990bcd8..1600107047cf 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -239,7 +239,7 @@ static int qs_prereset(struct ata_link *link, unsigned long deadline) struct ata_port *ap = link->ap; qs_reset_channel_logic(ap); - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) @@ -303,7 +303,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc) qs_enter_reg_mode(qc->ap); if (qc->tf.protocol != ATA_PROT_DMA) { - ata_qc_prep(qc); + ata_sff_qc_prep(qc); return; } @@ -362,7 +362,7 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) } pp->state = qs_state_mmio; - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status) @@ -451,7 +451,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) * and pretend we knew it was ours.. (ugh). * This does not affect packet mode. */ - ata_check_status(ap); + ata_sff_check_status(ap); handled = 1; continue; } @@ -459,7 +459,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) if (!pp || pp->state != qs_state_mmio) continue; if (!(qc->tf.flags & ATA_TFLAG_POLLING)) - handled |= ata_host_intr(ap, qc); + handled |= ata_sff_host_intr(ap, qc); } } return handled; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 659dfcbdc1b2..987313b68f3b 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -410,10 +410,10 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) goto err_hsm; /* ack bmdma irq events */ - ata_bmdma_irq_clear(ap); + ata_sff_irq_clear(ap); /* kick HSM in the ass */ - ata_hsm_move(ap, qc, status, 0); + ata_sff_hsm_move(ap, qc, status, 0); if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol)) ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); @@ -481,7 +481,7 @@ static void sil_thaw(struct ata_port *ap) /* clear IRQ */ ap->ops->check_status(ap); - ata_bmdma_irq_clear(ap); + ata_sff_irq_clear(ap); /* turn on SATA IRQ if supported */ if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ)) @@ -655,7 +655,7 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->ctl_addr = mmio_base + sil_port[i].ctl; ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; ioaddr->scr_addr = mmio_base + sil_port[i].scr; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio"); ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf"); diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 9089c7ab5000..6b8e45ba32e8 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -309,7 +309,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) return rc; @@ -327,8 +327,8 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); pci_intx(pdev, 1); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &sis_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &sis_sht); } static int __init sis_init(void) diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 8636f164256e..7b941106f7de 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -492,8 +492,8 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &k2_sata_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &k2_sata_sht); } /* 0x240 is device ID for Apple K2 device diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 8d7f39532d4a..40be2ff60902 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -232,7 +232,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, static void pdc20621_put_to_dimm(struct ata_host *host, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); -static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); +static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc); static struct scsi_host_template pdc_sata_sht = { @@ -244,17 +244,17 @@ static struct scsi_host_template pdc_sata_sht = { /* TODO: inherit from base port_ops after converting to new EH */ static struct ata_port_operations pdc_20621_ops = { .tf_load = pdc_tf_load_mmio, - .tf_read = ata_tf_read, - .check_status = ata_check_status, + .tf_read = ata_sff_tf_read, + .check_status = ata_sff_check_status, .exec_command = pdc_exec_command_mmio, - .dev_select = ata_std_dev_select, + .dev_select = ata_sff_dev_select, .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, - .qc_issue = pdc20621_qc_issue_prot, - .data_xfer = ata_data_xfer, + .qc_issue = pdc20621_qc_issue, + .data_xfer = ata_sff_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_clear = pdc20621_irq_clear, - .irq_on = ata_irq_on, + .irq_on = ata_sff_irq_on, .port_start = pdc_port_start, }; @@ -682,7 +682,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) } } -static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { case ATA_PROT_DMA: @@ -698,7 +698,7 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) break; } - return ata_qc_issue_prot(qc); + return ata_sff_qc_issue(qc); } static inline unsigned int pdc20621_host_intr(struct ata_port *ap, @@ -770,7 +770,7 @@ static inline unsigned int pdc20621_host_intr(struct ata_port *ap, /* command completion, but no data xfer */ } else if (qc->tf.protocol == ATA_PROT_NODATA) { - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + status = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); qc->err_mask |= ac_err_mask(status); ata_qc_complete(qc); @@ -879,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap) break; default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + drv_stat = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); ata_port_printk(ap, KERN_ERR, "unknown timeout, cmd 0x%x stat 0x%x\n", @@ -898,7 +898,7 @@ 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); - ata_tf_load(ap, tf); + ata_sff_tf_load(ap, tf); } @@ -906,7 +906,7 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile { WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); - ata_exec_command(ap, tf); + ata_sff_exec_command(ap, tf); } diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 6ecd13fefa1a..f277cea904ce 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -175,11 +175,11 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->private_data = hpriv; /* the first two ports are standard SFF */ - rc = ata_pci_init_sff_host(host); + rc = ata_pci_sff_init_host(host); if (rc) return rc; - rc = ata_pci_init_bmdma(host); + rc = ata_pci_bmdma_init(host); if (rc) return rc; @@ -200,7 +200,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4; ioaddr->bmdma_addr = iomap[4] + 16; hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_desc(host->ports[2], "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", @@ -215,7 +215,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4; ioaddr->bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_desc(host->ports[2], "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", @@ -242,8 +242,8 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); pci_intx(pdev, 1); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &uli_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &uli_sht); } static int __init uli_init(void) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 4bc6e849af2c..9323bc2a2785 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -174,7 +174,7 @@ static void svia_noop_freeze(struct ata_port *ap) * certain way. Leave it alone and just clear pending IRQ. */ ap->ops->check_status(ap); - ata_bmdma_irq_clear(ap); + ata_sff_irq_clear(ap); } /** @@ -242,7 +242,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) skip_scr: /* wait for !BSY */ - ata_wait_ready(ap, deadline); + ata_sff_wait_ready(ap, deadline); return 0; } @@ -304,7 +304,7 @@ static void vt6421_init_addrs(struct ata_port *ap) ioaddr->bmdma_addr = bmdma_addr; ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); - ata_std_ports(ioaddr); + ata_sff_std_ports(ioaddr); ata_port_pbar_desc(ap, ap->port_no, -1, "port"); ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma"); @@ -316,7 +316,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) struct ata_host *host; int rc; - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) return rc; *r_host = host; @@ -448,8 +448,8 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) svia_configure(pdev); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &svia_sht); + return ata_host_activate(host, pdev->irq, ata_sff_interrupt, + IRQF_SHARED, &svia_sht); } static int __init svia_init(void) diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index fb3a88722664..2c3c7693c750 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -200,7 +200,7 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) struct ata_ioports *ioaddr = &ap->ioaddr; u16 nsect, lbal, lbam, lbah, feature; - tf->command = ata_check_status(ap); + tf->command = ata_sff_check_status(ap); tf->device = readw(ioaddr->device_addr); feature = readw(ioaddr->error_addr); nsect = readw(ioaddr->nsect_addr); @@ -243,7 +243,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING))) - handled = ata_host_intr(ap, qc); + handled = ata_sff_host_intr(ap, qc); /* We received an interrupt during a polled command, * or some other spurious condition. Interrupt reporting diff --git a/include/linux/libata.h b/include/linux/libata.h index a05de2ba7a72..66663bfe2c71 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1342,45 +1342,48 @@ extern const struct ata_port_operations ata_bmdma_port_ops; .sg_tablesize = LIBATA_MAX_PRD, \ .dma_boundary = ATA_DMA_BOUNDARY -extern void ata_qc_prep(struct ata_queued_cmd *qc); -extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); -extern void ata_std_dev_select(struct ata_port *ap, unsigned int device); -extern u8 ata_check_status(struct ata_port *ap); -extern u8 ata_altstatus(struct ata_port *ap); -extern int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, unsigned long timeout); -extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline); -extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); -extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); -extern unsigned int ata_data_xfer(struct ata_device *dev, +extern void ata_sff_qc_prep(struct ata_queued_cmd *qc); +extern void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc); +extern void ata_sff_dev_select(struct ata_port *ap, unsigned int device); +extern u8 ata_sff_check_status(struct ata_port *ap); +extern u8 ata_sff_altstatus(struct ata_port *ap); +extern int ata_sff_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); +extern int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline); +extern void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); +extern void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_sff_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +extern unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw); -extern unsigned int ata_data_xfer_noirq(struct ata_device *dev, +extern unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw); -extern u8 ata_irq_on(struct ata_port *ap); -extern void ata_bmdma_irq_clear(struct ata_port *ap); -extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq); -extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); -extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); -extern irqreturn_t ata_interrupt(int irq, void *dev_instance); -extern void ata_bmdma_freeze(struct ata_port *ap); -extern void ata_bmdma_thaw(struct ata_port *ap); -extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); -extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present, - u8 *r_err); -extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline); -extern int ata_std_softreset(struct ata_link *link, unsigned int *classes, +extern u8 ata_sff_irq_on(struct ata_port *ap); +extern void ata_sff_irq_clear(struct ata_port *ap); +extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc); +extern unsigned int ata_sff_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc); +extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance); +extern void ata_sff_freeze(struct ata_port *ap); +extern void ata_sff_thaw(struct ata_port *ap); +extern int ata_sff_prereset(struct ata_link *link, unsigned long deadline); +extern unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, + u8 *r_err); +extern void ata_sff_wait_after_reset(struct ata_port *ap, + unsigned long deadline); +extern int ata_sff_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline); -extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); -extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); -extern void ata_bmdma_error_handler(struct ata_port *ap); -extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); +extern int sata_sff_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +extern void ata_sff_postreset(struct ata_link *link, unsigned int *classes); +extern void ata_sff_error_handler(struct ata_port *ap); +extern void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc); extern int ata_sff_port_start(struct ata_port *ap); -extern void ata_std_ports(struct ata_ioports *ioaddr); -extern unsigned long ata_pci_default_filter(struct ata_device *dev, - unsigned long xfer_mask); +extern void ata_sff_std_ports(struct ata_ioports *ioaddr); +extern unsigned long ata_bmdma_mode_filter(struct ata_device *dev, + unsigned long xfer_mask); extern void ata_bmdma_setup(struct ata_queued_cmd *qc); extern void ata_bmdma_start(struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); @@ -1388,35 +1391,35 @@ extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); #ifdef CONFIG_PCI -extern int ata_pci_clear_simplex(struct pci_dev *pdev); -extern int ata_pci_init_bmdma(struct ata_host *host); -extern int ata_pci_init_sff_host(struct ata_host *host); -extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, +extern int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev); +extern int ata_pci_bmdma_init(struct ata_host *host); +extern int ata_pci_sff_init_host(struct ata_host *host); +extern int ata_pci_sff_prepare_host(struct pci_dev *pdev, const struct ata_port_info * const * ppi, struct ata_host **r_host); -extern int ata_pci_activate_sff_host(struct ata_host *host, +extern int ata_pci_sff_activate_host(struct ata_host *host, irq_handler_t irq_handler, struct scsi_host_template *sht); -extern int ata_pci_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, - struct scsi_host_template *sht, void *host_priv); +extern int ata_pci_sff_init_one(struct pci_dev *pdev, + const struct ata_port_info * const * ppi, + struct scsi_host_template *sht, void *host_priv); #endif /* CONFIG_PCI */ /** - * ata_pause - Flush writes and pause 400 nanoseconds. + * ata_sff_pause - Flush writes and pause 400 nanoseconds. * @ap: Port to wait for. * * LOCKING: * Inherited from caller. */ -static inline void ata_pause(struct ata_port *ap) +static inline void ata_sff_pause(struct ata_port *ap) { - ata_altstatus(ap); + ata_sff_altstatus(ap); ndelay(400); } /** - * ata_busy_wait - Wait for a port status register + * ata_sff_busy_wait - Wait for a port status register * @ap: Port to wait for. * @bits: bits that must be clear * @max: number of 10uS waits to perform @@ -1428,8 +1431,8 @@ static inline void ata_pause(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, - unsigned int max) +static inline u8 ata_sff_busy_wait(struct ata_port *ap, unsigned int bits, + unsigned int max) { u8 status; @@ -1454,7 +1457,7 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, */ static inline u8 ata_wait_idle(struct ata_port *ap) { - u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + u8 status = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); #ifdef ATA_DEBUG if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) -- cgit v1.2.3 From 5682ed33aae05d10a25c95633ef9d9c062825888 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:16 +0900 Subject: libata: rename SFF port ops Add sff_ prefix to SFF specific port ops. This rename is in preparation of separating SFF support out of libata core layer. This patch strictly renames ops and doesn't introduce any behavior difference. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 6 +-- drivers/ata/libata-core.c | 18 +++---- drivers/ata/libata-scsi.c | 2 +- drivers/ata/libata-sff.c | 109 ++++++++++++++++++++++-------------------- drivers/ata/pata_bf54x.c | 20 ++++---- drivers/ata/pata_cmd640.c | 2 +- drivers/ata/pata_icside.c | 4 +- drivers/ata/pata_it821x.c | 2 +- drivers/ata/pata_ixp4xx_cf.c | 2 +- drivers/ata/pata_legacy.c | 14 +++--- drivers/ata/pata_mpc52xx.c | 2 +- drivers/ata/pata_ninja32.c | 2 +- drivers/ata/pata_ns87415.c | 8 ++-- drivers/ata/pata_pcmcia.c | 4 +- drivers/ata/pata_platform.c | 2 +- drivers/ata/pata_qdi.c | 2 +- drivers/ata/pata_rb500_cf.c | 4 +- drivers/ata/pata_scc.c | 42 ++++++++-------- drivers/ata/pata_via.c | 2 +- drivers/ata/pata_winbond.c | 2 +- drivers/ata/sata_fsl.c | 6 +-- drivers/ata/sata_inic162x.c | 12 ++--- drivers/ata/sata_nv.c | 20 ++++---- drivers/ata/sata_promise.c | 6 +-- drivers/ata/sata_sil.c | 6 +-- drivers/ata/sata_sil24.c | 6 +-- drivers/ata/sata_svw.c | 10 ++-- drivers/ata/sata_sx4.c | 16 +++---- drivers/ata/sata_via.c | 2 +- drivers/ata/sata_vsc.c | 6 +-- drivers/scsi/ipr.c | 8 ++-- drivers/scsi/libsas/sas_ata.c | 8 ++-- include/linux/libata.h | 25 +++++----- 33 files changed, 192 insertions(+), 188 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 771509c9a3fb..c5e4501daa74 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -292,10 +292,10 @@ static struct scsi_host_template ahci_sht = { static struct ata_port_operations ahci_ops = { .inherits = &sata_pmp_port_ops, - .check_status = ahci_check_status, - .check_altstatus = ahci_check_status, + .sff_check_status = ahci_check_status, + .sff_check_altstatus = ahci_check_status, - .tf_read = ahci_tf_read, + .sff_tf_read = ahci_tf_read, .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cbdbfb5eaeaa..a01e02c5ce7a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,7 +74,7 @@ const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { - .irq_clear = ata_noop_irq_clear, + .sff_irq_clear = ata_noop_irq_clear, .prereset = ata_sff_prereset, .hardreset = sata_sff_hardreset, .postreset = ata_sff_postreset, @@ -85,7 +85,7 @@ const struct ata_port_operations sata_port_ops = { .inherits = &ata_base_port_ops, .qc_defer = ata_std_qc_defer, - .dev_select = ata_noop_dev_select, + .sff_dev_select = ata_noop_dev_select, }; const struct ata_port_operations sata_pmp_port_ops = { @@ -3563,9 +3563,9 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes) /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); if (classes[1] != ATA_DEV_NONE) - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { @@ -4416,7 +4416,7 @@ static void fill_result_tf(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; qc->result_tf.flags = qc->tf.flags; - ap->ops->tf_read(ap, &qc->result_tf); + ap->ops->sff_tf_read(ap, &qc->result_tf); } static void ata_verify_xfer(struct ata_queued_cmd *qc) @@ -6049,16 +6049,16 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) } struct ata_port_operations ata_dummy_port_ops = { - .check_status = ata_dummy_check_status, - .check_altstatus = ata_dummy_check_status, - .dev_select = ata_noop_dev_select, + .sff_check_status = ata_dummy_check_status, + .sff_check_altstatus = ata_dummy_check_status, + .sff_dev_select = ata_noop_dev_select, .qc_prep = ata_noop_qc_prep, .qc_issue = ata_dummy_qc_issue, .freeze = ata_dummy_noret, .thaw = ata_dummy_noret, .error_handler = ata_dummy_noret, .post_internal_cmd = ata_dummy_qc_noret, - .irq_clear = ata_dummy_noret, + .sff_irq_clear = ata_dummy_noret, .port_start = ata_dummy_ret0, .port_stop = ata_dummy_noret, }; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 798ba5e45710..f8be92836a6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2393,7 +2393,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) /* FIXME: is this needed? */ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - ap->ops->tf_read(ap, &qc->tf); + ap->ops->sff_tf_read(ap, &qc->tf); /* fill these in, for the case where they are -not- overwritten */ cmd->sense_buffer[0] = 0x70; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 8544321293d4..04024a556660 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -51,13 +51,13 @@ const struct ata_port_operations ata_sff_port_ops = { .error_handler = ata_sff_error_handler, .post_internal_cmd = ata_sff_post_internal_cmd, - .dev_select = ata_sff_dev_select, - .check_status = ata_sff_check_status, - .tf_load = ata_sff_tf_load, - .tf_read = ata_sff_tf_read, - .exec_command = ata_sff_exec_command, - .data_xfer = ata_sff_data_xfer, - .irq_on = ata_sff_irq_on, + .sff_dev_select = ata_sff_dev_select, + .sff_check_status = ata_sff_check_status, + .sff_tf_load = ata_sff_tf_load, + .sff_tf_read = ata_sff_tf_read, + .sff_exec_command = ata_sff_exec_command, + .sff_data_xfer = ata_sff_data_xfer, + .sff_irq_on = ata_sff_irq_on, .port_start = ata_sff_port_start, }; @@ -71,7 +71,7 @@ const struct ata_port_operations ata_bmdma_port_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, - .irq_clear = ata_sff_irq_clear, + .sff_irq_clear = ata_sff_irq_clear, }; /** @@ -245,8 +245,8 @@ u8 ata_sff_check_status(struct ata_port *ap) */ u8 ata_sff_altstatus(struct ata_port *ap) { - if (ap->ops->check_altstatus) - return ap->ops->check_altstatus(ap); + if (ap->ops->sff_check_altstatus) + return ap->ops->sff_check_altstatus(ap); return ioread8(ap->ioaddr.altstatus_addr); } @@ -290,7 +290,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, while (status != 0xff && (status & ATA_BUSY) && time_before(jiffies, timeout)) { msleep(50); - status = ap->ops->check_status(ap); + status = ap->ops->sff_check_status(ap); } if (status == 0xff) @@ -326,7 +326,7 @@ int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline) int warned = 0; while (1) { - u8 status = ap->ops->check_status(ap); + u8 status = ap->ops->sff_check_status(ap); unsigned long now = jiffies; if (!(status & ATA_BUSY)) @@ -403,7 +403,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, if (wait) ata_wait_idle(ap); - ap->ops->dev_select(ap, device); + ap->ops->sff_dev_select(ap, device); if (wait) { if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) @@ -434,7 +434,7 @@ u8 ata_sff_irq_on(struct ata_port *ap) iowrite8(ap->ctl, ioaddr->ctl_addr); tmp = ata_wait_idle(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); return tmp; } @@ -593,8 +593,8 @@ void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) static inline void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) { - ap->ops->tf_load(ap, tf); - ap->ops->exec_command(ap, tf); + ap->ops->sff_tf_load(ap, tf); + ap->ops->sff_exec_command(ap, tf); } /** @@ -709,13 +709,15 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size, + do_write); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size, + do_write); } qc->curbytes += qc->sect_size; @@ -772,7 +774,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) DPRINTK("send cdb\n"); WARN_ON(qc->dev->cdb_len < 12); - ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); + ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); ata_sff_altstatus(ap); /* flush */ switch (qc->tf.protocol) { @@ -844,13 +846,13 @@ next_sg: buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); + consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - consumed = ap->ops->data_xfer(dev, buf + offset, count, rw); + consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw); } bytes -= min(bytes, consumed); @@ -893,7 +895,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) * error, qc->result_tf is later overwritten by ata_qc_complete(). * So, the correctness of qc->result_tf is not affected. */ - ap->ops->tf_read(ap, &qc->result_tf); + ap->ops->sff_tf_read(ap, &qc->result_tf); ireason = qc->result_tf.nsect; bc_lo = qc->result_tf.lbam; bc_hi = qc->result_tf.lbah; @@ -979,7 +981,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) qc = ata_qc_from_tag(ap, qc->tag); if (qc) { if (likely(!(qc->err_mask & AC_ERR_HSM))) { - ap->ops->irq_on(ap); + ap->ops->sff_irq_on(ap); ata_qc_complete(qc); } else ata_port_freeze(ap); @@ -995,7 +997,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } else { if (in_wq) { spin_lock_irqsave(ap->lock, flags); - ap->ops->irq_on(ap); + ap->ops->sff_irq_on(ap); ata_qc_complete(qc); spin_unlock_irqrestore(ap->lock, flags); } else @@ -1345,7 +1347,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) case ATA_PROT_DMA: WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); - ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ ap->ops->bmdma_start(qc); /* initiate bmdma */ ap->hsm_task_state = HSM_ST_LAST; @@ -1397,7 +1399,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) case ATAPI_PROT_DMA: WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); - ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ ap->hsm_task_state = HSM_ST_FIRST; @@ -1486,12 +1488,12 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap, goto idle_irq; /* check main status, clearing INTRQ */ - status = ap->ops->check_status(ap); + status = ap->ops->sff_check_status(ap); if (unlikely(status & ATA_BUSY)) goto idle_irq; /* ack bmdma irq events */ - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); ata_sff_hsm_move(ap, qc, status, 0); @@ -1506,8 +1508,8 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ap->ops->check_status(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_check_status(ap); + ap->ops->sff_irq_clear(ap); ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -1582,9 +1584,9 @@ void ata_sff_freeze(struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); } /** @@ -1599,9 +1601,9 @@ void ata_sff_freeze(struct ata_port *ap) void ata_sff_thaw(struct ata_port *ap) { /* clear & re-enable interrupts */ - ap->ops->check_status(ap); - ap->ops->irq_clear(ap); - ap->ops->irq_on(ap); + ap->ops->sff_check_status(ap); + ap->ops->sff_irq_clear(ap); + ap->ops->sff_irq_on(ap); } /** @@ -1626,7 +1628,7 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - ap->ops->dev_select(ap, device); + ap->ops->sff_dev_select(ap, device); iowrite8(0x55, ioaddr->nsect_addr); iowrite8(0xaa, ioaddr->lbal_addr); @@ -1675,11 +1677,11 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, unsigned int class; u8 err; - ap->ops->dev_select(ap, dev->devno); + ap->ops->sff_dev_select(ap, dev->devno); memset(&tf, 0, sizeof(tf)); - ap->ops->tf_read(ap, &tf); + ap->ops->sff_tf_read(ap, &tf); err = tf.feature; if (r_err) *r_err = err; @@ -1709,7 +1711,8 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, class = ATA_DEV_ATA; else class = ATA_DEV_NONE; - } else if ((class == ATA_DEV_ATA) && (ap->ops->check_status(ap) == 0)) + } else if ((class == ATA_DEV_ATA) && + (ap->ops->sff_check_status(ap) == 0)) class = ATA_DEV_NONE; return class; @@ -1741,7 +1744,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, if (dev1) { int i; - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); /* Wait for register access. Some ATAPI devices fail * to set nsect/lbal after reset, so don't waste too @@ -1766,11 +1769,11 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, } /* is all this really necessary? */ - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); if (dev1) - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); if (dev0) - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); return ret; } @@ -1820,7 +1823,7 @@ void ata_sff_wait_after_reset(struct ata_port *ap, unsigned long deadline) */ if (ap->flags & ATA_FLAG_SATA) { while (1) { - u8 status = ap->ops->check_status(ap); + u8 status = ap->ops->sff_check_status(ap); if (status != 0xff || time_after(jiffies, deadline)) return; @@ -1851,7 +1854,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ap->ops->check_status(ap) == 0xFF) + if (ap->ops->sff_check_status(ap) == 0xFF) return -ENODEV; return ata_bus_post_reset(ap, devmask, deadline); @@ -1894,7 +1897,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, devmask |= (1 << 1); /* select device 0 again */ - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* issue bus reset */ DPRINTK("about to softreset, devmask=%x\n", devmask); @@ -1977,7 +1980,7 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, return rc; } - ap->ops->dev_select(ap, 0); /* probably unnecessary */ + ap->ops->sff_dev_select(ap, 0); /* probably unnecessary */ *class = ata_sff_dev_classify(link->device, 1, NULL); @@ -2035,8 +2038,8 @@ void ata_sff_error_handler(struct ata_port *ap) } ata_sff_altstatus(ap); - ap->ops->check_status(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_check_status(ap); + ap->ops->sff_irq_clear(ap); spin_unlock_irqrestore(ap->lock, flags); @@ -2153,7 +2156,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc) iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } /** @@ -2277,7 +2280,7 @@ void ata_bus_reset(struct ata_port *ap) devmask |= (1 << 1); /* select device 0 again */ - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) { @@ -2295,9 +2298,9 @@ void ata_bus_reset(struct ata_port *ap) /* is double-select really necessary? */ if (device[1].class != ATA_DEV_NONE) - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); if (device[0].class != ATA_DEV_NONE) - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* if no devices were detected, disable this port */ if ((device[0].class == ATA_DEV_NONE) && diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index c854e882d4a9..d98bd7455e6b 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1264,7 +1264,7 @@ static void bfin_freeze(struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); bfin_irq_clear(ap); } @@ -1357,18 +1357,18 @@ static const struct ata_port_operations bfin_pata_ops = { .set_piomode = bfin_set_piomode, .set_dmamode = bfin_set_dmamode, - .tf_load = bfin_tf_load, - .tf_read = bfin_tf_read, - .exec_command = bfin_exec_command, - .check_status = bfin_check_status, - .check_altstatus = bfin_check_altstatus, - .dev_select = bfin_dev_select, + .sff_tf_load = bfin_tf_load, + .sff_tf_read = bfin_tf_read, + .sff_exec_command = bfin_exec_command, + .sff_check_status = bfin_check_status, + .sff_check_altstatus = bfin_check_altstatus, + .sff_dev_select = bfin_dev_select, .bmdma_setup = bfin_bmdma_setup, .bmdma_start = bfin_bmdma_start, .bmdma_stop = bfin_bmdma_stop, .bmdma_status = bfin_bmdma_status, - .data_xfer = bfin_data_xfer, + .sff_data_xfer = bfin_data_xfer, .qc_prep = ata_noop_qc_prep, @@ -1378,8 +1378,8 @@ static const struct ata_port_operations bfin_pata_ops = { .postreset = bfin_postreset, .post_internal_cmd = bfin_bmdma_stop, - .irq_clear = bfin_irq_clear, - .irq_on = bfin_irq_on, + .sff_irq_clear = bfin_irq_clear, + .sff_irq_on = bfin_irq_on, .port_start = bfin_port_start, .port_stop = bfin_port_stop, diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index a907cf478891..2de30b990278 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -172,7 +172,7 @@ static struct scsi_host_template cmd640_sht = { static struct ata_port_operations cmd640_port_ops = { .inherits = &ata_bmdma_port_ops, /* In theory xfer_noirq is not needed once we kill the prefetcher */ - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, .qc_issue = cmd640_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = cmd640_set_piomode, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 52de9f908fb0..17138436423d 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -250,7 +250,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ); /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } static void pata_icside_bmdma_start(struct ata_queued_cmd *qc) @@ -336,7 +336,7 @@ static struct ata_port_operations pata_icside_port_ops = { .inherits = &ata_sff_port_ops, /* no need to build any PRD tables for DMA */ .qc_prep = ata_noop_qc_prep, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, .bmdma_setup = pata_icside_bmdma_setup, .bmdma_start = pata_icside_bmdma_start, .bmdma_stop = pata_icside_bmdma_stop, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 88e37cfcfc4f..e10816931b2f 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -652,7 +652,7 @@ static struct ata_port_operations it821x_passthru_port_ops = { .inherits = &ata_bmdma_port_ops, .check_atapi_dma= it821x_check_atapi_dma, - .dev_select = it821x_passthru_dev_select, + .sff_dev_select = it821x_passthru_dev_select, .bmdma_start = it821x_passthru_bmdma_start, .bmdma_stop = it821x_passthru_bmdma_stop, .qc_issue = it821x_passthru_qc_issue, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 283a8fba79b3..8a175f23b907 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -93,7 +93,7 @@ static struct scsi_host_template ixp4xx_sht = { static struct ata_port_operations ixp4xx_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ixp4xx_mmio_data_xfer, + .sff_data_xfer = ixp4xx_mmio_data_xfer, .cable_detect = ata_cable_40wire, .set_mode = ixp4xx_set_mode, }; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index f13f10a55ef3..7af4b29cc422 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -226,12 +226,12 @@ static const struct ata_port_operations legacy_base_port_ops = { static struct ata_port_operations simple_port_ops = { .inherits = &legacy_base_port_ops, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, }; static struct ata_port_operations legacy_port_ops = { .inherits = &legacy_base_port_ops, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, .set_mode = legacy_set_mode, }; @@ -325,7 +325,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, static struct ata_port_operations pdc20230_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = pdc20230_set_piomode, - .data_xfer = pdc_data_xfer_vlb, + .sff_data_xfer = pdc_data_xfer_vlb, }; /* @@ -775,19 +775,19 @@ static struct ata_port_operations qdi6500_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = qdi6500_set_piomode, .qc_issue = qdi_qc_issue, - .data_xfer = vlb32_data_xfer, + .sff_data_xfer = vlb32_data_xfer, }; static struct ata_port_operations qdi6580_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = qdi6580_set_piomode, - .data_xfer = vlb32_data_xfer, + .sff_data_xfer = vlb32_data_xfer, }; static struct ata_port_operations qdi6580dp_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = qdi6580dp_set_piomode, - .data_xfer = vlb32_data_xfer, + .sff_data_xfer = vlb32_data_xfer, }; static DEFINE_SPINLOCK(winbond_lock); @@ -858,7 +858,7 @@ static int winbond_port(struct platform_device *dev, static struct ata_port_operations winbond_port_ops = { .inherits = &legacy_base_port_ops, .set_piomode = winbond_set_piomode, - .data_xfer = vlb32_data_xfer, + .sff_data_xfer = vlb32_data_xfer, }; static struct legacy_controller controllers[] = { diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 5d1d32a39c4d..bc79df6e7cb0 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -261,7 +261,7 @@ static struct scsi_host_template mpc52xx_ata_sht = { static struct ata_port_operations mpc52xx_ata_port_ops = { .inherits = &ata_sff_port_ops, - .dev_select = mpc52xx_ata_dev_select, + .sff_dev_select = mpc52xx_ata_dev_select, .cable_detect = ata_cable_40wire, .set_piomode = mpc52xx_ata_set_piomode, .post_internal_cmd = ATA_OP_NULL, diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index c9c0ea67c71a..565e67cd13fa 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -84,7 +84,7 @@ static struct scsi_host_template ninja32_sht = { static struct ata_port_operations ninja32_port_ops = { .inherits = &ata_bmdma_port_ops, - .dev_select = ninja32_dev_select, + .sff_dev_select = ninja32_dev_select, .cable_detect = ata_cable_40wire, .set_piomode = ninja32_set_piomode, }; diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 03a52cefc010..ae92b0049bd5 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -138,7 +138,7 @@ static void ns87415_bmdma_setup(struct ata_queued_cmd *qc) dmactl |= ATA_DMA_WR; iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } /** @@ -306,7 +306,7 @@ static struct ata_port_operations ns87415_pata_ops = { .bmdma_setup = ns87415_bmdma_setup, .bmdma_start = ns87415_bmdma_start, .bmdma_stop = ns87415_bmdma_stop, - .irq_clear = ns87415_irq_clear, + .sff_irq_clear = ns87415_irq_clear, .cable_detect = ata_cable_40wire, .set_piomode = ns87415_set_piomode, @@ -315,8 +315,8 @@ static struct ata_port_operations ns87415_pata_ops = { #if defined(CONFIG_SUPERIO) static struct ata_port_operations ns87560_pata_ops = { .inherits = &ns87415_pata_ops, - .tf_read = ns87560_tf_read, - .check_status = ns87560_check_status, + .sff_tf_read = ns87560_tf_read, + .sff_check_status = ns87560_check_status, .bmdma_status = ns87560_bmdma_status, }; #endif diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 2e206c5f869a..3d39f9dfec5a 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -133,14 +133,14 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, .cable_detect = ata_cable_40wire, .set_mode = pcmcia_set_mode, }; static struct ata_port_operations pcmcia_8bit_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ata_data_xfer_8bit, + .sff_data_xfer = ata_data_xfer_8bit, .cable_detect = ata_cable_40wire, .set_mode = pcmcia_set_mode_8bit, }; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 1edfc13d05d2..6527c56c34a3 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -52,7 +52,7 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, .cable_detect = ata_cable_unknown, .set_mode = pata_platform_set_mode, .port_start = ATA_OP_NULL, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 0d81dd5fdc38..bf45cf017753 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -160,7 +160,7 @@ static struct scsi_host_template qdi_sht = { static struct ata_port_operations qdi6500_port_ops = { .inherits = &ata_sff_port_ops, .qc_issue = qdi_qc_issue, - .data_xfer = qdi_data_xfer, + .sff_data_xfer = qdi_data_xfer, .cable_detect = ata_cable_40wire, .set_piomode = qdi6500_set_piomode, }; diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c index 5b23d79bc92b..800ae4601f44 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb500_cf.c @@ -119,8 +119,8 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) static struct ata_port_operations rb500_pata_port_ops = { .inherits = &ata_sff_port_ops, - .exec_command = rb500_pata_exec_command, - .data_xfer = rb500_pata_data_xfer, + .sff_exec_command = rb500_pata_exec_command, + .sff_data_xfer = rb500_pata_data_xfer, .freeze = rb500_pata_freeze, .thaw = rb500_pata_thaw, }; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 701d0addae73..2b9da715c704 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -441,7 +441,7 @@ static void scc_bmdma_setup (struct ata_queued_cmd *qc) out_be32(mmio + SCC_DMA_CMD, dmactl); /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } /** @@ -476,7 +476,7 @@ static unsigned int scc_devchk (struct ata_port *ap, struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; - ap->ops->dev_select(ap, device); + ap->ops->sff_dev_select(ap, device); out_be32(ioaddr->nsect_addr, 0x55); out_be32(ioaddr->lbal_addr, 0xaa); @@ -525,7 +525,7 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, while (dev1) { u8 nsect, lbal; - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); nsect = in_be32(ioaddr->nsect_addr); lbal = in_be32(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) @@ -541,11 +541,11 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, } /* is all this really necessary? */ - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); if (dev1) - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); if (dev0) - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); return 0; } @@ -616,7 +616,7 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, devmask |= (1 << 1); /* select device 0 again */ - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* issue bus reset */ DPRINTK("about to softreset, devmask=%x\n", devmask); @@ -829,7 +829,7 @@ static u8 scc_irq_on (struct ata_port *ap) out_be32(ioaddr->ctl_addr, ap->ctl); tmp = ata_wait_idle(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); return tmp; } @@ -854,9 +854,9 @@ static void scc_freeze (struct ata_port *ap) * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); } /** @@ -887,9 +887,9 @@ static void scc_postreset(struct ata_link *link, unsigned int *classes) /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) - ap->ops->dev_select(ap, 1); + ap->ops->sff_dev_select(ap, 1); if (classes[1] != ATA_DEV_NONE) - ap->ops->dev_select(ap, 0); + ap->ops->sff_dev_select(ap, 0); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { @@ -967,18 +967,18 @@ static struct ata_port_operations scc_pata_ops = { .set_dmamode = scc_set_dmamode, .mode_filter = scc_mode_filter, - .tf_load = scc_tf_load, - .tf_read = scc_tf_read, - .exec_command = scc_exec_command, - .check_status = scc_check_status, - .check_altstatus = scc_check_altstatus, - .dev_select = scc_dev_select, + .sff_tf_load = scc_tf_load, + .sff_tf_read = scc_tf_read, + .sff_exec_command = scc_exec_command, + .sff_check_status = scc_check_status, + .sff_check_altstatus = scc_check_altstatus, + .sff_dev_select = scc_dev_select, .bmdma_setup = scc_bmdma_setup, .bmdma_start = scc_bmdma_start, .bmdma_stop = scc_bmdma_stop, .bmdma_status = scc_bmdma_status, - .data_xfer = scc_data_xfer, + .sff_data_xfer = scc_data_xfer, .freeze = scc_freeze, .prereset = scc_pata_prereset, @@ -986,8 +986,8 @@ static struct ata_port_operations scc_pata_ops = { .postreset = scc_postreset, .post_internal_cmd = scc_bmdma_stop, - .irq_clear = scc_irq_clear, - .irq_on = scc_irq_on, + .sff_irq_clear = scc_irq_clear, + .sff_irq_on = scc_irq_on, .port_start = scc_port_start, .port_stop = scc_port_stop, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 4b85f84fbe76..d4840748fb5c 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -336,7 +336,7 @@ static struct ata_port_operations via_port_ops = { static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, - .data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, }; /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index cc18231e9334..6e52a3573fbf 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -127,7 +127,7 @@ static struct scsi_host_template winbond_sht = { static struct ata_port_operations winbond_port_ops = { .inherits = &ata_sff_port_ops, - .data_xfer = winbond_data_xfer, + .sff_data_xfer = winbond_data_xfer, .cable_detect = ata_cable_40wire, .set_piomode = winbond_set_piomode, }; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 676302fdaa97..37482d4e883f 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1190,10 +1190,10 @@ static struct scsi_host_template sata_fsl_sht = { static const struct ata_port_operations sata_fsl_ops = { .inherits = &sata_port_ops, - .check_status = sata_fsl_check_status, - .check_altstatus = sata_fsl_check_status, + .sff_check_status = sata_fsl_check_status, + .sff_check_altstatus = sata_fsl_check_status, - .tf_read = sata_fsl_tf_read, + .sff_tf_read = sata_fsl_tf_read, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 6e6fca4c20b6..0b5a736a45e3 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -222,7 +222,7 @@ static void inic_bmdma_setup(struct ata_queued_cmd *qc) writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL); /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } static void inic_bmdma_start(struct ata_queued_cmd *qc) @@ -267,14 +267,14 @@ static void inic_host_intr(struct ata_port *ap) ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { - ap->ops->check_status(ap); /* clear ATA interrupt */ + ap->ops->sff_check_status(ap); /* clear ATA interrupt */ return; } if (likely(ata_sff_host_intr(ap, qc))) return; - ap->ops->check_status(ap); /* clear ATA interrupt */ + ap->ops->sff_check_status(ap); /* clear ATA interrupt */ ata_port_printk(ap, KERN_WARNING, "unhandled " "interrupt, irq_stat=%x\n", irq_stat); return; @@ -351,7 +351,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) */ if (unlikely(qc->tf.command == ATA_CMD_ID_ATA || qc->tf.command == ATA_CMD_ID_ATAPI)) { - u8 stat = ap->ops->check_status(ap); + u8 stat = ap->ops->sff_check_status(ap); if (stat == 0x7f || stat == 0xff) return AC_ERR_HSM; } @@ -365,7 +365,7 @@ static void inic_freeze(struct ata_port *ap) __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE); - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); readb(port_base + PORT_IRQ_STAT); /* flush */ @@ -375,7 +375,7 @@ static void inic_thaw(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 63cc43765f04..109b07495721 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -429,11 +429,11 @@ static struct ata_port_operations nv_adma_ops = { .inherits = &nv_generic_ops, .check_atapi_dma = nv_adma_check_atapi_dma, - .tf_read = nv_adma_tf_read, + .sff_tf_read = nv_adma_tf_read, .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, - .irq_clear = nv_adma_irq_clear, + .sff_irq_clear = nv_adma_irq_clear, .freeze = nv_adma_freeze, .thaw = nv_adma_thaw, @@ -1440,7 +1440,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) else // No request pending? Clear interrupt status // anyway, in case there's one pending. - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); } } @@ -1739,7 +1739,7 @@ static void nv_swncq_ncq_stop(struct ata_port *ap) pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits); ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n", - ap->ops->check_status(ap), + ap->ops->sff_check_status(ap), ioread8(ap->ioaddr.error_addr)); sactive = readl(pp->sactive_block); @@ -1765,7 +1765,7 @@ static void nv_swncq_ncq_stop(struct ata_port *ap) } nv_swncq_pp_reinit(ap); - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); __ata_bmdma_stop(ap); nv_swncq_irq_clear(ap, 0xffff); } @@ -1987,8 +1987,8 @@ static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap, pp->dmafis_bits &= ~(1 << qc->tag); pp->qc_active |= (0x1 << qc->tag); - ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->sff_exec_command(ap, &qc->tf); DPRINTK("Issued tag %u\n", qc->tag); @@ -2060,7 +2060,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) return -EINVAL; } - ap->ops->irq_clear(ap); + ap->ops->sff_irq_clear(ap); __ata_bmdma_stop(ap); sactive = readl(pp->sactive_block); @@ -2182,7 +2182,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) u8 ata_stat; int rc = 0; - ata_stat = ap->ops->check_status(ap); + ata_stat = ap->ops->sff_check_status(ap); nv_swncq_irq_clear(ap, fis); if (!fis) return; @@ -2245,7 +2245,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) if (!(fis & NV_SWNCQ_IRQ_DMASETUP) && !(pp->ncq_flags & ncq_saw_dmas)) { - ata_stat = ap->ops->check_status(ap); + ata_stat = ap->ops->sff_check_status(ap); if (ata_stat & ATA_BUSY) goto irq_exit; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 9923e860eae3..5a10dc5048ad 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -162,12 +162,12 @@ static struct scsi_host_template pdc_ata_sht = { static const struct ata_port_operations pdc_common_ops = { .inherits = &ata_sff_port_ops, - .tf_load = pdc_tf_load_mmio, - .exec_command = pdc_exec_command_mmio, + .sff_tf_load = pdc_tf_load_mmio, + .sff_exec_command = pdc_exec_command_mmio, .check_atapi_dma = pdc_check_atapi_dma, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue, - .irq_clear = pdc_irq_clear, + .sff_irq_clear = pdc_irq_clear, .post_internal_cmd = pdc_post_internal_cmd, .error_handler = pdc_error_handler, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 987313b68f3b..88bf4212590f 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -369,7 +369,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { /* this sometimes happens, just clear IRQ */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); return; } @@ -405,7 +405,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) } /* check main status, clearing INTRQ */ - status = ap->ops->check_status(ap); + status = ap->ops->sff_check_status(ap); if (unlikely(status & ATA_BUSY)) goto err_hsm; @@ -480,7 +480,7 @@ static void sil_thaw(struct ata_port *ap) u32 tmp; /* clear IRQ */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); ata_sff_irq_clear(ap); /* turn on SATA IRQ if supported */ diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 67df1d753305..b83851f6e068 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -401,9 +401,9 @@ static struct scsi_host_template sil24_sht = { static struct ata_port_operations sil24_ops = { .inherits = &sata_pmp_port_ops, - .check_status = sil24_check_status, - .check_altstatus = sil24_check_status, - .tf_read = sil24_tf_read, + .sff_check_status = sil24_check_status, + .sff_check_altstatus = sil24_check_status, + .sff_tf_read = sil24_tf_read, .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 7b941106f7de..16aa6839aa5a 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -233,7 +233,7 @@ static void k2_bmdma_setup_mmio(struct ata_queued_cmd *qc) /* issue r/w command if this is not a ATA DMA command*/ if (qc->tf.protocol != ATA_PROT_DMA) - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } /** @@ -269,7 +269,7 @@ static void k2_bmdma_start_mmio(struct ata_queued_cmd *qc) and the start command. */ /* issue r/w command if the access is to ATA*/ if (qc->tf.protocol == ATA_PROT_DMA) - ap->ops->exec_command(ap, &qc->tf); + ap->ops->sff_exec_command(ap, &qc->tf); } @@ -336,9 +336,9 @@ static struct scsi_host_template k2_sata_sht = { static struct ata_port_operations k2_sata_ops = { .inherits = &ata_bmdma_port_ops, - .tf_load = k2_sata_tf_load, - .tf_read = k2_sata_tf_read, - .check_status = k2_stat_check_status, + .sff_tf_load = k2_sata_tf_load, + .sff_tf_read = k2_sata_tf_read, + .sff_check_status = k2_stat_check_status, .check_atapi_dma = k2_sata_check_atapi_dma, .bmdma_setup = k2_bmdma_setup_mmio, .bmdma_start = k2_bmdma_start_mmio, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 40be2ff60902..6107eff731f3 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -243,18 +243,18 @@ static struct scsi_host_template pdc_sata_sht = { /* TODO: inherit from base port_ops after converting to new EH */ static struct ata_port_operations pdc_20621_ops = { - .tf_load = pdc_tf_load_mmio, - .tf_read = ata_sff_tf_read, - .check_status = ata_sff_check_status, - .exec_command = pdc_exec_command_mmio, - .dev_select = ata_sff_dev_select, + .sff_tf_load = pdc_tf_load_mmio, + .sff_tf_read = ata_sff_tf_read, + .sff_check_status = ata_sff_check_status, + .sff_exec_command = pdc_exec_command_mmio, + .sff_dev_select = ata_sff_dev_select, .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, .qc_issue = pdc20621_qc_issue, - .data_xfer = ata_sff_data_xfer, + .sff_data_xfer = ata_sff_data_xfer, .eng_timeout = pdc_eng_timeout, - .irq_clear = pdc20621_irq_clear, - .irq_on = ata_sff_irq_on, + .sff_irq_clear = pdc20621_irq_clear, + .sff_irq_on = ata_sff_irq_on, .port_start = pdc_port_start, }; diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 9323bc2a2785..e5df37689740 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -173,7 +173,7 @@ static void svia_noop_freeze(struct ata_port *ap) /* Some VIA controllers choke if ATA_NIEN is manipulated in * certain way. Leave it alone and just clear pending IRQ. */ - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); ata_sff_irq_clear(ap); } diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 2c3c7693c750..f3d635c0a2e9 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -251,7 +251,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) * simply clear the interrupt */ if (unlikely(!handled)) - ap->ops->check_status(ap); + ap->ops->sff_check_status(ap); } /* @@ -306,8 +306,8 @@ static struct scsi_host_template vsc_sata_sht = { static struct ata_port_operations vsc_sata_ops = { .inherits = &ata_bmdma_port_ops, - .tf_load = vsc_sata_tf_load, - .tf_read = vsc_sata_tf_read, + .sff_tf_load = vsc_sata_tf_load, + .sff_tf_read = vsc_sata_tf_read, .freeze = vsc_freeze, .thaw = vsc_thaw, .scr_read = vsc_sata_scr_read, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 79fd2436bd70..5bddae19d1fb 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5271,13 +5271,13 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap) } static struct ata_port_operations ipr_sata_ops = { - .check_status = ipr_ata_check_status, - .check_altstatus = ipr_ata_check_altstatus, - .dev_select = ata_noop_dev_select, + .sff_check_status = ipr_ata_check_status, + .sff_check_altstatus = ipr_ata_check_altstatus, + .sff_dev_select = ata_noop_dev_select, .phy_reset = ipr_ata_phy_reset, .hardreset = ipr_sata_reset, .post_internal_cmd = ipr_ata_post_internal, - .tf_read = ipr_tf_read, + .sff_tf_read = ipr_tf_read, .qc_prep = ata_noop_qc_prep, .qc_issue = ipr_qc_issue, .port_start = ata_sas_port_start, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index b0e5ac372a32..a1664b87927a 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -348,12 +348,12 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, } static struct ata_port_operations sas_sata_ops = { - .check_status = sas_ata_check_status, - .check_altstatus = sas_ata_check_status, - .dev_select = ata_noop_dev_select, + .sff_check_status = sas_ata_check_status, + .sff_check_altstatus = sas_ata_check_status, + .sff_dev_select = ata_noop_dev_select, .phy_reset = sas_ata_phy_reset, .post_internal_cmd = sas_ata_post_internal, - .tf_read = sas_ata_tf_read, + .sff_tf_read = sas_ata_tf_read, .qc_prep = ata_noop_qc_prep, .qc_issue = sas_ata_qc_issue, .port_start = ata_sas_port_start, diff --git a/include/linux/libata.h b/include/linux/libata.h index 66663bfe2c71..584eca19b8f1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -743,17 +743,18 @@ struct ata_port_operations { /* * SFF / taskfile oriented ops */ - void (*dev_select)(struct ata_port *ap, unsigned int device); - u8 (*check_status)(struct ata_port *ap); - u8 (*check_altstatus)(struct ata_port *ap); - void (*tf_load)(struct ata_port *ap, const struct ata_taskfile *tf); - void (*tf_read)(struct ata_port *ap, struct ata_taskfile *tf); - void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); - unsigned int (*data_xfer)(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw); - u8 (*irq_on)(struct ata_port *); - - void (*irq_clear)(struct ata_port *); + void (*sff_dev_select)(struct ata_port *ap, unsigned int device); + u8 (*sff_check_status)(struct ata_port *ap); + u8 (*sff_check_altstatus)(struct ata_port *ap); + void (*sff_tf_load)(struct ata_port *ap, const struct ata_taskfile *tf); + void (*sff_tf_read)(struct ata_port *ap, struct ata_taskfile *tf); + void (*sff_exec_command)(struct ata_port *ap, + const struct ata_taskfile *tf); + unsigned int (*sff_data_xfer)(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw); + u8 (*sff_irq_on)(struct ata_port *); + void (*sff_irq_clear)(struct ata_port *); + void (*bmdma_setup)(struct ata_queued_cmd *qc); void (*bmdma_start)(struct ata_queued_cmd *qc); void (*bmdma_stop)(struct ata_queued_cmd *qc); @@ -1438,7 +1439,7 @@ static inline u8 ata_sff_busy_wait(struct ata_port *ap, unsigned int bits, do { udelay(10); - status = ap->ops->check_status(ap); + status = ap->ops->sff_check_status(ap); max--; } while (status != 0xff && (status & bits) && (max > 0)); -- cgit v1.2.3 From 288623a06c652239d2f57d271af12bb024cf7218 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:17 +0900 Subject: libata: clean up port_ops->sff_irq_clear() ->sff_irq_clear() is called only from SFF interrupt handler, so there is no reason to initialize it for non-SFF controllers. Also, ata_sff_irq_clear() can handle both BMDMA and non-BMDMA SFF controllers. This patch kills ata_noop_irq_clear() and removes it from base port_ops and sets ->sff_irq_clear to ata_sff_irq_clear() in sff port_ops instead of bmdma port_ops. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 10 ---------- drivers/ata/libata-sff.c | 2 +- include/linux/libata.h | 1 - 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a01e02c5ce7a..fd912ccb90f8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,7 +74,6 @@ const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { - .sff_irq_clear = ata_noop_irq_clear, .prereset = ata_sff_prereset, .hardreset = sata_sff_hardreset, .postreset = ata_sff_postreset, @@ -386,14 +385,6 @@ int atapi_cmd_type(u8 opcode) } } -/** - * ata_noop_irq_clear - Noop placeholder for irq_clear - * @ap: Port associated with this ATA transaction. - */ -void ata_noop_irq_clear(struct ata_port *ap) -{ -} - /** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert @@ -6108,7 +6099,6 @@ EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_std_qc_defer); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); -EXPORT_SYMBOL_GPL(ata_noop_irq_clear); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 04024a556660..c11601617134 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -58,6 +58,7 @@ const struct ata_port_operations ata_sff_port_ops = { .sff_exec_command = ata_sff_exec_command, .sff_data_xfer = ata_sff_data_xfer, .sff_irq_on = ata_sff_irq_on, + .sff_irq_clear = ata_sff_irq_clear, .port_start = ata_sff_port_start, }; @@ -71,7 +72,6 @@ const struct ata_port_operations ata_bmdma_port_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, - .sff_irq_clear = ata_sff_irq_clear, }; /** diff --git a/include/linux/libata.h b/include/linux/libata.h index 584eca19b8f1..603712b59cf3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -896,7 +896,6 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); -extern void ata_noop_irq_clear(struct ata_port *ap); extern void ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, void (*finish_qc)(struct ata_queued_cmd *)); -- cgit v1.2.3 From 0aa1113d544226bc2c4a20d6ac1d71170512a361 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:18 +0900 Subject: libata: separate out ata_std_prereset() from ata_sff_prereset() Separate out generic ATA portion from ata_sff_prereset() into ata_std_prereset() and implement ata_sff_prereset() using the std version. Waiting for device readiness is the only SFF specific part. ata_base_port_ops now has ata_std_prereset() for its prereset and ata_sff_port_ops overrides it to ata_sff_prereset(). This change can affect pdc_adma, ahci, sata_fsl and sata_sil24. pdc_adma implements its own prereset using ata_sff_prereset() and the rest has hardreset and thus are unaffected by this change. This change reflects real world situation. There is no generic way to wait for device readiness for non-SFF controllers and some of them don't have any mechanism for that. Non-sff drivers which don't have hardreset should wrap ata_std_prereset() and wait for device readiness itself but there's no such driver now and isn't likely to be popular in the future either. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 17 ++++------------- drivers/ata/libata-sff.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 48 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fd912ccb90f8..5f771bb44332 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,7 +74,7 @@ const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { - .prereset = ata_sff_prereset, + .prereset = ata_std_prereset, .hardreset = sata_sff_hardreset, .postreset = ata_sff_postreset, .error_handler = ata_std_error_handler, @@ -3416,7 +3416,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, } /** - * ata_sff_prereset - prepare for reset + * ata_std_prereset - prepare for reset * @link: ATA link to be reset * @deadline: deadline jiffies for the operation * @@ -3432,7 +3432,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_sff_prereset(struct ata_link *link, unsigned long deadline) +int ata_std_prereset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -3452,16 +3452,6 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) "link for reset (errno=%d)\n", rc); } - /* wait for !BSY if we don't know that no device is attached */ - if (!ata_link_offline(link)) { - rc = ata_sff_wait_ready(ap, deadline); - if (rc && rc != -ENODEV) { - ata_link_printk(link, KERN_WARNING, "device not ready " - "(errno=%d), forcing hardreset\n", rc); - ehc->i.action |= ATA_EH_HARDRESET; - } - } - return 0; } @@ -6104,6 +6094,7 @@ EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); +EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index c11601617134..9234bc047956 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -47,6 +47,7 @@ const struct ata_port_operations ata_sff_port_ops = { .freeze = ata_sff_freeze, .thaw = ata_sff_thaw, + .prereset = ata_sff_prereset, .softreset = ata_sff_softreset, .error_handler = ata_sff_error_handler, .post_internal_cmd = ata_sff_post_internal_cmd, @@ -1606,6 +1607,48 @@ void ata_sff_thaw(struct ata_port *ap) ap->ops->sff_irq_on(ap); } +/** + * ata_sff_prereset - prepare SFF link for reset + * @link: SFF link to be reset + * @deadline: deadline jiffies for the operation + * + * SFF link @link is about to be reset. Initialize it. It first + * calls ata_std_prereset() and wait for !BSY if the port is + * being softreset. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_sff_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; + int rc; + + rc = ata_std_prereset(link, deadline); + if (rc) + return rc; + + /* if we're about to do hardreset, nothing more to do */ + if (ehc->i.action & ATA_EH_HARDRESET) + return 0; + + /* wait for !BSY if we don't know that no device is attached */ + if (!ata_link_offline(link)) { + rc = ata_sff_wait_ready(ap, deadline); + if (rc && rc != -ENODEV) { + ata_link_printk(link, KERN_WARNING, "device not ready " + "(errno=%d), forcing hardreset\n", rc); + ehc->i.action |= ATA_EH_HARDRESET; + } + } + + return 0; +} + /** * ata_devchk - PATA device presence detection * @ap: ATA channel to examine diff --git a/include/linux/libata.h b/include/linux/libata.h index 603712b59cf3..595ede55fe4c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -824,6 +824,7 @@ static inline int ata_port_is_dummy(struct ata_port *ap) extern void sata_print_link_status(struct ata_link *link); extern void ata_port_probe(struct ata_port *); extern int sata_set_spd(struct ata_link *link); +extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); extern int sata_link_debounce(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, -- cgit v1.2.3 From 203c75b8245c5386044721d9c5eda5c6b71b3d14 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:18 +0900 Subject: libata: separate out ata_std_postreset() from ata_sff_postreset() Separate out generic ATA portion from ata_sff_postreset() into ata_std_postreset() and implement ata_sff_postreset() using the std version. ata_base_port_ops now has ata_std_postreset() for its postreset and ata_sff_port_ops overrides it to ata_sff_postreset(). This change affects pdc_adma, ahci, sata_fsl and sata_sil24. pdc_adma now specifies postreset to ata_sff_postreset() explicitly. sata_fsl and sata_sil24 now use ata_std_postreset() which makes no difference to them. ahci now calls ata_std_postreset() from its own postreset method, which causes no behavior difference. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 24 ++++-------------------- drivers/ata/libata-sff.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 4 files changed, 42 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c5e4501daa74..939dc1d4e50d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1444,7 +1444,7 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) void __iomem *port_mmio = ahci_port_base(ap); u32 new_tmp, tmp; - ata_sff_postreset(link, class); + ata_std_postreset(link, class); /* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp = readl(port_mmio + PORT_CMD); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5f771bb44332..eaead76c9443 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -76,7 +76,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { .prereset = ata_std_prereset, .hardreset = sata_sff_hardreset, - .postreset = ata_sff_postreset, + .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, }; @@ -3516,7 +3516,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, } /** - * ata_sff_postreset - standard postreset callback + * ata_std_postreset - standard postreset callback * @link: the target ata_link * @classes: classes of attached devices * @@ -3527,9 +3527,8 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, * LOCKING: * Kernel thread context (may sleep) */ -void ata_sff_postreset(struct ata_link *link, unsigned int *classes) +void ata_std_postreset(struct ata_link *link, unsigned int *classes) { - struct ata_port *ap = link->ap; u32 serror; DPRINTK("ENTER\n"); @@ -3542,22 +3541,6 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes) sata_scr_write(link, SCR_ERROR, serror); link->eh_info.serror = 0; - /* is double-select really necessary? */ - if (classes[0] != ATA_DEV_NONE) - ap->ops->sff_dev_select(ap, 1); - if (classes[1] != ATA_DEV_NONE) - ap->ops->sff_dev_select(ap, 0); - - /* bail out if no device is present */ - if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { - DPRINTK("EXIT, no device\n"); - return; - } - - /* set up device control */ - if (ap->ioaddr.ctl_addr) - iowrite8(ap->ctl, ap->ioaddr.ctl_addr); - DPRINTK("EXIT\n"); } @@ -6096,6 +6079,7 @@ EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(sata_link_hardreset); +EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9234bc047956..e530baccc9cb 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -49,6 +49,7 @@ const struct ata_port_operations ata_sff_port_ops = { .thaw = ata_sff_thaw, .prereset = ata_sff_prereset, .softreset = ata_sff_softreset, + .postreset = ata_sff_postreset, .error_handler = ata_sff_error_handler, .post_internal_cmd = ata_sff_post_internal_cmd, @@ -2031,6 +2032,41 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, return 0; } +/** + * ata_sff_postreset - SFF postreset callback + * @link: the target SFF ata_link + * @classes: classes of attached devices + * + * This function is invoked after a successful reset. It first + * calls ata_std_postreset() and performs SFF specific postreset + * processing. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_sff_postreset(struct ata_link *link, unsigned int *classes) +{ + struct ata_port *ap = link->ap; + + ata_std_postreset(link, classes); + + /* is double-select really necessary? */ + if (classes[0] != ATA_DEV_NONE) + ap->ops->sff_dev_select(ap, 1); + if (classes[1] != ATA_DEV_NONE) + ap->ops->sff_dev_select(ap, 0); + + /* bail out if no device is present */ + if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { + DPRINTK("EXIT, no device\n"); + return; + } + + /* set up device control */ + if (ap->ioaddr.ctl_addr) + iowrite8(ap->ctl, ap->ioaddr.ctl_addr); +} + /** * ata_sff_error_handler - Stock error handler for BMDMA controller * @ap: port to handle error for diff --git a/include/linux/libata.h b/include/linux/libata.h index 595ede55fe4c..6e14c27319d5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -831,6 +831,7 @@ extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline); +extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); -- cgit v1.2.3 From 705e76beb90b97421e1f61e857c4246799781bb5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:19 +0900 Subject: libata: restructure SFF post-reset readiness waits Previously, post-softreset readiness is waited as follows. 1. ata_sff_wait_after_reset() waits for 150ms and then for ATA_TMOUT_FF_WAIT if status is 0xff and other conditions meet. 2. ata_bus_softreset() finishes with -ENODEV if status is still 0xff. If not, continue to #3. 3. ata_bus_post_reset() waits readiness of dev0 and/or dev1 depending on devmask using ata_sff_wait_ready(). And for post-hardreset readiness, 1. ata_sff_wait_after_reset() waits for 150ms and then for ATA_TMOUT_FF_WAIT if status is 0xff and other conditions meet. 2. sata_sff_hardreset waits for device readiness using ata_sff_wait_ready(). This patch merges and unifies post-reset readiness waits into ata_sff_wait_ready() and ata_sff_wait_after_reset(). ATA_TMOUT_FF_WAIT handling is merged into ata_sff_wait_ready(). If TF status is 0xff, link status is unknown and the port is SATA, it will continue polling till ATA_TMOUT_FF_WAIT. ata_sff_wait_after_reset() is updated to perform the following steps. 1. waits for 150ms. 2. waits for dev0 readiness using ata_sff_wait_ready(). Note that this is done regardless of devmask, as ata_sff_wait_ready() handles 0xff status correctly, this preserves the original behavior except that it may wait longer after softreset if link is online but status is 0xff. This behavior change is very unlikely to cause any actual difference and is intended. It brings softreset behavior to that of hardreset. 3. waits for dev1 readiness just the same way ata_bus_post_reset() did. Now both soft and hard resets call ata_sff_wait_after_reset() after reset to wait for readiness after resets. As ata_sff_wait_after_reset() contains calls to ->sff_dev_select(), explicit call near the end of sata_sff_hardreset() is removed. This change makes reset implementation simpler and more consistent. While at it, make the magical 150ms wait post-reset wait duration a constant and ata_sff_wait_ready() and ata_sff_wait_after_reset() take @link instead of @ap. This is to make them consistent with other reset helpers and ease core changes. pata_scc is updated accordingly. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 11 +-- drivers/ata/libata-sff.c | 161 ++++++++++++++++++-------------------------- drivers/ata/pata_scc.c | 91 ++++++++++++++----------- drivers/ata/sata_inic162x.c | 6 +- drivers/ata/sata_via.c | 2 +- include/linux/libata.h | 18 ++++- 6 files changed, 139 insertions(+), 150 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 939dc1d4e50d..45a67a9ad8ab 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1302,10 +1302,8 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, tf.ctl &= ~ATA_SRST; ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); - /* wait a while before checking status */ - ata_sff_wait_after_reset(ap, deadline); - - rc = ata_sff_wait_ready(ap, deadline); + /* wait for link to become ready */ + rc = ata_sff_wait_after_reset(link, 1, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { reason = "device not ready"; @@ -1415,9 +1413,6 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, if (rc || ata_link_offline(link)) return rc; - /* spec mandates ">= 2ms" before checking status */ - msleep(150); - /* The pseudo configuration device on SIMG4726 attached to * ASUS P5W-DH Deluxe doesn't send signature FIS after * hardreset if no device is attached to the first downstream @@ -1431,7 +1426,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, * have to be reset again. For most cases, this should * suffice while making probing snappish enough. */ - rc = ata_sff_wait_ready(ap, jiffies + 2 * HZ); + rc = ata_sff_wait_after_reset(link, 1, jiffies + 2 * HZ); if (rc) ahci_kick_engine(ap, 0); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index e530baccc9cb..6e8de3c1595e 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -310,7 +310,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, /** * ata_sff_wait_ready - sleep until BSY clears, or timeout - * @ap: port containing status register to be polled + * @link: SFF link to wait ready status for * @deadline: deadline jiffies for the operation * * Sleep until ATA Status register bit BSY clears, or timeout @@ -322,26 +322,52 @@ int ata_sff_busy_sleep(struct ata_port *ap, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline) +int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned long start = jiffies; + unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT; int warned = 0; + if (time_after(nodev_deadline, deadline)) + nodev_deadline = deadline; + while (1) { u8 status = ap->ops->sff_check_status(ap); unsigned long now = jiffies; if (!(status & ATA_BUSY)) return 0; - if (!ata_link_online(&ap->link) && status == 0xff) - return -ENODEV; + + /* No device status could be transient. Ignore it if + * link is online. Also, some SATA devices take a + * long time to clear 0xff after reset. For example, + * HHD424020F7SV00 iVDR needs >= 800ms while Quantum + * GoVault needs even more than that. Wait for + * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline. + * + * Note that some PATA controllers (pata_ali) explode + * if status register is read more than once when + * there's no device attached. + */ + if (status == 0xff) { + if (ata_link_online(link)) + status = ATA_BUSY; + else if ((link->ap->flags & ATA_FLAG_SATA) && + !ata_link_offline(link) && + time_before(now, nodev_deadline)) + status = ATA_BUSY; + if (status == 0xff) + return -ENODEV; + } + if (time_after(now, deadline)) return -EBUSY; if (!warned && time_after(now, start + 5 * HZ) && (deadline - now > 3 * HZ)) { - ata_port_printk(ap, KERN_WARNING, - "port is slow to respond, please be patient " + ata_link_printk(link, KERN_WARNING, + "link is slow to respond, please be patient " "(Status 0x%x)\n", status); warned = 1; } @@ -1625,7 +1651,6 @@ void ata_sff_thaw(struct ata_port *ap) */ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) { - struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; int rc; @@ -1639,7 +1664,7 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) /* wait for !BSY if we don't know that no device is attached */ if (!ata_link_offline(link)) { - rc = ata_sff_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(link, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " "(errno=%d), forcing hardreset\n", rc); @@ -1762,25 +1787,41 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, return class; } -static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, - unsigned long deadline) +/** + * ata_sff_wait_after_reset - wait for devices to become ready after reset + * @link: SFF link which is just reset + * @devmask: mask of present devices + * @deadline: deadline jiffies for the operation + * + * Wait devices attached to SFF @link to become ready after + * reset. It contains preceding 150ms wait to avoid accessing TF + * status register too early. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -ENODEV if some or all of devices in @devmask + * don't seem to exist. -errno on other errors. + */ +int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, + unsigned long deadline) { + struct ata_port *ap = link->ap; struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int dev0 = devmask & (1 << 0); unsigned int dev1 = devmask & (1 << 1); int rc, ret = 0; - /* if device 0 was found in ata_devchk, wait for its - * BSY bit to clear + msleep(ATA_WAIT_AFTER_RESET_MSECS); + + /* always check readiness of the master device */ + rc = ata_sff_wait_ready(link, deadline); + /* -ENODEV means the odd clown forgot the D7 pulldown resistor + * and TF status is 0xff, bail out on it too. */ - if (dev0) { - rc = ata_sff_wait_ready(ap, deadline); - if (rc) { - if (rc != -ENODEV) - return rc; - ret = rc; - } - } + if (rc) + return rc; /* if device 1 was found in ata_devchk, wait for register * access briefly, then wait for BSY to clear. @@ -1804,7 +1845,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, msleep(50); /* give drive a breather */ } - rc = ata_sff_wait_ready(ap, deadline); + rc = ata_sff_wait_ready(link, deadline); if (rc) { if (rc != -ENODEV) return rc; @@ -1822,61 +1863,6 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, return ret; } -/** - * ata_sff_wait_after_reset - wait before checking status after reset - * @ap: port containing status register to be polled - * @deadline: deadline jiffies for the operation - * - * After reset, we need to pause a while before reading status. - * Also, certain combination of controller and device report 0xff - * for some duration (e.g. until SATA PHY is up and running) - * which is interpreted as empty port in ATA world. This - * function also waits for such devices to get out of 0xff - * status. - * - * LOCKING: - * Kernel thread context (may sleep). - */ -void ata_sff_wait_after_reset(struct ata_port *ap, unsigned long deadline) -{ - unsigned long until = jiffies + ATA_TMOUT_FF_WAIT; - - if (time_before(until, deadline)) - deadline = until; - - /* Spec mandates ">= 2ms" before checking status. We wait - * 150ms, because that was the magic delay used for ATAPI - * devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready. - */ - msleep(150); - - /* Wait for 0xff to clear. Some SATA devices take a long time - * to clear 0xff after reset. For example, HHD424020F7SV00 - * iVDR needs >= 800ms while. Quantum GoVault needs even more - * than that. - * - * Note that some PATA controllers (pata_ali) explode if - * status register is read more than once when there's no - * device attached. - */ - if (ap->flags & ATA_FLAG_SATA) { - while (1) { - u8 status = ap->ops->sff_check_status(ap); - - if (status != 0xff || time_after(jiffies, deadline)) - return; - - msleep(50); - } - } -} - static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { @@ -1891,17 +1877,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); /* FIXME: flush */ iowrite8(ap->ctl, ioaddr->ctl_addr); - /* wait a while before checking status */ - ata_sff_wait_after_reset(ap, deadline); - - /* Before we perform post reset processing we want to see if - * the bus shows 0xFF because the odd clown forgets the D7 - * pulldown resistor. - */ - if (ap->ops->sff_check_status(ap) == 0xFF) - return -ENODEV; - - return ata_bus_post_reset(ap, devmask, deadline); + /* wait the port to become ready */ + return ata_sff_wait_after_reset(&ap->link, devmask, deadline); } /** @@ -2003,20 +1980,18 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, return 0; } - /* wait a while before checking status */ - ata_sff_wait_after_reset(ap, deadline); - /* If PMP is supported, we have to do follow-up SRST. Note * that some PMPs don't send D2H Reg FIS after hardreset at * all if the first port is empty. Wait for it just for a * second and request follow-up SRST. */ if (ap->flags & ATA_FLAG_PMP) { - ata_sff_wait_ready(ap, jiffies + HZ); + ata_sff_wait_after_reset(link, 1, jiffies + HZ); return -EAGAIN; } - rc = ata_sff_wait_ready(ap, deadline); + /* wait for the link to become online */ + rc = ata_sff_wait_after_reset(link, 1, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { ata_link_printk(link, KERN_ERR, @@ -2024,8 +1999,6 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, return rc; } - ap->ops->sff_dev_select(ap, 0); /* probably unnecessary */ - *class = ata_sff_dev_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2b9da715c704..accc275e74cc 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -497,47 +497,68 @@ static unsigned int scc_devchk (struct ata_port *ap, } /** - * scc_bus_post_reset - PATA device post reset + * scc_wait_after_reset - wait for devices to become ready after reset * - * Note: Original code is ata_bus_post_reset(). + * Note: Original code is ata_sff_wait_after_reset */ -static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, - unsigned long deadline) +int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, + unsigned long deadline) { + struct ata_port *ap = link->ap; struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int dev0 = devmask & (1 << 0); unsigned int dev1 = devmask & (1 << 1); - int rc; + int rc, ret = 0; + + /* Spec mandates ">= 2ms" before checking status. We wait + * 150ms, because that was the magic delay used for ATAPI + * devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready. + */ + msleep(150); - /* if device 0 was found in ata_devchk, wait for its - * BSY bit to clear + /* always check readiness of the master device */ + rc = ata_sff_wait_ready(link, deadline); + /* -ENODEV means the odd clown forgot the D7 pulldown resistor + * and TF status is 0xff, bail out on it too. */ - if (dev0) { - rc = ata_sff_wait_ready(ap, deadline); - if (rc && rc != -ENODEV) - return rc; - } + if (rc) + return rc; - /* if device 1 was found in ata_devchk, wait for - * register access, then wait for BSY to clear + /* if device 1 was found in ata_devchk, wait for register + * access briefly, then wait for BSY to clear. */ - while (dev1) { - u8 nsect, lbal; + if (dev1) { + int i; ap->ops->sff_dev_select(ap, 1); - nsect = in_be32(ioaddr->nsect_addr); - lbal = in_be32(ioaddr->lbal_addr); - if ((nsect == 1) && (lbal == 1)) - break; - if (time_after(jiffies, deadline)) - return -EBUSY; - msleep(50); /* give drive a breather */ - } - if (dev1) { - rc = ata_sff_wait_ready(ap, deadline); - if (rc && rc != -ENODEV) - return rc; + + /* Wait for register access. Some ATAPI devices fail + * to set nsect/lbal after reset, so don't waste too + * much time on it. We're gonna wait for !BSY anyway. + */ + for (i = 0; i < 2; i++) { + u8 nsect, lbal; + + nsect = in_be32(ioaddr->nsect_addr); + lbal = in_be32(ioaddr->lbal_addr); + if ((nsect == 1) && (lbal == 1)) + break; + msleep(50); /* give drive a breather */ + } + + rc = ata_sff_wait_ready(link, deadline); + if (rc) { + if (rc != -ENODEV) + return rc; + ret = rc; + } } /* is all this really necessary? */ @@ -547,7 +568,7 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask, if (dev0) ap->ops->sff_dev_select(ap, 0); - return 0; + return ret; } /** @@ -570,17 +591,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); out_be32(ioaddr->ctl_addr, ap->ctl); - /* wait a while before checking status */ - ata_sff_wait_after_reset(ap, deadline); - - /* Before we perform post reset processing we want to see if - * the bus shows 0xFF because the odd clown forgets the D7 - * pulldown resistor. - */ - if (scc_check_status(ap) == 0xFF) - return 0; - - scc_bus_post_reset(ap, devmask, deadline); + scc_wait_after_reset(&ap->link, devmask, deadlien); return 0; } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 0b5a736a45e3..9f47d0022453 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -417,10 +417,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, if (ata_link_online(link)) { struct ata_taskfile tf; - /* wait a while before checking status */ - ata_sff_wait_after_reset(ap, deadline); - - rc = ata_sff_wait_ready(ap, deadline); + /* wait for link to become ready */ + rc = ata_sff_wait_after_reset(link, 1, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { ata_link_printk(link, KERN_WARNING, "device not ready " diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index e5df37689740..96deeb354e16 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -242,7 +242,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) skip_scr: /* wait for !BSY */ - ata_sff_wait_ready(ap, deadline); + ata_sff_wait_ready(link, deadline); return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 6e14c27319d5..da5560244787 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -249,6 +249,18 @@ enum { */ ATA_TMOUT_FF_WAIT = 4 * HZ / 5, + /* Spec mandates to wait for ">= 2ms" before checking status + * after reset. We wait 150ms, because that was the magic + * delay used for ATAPI devices in Hale Landis's ATADRVR, for + * the period of time between when the ATA command register is + * written, and then status is checked. Because waiting for + * "a while" before checking status is fine, post SRST, we + * perform this magic delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready. + */ + ATA_WAIT_AFTER_RESET_MSECS = 150, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -1351,7 +1363,7 @@ extern u8 ata_sff_check_status(struct ata_port *ap); extern u8 ata_sff_altstatus(struct ata_port *ap); extern int ata_sff_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, unsigned long timeout); -extern int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline); +extern int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline); extern void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_sff_exec_command(struct ata_port *ap, @@ -1373,8 +1385,8 @@ extern void ata_sff_thaw(struct ata_port *ap); extern int ata_sff_prereset(struct ata_link *link, unsigned long deadline); extern unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, u8 *r_err); -extern void ata_sff_wait_after_reset(struct ata_port *ap, - unsigned long deadline); +extern int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, + unsigned long deadline); extern int ata_sff_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline); extern int sata_sff_hardreset(struct ata_link *link, unsigned int *class, -- cgit v1.2.3 From aa2731ad9ad80ac3fca48bd1c4cf0eceede4810e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:19 +0900 Subject: libata: separate out ata_wait_ready() and implement ata_wait_after_reset() Factor out waiting logic (which is common to all ATA controllers) from ata_sff_wait_ready() into ata_wait_ready(). ata_wait_ready() takes @check_ready function pointer and uses it to poll for readiness. This allows non-SFF controllers to use ata_wait_ready() to wait for link readiness. This patch also implements ata_wait_after_reset() - generic version of ata_sff_wait_after_reset() - using ata_wait_ready(). ata_sff_wait_ready() is reimplemented using ata_wait_ready() and ata_sff_check_ready(). Functionality remains the same. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-sff.c | 62 ++++++------------------------ drivers/ata/libata.h | 2 + include/linux/libata.h | 2 + 4 files changed, 114 insertions(+), 50 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index eaead76c9443..3bad6f189190 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3310,6 +3310,103 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) return rc; } +/** + * ata_wait_ready - wait for link to become ready + * @link: link to be waited on + * @deadline: deadline jiffies for the operation + * @check_ready: callback to check link readiness + * + * Wait for @link to become ready. @check_ready should return + * positive number if @link is ready, 0 if it isn't, -ENODEV if + * link doesn't seem to be occupied, other errno for other error + * conditions. + * + * Transient -ENODEV conditions are allowed for + * ATA_TMOUT_FF_WAIT. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 if @linke is ready before @deadline; otherwise, -errno. + */ +int ata_wait_ready(struct ata_link *link, unsigned long deadline, + int (*check_ready)(struct ata_link *link)) +{ + unsigned long start = jiffies; + unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT; + int warned = 0; + + if (time_after(nodev_deadline, deadline)) + nodev_deadline = deadline; + + while (1) { + unsigned long now = jiffies; + int ready, tmp; + + ready = tmp = check_ready(link); + if (ready > 0) + return 0; + + /* -ENODEV could be transient. Ignore -ENODEV if link + * is online. Also, some SATA devices take a long + * time to clear 0xff after reset. For example, + * HHD424020F7SV00 iVDR needs >= 800ms while Quantum + * GoVault needs even more than that. Wait for + * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline. + * + * Note that some PATA controllers (pata_ali) explode + * if status register is read more than once when + * there's no device attached. + */ + if (ready == -ENODEV) { + if (ata_link_online(link)) + ready = 0; + else if ((link->ap->flags & ATA_FLAG_SATA) && + !ata_link_offline(link) && + time_before(now, nodev_deadline)) + ready = 0; + } + + if (ready) + return ready; + if (time_after(now, deadline)) + return -EBUSY; + + if (!warned && time_after(now, start + 5 * HZ) && + (deadline - now > 3 * HZ)) { + ata_link_printk(link, KERN_WARNING, + "link is slow to respond, please be patient " + "(ready=%d)\n", tmp); + warned = 1; + } + + msleep(50); + } +} + +/** + * ata_wait_after_reset - wait for link to become ready after reset + * @link: link to be waited on + * @deadline: deadline jiffies for the operation + * @check_ready: callback to check link readiness + * + * Wait for @link to become ready after reset. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 if @linke is ready before @deadline; otherwise, -errno. + */ +extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, + int (*check_ready)(struct ata_link *link)) +{ + msleep(ATA_WAIT_AFTER_RESET_MSECS); + + return ata_wait_ready(link, deadline, check_ready); +} + /** * sata_link_debounce - debounce SATA phy status * @link: ATA link to debounce SATA phy status for @@ -6075,6 +6172,7 @@ EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); +EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(ata_std_prereset); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 6e8de3c1595e..78912c5011ad 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -308,6 +308,17 @@ int ata_sff_busy_sleep(struct ata_port *ap, return 0; } +static int ata_sff_check_ready(struct ata_link *link) +{ + u8 status = link->ap->ops->sff_check_status(link->ap); + + if (!(status & ATA_BUSY)) + return 1; + if (status == 0xff) + return -ENODEV; + return 0; +} + /** * ata_sff_wait_ready - sleep until BSY clears, or timeout * @link: SFF link to wait ready status for @@ -324,56 +335,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, */ int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline) { - struct ata_port *ap = link->ap; - unsigned long start = jiffies; - unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT; - int warned = 0; - - if (time_after(nodev_deadline, deadline)) - nodev_deadline = deadline; - - while (1) { - u8 status = ap->ops->sff_check_status(ap); - unsigned long now = jiffies; - - if (!(status & ATA_BUSY)) - return 0; - - /* No device status could be transient. Ignore it if - * link is online. Also, some SATA devices take a - * long time to clear 0xff after reset. For example, - * HHD424020F7SV00 iVDR needs >= 800ms while Quantum - * GoVault needs even more than that. Wait for - * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline. - * - * Note that some PATA controllers (pata_ali) explode - * if status register is read more than once when - * there's no device attached. - */ - if (status == 0xff) { - if (ata_link_online(link)) - status = ATA_BUSY; - else if ((link->ap->flags & ATA_FLAG_SATA) && - !ata_link_offline(link) && - time_before(now, nodev_deadline)) - status = ATA_BUSY; - if (status == 0xff) - return -ENODEV; - } - - if (time_after(now, deadline)) - return -EBUSY; - - if (!warned && time_after(now, start + 5 * HZ) && - (deadline - now > 3 * HZ)) { - ata_link_printk(link, KERN_WARNING, - "link is slow to respond, please be patient " - "(Status 0x%x)\n", status); - warned = 1; - } - - msleep(50); - } + return ata_wait_ready(link, deadline, ata_sff_check_ready); } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 11b5f67a19d4..08af43e2c081 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -81,6 +81,8 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev, int dma_dir, struct scatterlist *sg, unsigned int n_elem, unsigned long timeout); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); +extern int ata_wait_ready(struct ata_link *link, unsigned long deadline, + int (*check_ready)(struct ata_link *link)); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); diff --git a/include/linux/libata.h b/include/linux/libata.h index da5560244787..4bbf2524e473 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -837,6 +837,8 @@ extern void sata_print_link_status(struct ata_link *link); extern void ata_port_probe(struct ata_port *); extern int sata_set_spd(struct ata_link *link); extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); +extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, + int (*check_ready)(struct ata_link *link)); extern int sata_link_debounce(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, -- cgit v1.2.3 From 9dadd45b24145d6aee2fabb28d7aef972301892b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:19 +0900 Subject: libata: move generic hardreset code from sata_sff_hardreset() to sata_link_hardreset() sata_sff_hardreset() contains link readiness wait logic which isn't SFF specific. Move that part into sata_link_hardreset(), which now takes two more parameters - @online and @check_ready. Both are optional. The former is out parameter for link onlineness after reset. The latter is used to wait for link readiness after hardreset. Users of sata_link_hardreset() is updated to use new funtionality and ahci_hardreset() is updated to use sata_link_hardreset() instead of sata_sff_hardreset(). This doesn't really cause any behavior change. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 35 +++++++++++++++++++-------------- drivers/ata/ata_piix.c | 2 +- drivers/ata/libata-core.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/ata/libata-pmp.c | 7 ++++--- drivers/ata/libata-sff.c | 49 +++++++++------------------------------------- include/linux/libata.h | 10 +++++++++- 6 files changed, 92 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7e251a2cbda5..0f553aaa6f79 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1343,10 +1343,12 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; + bool online; int rc; DPRINTK("ENTER\n"); @@ -1358,14 +1360,14 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); - rc = sata_sff_hardreset(link, class, deadline); + rc = sata_link_hardreset(link, timing, deadline, &online, + ahci_check_ready); ahci_start_engine(ap); - if (rc == 0 && ata_link_online(link)) + *class = ATA_DEV_NONE; + if (online) *class = ahci_dev_classify(ap); - if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) - *class = ATA_DEV_NONE; DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); return rc; @@ -1376,6 +1378,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; u32 serror; + bool online; int rc; DPRINTK("ENTER\n"); @@ -1383,7 +1386,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, ahci_stop_engine(ap); rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), - deadline); + deadline, &online, NULL); /* vt8251 needs SError cleared for the port to operate */ ahci_scr_read(ap, SCR_ERROR, &serror); @@ -1396,7 +1399,8 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, /* vt8251 doesn't clear BSY on signature FIS reception, * request follow-up softreset. */ - return rc ?: -EAGAIN; + *class = ATA_DEV_NONE; + return online ? -EAGAIN : rc; } static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, @@ -1406,6 +1410,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; + bool online; int rc; ahci_stop_engine(ap); @@ -1416,13 +1421,10 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, ata_tf_to_fis(&tf, 0, 0, d2h_fis); rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), - deadline); + deadline, &online, NULL); ahci_start_engine(ap); - if (rc || ata_link_offline(link)) - return rc; - /* The pseudo configuration device on SIMG4726 attached to * ASUS P5W-DH Deluxe doesn't send signature FIS after * hardreset if no device is attached to the first downstream @@ -1436,11 +1438,14 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, * have to be reset again. For most cases, this should * suffice while making probing snappish enough. */ - rc = ata_wait_after_reset(link, jiffies + 2 * HZ, ahci_check_ready); - if (rc) - ahci_kick_engine(ap, 0); - - return 0; + if (online) { + rc = ata_wait_after_reset(link, jiffies + 2 * HZ, + ahci_check_ready); + if (rc) + ahci_kick_engine(ap, 0); + } + *class = ATA_DEV_NONE; + return rc; } static void ahci_postreset(struct ata_link *link, unsigned int *class) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7ab76a413cdf..f59a55bfade4 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1022,7 +1022,7 @@ static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, int rc; /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline); + rc = sata_link_hardreset(link, timing, deadline, NULL, NULL); if (rc) { ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3bad6f189190..b607292b6480 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3557,8 +3557,18 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) * @link: link to reset * @timing: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation + * @online: optional out parameter indicating link onlineness + * @check_ready: optional callback to check link readiness * * SATA phy-reset @link using DET bits of SControl register. + * After hardreset, link readiness is waited upon using + * ata_wait_ready() if @check_ready is specified. LLDs are + * allowed to not specify @check_ready and wait itself after this + * function returns. Device classification is LLD's + * responsibility. + * + * *@online is set to one iff reset succeeded and @link is online + * after reset. * * LOCKING: * Kernel thread context (may sleep) @@ -3567,13 +3577,17 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) * 0 on success, -errno otherwise. */ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, - unsigned long deadline) + unsigned long deadline, + bool *online, int (*check_ready)(struct ata_link *)) { u32 scontrol; int rc; DPRINTK("ENTER\n"); + if (online) + *online = false; + if (sata_set_spd_needed(link)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during @@ -3607,7 +3621,41 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, /* bring link back */ rc = sata_link_resume(link, timing, deadline); + if (rc) + goto out; + /* if link is offline nothing more to do */ + if (ata_link_offline(link)) + goto out; + + /* Link is online. From this point, -ENODEV too is an error. */ + if (online) + *online = true; + + if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) { + /* If PMP is supported, we have to do follow-up SRST. + * Some PMPs don't send D2H Reg FIS after hardreset if + * the first port is empty. Wait only for + * ATA_TMOUT_PMP_SRST_WAIT. + */ + if (check_ready) { + unsigned long pmp_deadline; + + pmp_deadline = jiffies + ATA_TMOUT_PMP_SRST_WAIT; + if (time_after(pmp_deadline, deadline)) + pmp_deadline = deadline; + ata_wait_ready(link, pmp_deadline, check_ready); + } + rc = -EAGAIN; + goto out; + } + + rc = 0; + if (check_ready) + rc = ata_wait_ready(link, deadline, check_ready); out: + if (rc && rc != -EAGAIN) + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); DPRINTK("EXIT, rc=%d\n", rc); return rc; } diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index a7cb1498c9b2..7f1a87f01ab2 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -239,13 +239,14 @@ int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + bool online; u32 tmp; int rc; DPRINTK("ENTER\n"); /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline); + rc = sata_link_hardreset(link, timing, deadline, &online, NULL); if (rc) { ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); @@ -261,7 +262,7 @@ int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, } /* if device is present, follow up with srst to wait for !BSY */ - if (ata_link_online(link)) + if (online) rc = -EAGAIN; out: /* if SCR isn't accessible, we need to reset the PMP */ @@ -916,7 +917,7 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) * SError.N working. */ sata_link_hardreset(link, sata_deb_timing_normal, - jiffies + ATA_TMOUT_INTERNAL_QUICK); + jiffies + ATA_TMOUT_INTERNAL_QUICK, NULL, NULL); /* unconditionally clear SError.N */ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 78912c5011ad..0b97e84d3af6 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1921,50 +1921,19 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, int sata_sff_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - struct ata_port *ap = link->ap; - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_eh_context *ehc = &link->eh_context; + const unsigned long *timing = sata_ehc_deb_timing(ehc); + bool online; int rc; - DPRINTK("ENTER\n"); - - /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline); - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_link_offline(link)) { - *class = ATA_DEV_NONE; - DPRINTK("EXIT, link offline\n"); - return 0; - } - - /* If PMP is supported, we have to do follow-up SRST. Note - * that some PMPs don't send D2H Reg FIS after hardreset at - * all if the first port is empty. Wait for it just for a - * second and request follow-up SRST. - */ - if (ap->flags & ATA_FLAG_PMP) { - ata_sff_wait_after_reset(link, 1, jiffies + HZ); - return -EAGAIN; - } - - /* wait for the link to become online */ - rc = ata_sff_wait_after_reset(link, 1, deadline); - /* link occupied, -ENODEV too is an error */ - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - *class = ata_sff_dev_classify(link->device, 1, NULL); + rc = sata_link_hardreset(link, timing, deadline, &online, + ata_sff_check_ready); + *class = ATA_DEV_NONE; + if (online) + *class = ata_sff_dev_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); - return 0; + return rc; } /** diff --git a/include/linux/libata.h b/include/linux/libata.h index 4bbf2524e473..d9ebce2bf5e7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -261,6 +261,13 @@ enum { */ ATA_WAIT_AFTER_RESET_MSECS = 150, + /* If PMP is supported, we have to do follow-up SRST. As some + * PMPs don't send D2H Reg FIS after hardreset, LLDs are + * advised to wait only for the following duration before + * doing SRST. + */ + ATA_TMOUT_PMP_SRST_WAIT = 1 * HZ, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -844,7 +851,8 @@ extern int sata_link_debounce(struct ata_link *link, extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_hardreset(struct ata_link *link, - const unsigned long *timing, unsigned long deadline); + const unsigned long *timing, unsigned long deadline, + bool *online, int (*check_ready)(struct ata_link *)); extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); -- cgit v1.2.3 From 57c9efdfb3cee5d4564fcb5f70555e2edb1bc52a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:19 +0900 Subject: libata: implement and use sata_std_hardreset() Implement sata_std_hardreset(), which simply wraps around sata_link_hardreset(). sata_std_hardreset() becomes new standard hardreset method for sata_port_ops and sata_sff_hardreset() moves from ata_base_port_ops to ata_sff_port_ops, which is where it really belongs. ata_is_builtin_hardreset() is added so that both ata_std_error_handler() and ata_sff_error_handler() skip both builtin hardresets if SCR isn't accessible. piix_sidpr_hardreset() in ata_piix.c is identical to sata_std_hardreset() in functionality and got replaced with the standard function. Signed-off-by: Tejun Heo --- drivers/ata/ata_piix.c | 27 +-------------------------- drivers/ata/libata-core.c | 30 +++++++++++++++++++++++++++++- drivers/ata/libata-eh.c | 7 ++----- drivers/ata/libata-sff.c | 9 ++++----- drivers/ata/libata.h | 9 +++++++++ include/linux/libata.h | 2 ++ 6 files changed, 47 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index f59a55bfade4..b7c38eeb498f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -165,8 +165,6 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int ich_pata_cable_detect(struct ata_port *ap); static u8 piix_vmw_bmdma_status(struct ata_port *ap); -static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); #ifdef CONFIG_PM @@ -319,7 +317,7 @@ static struct ata_port_operations piix_sata_ops = { static struct ata_port_operations piix_sidpr_sata_ops = { .inherits = &piix_sata_ops, - .hardreset = piix_sidpr_hardreset, + .hardreset = sata_std_hardreset, .scr_read = piix_sidpr_scr_read, .scr_write = piix_sidpr_scr_write, }; @@ -1015,29 +1013,6 @@ static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) return 0; } -static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); - int rc; - - /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline, NULL, NULL); - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_link_offline(link)) { - *class = ATA_DEV_NONE; - return 0; - } - - return -EAGAIN; -} - #ifdef CONFIG_PM static int piix_broken_suspend(void) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b607292b6480..c4fd4afbf349 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -75,7 +75,6 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { .prereset = ata_std_prereset, - .hardreset = sata_sff_hardreset, .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, }; @@ -84,6 +83,7 @@ const struct ata_port_operations sata_port_ops = { .inherits = &ata_base_port_ops, .qc_defer = ata_std_qc_defer, + .hardreset = sata_std_hardreset, .sff_dev_select = ata_noop_dev_select, }; @@ -3660,6 +3660,33 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, return rc; } +/** + * sata_std_hardreset - COMRESET w/o waiting or classification + * @link: link to reset + * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation + * + * Standard SATA COMRESET w/o waiting or classification. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 if link offline, -EAGAIN if link online, -errno on errors. + */ +int sata_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + bool online; + int rc; + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline, &online, NULL); + *class = ATA_DEV_NONE; + return online ? -EAGAIN : rc; +} + /** * ata_std_postreset - standard postreset callback * @link: the target ata_link @@ -6225,6 +6252,7 @@ EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(sata_link_hardreset); +EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f4f9c2783821..21687bbd9a70 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2857,11 +2857,8 @@ void ata_std_error_handler(struct ata_port *ap) struct ata_port_operations *ops = ap->ops; ata_reset_fn_t hardreset = ops->hardreset; - /* sata_std_hardreset is inherited to all drivers from - * ata_base_port_ops. Ignore it if SCR access is not - * available. - */ - if (hardreset == sata_sff_hardreset && !sata_scr_valid(&ap->link)) + /* ignore built-in hardreset if SCR access is not available */ + if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link)) hardreset = NULL; ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 0b97e84d3af6..f464ca1fa261 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -49,6 +49,7 @@ const struct ata_port_operations ata_sff_port_ops = { .thaw = ata_sff_thaw, .prereset = ata_sff_prereset, .softreset = ata_sff_softreset, + .hardreset = sata_sff_hardreset, .postreset = ata_sff_postreset, .error_handler = ata_sff_error_handler, .post_internal_cmd = ata_sff_post_internal_cmd, @@ -2031,14 +2032,12 @@ void ata_sff_error_handler(struct ata_port *ap) /* PIO and DMA engines have been stopped, perform recovery */ - /* ata_sff_softreset and sata_sff_hardreset are inherited to - * all SFF drivers from ata_sff_port_ops. Ignore softreset if - * ctl isn't accessible. Ignore hardreset if SCR access isn't - * available. + /* Ignore ata_sff_softreset if ctl isn't accessible and + * built-in hardresets if SCR access isn't available. */ if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr) softreset = NULL; - if (hardreset == sata_sff_hardreset && !sata_scr_valid(&ap->link)) + if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link)) hardreset = NULL; ata_do_eh(ap, ap->ops->prereset, softreset, hardreset, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 08af43e2c081..87f54a1db3b0 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -38,6 +38,15 @@ struct ata_scsi_args { void (*done)(struct scsi_cmnd *); }; +static inline int ata_is_builtin_hardreset(ata_reset_fn_t reset) +{ + if (reset == sata_std_hardreset) + return 1; + if (reset == sata_sff_hardreset) + return 1; + return 0; +} + /* libata-core.c */ enum { /* flags for ata_dev_read_id() */ diff --git a/include/linux/libata.h b/include/linux/libata.h index d9ebce2bf5e7..c060cd3cba66 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -853,6 +853,8 @@ extern int sata_link_resume(struct ata_link *link, const unsigned long *params, extern int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline, bool *online, int (*check_ready)(struct ata_link *)); +extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); -- cgit v1.2.3 From ac371987a81c61c2efbd6931245cdcaf43baad89 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:19 +0900 Subject: libata: clear SError after link resume SError used to be cleared in ->postreset. This has small hotplug race condition. If a device is plugged in after reset is complete but postreset hasn't run yet, its hotplug event gets lost when SError is cleared. This patch makes sata_link_resume() clear SError. This kills the race condition and makes a lot of sense as some PMP and host PHYs don't work properly without SError cleared. This change makes sata_pmp_std_{pre|post}_reset()'s unnecessary as they become identical to ata_std counterparts. It also simplifies sata_pmp_hardreset() and ahci_vt8251_hardreset(). Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 5 --- drivers/ata/libata-core.c | 35 +++++++++++------- drivers/ata/libata-pmp.c | 93 +---------------------------------------------- include/linux/libata.h | 2 - 4 files changed, 23 insertions(+), 112 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0f553aaa6f79..a69bcca4eb1b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1377,7 +1377,6 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_port *ap = link->ap; - u32 serror; bool online; int rc; @@ -1388,10 +1387,6 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); - /* vt8251 needs SError cleared for the port to operate */ - ahci_scr_read(ap, SCR_ERROR, &serror); - ahci_scr_write(ap, SCR_ERROR, serror); - ahci_start_engine(ap); DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c4fd4afbf349..e00b620f161a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -90,9 +90,9 @@ const struct ata_port_operations sata_port_ops = { const struct ata_port_operations sata_pmp_port_ops = { .inherits = &sata_port_ops, - .pmp_prereset = sata_pmp_std_prereset, + .pmp_prereset = ata_std_prereset, .pmp_hardreset = sata_pmp_std_hardreset, - .pmp_postreset = sata_pmp_std_postreset, + .pmp_postreset = ata_std_postreset, .error_handler = sata_pmp_error_handler, }; @@ -3493,7 +3493,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline) { - u32 scontrol; + u32 scontrol, serror; int rc; if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) @@ -3509,7 +3509,25 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, */ msleep(200); - return sata_link_debounce(link, params, deadline); + if ((rc = sata_link_debounce(link, params, deadline))) + return rc; + + /* Clear SError. PMP and some host PHYs require this to + * operate and clearing should be done before checking PHY + * online status to avoid race condition (hotplugging between + * link resume and status check). + */ + if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) + rc = sata_scr_write(link, SCR_ERROR, serror); + if (rc == 0 || rc == -EINVAL) { + unsigned long flags; + + spin_lock_irqsave(link->ap->lock, flags); + link->eh_info.serror = 0; + spin_unlock_irqrestore(link->ap->lock, flags); + rc = 0; + } + return rc; } /** @@ -3701,18 +3719,11 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, */ void ata_std_postreset(struct ata_link *link, unsigned int *classes) { - u32 serror; - DPRINTK("ENTER\n"); /* print link status */ sata_print_link_status(link); - /* clear SError */ - if (sata_scr_read(link, SCR_ERROR, &serror) == 0) - sata_scr_write(link, SCR_ERROR, serror); - link->eh_info.serror = 0; - DPRINTK("EXIT\n"); } @@ -6296,9 +6307,7 @@ EXPORT_SYMBOL_GPL(ata_pci_device_resume); #endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); -EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); -EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); EXPORT_SYMBOL_GPL(sata_pmp_error_handler); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 7f1a87f01ab2..2f8a9577c26d 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -175,49 +175,6 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) return 0; } -/** - * sata_pmp_std_prereset - prepare PMP link for reset - * @link: link to be reset - * @deadline: deadline jiffies for the operation - * - * @link is about to be reset. Initialize it. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) -{ - struct ata_eh_context *ehc = &link->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); - int rc; - - /* if we're about to do hardreset, nothing more to do */ - if (ehc->i.action & ATA_EH_HARDRESET) - return 0; - - /* resume link */ - rc = sata_link_resume(link, timing, deadline); - if (rc) { - /* phy resume failed */ - ata_link_printk(link, KERN_WARNING, "failed to resume link " - "for reset (errno=%d)\n", rc); - return rc; - } - - /* clear SError bits including .X which blocks the port when set */ - rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); - if (rc) { - ata_link_printk(link, KERN_ERR, - "failed to clear SError (errno=%d)\n", rc); - return rc; - } - - return 0; -} - /** * sata_pmp_std_hardreset - standard hardreset method for PMP link * @link: link to be reset @@ -238,33 +195,13 @@ int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); - bool online; u32 tmp; int rc; DPRINTK("ENTER\n"); - /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline, &online, NULL); - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - goto out; - } - - /* clear SError bits including .X which blocks the port when set */ - rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); - if (rc) { - ata_link_printk(link, KERN_ERR, "failed to clear SError " - "during hardreset (errno=%d)\n", rc); - goto out; - } + rc = sata_std_hardreset(link, class, deadline); - /* if device is present, follow up with srst to wait for !BSY */ - if (online) - rc = -EAGAIN; - out: /* if SCR isn't accessible, we need to reset the PMP */ if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp)) rc = -ERESTART; @@ -273,34 +210,6 @@ int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, return rc; } -/** - * ata_std_postreset - standard postreset method for PMP link - * @link: the target ata_link - * @classes: classes of attached devices - * - * This function is invoked after a successful reset. Note that - * the device might have been reset more than once using - * different reset methods before postreset is invoked. - * - * LOCKING: - * Kernel thread context (may sleep) - */ -void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) -{ - u32 serror; - - DPRINTK("ENTER\n"); - - /* clear SError */ - if (sata_scr_read(link, SCR_ERROR, &serror) == 0) - sata_scr_write(link, SCR_ERROR, serror); - - /* print link status */ - sata_print_link_status(link); - - DPRINTK("EXIT\n"); -} - /** * sata_pmp_read_gscr - read GSCR block of SATA PMP * @dev: PMP device diff --git a/include/linux/libata.h b/include/linux/libata.h index c060cd3cba66..b9188371b12a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1025,10 +1025,8 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap, * PMP - drivers/ata/libata-pmp.c */ extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); -extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class); extern void sata_pmp_error_handler(struct ata_port *ap); /* -- cgit v1.2.3 From 5958e3025fd9d97429163e074d9cfa3848f51f28 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:20 +0900 Subject: libata: move PMP SCR access failure during reset to ata_eh_reset() If PMP fan-out reset fails and SCR isn't accessible, PMP should be reset. This used to be tested by sata_pmp_std_hardreset() and communicated to EH by -ERESTART. However, this logic is generic and doesn't really have much to do with specific hardreset implementation. This patch moves SCR access failure detection logic to ata_eh_reset() where it belongs. As this makes sata_pmp_std_hardreset() identical to sata_std_hardreset(), the function is killed and replaced with the standard method. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 3 +-- drivers/ata/libata-eh.c | 5 +++++ drivers/ata/libata-pmp.c | 35 ----------------------------------- drivers/ata/sata_sil24.c | 2 +- include/linux/libata.h | 2 -- 5 files changed, 7 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e00b620f161a..2da579b46bdd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -91,7 +91,7 @@ const struct ata_port_operations sata_pmp_port_ops = { .inherits = &sata_port_ops, .pmp_prereset = ata_std_prereset, - .pmp_hardreset = sata_pmp_std_hardreset, + .pmp_hardreset = sata_std_hardreset, .pmp_postreset = ata_std_postreset, .error_handler = sata_pmp_error_handler, }; @@ -6307,7 +6307,6 @@ EXPORT_SYMBOL_GPL(ata_pci_device_resume); #endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); -EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); EXPORT_SYMBOL_GPL(sata_pmp_error_handler); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 21687bbd9a70..d8c4a45dcf26 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2276,6 +2276,11 @@ int ata_eh_reset(struct ata_link *link, int classify, return rc; fail: + /* if SCR isn't accessible on a fan-out port, PMP needs to be reset */ + if (!ata_is_host_link(link) && + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + if (rc == -ERESTART || try >= max_tries) goto out; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 2f8a9577c26d..9c998611b644 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -175,41 +175,6 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) return 0; } -/** - * sata_pmp_std_hardreset - standard hardreset method for PMP link - * @link: link to be reset - * @class: resulting class of attached device - * @deadline: deadline jiffies for the operation - * - * Hardreset PMP port @link. Note that this function doesn't - * wait for BSY clearance. There simply isn't a generic way to - * wait the event. Instead, this function return -EAGAIN thus - * telling libata-EH to followup with softreset. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - u32 tmp; - int rc; - - DPRINTK("ENTER\n"); - - rc = sata_std_hardreset(link, class, deadline); - - /* if SCR isn't accessible, we need to reset the PMP */ - if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp)) - rc = -ERESTART; - - DPRINTK("EXIT, rc=%d\n", rc); - return rc; -} - /** * sata_pmp_read_gscr - read GSCR block of SATA PMP * @dev: PMP device diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index b83851f6e068..fc9d48cd8122 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -944,7 +944,7 @@ static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, return rc; } - return sata_pmp_std_hardreset(link, class, deadline); + return sata_std_hardreset(link, class, deadline); } static void sil24_freeze(struct ata_port *ap) diff --git a/include/linux/libata.h b/include/linux/libata.h index b9188371b12a..2b5a0b77e179 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1025,8 +1025,6 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap, * PMP - drivers/ata/libata-pmp.c */ extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); -extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); extern void sata_pmp_error_handler(struct ata_port *ap); /* -- cgit v1.2.3 From 22183bf569c8600ff414ac25f23134044e0ef453 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:20 +0900 Subject: libata: add qc_fill_rtf port operation On command completion, ata_qc_complete() directly called ops->tf_read to fill qc->result_tf. This patch adds ops->qc_fill_rtf to replace hardcoded ops->tf_read usage. ata_sff_qc_fill_rtf() which uses ops->tf_read to fill result_tf is implemented and set in ata_base_port_ops and other ops tables which don't inherit from ata_base_port_ops, so this patch doesn't introduce any behavior change. ops->qc_fill_rtf() is similar to ops->sff_tf_read() but can only be called when a command finishes. As some non-SFF controllers don't have TF registers defined unless they're associated with in-flight commands, this limited operation makes life easier for those drivers and help lifting SFF assumptions from libata core layer. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 3 ++- drivers/ata/libata-sff.c | 20 ++++++++++++++++++++ drivers/ata/sata_sx4.c | 1 + drivers/scsi/ipr.c | 1 + drivers/scsi/libsas/sas_ata.c | 1 + include/linux/libata.h | 2 ++ 6 files changed, 27 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 51876b93c1b7..3b822124e97e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -74,6 +74,7 @@ const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; const struct ata_port_operations ata_base_port_ops = { + .qc_fill_rtf = ata_sff_qc_fill_rtf, .prereset = ata_std_prereset, .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, @@ -4562,7 +4563,7 @@ static void fill_result_tf(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; qc->result_tf.flags = qc->tf.flags; - ap->ops->sff_tf_read(ap, &qc->result_tf); + ap->ops->qc_fill_rtf(qc); } static void ata_verify_xfer(struct ata_queued_cmd *qc) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 5be8a6058dac..5ae813f54420 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1407,6 +1407,25 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) return 0; } +/** + * ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read + * @qc: qc to fill result TF for + * + * @qc is finished and result TF needs to be filled. Fill it + * using ->sff_tf_read. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * true indicating that result TF is successfully filled. + */ +bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) +{ + qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf); + return true; +} + /** * ata_sff_host_intr - Handle host interrupt for given (port, task) * @ap: Port on which interrupt arrived (possibly...) @@ -2724,6 +2743,7 @@ EXPORT_SYMBOL_GPL(ata_sff_irq_on); EXPORT_SYMBOL_GPL(ata_sff_irq_clear); EXPORT_SYMBOL_GPL(ata_sff_hsm_move); EXPORT_SYMBOL_GPL(ata_sff_qc_issue); +EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); EXPORT_SYMBOL_GPL(ata_sff_host_intr); EXPORT_SYMBOL_GPL(ata_sff_interrupt); EXPORT_SYMBOL_GPL(ata_sff_freeze); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 6107eff731f3..ec04b8d3c791 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -251,6 +251,7 @@ static struct ata_port_operations pdc_20621_ops = { .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, .qc_issue = pdc20621_qc_issue, + .qc_fill_rtf = ata_sff_qc_fill_rtf, .sff_data_xfer = ata_sff_data_xfer, .eng_timeout = pdc_eng_timeout, .sff_irq_clear = pdc20621_irq_clear, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5bddae19d1fb..2ecd32991522 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5280,6 +5280,7 @@ static struct ata_port_operations ipr_sata_ops = { .sff_tf_read = ipr_tf_read, .qc_prep = ata_noop_qc_prep, .qc_issue = ipr_qc_issue, + .qc_fill_rtf = ata_sff_qc_fill_rtf, .port_start = ata_sas_port_start, .port_stop = ata_sas_port_stop }; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a1664b87927a..2ec255839dcd 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -356,6 +356,7 @@ static struct ata_port_operations sas_sata_ops = { .sff_tf_read = sas_ata_tf_read, .qc_prep = ata_noop_qc_prep, .qc_issue = sas_ata_qc_issue, + .qc_fill_rtf = ata_sff_qc_fill_rtf, .port_start = ata_sas_port_start, .port_stop = ata_sas_port_stop, .scr_read = sas_ata_scr_read, diff --git a/include/linux/libata.h b/include/linux/libata.h index 2b5a0b77e179..bb4200d42f0d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -715,6 +715,7 @@ struct ata_port_operations { int (*check_atapi_dma)(struct ata_queued_cmd *qc); void (*qc_prep)(struct ata_queued_cmd *qc); unsigned int (*qc_issue)(struct ata_queued_cmd *qc); + bool (*qc_fill_rtf)(struct ata_queued_cmd *qc); /* * Configuration and exception handling @@ -1385,6 +1386,7 @@ extern void ata_sff_irq_clear(struct ata_port *ap); extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, u8 status, int in_wq); extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc); +extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); extern unsigned int ata_sff_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance); -- cgit v1.2.3 From 79f97dadfe9b4b561634d202225ba2fa910dc225 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:20 +0900 Subject: libata: drop @finish_qc from ata_qc_complete_multiple() ata_qc_complete_multiple() took @finish_qc and called it on every qc before completing it. This was to give opportunity to update TF cache before ata_qc_complete() tries to fill result_tf. Now that result TF is a separate operation, this is no longer necessary. Update sata_sil24, which was the only user of this mechanism, such that it implements its own ops->qc_fill_rtf() and drop @finish_qc from ata_qc_complete_multiple(). Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 6 +----- drivers/ata/sata_sil24.c | 19 +++++++++---------- include/linux/libata.h | 3 +-- 4 files changed, 12 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3071a2341be3..1389c64e0027 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1696,7 +1696,7 @@ static void ahci_port_intr(struct ata_port *ap) else qc_active = readl(port_mmio + PORT_CMD_ISSUE); - rc = ata_qc_complete_multiple(ap, qc_active, NULL); + rc = ata_qc_complete_multiple(ap, qc_active); /* while resetting, invalid completions are expected */ if (unlikely(rc < 0 && !resetting)) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3b822124e97e..dcc5a28e26c1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4673,7 +4673,6 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * ata_qc_complete_multiple - Complete multiple qcs successfully * @ap: port in question * @qc_active: new qc_active mask - * @finish_qc: LLDD callback invoked before completing a qc * * Complete in-flight commands. This functions is meant to be * called from low-level driver's interrupt routine to complete @@ -4686,8 +4685,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * RETURNS: * Number of completed commands on success, -errno otherwise. */ -int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, - void (*finish_qc)(struct ata_queued_cmd *)) +int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) { int nr_done = 0; u32 done_mask; @@ -4708,8 +4706,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, continue; if ((qc = ata_qc_from_tag(ap, i))) { - if (finish_qc) - finish_qc(qc); ata_qc_complete(qc); nr_done++; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index fc9d48cd8122..79952f825b40 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -348,6 +348,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static int sil24_qc_defer(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); +static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); @@ -407,6 +408,7 @@ static struct ata_port_operations sil24_ops = { .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, + .qc_fill_rtf = sil24_qc_fill_rtf, .freeze = sil24_freeze, .thaw = sil24_thaw, @@ -914,6 +916,12 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) return 0; } +static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc) +{ + sil24_read_tf(qc->ap, qc->tag, &qc->result_tf); + return true; +} + static void sil24_pmp_attach(struct ata_port *ap) { sil24_config_pmp(ap, 1); @@ -1098,15 +1106,6 @@ static void sil24_error_intr(struct ata_port *ap) } } -static void sil24_finish_qc(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct sil24_port_priv *pp = ap->private_data; - - if (qc->flags & ATA_QCFLAG_RESULT_TF) - sil24_read_tf(ap, qc->tag, &pp->tf); -} - static inline void sil24_host_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -1131,7 +1130,7 @@ static inline void sil24_host_intr(struct ata_port *ap) } qc_active = slot_stat & ~HOST_SSTAT_ATTN; - rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc); + rc = ata_qc_complete_multiple(ap, qc_active); if (rc > 0) return; if (rc < 0) { diff --git a/include/linux/libata.h b/include/linux/libata.h index bb4200d42f0d..1d8b6b7de0a2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -924,8 +924,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_qc_complete(struct ata_queued_cmd *qc); -extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, - void (*finish_qc)(struct ata_queued_cmd *)); +extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active); extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_std_bios_param(struct scsi_device *sdev, -- cgit v1.2.3 From c9f75b04ed5ed65a058d18a8a8dda50632a96de8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:21 +0900 Subject: libata: kill ata_noop_dev_select() Now that SFF assumptions are separated out from non-SFF reset sequence, port_ops->sff_dev_select() is no longer necessary for non-SFF controllers. Kill ata_noop_dev_select() and ->sff_dev_select initialization from base and other non-SFF port_ops. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 19 ------------------- drivers/scsi/ipr.c | 1 - drivers/scsi/libsas/sas_ata.c | 1 - include/linux/libata.h | 1 - 4 files changed, 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e8598eeeec39..f23f50af551c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -84,7 +84,6 @@ const struct ata_port_operations sata_port_ops = { .qc_defer = ata_std_qc_defer, .hardreset = sata_std_hardreset, - .sff_dev_select = ata_noop_dev_select, }; const struct ata_port_operations sata_pmp_port_ops = { @@ -1431,22 +1430,6 @@ static int ata_hpa_resize(struct ata_device *dev) return 0; } -/** - * ata_noop_dev_select - Select device 0/1 on ATA bus - * @ap: ATA channel to manipulate - * @device: ATA device (numbered from zero) to select - * - * This function performs no actual function. - * - * May be used as the dev_select() entry in ata_port_operations. - * - * LOCKING: - * caller. - */ -void ata_noop_dev_select(struct ata_port *ap, unsigned int device) -{ -} - /** * ata_dump_id - IDENTIFY DEVICE info debugging output * @id: IDENTIFY DEVICE page to dump @@ -6193,7 +6176,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) struct ata_port_operations ata_dummy_port_ops = { .sff_check_status = ata_dummy_check_status, .sff_check_altstatus = ata_dummy_check_status, - .sff_dev_select = ata_noop_dev_select, .qc_prep = ata_noop_qc_prep, .qc_issue = ata_dummy_qc_issue, .freeze = ata_dummy_noret, @@ -6234,7 +6216,6 @@ EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); -EXPORT_SYMBOL_GPL(ata_noop_dev_select); EXPORT_SYMBOL_GPL(sata_print_link_status); EXPORT_SYMBOL_GPL(atapi_cmd_type); EXPORT_SYMBOL_GPL(ata_tf_to_fis); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5a95ea7c4dba..65dc18dea845 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5247,7 +5247,6 @@ static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) } static struct ata_port_operations ipr_sata_ops = { - .sff_dev_select = ata_noop_dev_select, .phy_reset = ipr_ata_phy_reset, .hardreset = ipr_sata_reset, .post_internal_cmd = ipr_ata_post_internal, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 5c114bb7e907..a4811e4106df 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -344,7 +344,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, } static struct ata_port_operations sas_sata_ops = { - .sff_dev_select = ata_noop_dev_select, .phy_reset = sas_ata_phy_reset, .post_internal_cmd = sas_ata_post_internal, .qc_prep = ata_noop_qc_prep, diff --git a/include/linux/libata.h b/include/linux/libata.h index 1d8b6b7de0a2..037db1883bae 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -911,7 +911,6 @@ extern unsigned long ata_xfer_mode2mask(u8 xfer_mode); extern int ata_xfer_mode2shift(unsigned long xfer_mode); extern const char *ata_mode_string(unsigned long xfer_mask); extern unsigned long ata_id_xfermask(const u16 *id); -extern void ata_noop_dev_select(struct ata_port *ap, unsigned int device); extern int ata_port_start(struct ata_port *ap); extern int ata_std_qc_defer(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); -- cgit v1.2.3 From 127102aea2ea9ec4e9ca233e2b1a75c8d3b058c4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:21 +0900 Subject: libata: make SFF support optional Now that SFF support is completely separated out from the core layer, it can be made optional. Add CONFIG_ATA_SFF and let SFF drivers depend on it. If CONFIG_ATA_SFF isn't set, all codes in libata-sff.c and data structures for SFF support are disabled. This saves good number of bytes for small systems. Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 44 +++++++++++++++++++++++++++----------------- drivers/ata/Makefile | 4 ++-- drivers/ata/libata-core.c | 2 ++ drivers/ata/libata-scsi.c | 2 ++ drivers/ata/libata.h | 4 ++++ include/linux/libata.h | 9 +++++++++ 6 files changed, 46 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ea665c249035..48c8fc55391e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -49,6 +49,32 @@ config SATA_AHCI If unsure, say N. +config SATA_SIL24 + tristate "Silicon Image 3124/3132 SATA support" + depends on PCI + help + This option enables support for Silicon Image 3124/3132 Serial ATA. + + If unsure, say N. + +config SATA_FSL + tristate "Freescale 3.0Gbps SATA support" + depends on FSL_SOC + help + This option enables support for Freescale 3.0Gbps SATA controller. + It can be found on MPC837x and MPC8315. + + If unsure, say N. + +config ATA_SFF + bool "ATA SFF support" + default y + help + This option adds support for ATA controllers with SFF + compliant or similar programming interface. + +if ATA_SFF + config SATA_SVW tristate "ServerWorks Frodo / Apple K2 SATA support" depends on PCI @@ -125,14 +151,6 @@ config SATA_SIL If unsure, say N. -config SATA_SIL24 - tristate "Silicon Image 3124/3132 SATA support" - depends on PCI - help - This option enables support for Silicon Image 3124/3132 Serial ATA. - - If unsure, say N. - config SATA_SIS tristate "SiS 964/965/966/180 SATA support" depends on PCI @@ -183,15 +201,6 @@ config PATA_ACPI firmware in the BIOS. This driver can sometimes handle otherwise unsupported hardware. -config SATA_FSL - tristate "Freescale 3.0Gbps SATA support" - depends on FSL_SOC - help - This option enables support for Freescale 3.0Gbps SATA controller. - It can be found on MPC837x and MPC8315. - - If unsure, say N. - config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL @@ -679,4 +688,5 @@ config PATA_BF54X If unsure, say N. +endif # ATA_SFF endif # ATA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 0511e6f0bb58..e6e41b2c731c 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -78,6 +78,6 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \ - libata-pmp.o +libata-objs := libata-core.o libata-scsi.o libata-eh.o libata-pmp.o +libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3a94c69c7fe7..ca60af0cb051 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5195,7 +5195,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif +#ifdef CONFIG_ATA_SFF INIT_DELAYED_WORK(&ap->port_task, ata_pio_task); +#endif INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f8be92836a6e..a70881c408e5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2393,7 +2393,9 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) /* FIXME: is this needed? */ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); +#ifdef CONFIG_ATA_SFF ap->ops->sff_tf_read(ap, &qc->tf); +#endif /* fill these in, for the case where they are -not- overwritten */ cmd->sense_buffer[0] = 0x70; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 87f54a1db3b0..6b70a624828c 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -42,8 +42,10 @@ static inline int ata_is_builtin_hardreset(ata_reset_fn_t reset) { if (reset == sata_std_hardreset) return 1; +#ifdef CONFIG_ATA_SFF if (reset == sata_sff_hardreset) return 1; +#endif return 0; } @@ -206,9 +208,11 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, extern void ata_eh_finish(struct ata_port *ap); /* libata-sff.c */ +#ifdef CONFIG_ATA_SFF extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern u8 ata_irq_on(struct ata_port *ap); extern void ata_pio_task(struct work_struct *work); +#endif /* CONFIG_ATA_SFF */ #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 037db1883bae..db77b90003fd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -445,6 +445,7 @@ enum link_pm { }; extern struct class_device_attribute class_device_attr_link_power_management_policy; +#ifdef CONFIG_ATA_SFF struct ata_ioports { void __iomem *cmd_addr; void __iomem *data_addr; @@ -462,6 +463,7 @@ struct ata_ioports { void __iomem *bmdma_addr; void __iomem *scr_addr; }; +#endif /* CONFIG_ATA_SFF */ struct ata_host { spinlock_t lock; @@ -648,7 +650,9 @@ struct ata_port { struct ata_prd *prd; /* our SG list */ dma_addr_t prd_dma; /* and its DMA mapping */ +#ifdef CONFIG_ATA_SFF struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ +#endif /* CONFIG_ATA_SFF */ u8 ctl; /* cache of ATA control register */ u8 last_ctl; /* Cache last written value */ @@ -760,6 +764,7 @@ struct ata_port_operations { void (*port_stop)(struct ata_port *ap); void (*host_stop)(struct ata_host *host); +#ifdef CONFIG_ATA_SFF /* * SFF / taskfile oriented ops */ @@ -779,6 +784,7 @@ struct ata_port_operations { void (*bmdma_start)(struct ata_queued_cmd *qc); void (*bmdma_stop)(struct ata_queued_cmd *qc); u8 (*bmdma_status)(struct ata_port *ap); +#endif /* CONFIG_ATA_SFF */ /* * Obsolete @@ -1349,6 +1355,8 @@ static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) /************************************************************************** * SFF - drivers/ata/libata-sff.c */ +#ifdef CONFIG_ATA_SFF + extern const struct ata_port_operations ata_sff_port_ops; extern const struct ata_port_operations ata_bmdma_port_ops; @@ -1489,5 +1497,6 @@ static inline u8 ata_wait_idle(struct ata_port *ap) return status; } +#endif /* CONFIG_ATA_SFF */ #endif /* __LINUX_LIBATA_H__ */ -- cgit v1.2.3 From 48515f6c006c2a9d7b624ee8ad068018c2d3fe0e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:21 +0900 Subject: libata: separate PMP support code from core code Most of PMP support code is already in libata-pmp.c. All that are in libata-core.c are sata_pmp_port_ops and EXPORTs. Move them to libata-pmp.c. Also, collect PMP related prototypes and declarations in header files and move them right above of SFF stuff. This change is to make PMP support optional. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 13 ------------- drivers/ata/libata-pmp.c | 12 ++++++++++++ drivers/ata/libata.h | 10 +++++----- include/linux/libata.h | 17 ++++++++++------- 4 files changed, 27 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ca60af0cb051..b2d5d63fb6c9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -86,15 +86,6 @@ const struct ata_port_operations sata_port_ops = { .hardreset = sata_std_hardreset, }; -const struct ata_port_operations sata_pmp_port_ops = { - .inherits = &sata_port_ops, - - .pmp_prereset = ata_std_prereset, - .pmp_hardreset = sata_std_hardreset, - .pmp_postreset = ata_std_postreset, - .error_handler = sata_pmp_error_handler, -}; - static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -6192,7 +6183,6 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_long); EXPORT_SYMBOL_GPL(ata_base_port_ops); EXPORT_SYMBOL_GPL(sata_port_ops); -EXPORT_SYMBOL_GPL(sata_pmp_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_std_bios_param); @@ -6272,9 +6262,6 @@ EXPORT_SYMBOL_GPL(ata_pci_device_resume); #endif /* CONFIG_PM */ #endif /* CONFIG_PCI */ -EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); -EXPORT_SYMBOL_GPL(sata_pmp_error_handler); - EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 9c998611b644..bb10c0630791 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -11,6 +11,14 @@ #include #include "libata.h" +const struct ata_port_operations sata_pmp_port_ops = { + .inherits = &sata_port_ops, + .pmp_prereset = ata_std_prereset, + .pmp_hardreset = sata_std_hardreset, + .pmp_postreset = ata_std_postreset, + .error_handler = sata_pmp_error_handler, +}; + /** * sata_pmp_read - read PMP register * @link: link to read PMP register for @@ -1012,3 +1020,7 @@ void sata_pmp_error_handler(struct ata_port *ap) sata_pmp_eh_recover(ap); ata_eh_finish(ap); } + +EXPORT_SYMBOL_GPL(sata_pmp_port_ops); +EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); +EXPORT_SYMBOL_GPL(sata_pmp_error_handler); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 6b70a624828c..42b30e38495d 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -179,11 +179,6 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); -/* libata-pmp.c */ -extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); -extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); -extern int sata_pmp_attach(struct ata_device *dev); - /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); @@ -207,6 +202,11 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_link **r_failed_disk); extern void ata_eh_finish(struct ata_port *ap); +/* libata-pmp.c */ +extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_pmp_attach(struct ata_device *dev); + /* libata-sff.c */ #ifdef CONFIG_ATA_SFF extern void ata_dev_select(struct ata_port *ap, unsigned int device, diff --git a/include/linux/libata.h b/include/linux/libata.h index db77b90003fd..eb86d6f39635 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1026,12 +1026,6 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap, } #endif -/* - * PMP - drivers/ata/libata-pmp.c - */ -extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); -extern void sata_pmp_error_handler(struct ata_port *ap); - /* * EH - drivers/ata/libata-eh.c */ @@ -1075,7 +1069,6 @@ extern void ata_std_error_handler(struct ata_port *ap); */ extern const struct ata_port_operations ata_base_port_ops; extern const struct ata_port_operations sata_port_ops; -extern const struct ata_port_operations sata_pmp_port_ops; #define ATA_BASE_SHT(drv_name) \ .module = THIS_MODULE, \ @@ -1352,6 +1345,16 @@ static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) return *(struct ata_port **)&host->hostdata[0]; } + +/************************************************************************** + * PMP - drivers/ata/libata-pmp.c + */ +extern const struct ata_port_operations sata_pmp_port_ops; + +extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); +extern void sata_pmp_error_handler(struct ata_port *ap); + + /************************************************************************** * SFF - drivers/ata/libata-sff.c */ -- cgit v1.2.3 From 071f44b1d2c051641b62a3571223314737ccbe59 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:22 +0900 Subject: libata: implement PMP helpers Implement helpers to test whether PMP is supported, attached and determine pmp number to use when issuing SRST to a link. While at it, move ata_is_host_link() so that it's together with the two new PMP helpers. This change simplifies LLDs and helps making PMP support optional. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 30 ++++++------------------------ drivers/ata/libata-acpi.c | 2 +- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-eh.c | 14 +++++++------- drivers/ata/libata-pmp.c | 6 +++--- drivers/ata/libata-scsi.c | 6 +++--- drivers/ata/sata_sil24.c | 27 +++++++-------------------- include/linux/libata.h | 38 +++++++++++++++++++++++++++++--------- 8 files changed, 58 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6281f7f9eae6..0de6432ee026 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -260,8 +260,6 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static void ahci_postreset(struct ata_link *link, unsigned int *class); -static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static void ahci_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_resume(struct ata_port *ap); @@ -301,7 +299,7 @@ static struct ata_port_operations ahci_ops = { .softreset = ahci_softreset, .hardreset = ahci_hardreset, .postreset = ahci_postreset, - .pmp_softreset = ahci_pmp_softreset, + .pmp_softreset = ahci_softreset, .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, .dev_config = ahci_dev_config, @@ -1263,10 +1261,11 @@ static int ahci_check_ready(struct ata_link *link) return 0; } -static int ahci_do_softreset(struct ata_link *link, unsigned int *class, - int pmp, unsigned long deadline) +static int ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { struct ata_port *ap = link->ap; + int pmp = sata_srst_pmp(link); const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1326,17 +1325,6 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, return rc; } -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - int pmp = 0; - - if (link->ap->flags & ATA_FLAG_PMP) - pmp = SATA_PMP_CTRL_PORT; - - return ahci_do_softreset(link, class, pmp, deadline); -} - static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -1457,12 +1445,6 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) } } -static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - return ahci_do_softreset(link, class, link->pmp, deadline); -} - static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) { struct scatterlist *sg; @@ -1581,7 +1563,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) unk[0], unk[1], unk[2], unk[3]); } - if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { + if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) { active_ehi->err_mask |= AC_ERR_HSM; active_ehi->action |= ATA_EH_RESET; ata_ehi_push_desc(active_ehi, "incorrect PMP"); @@ -1847,7 +1829,7 @@ static int ahci_port_resume(struct ata_port *ap) ahci_power_up(ap); ahci_start_port(ap); - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) ahci_pmp_attach(ap); else ahci_pmp_detach(ap); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index bf98a566adac..f88a4f940e11 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -77,7 +77,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap) { WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); - if (!ap->nr_pmp_links) { + if (!sata_pmp_attached(ap)) { acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); ap->link.device->acpi_handle = diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b2d5d63fb6c9..3401248180c9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2278,7 +2278,7 @@ int ata_dev_configure(struct ata_device *dev) * changed notifications and ATAPI ANs. */ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && - (!ap->nr_pmp_links || + (!sata_pmp_attached(ap) || sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { unsigned int err_mask; @@ -3623,7 +3623,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, if (online) *online = true; - if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) { + if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) { /* If PMP is supported, we have to do follow-up SRST. * Some PMPs don't send D2H Reg FIS after hardreset if * the first port is empty. Wait only for diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 4ec1397434c0..99f83bdc572b 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -873,9 +873,9 @@ int sata_async_notification(struct ata_port *ap) if (rc == 0) sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); - if (!ap->nr_pmp_links || rc) { + if (!sata_pmp_attached(ap) || rc) { /* PMP is not attached or SNTF is not available */ - if (!ap->nr_pmp_links) { + if (!sata_pmp_attached(ap)) { /* PMP is not attached. Check whether ATAPI * AN is configured. If so, notify media * change. @@ -1853,7 +1853,7 @@ void ata_eh_autopsy(struct ata_port *ap) /* Autopsy of fanout ports can affect host link autopsy. * Perform host link autopsy last. */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) ata_eh_link_autopsy(&ap->link); } @@ -2076,7 +2076,7 @@ static int ata_eh_followup_srst_needed(struct ata_link *link, } if (rc != 0) return 0; - if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) + if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) return 1; return 0; } @@ -2668,7 +2668,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* if PMP is attached, this function only deals with * downstream links, port should stay thawed. */ - if (!ap->nr_pmp_links) + if (!sata_pmp_attached(ap)) ata_eh_freeze_port(ap); ata_port_for_each_link(link, ap) { @@ -2687,7 +2687,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } } - if (!ap->nr_pmp_links) + if (!sata_pmp_attached(ap)) ata_eh_thaw_port(ap); } @@ -2731,7 +2731,7 @@ dev_fail: /* PMP reset requires working host port. * Can't retry if it's frozen. */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) goto out; break; } diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index bb10c0630791..ff1822a7da38 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -411,7 +411,7 @@ int sata_pmp_attach(struct ata_device *dev) int rc; /* is it hanging off the right place? */ - if (!(ap->flags & ATA_FLAG_PMP)) { + if (!sata_pmp_supported(ap)) { ata_dev_printk(dev, KERN_ERR, "host does not support Port Multiplier\n"); return -EINVAL; @@ -876,7 +876,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) retry: /* PMP attached? */ - if (!ap->nr_pmp_links) { + if (!sata_pmp_attached(ap)) { rc = ata_eh_recover(ap, ops->prereset, ops->softreset, ops->hardreset, ops->postreset, NULL); if (rc) { @@ -983,7 +983,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) if (ap->pflags & ATA_PFLAG_UNLOADING) return rc; - if (!ap->nr_pmp_links) + if (!sata_pmp_attached(ap)) goto retry; if (--pmp_tries) { diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a70881c408e5..fedf62de9460 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2617,7 +2617,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) { - if (ap->nr_pmp_links == 0) { + if (!sata_pmp_attached(ap)) { if (likely(devno < ata_link_max_devices(&ap->link))) return &ap->link.device[devno]; } else { @@ -2634,7 +2634,7 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, int devno; /* skip commands not addressed to targets we simulate */ - if (ap->nr_pmp_links == 0) { + if (!sata_pmp_attached(ap)) { if (unlikely(scsidev->channel || scsidev->lun)) return NULL; devno = scsidev->id; @@ -3492,7 +3492,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, if (lun != SCAN_WILD_CARD && lun) return -EINVAL; - if (ap->nr_pmp_links == 0) { + if (!sata_pmp_attached(ap)) { if (channel != SCAN_WILD_CARD && channel) return -EINVAL; devno = id; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 6039614e956c..068789361895 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -354,8 +354,6 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int sil24_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static void sil24_error_handler(struct ata_port *ap); @@ -408,7 +406,7 @@ static struct ata_port_operations sil24_ops = { .thaw = sil24_thaw, .softreset = sil24_softreset, .hardreset = sil24_hardreset, - .pmp_softreset = sil24_pmp_softreset, + .pmp_softreset = sil24_softreset, .pmp_hardreset = sil24_pmp_hardreset, .error_handler = sil24_error_handler, .post_internal_cmd = sil24_post_internal_cmd, @@ -588,7 +586,7 @@ static int sil24_init_port(struct ata_port *ap) u32 tmp; /* clear PMP error status */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) sil24_clear_pmp(ap); writel(PORT_CS_INIT, port + PORT_CTRL_STAT); @@ -653,10 +651,11 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, return rc; } -static int sil24_do_softreset(struct ata_link *link, unsigned int *class, - int pmp, unsigned long deadline) +static int sil24_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { struct ata_port *ap = link->ap; + int pmp = sata_srst_pmp(link); unsigned long timeout_msec = 0; struct ata_taskfile tf; const char *reason; @@ -706,12 +705,6 @@ static int sil24_do_softreset(struct ata_link *link, unsigned int *class, return -EIO; } -static int sil24_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline); -} - static int sil24_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -926,12 +919,6 @@ static void sil24_pmp_detach(struct ata_port *ap) sil24_config_pmp(ap, 0); } -static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - return sil24_do_softreset(link, class, link->pmp, deadline); -} - static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -1034,7 +1021,7 @@ static void sil24_error_intr(struct ata_port *ap) } /* find out the offending link and qc */ - if (ap->nr_pmp_links) { + if (sata_pmp_attached(ap)) { context = readl(port + PORT_CONTEXT); pmp = (context >> 5) & 0xf; @@ -1082,7 +1069,7 @@ static void sil24_error_intr(struct ata_port *ap) ehi->action |= action; /* if PMP, resume */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT); } diff --git a/include/linux/libata.h b/include/linux/libata.h index eb86d6f39635..1908bf484743 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1089,6 +1089,31 @@ extern const struct ata_port_operations sata_port_ops; ATA_BASE_SHT(drv_name), \ .change_queue_depth = ata_scsi_change_queue_depth +/* + * PMP helpers + */ +static inline bool sata_pmp_supported(struct ata_port *ap) +{ + return ap->flags & ATA_FLAG_PMP; +} + +static inline bool sata_pmp_attached(struct ata_port *ap) +{ + return ap->nr_pmp_links != 0; +} + +static inline int ata_is_host_link(const struct ata_link *link) +{ + return link == &link->ap->link; +} + +static inline int sata_srst_pmp(struct ata_link *link) +{ + if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) + return SATA_PMP_CTRL_PORT; + return link->pmp; +} + /* * printk helpers */ @@ -1096,7 +1121,7 @@ extern const struct ata_port_operations sata_port_ops; printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) #define ata_link_printk(link, lv, fmt, args...) do { \ - if ((link)->ap->nr_pmp_links) \ + if (sata_pmp_attached((link)->ap)) \ printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ (link)->pmp , ##args); \ else \ @@ -1182,11 +1207,6 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) /* * link helpers */ -static inline int ata_is_host_link(const struct ata_link *link) -{ - return link == &link->ap->link; -} - static inline int ata_link_max_devices(const struct ata_link *link) { if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS) @@ -1201,7 +1221,7 @@ static inline int ata_link_active(struct ata_link *link) static inline struct ata_link *ata_port_first_link(struct ata_port *ap) { - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) return ap->pmp_link; return &ap->link; } @@ -1210,8 +1230,8 @@ static inline struct ata_link *ata_port_next_link(struct ata_link *link) { struct ata_port *ap = link->ap; - if (link == &ap->link) { - if (!ap->nr_pmp_links) + if (ata_is_host_link(link)) { + if (!sata_pmp_attached(ap)) return NULL; return ap->pmp_link; } -- cgit v1.2.3 From 88fcd5627563722483427a55113c0a83f56e8080 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Apr 2008 22:47:22 +0900 Subject: libata: make PMP support optional Make PMP support optional by adding CONFIG_SATA_PMP and leaving out libata-pmp.c if it isn't set. PMP helpers return constant values if PMP support is not enabled and PMP declarations alias non-PMP counterparts. This makes the compiler to leave out PMP related part out and LLDs to use non-PMP counterparts automatically. Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 6 ++++++ drivers/ata/Makefile | 3 ++- drivers/ata/libata.h | 17 +++++++++++++++++ include/linux/libata.h | 27 +++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 48c8fc55391e..3eb6035b61b8 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -41,6 +41,12 @@ config ATA_ACPI You can disable this at kernel boot time by using the option libata.noacpi=1 +config SATA_PMP + bool "SATA Port Multiplier support" + default y + help + This option adds support for SATA Port Multipliers. + config SATA_AHCI tristate "AHCI SATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index e6e41b2c731c..1fbc2aa648b7 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-eh.o libata-pmp.o +libata-objs := libata-core.o libata-scsi.o libata-eh.o libata-$(CONFIG_ATA_SFF) += libata-sff.o +libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 42b30e38495d..4aeeabb10a47 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -203,9 +203,26 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, extern void ata_eh_finish(struct ata_port *ap); /* libata-pmp.c */ +#ifdef CONFIG_SATA_PMP extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); extern int sata_pmp_attach(struct ata_device *dev); +#else /* CONFIG_SATA_PMP */ +static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val) +{ + return -EINVAL; +} + +static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) +{ + return -EINVAL; +} + +static inline int sata_pmp_attach(struct ata_device *dev) +{ + return -EINVAL; +} +#endif /* CONFIG_SATA_PMP */ /* libata-sff.c */ #ifdef CONFIG_ATA_SFF diff --git a/include/linux/libata.h b/include/linux/libata.h index 1908bf484743..165734a2dd47 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1092,6 +1092,7 @@ extern const struct ata_port_operations sata_port_ops; /* * PMP helpers */ +#ifdef CONFIG_SATA_PMP static inline bool sata_pmp_supported(struct ata_port *ap) { return ap->flags & ATA_FLAG_PMP; @@ -1106,6 +1107,22 @@ static inline int ata_is_host_link(const struct ata_link *link) { return link == &link->ap->link; } +#else /* CONFIG_SATA_PMP */ +static inline bool sata_pmp_supported(struct ata_port *ap) +{ + return false; +} + +static inline bool sata_pmp_attached(struct ata_port *ap) +{ + return false; +} + +static inline int ata_is_host_link(const struct ata_link *link) +{ + return 1; +} +#endif /* CONFIG_SATA_PMP */ static inline int sata_srst_pmp(struct ata_link *link) { @@ -1369,11 +1386,21 @@ static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) /************************************************************************** * PMP - drivers/ata/libata-pmp.c */ +#ifdef CONFIG_SATA_PMP + extern const struct ata_port_operations sata_pmp_port_ops; extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); extern void sata_pmp_error_handler(struct ata_port *ap); +#else /* CONFIG_SATA_PMP */ + +#define sata_pmp_port_ops sata_port_ops +#define sata_pmp_qc_defer_cmd_switch ata_std_qc_defer +#define sata_pmp_error_handler ata_std_error_handler + +#endif /* CONFIG_SATA_PMP */ + /************************************************************************** * SFF - drivers/ata/libata-sff.c -- cgit v1.2.3 From 19242d7233df7d658405d4b7ee1758d21414cfaa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:25 -0700 Subject: async_tx: fix multiple dependency submission Shrink struct dma_async_tx_descriptor and introduce async_tx_channel_switch to properly inject a channel switch interrupt in the descriptor stream. This simplifies the locking model as drivers no longer need to handle dma_async_tx_descriptor.lock. Acked-by: Shannon Nelson Signed-off-by: Dan Williams --- crypto/async_tx/async_tx.c | 197 +++++++++++++++++++++++++++++++++++++-------- drivers/dma/dmaengine.c | 2 - drivers/dma/iop-adma.c | 9 ++- include/linux/dmaengine.h | 9 +-- 4 files changed, 170 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index 2be3bae89930..69756164b61d 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c @@ -89,13 +89,19 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) iter = tx; /* find the root of the unsubmitted dependency chain */ - while (iter->cookie == -EBUSY) { + do { parent = iter->parent; - if (parent && parent->cookie == -EBUSY) - iter = iter->parent; - else + if (!parent) break; - } + else + iter = parent; + } while (parent); + + /* there is a small window for ->parent == NULL and + * ->cookie == -EBUSY + */ + while (iter->cookie == -EBUSY) + cpu_relax(); status = dma_sync_wait(iter->chan, iter->cookie); } while (status == DMA_IN_PROGRESS || (iter != tx)); @@ -111,24 +117,33 @@ EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx) { - struct dma_async_tx_descriptor *dep_tx, *_dep_tx; - struct dma_device *dev; + struct dma_async_tx_descriptor *next = tx->next; struct dma_chan *chan; - list_for_each_entry_safe(dep_tx, _dep_tx, &tx->depend_list, - depend_node) { - chan = dep_tx->chan; - dev = chan->device; - /* we can't depend on ourselves */ - BUG_ON(chan == tx->chan); - list_del(&dep_tx->depend_node); - tx->tx_submit(dep_tx); - - /* we need to poke the engine as client code does not - * know about dependency submission events - */ - dev->device_issue_pending(chan); + if (!next) + return; + + tx->next = NULL; + chan = next->chan; + + /* keep submitting up until a channel switch is detected + * in that case we will be called again as a result of + * processing the interrupt from async_tx_channel_switch + */ + while (next && next->chan == chan) { + struct dma_async_tx_descriptor *_next; + + spin_lock_bh(&next->lock); + next->parent = NULL; + _next = next->next; + next->next = NULL; + spin_unlock_bh(&next->lock); + + next->tx_submit(next); + next = _next; } + + chan->device->device_issue_pending(chan); } EXPORT_SYMBOL_GPL(async_tx_run_dependencies); @@ -397,6 +412,92 @@ static void __exit async_tx_exit(void) } #endif + +/** + * async_tx_channel_switch - queue an interrupt descriptor with a dependency + * pre-attached. + * @depend_tx: the operation that must finish before the new operation runs + * @tx: the new operation + */ +static void +async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, + struct dma_async_tx_descriptor *tx) +{ + struct dma_chan *chan; + struct dma_device *device; + struct dma_async_tx_descriptor *intr_tx = (void *) ~0; + + /* first check to see if we can still append to depend_tx */ + spin_lock_bh(&depend_tx->lock); + if (depend_tx->parent && depend_tx->chan == tx->chan) { + tx->parent = depend_tx; + depend_tx->next = tx; + intr_tx = NULL; + } + spin_unlock_bh(&depend_tx->lock); + + if (!intr_tx) + return; + + chan = depend_tx->chan; + device = chan->device; + + /* see if we can schedule an interrupt + * otherwise poll for completion + */ + if (dma_has_cap(DMA_INTERRUPT, device->cap_mask)) + intr_tx = device->device_prep_dma_interrupt(chan); + else + intr_tx = NULL; + + if (intr_tx) { + intr_tx->callback = NULL; + intr_tx->callback_param = NULL; + tx->parent = intr_tx; + /* safe to set ->next outside the lock since we know we are + * not submitted yet + */ + intr_tx->next = tx; + + /* check if we need to append */ + spin_lock_bh(&depend_tx->lock); + if (depend_tx->parent) { + intr_tx->parent = depend_tx; + depend_tx->next = intr_tx; + async_tx_ack(intr_tx); + intr_tx = NULL; + } + spin_unlock_bh(&depend_tx->lock); + + if (intr_tx) { + intr_tx->parent = NULL; + intr_tx->tx_submit(intr_tx); + async_tx_ack(intr_tx); + } + } else { + if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) + panic("%s: DMA_ERROR waiting for depend_tx\n", + __func__); + tx->tx_submit(tx); + } +} + + +/** + * submit_disposition - while holding depend_tx->lock we must avoid submitting + * new operations to prevent a circular locking dependency with + * drivers that already hold a channel lock when calling + * async_tx_run_dependencies. + * @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock + * @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch + * @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly + */ +enum submit_disposition { + ASYNC_TX_SUBMITTED, + ASYNC_TX_CHANNEL_SWITCH, + ASYNC_TX_DIRECT_SUBMIT, +}; + void async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx, @@ -405,28 +506,54 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, tx->callback = cb_fn; tx->callback_param = cb_param; - /* set this new tx to run after depend_tx if: - * 1/ a dependency exists (depend_tx is !NULL) - * 2/ the tx can not be submitted to the current channel - */ - if (depend_tx && depend_tx->chan != chan) { - /* if ack is already set then we cannot be sure + if (depend_tx) { + enum submit_disposition s; + + /* sanity check the dependency chain: + * 1/ if ack is already set then we cannot be sure * we are referring to the correct operation + * 2/ dependencies are 1:1 i.e. two transactions can + * not depend on the same parent */ - BUG_ON(depend_tx->ack); + BUG_ON(depend_tx->ack || depend_tx->next || tx->parent); - tx->parent = depend_tx; + /* the lock prevents async_tx_run_dependencies from missing + * the setting of ->next when ->parent != NULL + */ spin_lock_bh(&depend_tx->lock); - list_add_tail(&tx->depend_node, &depend_tx->depend_list); - if (depend_tx->cookie == 0) { - struct dma_chan *dep_chan = depend_tx->chan; - struct dma_device *dep_dev = dep_chan->device; - dep_dev->device_dependency_added(dep_chan); + if (depend_tx->parent) { + /* we have a parent so we can not submit directly + * if we are staying on the same channel: append + * else: channel switch + */ + if (depend_tx->chan == chan) { + tx->parent = depend_tx; + depend_tx->next = tx; + s = ASYNC_TX_SUBMITTED; + } else + s = ASYNC_TX_CHANNEL_SWITCH; + } else { + /* we do not have a parent so we may be able to submit + * directly if we are staying on the same channel + */ + if (depend_tx->chan == chan) + s = ASYNC_TX_DIRECT_SUBMIT; + else + s = ASYNC_TX_CHANNEL_SWITCH; } spin_unlock_bh(&depend_tx->lock); - /* schedule an interrupt to trigger the channel switch */ - async_trigger_callback(ASYNC_TX_ACK, depend_tx, NULL, NULL); + switch (s) { + case ASYNC_TX_SUBMITTED: + break; + case ASYNC_TX_CHANNEL_SWITCH: + async_tx_channel_switch(depend_tx, tx); + break; + case ASYNC_TX_DIRECT_SUBMIT: + tx->parent = NULL; + tx->tx_submit(tx); + break; + } } else { tx->parent = NULL; tx->tx_submit(tx); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 8db0e7f9d3f4..9cb898a76bb3 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -600,8 +600,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, { tx->chan = chan; spin_lock_init(&tx->lock); - INIT_LIST_HEAD(&tx->depend_node); - INIT_LIST_HEAD(&tx->depend_list); } EXPORT_SYMBOL(dma_async_tx_descriptor_init); diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index f82b0906d466..21854cd7190f 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -63,7 +63,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, struct iop_adma_chan *iop_chan, dma_cookie_t cookie) { BUG_ON(desc->async_tx.cookie < 0); - spin_lock_bh(&desc->async_tx.lock); if (desc->async_tx.cookie > 0) { cookie = desc->async_tx.cookie; desc->async_tx.cookie = 0; @@ -101,7 +100,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, /* run dependent operations */ async_tx_run_dependencies(&desc->async_tx); - spin_unlock_bh(&desc->async_tx.lock); return cookie; } @@ -275,8 +273,11 @@ iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) static void iop_adma_tasklet(unsigned long data) { - struct iop_adma_chan *chan = (struct iop_adma_chan *) data; - __iop_adma_slot_cleanup(chan); + struct iop_adma_chan *iop_chan = (struct iop_adma_chan *) data; + + spin_lock(&iop_chan->lock); + __iop_adma_slot_cleanup(iop_chan); + spin_unlock(&iop_chan->lock); } static struct iop_adma_desc_slot * diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 34d440698293..91252a7e4d03 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -221,11 +221,9 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); * @callback: routine to call after this operation is complete * @callback_param: general parameter to pass to the callback routine * ---async_tx api specific fields--- - * @depend_list: at completion this list of transactions are submitted - * @depend_node: allow this transaction to be executed after another - * transaction has completed, possibly on another channel + * @next: at completion submit this descriptor * @parent: pointer to the next level up in the dependency chain - * @lock: protect the dependency list + * @lock: protect the parent and next pointers */ struct dma_async_tx_descriptor { dma_cookie_t cookie; @@ -236,8 +234,7 @@ struct dma_async_tx_descriptor { dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); dma_async_tx_callback callback; void *callback_param; - struct list_head depend_list; - struct list_head depend_node; + struct dma_async_tx_descriptor *next; struct dma_async_tx_descriptor *parent; spinlock_t lock; }; -- cgit v1.2.3 From ce4d65a5db77e1568c82d5151a746f627c4f6ed5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:26 -0700 Subject: async_tx: kill ->device_dependency_added DMA drivers no longer need to be notified of dependency submission events as async_tx_run_dependencies and async_tx_channel_switch will handle the scheduling and execution of dependent operations. [sfr@canb.auug.org.au: extend this for fsldma] Acked-by: Shannon Nelson Signed-off-by: Dan Williams --- drivers/dma/dmaengine.c | 1 - drivers/dma/fsldma.c | 8 -------- drivers/dma/ioat_dma.c | 12 ------------ drivers/dma/iop-adma.c | 7 ------- include/linux/dmaengine.h | 2 -- 5 files changed, 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 9cb898a76bb3..af6911a75dae 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -362,7 +362,6 @@ int dma_async_device_register(struct dma_device *device) BUG_ON(!device->device_alloc_chan_resources); BUG_ON(!device->device_free_chan_resources); - BUG_ON(!device->device_dependency_added); BUG_ON(!device->device_is_tx_complete); BUG_ON(!device->device_issue_pending); BUG_ON(!device->dev); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index d8ae18dbf1a7..95b36b7934a5 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -658,13 +658,6 @@ static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan) fsl_chan_xfer_ld_queue(fsl_chan); } -static void fsl_dma_dependency_added(struct dma_chan *chan) -{ - struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); - - fsl_chan_ld_cleanup(fsl_chan); -} - /** * fsl_dma_is_complete - Determine the DMA status * @fsl_chan : Freescale DMA channel @@ -1089,7 +1082,6 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; fdev->common.device_is_tx_complete = fsl_dma_is_complete; fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; - fdev->common.device_dependency_added = fsl_dma_dependency_added; fdev->common.dev = &dev->dev; irq = irq_of_parse_and_map(dev->node, 0); diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index 4017d9e7acd2..1517fe4e2d14 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -924,17 +924,6 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) spin_unlock_bh(&ioat_chan->cleanup_lock); } -static void ioat_dma_dependency_added(struct dma_chan *chan) -{ - struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); - spin_lock_bh(&ioat_chan->desc_lock); - if (ioat_chan->pending == 0) { - spin_unlock_bh(&ioat_chan->desc_lock); - ioat_dma_memcpy_cleanup(ioat_chan); - } else - spin_unlock_bh(&ioat_chan->desc_lock); -} - /** * ioat_dma_is_complete - poll the status of a IOAT DMA transaction * @chan: IOAT DMA channel handle @@ -1316,7 +1305,6 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, dma_cap_set(DMA_MEMCPY, device->common.cap_mask); device->common.device_is_tx_complete = ioat_dma_is_complete; - device->common.device_dependency_added = ioat_dma_dependency_added; switch (device->version) { case IOAT_VER_1_2: device->common.device_prep_dma_memcpy = ioat1_dma_prep_memcpy; diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 21854cd7190f..2aa3df50c842 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -672,12 +672,6 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, return sw_desc ? &sw_desc->async_tx : NULL; } -static void iop_adma_dependency_added(struct dma_chan *chan) -{ - struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); - tasklet_schedule(&iop_chan->irq_tasklet); -} - static void iop_adma_free_chan_resources(struct dma_chan *chan) { struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); @@ -1178,7 +1172,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) dma_dev->device_free_chan_resources = iop_adma_free_chan_resources; dma_dev->device_is_tx_complete = iop_adma_is_complete; dma_dev->device_issue_pending = iop_adma_issue_pending; - dma_dev->device_dependency_added = iop_adma_dependency_added; dma_dev->dev = &pdev->dev; /* set prep routines based on capability */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 91252a7e4d03..cd34df78c6aa 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -258,7 +258,6 @@ struct dma_async_tx_descriptor { * @device_prep_dma_zero_sum: prepares a zero_sum operation * @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation - * @device_dependency_added: async_tx notifies the channel about new deps * @device_issue_pending: push pending transactions to hardware */ struct dma_device { @@ -293,7 +292,6 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan); - void (*device_dependency_added)(struct dma_chan *chan); enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used); -- cgit v1.2.3 From 636bdeaa1243327501edfd2a597ed7443eb4239a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:26 -0700 Subject: dmaengine: ack to flags: make use of the unused bits in the 'ack' field 'ack' is currently a simple integer that flags whether or not a client is done touching fields in the given descriptor. It is effectively just a single bit of information. Converting this to a flags parameter allows the other bits to be put to use to control completion actions, like dma-unmap, and capture results, like xor-zero-sum == 0. Changes are one of: 1/ convert all open-coded ->ack manipulations to use async_tx_ack and async_tx_test_ack. 2/ set the ack bit at prep time where possible 3/ make drivers store the flags at prep time 4/ add flags to the device_prep_dma_interrupt prototype Acked-by: Maciej Sosnowski Signed-off-by: Dan Williams --- crypto/async_tx/async_memcpy.c | 2 +- crypto/async_tx/async_tx.c | 9 +++++---- crypto/async_tx/async_xor.c | 2 +- drivers/dma/dmaengine.c | 12 ++++++------ drivers/dma/fsldma.c | 10 +++++----- drivers/dma/ioat_dma.c | 24 ++++++++++++------------ drivers/dma/iop-adma.c | 39 +++++++++++++++++++++------------------ include/linux/dmaengine.h | 25 ++++++++++++++++++------- 8 files changed, 69 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c index 84caa4efc0d4..a5eda80e8427 100644 --- a/crypto/async_tx/async_memcpy.c +++ b/crypto/async_tx/async_memcpy.c @@ -77,7 +77,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, /* if ack is already set then we cannot be sure * we are referring to the correct operation */ - BUG_ON(depend_tx->ack); + BUG_ON(async_tx_test_ack(depend_tx)); if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) panic("%s: DMA_ERROR waiting for depend_tx\n", __func__); diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index 69756164b61d..c6e772fc5ccd 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c @@ -446,7 +446,7 @@ async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, * otherwise poll for completion */ if (dma_has_cap(DMA_INTERRUPT, device->cap_mask)) - intr_tx = device->device_prep_dma_interrupt(chan); + intr_tx = device->device_prep_dma_interrupt(chan, 0); else intr_tx = NULL; @@ -515,7 +515,8 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, * 2/ dependencies are 1:1 i.e. two transactions can * not depend on the same parent */ - BUG_ON(depend_tx->ack || depend_tx->next || tx->parent); + BUG_ON(async_tx_test_ack(depend_tx) || depend_tx->next || + tx->parent); /* the lock prevents async_tx_run_dependencies from missing * the setting of ->next when ->parent != NULL @@ -594,7 +595,7 @@ async_trigger_callback(enum async_tx_flags flags, if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask)) device = NULL; - tx = device ? device->device_prep_dma_interrupt(chan) : NULL; + tx = device ? device->device_prep_dma_interrupt(chan, 0) : NULL; } else tx = NULL; @@ -610,7 +611,7 @@ async_trigger_callback(enum async_tx_flags flags, /* if ack is already set then we cannot be sure * we are referring to the correct operation */ - BUG_ON(depend_tx->ack); + BUG_ON(async_tx_test_ack(depend_tx)); if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) panic("%s: DMA_ERROR waiting for depend_tx\n", __func__); diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c index 1c445c7bdab7..3a0dddca5a10 100644 --- a/crypto/async_tx/async_xor.c +++ b/crypto/async_tx/async_xor.c @@ -191,7 +191,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, /* if ack is already set then we cannot be sure * we are referring to the correct operation */ - BUG_ON(depend_tx->ack); + BUG_ON(async_tx_test_ack(depend_tx)); if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) panic("%s: DMA_ERROR waiting for " diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index af6911a75dae..d6dc70fd7527 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -478,7 +478,8 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE); dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE); - tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); + tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, + DMA_CTRL_ACK); if (!tx) { dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE); @@ -486,7 +487,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, return -ENOMEM; } - tx->ack = 1; tx->callback = NULL; cookie = tx->tx_submit(tx); @@ -524,7 +524,8 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page, dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE); dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE); - tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); + tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, + DMA_CTRL_ACK); if (!tx) { dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE); @@ -532,7 +533,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page, return -ENOMEM; } - tx->ack = 1; tx->callback = NULL; cookie = tx->tx_submit(tx); @@ -573,7 +573,8 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE); dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE); - tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); + tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, + DMA_CTRL_ACK); if (!tx) { dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE); @@ -581,7 +582,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, return -ENOMEM; } - tx->ack = 1; tx->callback = NULL; cookie = tx->tx_submit(tx); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 95b36b7934a5..054eabffc185 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -412,7 +412,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan) } static struct dma_async_tx_descriptor * -fsl_dma_prep_interrupt(struct dma_chan *chan) +fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags) { struct fsl_dma_chan *fsl_chan; struct fsl_desc_sw *new; @@ -429,7 +429,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan) } new->async_tx.cookie = -EBUSY; - new->async_tx.ack = 0; + new->async_tx.flags = flags; /* Insert the link descriptor to the LD ring */ list_add_tail(&new->node, &new->async_tx.tx_list); @@ -482,7 +482,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys); new->async_tx.cookie = 0; - new->async_tx.ack = 1; + async_tx_ack(&new->async_tx); prev = new; len -= copy; @@ -493,7 +493,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( list_add_tail(&new->node, &first->async_tx.tx_list); } while (len); - new->async_tx.ack = 0; /* client is in control of this ack */ + new->async_tx.flags = flags; /* client is in control of this ack */ new->async_tx.cookie = -EBUSY; /* Set End-of-link to the last link descriptor of new list*/ @@ -874,7 +874,7 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) async_tx_ack(tx3); /* Interrupt tx test */ - tx1 = fsl_dma_prep_interrupt(chan); + tx1 = fsl_dma_prep_interrupt(chan, 0); async_tx_ack(tx1); cookie = fsl_dma_tx_submit(tx1); diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index 1517fe4e2d14..318e8a22d814 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -212,14 +212,14 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) u32 copy; size_t len; dma_addr_t src, dst; - int orig_ack; + unsigned long orig_flags; unsigned int desc_count = 0; /* src and dest and len are stored in the initial descriptor */ len = first->len; src = first->src; dst = first->dst; - orig_ack = first->async_tx.ack; + orig_flags = first->async_tx.flags; new = first; spin_lock_bh(&ioat_chan->desc_lock); @@ -228,7 +228,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) do { copy = min_t(size_t, len, ioat_chan->xfercap); - new->async_tx.ack = 1; + async_tx_ack(&new->async_tx); hw = new->hw; hw->size = copy; @@ -264,7 +264,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) } new->tx_cnt = desc_count; - new->async_tx.ack = orig_ack; /* client is in control of this ack */ + new->async_tx.flags = orig_flags; /* client is in control of this ack */ /* store the original values for use in later cleanup */ if (new != first) { @@ -304,14 +304,14 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) u32 copy; size_t len; dma_addr_t src, dst; - int orig_ack; + unsigned long orig_flags; unsigned int desc_count = 0; /* src and dest and len are stored in the initial descriptor */ len = first->len; src = first->src; dst = first->dst; - orig_ack = first->async_tx.ack; + orig_flags = first->async_tx.flags; new = first; /* @@ -321,7 +321,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) do { copy = min_t(size_t, len, ioat_chan->xfercap); - new->async_tx.ack = 1; + async_tx_ack(&new->async_tx); hw = new->hw; hw->size = copy; @@ -349,7 +349,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) } new->tx_cnt = desc_count; - new->async_tx.ack = orig_ack; /* client is in control of this ack */ + new->async_tx.flags = orig_flags; /* client is in control of this ack */ /* store the original values for use in later cleanup */ if (new != first) { @@ -714,7 +714,7 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy( new->len = len; new->dst = dma_dest; new->src = dma_src; - new->async_tx.ack = 0; + new->async_tx.flags = flags; return &new->async_tx; } else return NULL; @@ -742,7 +742,7 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy( new->len = len; new->dst = dma_dest; new->src = dma_src; - new->async_tx.ack = 0; + new->async_tx.flags = flags; return &new->async_tx; } else return NULL; @@ -842,7 +842,7 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) * a completed entry, but not the last, so clean * up if the client is done with the descriptor */ - if (desc->async_tx.ack) { + if (async_tx_test_ack(&desc->async_tx)) { list_del(&desc->node); list_add_tail(&desc->node, &ioat_chan->free_desc); @@ -979,7 +979,7 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) desc->hw->size = 0; desc->hw->src_addr = 0; desc->hw->dst_addr = 0; - desc->async_tx.ack = 1; + async_tx_ack(&desc->async_tx); switch (ioat_chan->device->version) { case IOAT_VER_1_2: desc->hw->next = 0; diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 93252294f32b..762b729672e0 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -111,7 +111,7 @@ iop_adma_clean_slot(struct iop_adma_desc_slot *desc, /* the client is allowed to attach dependent operations * until 'ack' is set */ - if (!desc->async_tx.ack) + if (!async_tx_test_ack(&desc->async_tx)) return 0; /* leave the last descriptor in the chain @@ -148,7 +148,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) "this_desc: %#x next_desc: %#x ack: %d\n", iter->async_tx.cookie, iter->idx, busy, iter->async_tx.phys, iop_desc_get_next_desc(iter), - iter->async_tx.ack); + async_tx_test_ack(&iter->async_tx)); prefetch(_iter); prefetch(&_iter->async_tx); @@ -338,9 +338,7 @@ retry: /* pre-ack all but the last descriptor */ if (num_slots != slots_per_op) - iter->async_tx.ack = 1; - else - iter->async_tx.ack = 0; + async_tx_ack(&iter->async_tx); list_add_tail(&iter->chain_node, &chain); alloc_tail = iter; @@ -513,7 +511,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan) } static struct dma_async_tx_descriptor * -iop_adma_prep_dma_interrupt(struct dma_chan *chan) +iop_adma_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags) { struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); struct iop_adma_desc_slot *sw_desc, *grp_start; @@ -528,6 +526,7 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan) grp_start = sw_desc->group_head; iop_desc_init_interrupt(grp_start, iop_chan); grp_start->unmap_len = 0; + sw_desc->async_tx.flags = flags; } spin_unlock_bh(&iop_chan->lock); @@ -560,6 +559,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest, iop_desc_set_memcpy_src_addr(grp_start, dma_src); sw_desc->unmap_src_cnt = 1; sw_desc->unmap_len = len; + sw_desc->async_tx.flags = flags; } spin_unlock_bh(&iop_chan->lock); @@ -592,6 +592,7 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest, iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest); sw_desc->unmap_src_cnt = 1; sw_desc->unmap_len = len; + sw_desc->async_tx.flags = flags; } spin_unlock_bh(&iop_chan->lock); @@ -625,6 +626,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest, iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest); sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_len = len; + sw_desc->async_tx.flags = flags; while (src_cnt--) iop_desc_set_xor_src_addr(grp_start, src_cnt, dma_src[src_cnt]); @@ -661,6 +663,7 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, __func__, grp_start->xor_check_result); sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_len = len; + sw_desc->async_tx.flags = flags; while (src_cnt--) iop_desc_set_zero_sum_src_addr(grp_start, src_cnt, dma_src[src_cnt]); @@ -847,11 +850,11 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) src_dma = dma_map_single(dma_chan->device->dev, src, IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE); tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma, - IOP_ADMA_TEST_SIZE, 1); + IOP_ADMA_TEST_SIZE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); cookie = iop_adma_tx_submit(tx); iop_adma_issue_pending(dma_chan); - async_tx_ack(tx); msleep(1); if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != @@ -947,11 +950,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs, - IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, 1); + IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); cookie = iop_adma_tx_submit(tx); iop_adma_issue_pending(dma_chan); - async_tx_ack(tx); msleep(8); if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != @@ -994,11 +997,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) DMA_TO_DEVICE); tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs, IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE, - &zero_sum_result, 1); + &zero_sum_result, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); cookie = iop_adma_tx_submit(tx); iop_adma_issue_pending(dma_chan); - async_tx_ack(tx); msleep(8); if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { @@ -1018,11 +1021,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) /* test memset */ dma_addr = dma_map_page(dma_chan->device->dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE); - tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, 1); + tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); cookie = iop_adma_tx_submit(tx); iop_adma_issue_pending(dma_chan); - async_tx_ack(tx); msleep(8); if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { @@ -1050,11 +1053,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) DMA_TO_DEVICE); tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs, IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE, - &zero_sum_result, 1); + &zero_sum_result, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); cookie = iop_adma_tx_submit(tx); iop_adma_issue_pending(dma_chan); - async_tx_ack(tx); msleep(8); if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { @@ -1287,7 +1290,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan) grp_start = sw_desc->group_head; list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); - sw_desc->async_tx.ack = 1; + async_tx_ack(&sw_desc->async_tx); iop_desc_init_memcpy(grp_start, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0); iop_desc_set_dest_addr(grp_start, iop_chan, 0); @@ -1343,7 +1346,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) if (sw_desc) { grp_start = sw_desc->group_head; list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); - sw_desc->async_tx.ack = 1; + async_tx_ack(&sw_desc->async_tx); iop_desc_init_null_xor(grp_start, 2, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0); iop_desc_set_dest_addr(grp_start, iop_chan, 0); diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index cd34df78c6aa..b4d84ed6187d 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -95,12 +95,17 @@ enum dma_transaction_type { #define DMA_TX_TYPE_END (DMA_INTERRUPT + 1) /** - * enum dma_prep_flags - DMA flags to augment operation preparation + * enum dma_ctrl_flags - DMA flags to augment operation preparation, + * control completion, and communicate status. * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of * this transaction + * @DMA_CTRL_ACK - the descriptor cannot be reused until the client + * acknowledges receipt, i.e. has has a chance to establish any + * dependency chains */ -enum dma_prep_flags { +enum dma_ctrl_flags { DMA_PREP_INTERRUPT = (1 << 0), + DMA_CTRL_ACK = (1 << 1), }; /** @@ -211,8 +216,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); * ---dma generic offload fields--- * @cookie: tracking cookie for this transaction, set to -EBUSY if * this tx is sitting on a dependency list - * @ack: the descriptor can not be reused until the client acknowledges - * receipt, i.e. has has a chance to establish any dependency chains + * @flags: flags to augment operation preparation, control completion, and + * communicate status * @phys: physical address of the descriptor * @tx_list: driver common field for operations that require multiple * descriptors @@ -227,7 +232,7 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); */ struct dma_async_tx_descriptor { dma_cookie_t cookie; - int ack; + enum dma_ctrl_flags flags; /* not a 'long' to pack with cookie */ dma_addr_t phys; struct list_head tx_list; struct dma_chan *chan; @@ -290,7 +295,7 @@ struct dma_device { struct dma_chan *chan, dma_addr_t dest, int value, size_t len, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( - struct dma_chan *chan); + struct dma_chan *chan, unsigned long flags); enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t *last, @@ -316,7 +321,13 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, static inline void async_tx_ack(struct dma_async_tx_descriptor *tx) { - tx->ack = 1; + tx->flags |= DMA_CTRL_ACK; +} + +static inline int +async_tx_test_ack(struct dma_async_tx_descriptor *tx) +{ + return tx->flags & DMA_CTRL_ACK; } #define first_dma_cap(mask) __first_dma_cap(&(mask)) -- cgit v1.2.3 From a594eeb1a1d320981fccc29584b6f21fcebd765f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 18 Apr 2008 00:46:20 +0200 Subject: IDE: remove ide=reverse IDE core This option is obsolete and can be removed safely. It allows us to remove the pci_get_device_reverse() function from the PCI core. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Bartlomiej Zolnierkiewicz --- Documentation/ide/ide.txt | 2 -- Documentation/kernel-parameters.txt | 2 +- drivers/ide/Kconfig | 9 +-------- drivers/ide/ide-scan-pci.c | 9 ++------- drivers/ide/ide.c | 12 ------------ include/linux/ide.h | 1 - 6 files changed, 4 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt index 818676aad45a..ce7c01af30f6 100644 --- a/Documentation/ide/ide.txt +++ b/Documentation/ide/ide.txt @@ -269,8 +269,6 @@ Summary of ide driver parameters for kernel command line ability to bit test for detection is currently unknown. - "ide=reverse" : formerly called to pci sub-system, but now local. - "ide=doubler" : probe/support IDE doublers on Amiga There may be more options than shown -- use the source, Luke! diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dafd001bf833..228d85a3f319 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -763,7 +763,7 @@ and is between 256 and 4096 characters. It is defined in the file Format: [,[,[,]]] ide= [HW] (E)IDE subsystem - Format: ide=nodma or ide=doubler or ide=reverse + Format: ide=nodma or ide=doubler See Documentation/ide/ide.txt. ide?= [HW] (E)IDE subsystem diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index eed6d8e1b5c7..ac5875783430 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -416,12 +416,6 @@ config BLK_DEV_OFFBOARD This can improve the usability of some boot managers such as lilo when booting from a drive on an off-board controller. - If you say Y here, and you actually want to reverse the device scan - order as explained above, you also need to issue the kernel command - line option "ide=reverse". (Try "man bootparam" or see the - documentation of your boot loader (lilo or loadlin) about how to - pass options to the kernel at boot time.) - Note that, if you do this, the order of the hd* devices will be rearranged which may require modification of fstab and other files. @@ -615,8 +609,7 @@ config BLK_DEV_HPT366 reference to device 0x80. The other solution is to say Y to "Boot off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless your mother board has the chipset natively mounted. Regardless one - should use the fore mentioned option and call at LILO or include - "ide=reverse" in LILO's append-line. + should use the fore mentioned option and call at LILO. This driver requires dynamic tuning of the chipset during the ide-probe at boot. It is reported to support DVD II drives, by the diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c index 93d2e41be853..98888da1b600 100644 --- a/drivers/ide/ide-scan-pci.c +++ b/drivers/ide/ide-scan-pci.c @@ -88,13 +88,8 @@ static int __init ide_scan_pcibus(void) struct list_head *l, *n; pre_init = 0; - if (!ide_scan_direction) - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) - ide_scan_pcidev(dev); - else - while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, - dev))) - ide_scan_pcidev(dev); + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) + ide_scan_pcidev(dev); /* * Hand the drivers over to the PCI layer now we diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index fc69fe2e3ec0..5f545153391a 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -90,10 +90,6 @@ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ DEFINE_MUTEX(ide_cfg_mtx); __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock); -#ifdef CONFIG_IDEPCI_PCIBUS_ORDER -int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ -#endif - int noautodma = 0; #ifdef CONFIG_BLK_DEV_IDEACPI @@ -1217,14 +1213,6 @@ static int __init ide_setup(char *s) goto obsolete_option; } -#ifdef CONFIG_IDEPCI_PCIBUS_ORDER - if (!strcmp(s, "ide=reverse")) { - ide_scan_direction = 1; - printk(" : Enabled support for IDE inverse scan order.\n"); - goto obsolete_option; - } -#endif - #ifdef CONFIG_BLK_DEV_IDEACPI if (!strcmp(s, "ide=noacpi")) { //printk(" : Disable IDE ACPI support.\n"); diff --git a/include/linux/ide.h b/include/linux/ide.h index bc26b2f27359..43d2968a4e13 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -990,7 +990,6 @@ extern void do_ide_request(struct request_queue *); void ide_init_disk(struct gendisk *, ide_drive_t *); #ifdef CONFIG_IDEPCI_PCIBUS_ORDER -extern int ide_scan_direction; extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name); #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME) #else -- cgit v1.2.3 From 4f0eee4d877e3b617b6a22d209d52b3dfca2b2a7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:21 +0200 Subject: ide: use ide_find_port() instead of ide_deprecated_find_port() * Use ide_find_port() instead of ide_deprecated_find_port() in bast-ide/ palm_bk3710/ide-cs/delkin_cb host drivers and in ide_register_hw(). * Remove no longer needed ide_deprecated_find_port(). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/bast-ide.c | 2 +- drivers/ide/arm/palm_bk3710.c | 2 +- drivers/ide/ide.c | 27 +-------------------------- drivers/ide/legacy/ide-cs.c | 2 +- drivers/ide/pci/delkin_cb.c | 2 +- include/linux/ide.h | 1 - 6 files changed, 5 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index 161d30c8481e..a22da7ab2b57 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -41,7 +41,7 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq) hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20); hw.irq = irq; - hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) goto out; diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index 8e1f6bd33887..0a722503c102 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -378,7 +378,7 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev) hw.irq = irq->start; hw.chipset = ide_palm3710; - hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) goto out; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 67ce697a9d51..bd5ff7d987d0 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -618,31 +618,6 @@ void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) } EXPORT_SYMBOL_GPL(ide_init_port_hw); -ide_hwif_t *ide_deprecated_find_port(unsigned long base) -{ - ide_hwif_t *hwif; - int i; - - for (i = 0; i < MAX_HWIFS; i++) { - hwif = &ide_hwifs[i]; - if (hwif->io_ports[IDE_DATA_OFFSET] == base) - goto found; - } - - for (i = 0; i < MAX_HWIFS; i++) { - hwif = &ide_hwifs[i]; - if (hwif->hold) - continue; - if (!hwif->present && hwif->mate == NULL) - goto found; - } - - hwif = NULL; -found: - return hwif; -} -EXPORT_SYMBOL_GPL(ide_deprecated_find_port); - /** * ide_register_hw - register IDE interface * @hw: hardware registers @@ -662,7 +637,7 @@ int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; do { - hwif = ide_deprecated_find_port(hw->io_ports[IDE_DATA_OFFSET]); + hwif = ide_find_port(hw->io_ports[IDE_DATA_OFFSET]); if (hwif) goto found; for (index = 0; index < MAX_HWIFS; index++) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 15ccf6944ae2..de2e5944809e 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -156,7 +156,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq hw.chipset = ide_pci; hw.dev = &handle->dev; - hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) return -1; diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 3f9cd64c26a6..e08e13a0bb6e 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -78,7 +78,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) hw.irq = dev->irq; hw.chipset = ide_pci; /* this enables IRQ sharing */ - hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) goto out_disable; diff --git a/include/linux/ide.h b/include/linux/ide.h index 43d2968a4e13..1b423958a894 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -186,7 +186,6 @@ typedef struct hw_regs_s { } hw_regs_t; struct hwif_s * ide_find_port(unsigned long); -struct hwif_s *ide_deprecated_find_port(unsigned long); void ide_init_port_data(struct hwif_s *, unsigned int); void ide_init_port_hw(struct hwif_s *, hw_regs_t *); -- cgit v1.2.3 From 5b0c4b30a625927340a3e7f565aa4de8b60489cc Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:22 +0200 Subject: ide: remove IDE devices from /proc/ide/ before unregistering them IDE devices need to be removed from /proc/ide/ _before_ being unregistered: * Drop 'ide_hwif_t *hwif' argument from destroy_proc_ide_device() and use drive->hwif instead. * Rename destroy_proc_ide_device() to ide_proc_unregister_device(). * Call ide_proc_unregister_device() in drive_release_dev(). * Remove no longer needed destroy_proc_ide_drives(). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-probe.c | 2 ++ drivers/ide/ide-proc.c | 16 ++-------------- include/linux/ide.h | 2 ++ 3 files changed, 6 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 9db8978ad394..dea314ce33d3 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1199,6 +1199,8 @@ static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); + ide_proc_unregister_device(drive); + spin_lock_irq(&ide_lock); ide_remove_drive_from_hwgroup(drive); kfree(drive->id); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index bab88ca7f7ec..77025d1057b5 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -764,27 +764,16 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif) } } -static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) +void ide_proc_unregister_device(ide_drive_t *drive) { if (drive->proc) { ide_remove_proc_entries(drive->proc, generic_drive_entries); remove_proc_entry(drive->name, proc_ide_root); - remove_proc_entry(drive->name, hwif->proc); + remove_proc_entry(drive->name, drive->hwif->proc); drive->proc = NULL; } } -static void destroy_proc_ide_drives(ide_hwif_t *hwif) -{ - int d; - - for (d = 0; d < MAX_DRIVES; d++) { - ide_drive_t *drive = &hwif->drives[d]; - if (drive->proc) - destroy_proc_ide_device(hwif, drive); - } -} - static ide_proc_entry_t hwif_entries[] = { { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL }, { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL }, @@ -816,7 +805,6 @@ EXPORT_SYMBOL_GPL(ide_pci_create_host_proc); void ide_proc_unregister_port(ide_hwif_t *hwif) { if (hwif->proc) { - destroy_proc_ide_drives(hwif); ide_remove_proc_entries(hwif->proc, hwif_entries); remove_proc_entry(hwif->name, proc_ide_root); hwif->proc = NULL; diff --git a/include/linux/ide.h b/include/linux/ide.h index 1b423958a894..f9449ecd79d9 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -690,6 +690,7 @@ void proc_ide_create(void); void proc_ide_destroy(void); void ide_proc_register_port(ide_hwif_t *); void ide_proc_port_register_devices(ide_hwif_t *); +void ide_proc_unregister_device(ide_drive_t *); void ide_proc_unregister_port(ide_hwif_t *); void ide_proc_register_driver(ide_drive_t *, ide_driver_t *); void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *); @@ -723,6 +724,7 @@ static inline void proc_ide_create(void) { ; } static inline void proc_ide_destroy(void) { ; } static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; } static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; } +static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; } static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; } static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } -- cgit v1.2.3 From 2dde7861afa23cd59db83515cb0b810b92b220aa Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:23 +0200 Subject: ide: rework PowerMac media-bay support (take 2) Rework PowerMac media-bay support in such way that instead of un/registering the IDE interface we un/register IDE devices: * Add ide_port_scan() helper for probing+registerering devices on a port. * Rename ide_port_unregister_devices() to __ide_port_unregister_devices(). * Add ide_port_unregister_devices() helper for unregistering devices on a port. * Add 'ide_hwif_t *cd_port' to 'struct media_bay_info', pass 'hwif' instead of hwif->index to media_bay_set_ide_infos() and use it to setup 'cd_port'. * Use ide_port_unregister_devices() instead of ide_unregister() and ide_port_scan() instead of ide_register_hw() in media_bay_step(). * Unexport ide_register_hw() and make it static. v2: * Fix build by adding include to . (Reported by Michael/Kamalesh/Andrew). Cc: Kamalesh Babulal Cc: Michael Ellerman Cc: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-probe.c | 18 ++++++++++++++++++ drivers/ide/ide.c | 22 ++++++++++++++++------ drivers/ide/ppc/pmac.c | 3 ++- drivers/macintosh/mediabay.c | 17 +++++++---------- include/asm-powerpc/mediabay.h | 6 +++++- include/linux/ide.h | 6 ++---- 6 files changed, 50 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index f3ee098b69c7..468c4ac4181d 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1494,3 +1494,21 @@ int ide_device_add(u8 idx[4], const struct ide_port_info *d) return ide_device_add_all(idx_all, d); } EXPORT_SYMBOL_GPL(ide_device_add); + +void ide_port_scan(ide_hwif_t *hwif) +{ + ide_port_cable_detect(hwif); + ide_port_init_devices(hwif); + + if (ide_probe_port(hwif) < 0) + return; + + hwif->present = 1; + + ide_port_tune_devices(hwif); + ide_acpi_port_init_devices(hwif); + ide_port_setup_devices(hwif); + hwif_register_devices(hwif); + ide_proc_port_register_devices(hwif); +} +EXPORT_SYMBOL_GPL(ide_port_scan); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 47c44d15ad4a..a8b5b08dd6e2 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -502,7 +502,7 @@ void ide_remove_port_from_hwgroup(ide_hwif_t *hwif) } /* Called with ide_lock held. */ -static void ide_port_unregister_devices(ide_hwif_t *hwif) +static void __ide_port_unregister_devices(ide_hwif_t *hwif) { int i; @@ -518,6 +518,18 @@ static void ide_port_unregister_devices(ide_hwif_t *hwif) } } +void ide_port_unregister_devices(ide_hwif_t *hwif) +{ + mutex_lock(&ide_cfg_mtx); + spin_lock_irq(&ide_lock); + __ide_port_unregister_devices(hwif); + hwif->present = 0; + ide_port_init_devices_data(hwif); + spin_unlock_irq(&ide_lock); + mutex_unlock(&ide_cfg_mtx); +} +EXPORT_SYMBOL_GPL(ide_port_unregister_devices); + /** * ide_unregister - free an IDE interface * @index: index of interface (will change soon to a pointer) @@ -558,7 +570,7 @@ void ide_unregister(unsigned int index, int init_default, int restore) hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; - ide_port_unregister_devices(hwif); + __ide_port_unregister_devices(hwif); hwif->present = 0; spin_unlock_irq(&ide_lock); @@ -648,8 +660,8 @@ EXPORT_SYMBOL_GPL(ide_init_port_hw); * Returns -1 on error. */ -int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), - ide_hwif_t **hwifp) +static int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), + ide_hwif_t **hwifp) { int index, retry = 1; ide_hwif_t *hwif; @@ -683,8 +695,6 @@ found: return hwif->present ? index : -1; } -EXPORT_SYMBOL(ide_register_hw); - /* * Locks for IDE setting functionality */ diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index d9ca52e6cdab..7889f5f5c49a 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1088,7 +1088,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { #ifdef CONFIG_PMAC_MEDIABAY - media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index); + media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, + hwif); #endif /* CONFIG_PMAC_MEDIABAY */ pmif->mediabay = 1; if (!bidp) diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index bd8a1d14b45d..82add26cc665 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -79,6 +79,7 @@ struct media_bay_info { int sleeping; struct semaphore lock; #ifdef CONFIG_BLK_DEV_IDE_PMAC + ide_hwif_t *cd_port; void __iomem *cd_base; int cd_irq; int cd_retry; @@ -448,7 +449,7 @@ int check_media_bay_by_base(unsigned long base, int what) } int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, - int irq, int index) + int irq, ide_hwif_t *hwif) { int i; @@ -456,10 +457,11 @@ int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, struct media_bay_info* bay = &media_bays[i]; if (bay->mdev && which_bay == bay->mdev->ofdev.node) { - int timeout = 5000; + int timeout = 5000, index = hwif->index; down(&bay->lock); + bay->cd_port = hwif; bay->cd_base = (void __iomem *) base; bay->cd_irq = irq; @@ -551,15 +553,10 @@ static void media_bay_step(int i) bay->timer = 0; bay->state = mb_up; if (bay->cd_index < 0) { - hw_regs_t hw; - printk("mediabay %d, registering IDE...\n", i); pmu_suspend(); - ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); - hw.irq = bay->cd_irq; - hw.chipset = ide_pmac; - bay->cd_index = - ide_register_hw(&hw, NULL, NULL); + ide_port_scan(bay->cd_port); + bay->cd_index = bay->cd_port->index; pmu_resume(); } if (bay->cd_index == -1) { @@ -589,7 +586,7 @@ static void media_bay_step(int i) if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index, 1, 1); + ide_port_unregister_devices(bay->cd_port); bay->cd_index = -1; } if (bay->cd_retry) { diff --git a/include/asm-powerpc/mediabay.h b/include/asm-powerpc/mediabay.h index de83fe196309..df111c362a7f 100644 --- a/include/asm-powerpc/mediabay.h +++ b/include/asm-powerpc/mediabay.h @@ -22,10 +22,14 @@ int check_media_bay(struct device_node *which_bay, int what); /* Number of bays in the machine or 0 */ extern int media_bay_count; +#ifdef CONFIG_BLK_DEV_IDE_PMAC +#include + int check_media_bay_by_base(unsigned long base, int what); /* called by IDE PMAC host driver to register IDE controller for media bay */ int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base, - int irq, int index); + int irq, ide_hwif_t *hwif); +#endif #endif /* __KERNEL__ */ #endif /* _PPC_MEDIABAY_H */ diff --git a/include/linux/ide.h b/include/linux/ide.h index f9449ecd79d9..9aaad7e70593 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -189,10 +189,6 @@ struct hwif_s * ide_find_port(unsigned long); void ide_init_port_data(struct hwif_s *, unsigned int); void ide_init_port_hw(struct hwif_s *, hw_regs_t *); -struct ide_drive_s; -int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *), - struct hwif_s **); - static inline void ide_std_init_ports(hw_regs_t *hw, unsigned long io_addr, unsigned long ctl_addr) @@ -1204,6 +1200,8 @@ void ide_undecoded_slave(ide_drive_t *); int ide_device_add_all(u8 *idx, const struct ide_port_info *); int ide_device_add(u8 idx[4], const struct ide_port_info *); +void ide_port_unregister_devices(ide_hwif_t *); +void ide_port_scan(ide_hwif_t *); static inline void *ide_get_hwifdata (ide_hwif_t * hwif) { -- cgit v1.2.3 From 50672e5d7486c9ab312432cbe180ac071f1de8e0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:23 +0200 Subject: ide: remove dead/obsolete ->busproc method ->busproc method is used by HDIO_SET_BUSSTATE ioctl but it has no chance of working as intended (in 2.4.x days) because to issue an ioctl there is a device node needed and: - for BUSSTATE_TRISTATE+OFF it is too late (devices are already gone) - for BUSSTATE_TRISTATE+ON it is too early (devices are not registered yet) Just remove ->busproc method for now (it was only implemented by hpt366, siimage and tc86c001 host drivers). Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide.c | 3 --- drivers/ide/pci/hpt366.c | 59 ---------------------------------------------- drivers/ide/pci/sgiioc4.c | 1 - drivers/ide/pci/siimage.c | 43 --------------------------------- drivers/ide/pci/tc86c001.c | 36 ---------------------------- include/linux/ide.h | 2 -- 6 files changed, 144 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index a8b5b08dd6e2..cb18ba8de22d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -414,7 +414,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->resetproc = tmp_hwif->resetproc; hwif->maskproc = tmp_hwif->maskproc; hwif->quirkproc = tmp_hwif->quirkproc; - hwif->busproc = tmp_hwif->busproc; hwif->ata_input_data = tmp_hwif->ata_input_data; hwif->ata_output_data = tmp_hwif->ata_output_data; @@ -1071,8 +1070,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device case HDIO_SET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (HWIF(drive)->busproc) - return HWIF(drive)->busproc(drive, (int)arg); return -EOPNOTSUPP; default: return -EINVAL; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 6357bb6269ab..d03a231d965e 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -929,64 +929,6 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21); } -/* - * Set/get power state for a drive. - * NOTE: affects both drives on each channel. - * - * When we turn the power back on, we need to re-initialize things. - */ -#define TRISTATE_BIT 0x8000 - -static int hpt3xx_busproc(ide_drive_t *drive, int state) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 mcr_addr = hwif->select_data + 2; - u8 resetmask = hwif->channel ? 0x80 : 0x40; - u8 bsr2 = 0; - u16 mcr = 0; - - hwif->bus_state = state; - - /* Grab the status. */ - pci_read_config_word(dev, mcr_addr, &mcr); - pci_read_config_byte(dev, 0x59, &bsr2); - - /* - * Set the state. We don't set it if we don't need to do so. - * Make sure that the drive knows that it has failed if it's off. - */ - switch (state) { - case BUSSTATE_ON: - if (!(bsr2 & resetmask)) - return 0; - hwif->drives[0].failures = hwif->drives[1].failures = 0; - - pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask); - pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT); - return 0; - case BUSSTATE_OFF: - if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT)) - return 0; - mcr &= ~TRISTATE_BIT; - break; - case BUSSTATE_TRISTATE: - if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT)) - return 0; - mcr |= TRISTATE_BIT; - break; - default: - return -EINVAL; - } - - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - - pci_write_config_word(dev, mcr_addr, mcr); - pci_write_config_byte(dev, 0x59, bsr2 | resetmask); - return 0; -} - /** * hpt37x_calibrate_dpll - calibrate the DPLL * @dev: PCI device @@ -1334,7 +1276,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->quirkproc = &hpt3xx_quirkproc; hwif->maskproc = &hpt3xx_maskproc; - hwif->busproc = &hpt3xx_busproc; hwif->udma_filter = &hpt3xx_udma_filter; hwif->mdma_filter = &hpt3xx_mdma_filter; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 054626497be4..9046a69117ff 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -562,7 +562,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif) clear interrupts */ hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */ hwif->quirkproc = NULL; - hwif->busproc = NULL; hwif->INB = &sgiioc4_INB; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 8d624afe8529..b6be1b45f329 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -369,48 +369,6 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) return 0; } -/** - * sil_sata_busproc - bus isolation IOCTL - * @drive: drive to isolate/restore - * @state: bus state to set - * - * Used by the SII3112 to handle bus isolation. As this is a - * SATA controller the work required is quite limited, we - * just have to clean up the statistics - */ - -static int sil_sata_busproc(ide_drive_t * drive, int state) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = to_pci_dev(hwif->dev); - u32 stat_config = 0; - unsigned long addr = siimage_selreg(hwif, 0); - - if (hwif->mmio) - stat_config = readl((void __iomem *)addr); - else - pci_read_config_dword(dev, addr, &stat_config); - - switch (state) { - case BUSSTATE_ON: - hwif->drives[0].failures = 0; - hwif->drives[1].failures = 0; - break; - case BUSSTATE_OFF: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - break; - case BUSSTATE_TRISTATE: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - break; - default: - return -EINVAL; - } - hwif->bus_state = state; - return 0; -} - /** * sil_sata_reset_poll - wait for SATA reset * @drive: drive we are resetting @@ -818,7 +776,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) if (sata) { static int first = 1; - hwif->busproc = &sil_sata_busproc; hwif->reset_poll = &sil_sata_reset_poll; hwif->pre_reset = &sil_sata_pre_reset; hwif->udma_filter = &sil_sata_udma_filter; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index 2ef2ed2f2b32..1e4a6262bcef 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -126,40 +126,6 @@ static void tc86c001_dma_start(ide_drive_t *drive) ide_dma_start(drive); } -static int tc86c001_busproc(ide_drive_t *drive, int state) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long sc_base = hwif->config_data; - u16 scr1; - - /* System Control 1 Register bit 11 (ATA Hard Reset) read */ - scr1 = inw(sc_base + 0x00); - - switch (state) { - case BUSSTATE_ON: - if (!(scr1 & 0x0800)) - return 0; - scr1 &= ~0x0800; - - hwif->drives[0].failures = hwif->drives[1].failures = 0; - break; - case BUSSTATE_OFF: - if (scr1 & 0x0800) - return 0; - scr1 |= 0x0800; - - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - break; - default: - return -EINVAL; - } - - /* System Control 1 Register bit 11 (ATA Hard Reset) write */ - outw(scr1, sc_base + 0x00); - return 0; -} - static u8 __devinit tc86c001_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -194,8 +160,6 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) hwif->set_pio_mode = &tc86c001_set_pio_mode; hwif->set_dma_mode = &tc86c001_set_mode; - hwif->busproc = &tc86c001_busproc; - hwif->cable_detect = tc86c001_cable_detect; if (!hwif->dma_base) diff --git a/include/linux/ide.h b/include/linux/ide.h index 9aaad7e70593..e43570a19200 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -502,8 +502,6 @@ typedef struct hwif_s { void (*maskproc)(ide_drive_t *, int); /* check host's drive quirk list */ void (*quirkproc)(ide_drive_t *); - /* driver soft-power interface */ - int (*busproc)(ide_drive_t *, int); #endif u8 (*mdma_filter)(ide_drive_t *); u8 (*udma_filter)(ide_drive_t *); -- cgit v1.2.3 From f74c91413ec6140ee0553180c5f56fdd27c22a2e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:23 +0200 Subject: ide: add warm-plug support for IDE devices (take 2) * Add 'struct class ide_port_class' ('ide_port' class) and a 'struct device *portdev' ('ide_port' class device) in ide_hwif_t. * Register 'ide_port' class in ide_init() and unregister it in cleanup_module(). * Create ->portdev in ide_register_port () and unregister it in ide_unregister(). * Add "delete_devices" class device attribute for unregistering IDE devices on a port and "scan" one for probing+registering IDE devices on a port. * Add ide_sysfs_register_port() helper for registering "delete_devices" and "scan" attributes with ->portdev. Call it in ide_device_add_all(). * Document IDE warm-plug support in Documentation/ide/warm-plug-howto.txt. v2: * Convert patch from using 'struct class_device' to use 'struct device'. (thanks to Kay Sievers for doing it) Signed-off-by: Bartlomiej Zolnierkiewicz --- Documentation/ide/warm-plug-howto.txt | 13 +++++++ drivers/ide/ide-probe.c | 71 ++++++++++++++++++++++++++++++++++- drivers/ide/ide.c | 24 ++++++++++++ include/linux/ide.h | 5 ++- 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 Documentation/ide/warm-plug-howto.txt (limited to 'include/linux') diff --git a/Documentation/ide/warm-plug-howto.txt b/Documentation/ide/warm-plug-howto.txt new file mode 100644 index 000000000000..d5885468b072 --- /dev/null +++ b/Documentation/ide/warm-plug-howto.txt @@ -0,0 +1,13 @@ + +IDE warm-plug HOWTO +=================== + +To warm-plug devices on a port 'idex': + +# echo -n "1" > /sys/class/ide_port/idex/delete_devices + +unplug old device(s) and plug new device(s) + +# echo -n "1" > /sys/class/ide_port/idex/scan + +done diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 468c4ac4181d..510254ab3c9b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -623,7 +623,7 @@ static void hwif_release_dev (struct device *dev) complete(&hwif->gendev_rel_comp); } -static void ide_register_port(ide_hwif_t *hwif) +static int ide_register_port(ide_hwif_t *hwif) { int ret; @@ -639,9 +639,23 @@ static void ide_register_port(ide_hwif_t *hwif) } hwif->gendev.release = hwif_release_dev; ret = device_register(&hwif->gendev); - if (ret < 0) + if (ret < 0) { printk(KERN_WARNING "IDE: %s: device_register error: %d\n", __FUNCTION__, ret); + goto out; + } + + get_device(&hwif->gendev); + + hwif->portdev = device_create(ide_port_class, &hwif->gendev, + MKDEV(0, 0), hwif->name); + if (IS_ERR(hwif->portdev)) { + ret = PTR_ERR(hwif->portdev); + device_unregister(&hwif->gendev); + } + dev_set_drvdata(hwif->portdev, hwif); +out: + return ret; } /** @@ -1378,6 +1392,58 @@ static void ide_port_cable_detect(ide_hwif_t *hwif) } } +static ssize_t store_delete_devices(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + + return n; +}; + +static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices); + +static ssize_t store_scan(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + ide_port_scan(hwif); + + return n; +}; + +static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); + +static struct device_attribute *ide_port_attrs[] = { + &dev_attr_delete_devices, + &dev_attr_scan, + NULL +}; + +static int ide_sysfs_register_port(ide_hwif_t *hwif) +{ + int i, rc; + + for (i = 0; ide_port_attrs[i]; i++) { + rc = device_create_file(hwif->portdev, ide_port_attrs[i]); + if (rc) + break; + } + + return rc; +} + int ide_device_add_all(u8 *idx, const struct ide_port_info *d) { ide_hwif_t *hwif, *mate = NULL; @@ -1474,6 +1540,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; if (hwif->present) { + ide_sysfs_register_port(hwif); ide_proc_register_port(hwif); ide_proc_port_register_devices(hwif); } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index cb18ba8de22d..d791b1ffb586 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -78,6 +78,8 @@ /* default maximum number of failures */ #define IDE_DEFAULT_MAX_FAILURES 1 +struct class *ide_port_class; + static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, @@ -591,6 +593,7 @@ void ide_unregister(unsigned int index, int init_default, int restore) ide_remove_port_from_hwgroup(hwif); + device_unregister(hwif->portdev); device_unregister(&hwif->gendev); wait_for_completion(&hwif->gendev_rel_comp); @@ -1590,6 +1593,13 @@ struct bus_type ide_bus_type = { EXPORT_SYMBOL_GPL(ide_bus_type); +static void ide_port_class_release(struct device *portdev) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + put_device(&hwif->gendev); +} + /* * This is gets invoked once during initialization, to set *everything* up */ @@ -1610,11 +1620,23 @@ static int __init ide_init(void) return ret; } + ide_port_class = class_create(THIS_MODULE, "ide_port"); + if (IS_ERR(ide_port_class)) { + ret = PTR_ERR(ide_port_class); + goto out_port_class; + } + ide_port_class->dev_release = ide_port_class_release; + init_ide_data(); proc_ide_create(); return 0; + +out_port_class: + bus_unregister(&ide_bus_type); + + return ret; } #ifdef MODULE @@ -1651,6 +1673,8 @@ void __exit cleanup_module (void) proc_ide_destroy(); + class_destroy(ide_port_class); + bus_unregister(&ide_bus_type); } diff --git a/include/linux/ide.h b/include/linux/ide.h index e43570a19200..9cebf3054080 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -579,7 +579,9 @@ typedef struct hwif_s { unsigned mmio : 1; /* host uses MMIO */ unsigned straight8 : 1; /* Alan's straight 8 check */ - struct device gendev; + struct device gendev; + struct device *portdev; + struct completion gendev_rel_comp; /* To deal with device release() */ void *hwif_data; /* extra hwif data */ @@ -1275,6 +1277,7 @@ extern struct mutex ide_cfg_mtx; #define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0) extern struct bus_type ide_bus_type; +extern struct class *ide_port_class; /* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ #define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) -- cgit v1.2.3 From 9a0e77f28b50128df0c9e26ae489e44e29a7270a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:24 +0200 Subject: ide: remove obsoleted "idex=base[,ctl[,irq]]" kernel parameters (take 2) * Remove obsoleted "idex=base[,ctl[,irq]]" kernel parameters and update Documentation/ide/ide.txt. * Remove no longer needed ide_forced chipset type. v2: * is_chipset_set[] -> is_chipset_set in ide.c. * Documentation/ide/ide.txt fix. Signed-off-by: Bartlomiej Zolnierkiewicz --- Documentation/ide/ide.txt | 33 +-------------------------------- drivers/ide/ide-generic.c | 3 +-- drivers/ide/ide-probe.c | 3 +-- drivers/ide/ide-proc.c | 3 --- drivers/ide/ide.c | 41 ++++++++++++----------------------------- drivers/ide/pci/cmd640.c | 2 +- drivers/ide/setup-pci.c | 11 ----------- include/linux/ide.h | 2 +- 8 files changed, 17 insertions(+), 81 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt index ae4f4f43c25c..18c02df2f78f 100644 --- a/Documentation/ide/ide.txt +++ b/Documentation/ide/ide.txt @@ -71,29 +71,6 @@ This driver automatically probes for most IDE interfaces (including all PCI ones), for the drives/geometries attached to those interfaces, and for the IRQ lines being used by the interfaces (normally 14, 15 for ide0/ide1). -For special cases, interfaces may be specified using kernel "command line" -options. For example, - - ide3=0x168,0x36e,10 /* ioports 0x168-0x16f,0x36e, irq 10 */ - -Normally the irq number need not be specified, as ide.c will probe for it: - - ide3=0x168,0x36e /* ioports 0x168-0x16f,0x36e */ - -The standard port, and irq values are these: - - ide0=0x1f0,0x3f6,14 - ide1=0x170,0x376,15 - ide2=0x1e8,0x3ee,11 - ide3=0x168,0x36e,10 - -Note that the first parameter reserves 8 contiguous ioports, whereas the -second value denotes a single ioport. If in doubt, do a 'cat /proc/ioports'. - -In all probability the device uses these ports and IRQs if it is attached -to the appropriate ide channel. Pass the parameter for the correct ide -channel to the kernel, as explained above. - Any number of interfaces may share a single IRQ if necessary, at a slight performance penalty, whether on separate cards or a single VLB card. The IDE driver automatically detects and handles this. However, this may @@ -199,7 +176,7 @@ When ide.c is used as a module, you can pass command line parameters to the driver using the "options=" keyword to insmod, while replacing any ',' with ';'. For example: - insmod ide.o options="ide0=serialize ide1=serialize ide2=0x1e8;0x3ee;11" + insmod ide.o options="hda=nodma hdb=nodma" ================================================================================ @@ -240,14 +217,6 @@ Summary of ide driver parameters for kernel command line As for VLB, it is safest to not specify it. Bigger values are safer than smaller ones. - "idex=base" : probe for an interface at the addr specified, - where "base" is usually 0x1f0 or 0x170 - and "ctl" is assumed to be "base"+0x206 - - "idex=base,ctl" : specify both base and ctl - - "idex=base,ctl,irq" : specify base, ctl, and irq number - "idex=serialize" : do not overlap operations on idex. Please note that you will have to specify this option for both the respective primary and secondary channel diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 387574fe4b2b..bae41459192d 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -93,8 +93,7 @@ static int __init ide_generic_init(void) ide_hwif_t *hwif = &ide_hwifs[i]; if (hwif->io_ports[IDE_DATA_OFFSET] && - (hwif->chipset == ide_unknown || - hwif->chipset == ide_forced)) + hwif->chipset == ide_unknown) idx[i] = i; else idx[i] = 0xff; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 8ef5194f6d47..33cb5e5a249b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1519,8 +1519,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) hwif = &ide_hwifs[idx[i]]; if (hwif->present) { - if (hwif->chipset == ide_unknown || - hwif->chipset == ide_forced) + if (hwif->chipset == ide_unknown) hwif->chipset = ide_generic; hwif_register_devices(hwif); } diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 77025d1057b5..edd7f186dc4d 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -46,9 +46,6 @@ static int proc_ide_read_imodel int len; const char *name; - /* - * Neither ide_unknown nor ide_forced should be set at this point. - */ switch (hwif->chipset) { case ide_generic: name = "generic"; break; case ide_pci: name = "pci"; break; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 96126b3b12e9..7e789c97a8b8 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1170,7 +1170,7 @@ extern int probe_ht6560b; extern int probe_qd65xx; extern int cmd640_vlb; -static int __initdata is_chipset_set[MAX_HWIFS]; +static int __initdata is_chipset_set; /* * ide_setup() gets called VERY EARLY during initialization, @@ -1328,8 +1328,6 @@ static int __init ide_setup(char *s) "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL }; - hw_regs_t hwregs; - hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -1338,19 +1336,14 @@ static int __init ide_setup(char *s) * Cryptic check to ensure chipset not already set for hwif. * Note: we can't depend on hwif->chipset here. */ - if ((i >= -18 && i <= -11) || (i > 0 && i <= 3)) { + if (i >= -18 && i <= -11) { /* chipset already specified */ - if (is_chipset_set[hw]) + if (is_chipset_set) goto bad_option; - if (i > -18 && i <= -11) { - /* these drivers are for "ide0=" only */ - if (hw != 0) - goto bad_hwif; - /* chipset already specified for 2nd port */ - if (is_chipset_set[hw+1]) - goto bad_option; - } - is_chipset_set[hw] = 1; + /* these drivers are for "ide0=" only */ + if (hw != 0) + goto bad_hwif; + is_chipset_set = 1; printk("\n"); } @@ -1430,21 +1423,11 @@ static int __init ide_setup(char *s) case -1: /* "noprobe" */ hwif->noprobe = 1; goto obsolete_option; - - case 1: /* base */ - vals[1] = vals[0] + 0x206; /* default ctl */ - case 2: /* base,ctl */ - vals[2] = 0; /* default irq = probe for it */ - case 3: /* base,ctl,irq */ - memset(&hwregs, 0, sizeof(hwregs)); - ide_init_hwif_ports(&hwregs, vals[0], vals[1], &hwif->irq); - memcpy(hwif->io_ports, hwregs.io_ports, sizeof(hwif->io_ports)); - hwif->irq = vals[2]; - hwif->noprobe = 0; - hwif->chipset = ide_forced; - goto obsolete_option; - - case 0: goto bad_option; + case 0: + case 1: + case 2: + case 3: + goto bad_option; default: printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n"); return 1; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 29fbc5ead03b..58a95f62e383 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -415,7 +415,7 @@ static void __init setup_device_ptrs (void) cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */ for (i = 0; i < MAX_HWIFS; i++) { ide_hwif_t *hwif = &ide_hwifs[i]; - if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced) { + if (hwif->chipset == ide_unknown) { if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) cmd_hwif0 = hwif; else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 634e3f6a9608..ea66c996e4ec 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -40,17 +40,6 @@ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char int h; ide_hwif_t *hwif; - /* - * Look for a hwif with matching io_base specified using - * parameters to ide_setup(). - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { - if (hwif->chipset == ide_forced) - return hwif; /* a perfect match */ - } - } /* * Look for a hwif with matching io_base default value. * If chipset is "ide_unknown", then claim that hwif slot. diff --git a/include/linux/ide.h b/include/linux/ide.h index 9cebf3054080..67f83c60845f 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -169,7 +169,7 @@ enum { ide_unknown, ide_generic, ide_pci, ide_rz1000, ide_trm290, ide_cmd646, ide_cy82c693, ide_4drives, ide_pmac, ide_etrax100, ide_acorn, - ide_au1xxx, ide_palm3710, ide_forced + ide_au1xxx, ide_palm3710 }; typedef u8 hwif_chipset_t; -- cgit v1.2.3 From 93de00fd1c70e1a23a73a865e0f9abfe74a7a719 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:24 +0200 Subject: ide: remove broken/dangerous HDIO_[UNREGISTER,SCAN]_HWIF ioctls (take 3) hdparm explicitely marks HDIO_[UNREGISTER,SCAN]_HWIF ioctls as DANGEROUS and given the number of bugs we can assume that there are no real users: * DMA has no chance of working because DMA resources are released by ide_unregister() and they are never allocated again. * Since ide_init_hwif_ports() is used for ->io_ports[] setup the ioctls don't work for almost all hosts with "non-standard" (== non ISA-like) layout of IDE taskfile registers (there is a lot of such host drivers). * ide_port_init_devices() is not called when probing IDE devices so: - drive->autotune is never set and IDE host/devices are not programmed for the correct PIO/DMA transfer modes (=> possible data corruption) - host specific I/O 32-bit and IRQ unmasking settings are not applied (=> possible data corruption) - host specific ->port_init_devs method is not called (=> no luck with ht6560b, qd65xx and opti621 host drivers) * ->rw_disk method is not preserved (=> no HPT3xxN chipsets support). * ->serialized flag is not preserved (=> possible data corruption when using icside, aec62xx (ATP850UF chipset), cmd640, cs5530, hpt366 (HPT3xxN chipsets), rz1000, sc1200, dtc2278 and ht6560b host drivers). * ->ack_intr method is not preserved (=> needed by ide-cris, buddha, gayle and macide host drivers). * ->sata_scr[] and sata_misc[] is cleared by ide_unregister() and it isn't initialized again (SiI3112 support needs them). * To issue an ioctl() there need to be at least one IDE device present in the system. * ->cable_detect method is not preserved + it is not called when probing IDE devices so cable detection is broken (however since DMA support is also broken it doesn't really matter ;-). * Some objects which may have already been freed in ide_unregister() are restored by ide_hwif_restore() (i.e. ->hwgroup). * ide_register_hw() may unregister unrelated IDE ports if free ide_hwifs[] slot cannot be found. * When IDE host drivers are modular unregistered port may be re-used by different host driver that owned it first causing subtle bugs. Since we now have a proper warm-plug support remove these ioctls, then remove no longer needed: - ide_register_hw() and ide_hwif_restore() functions - 'init_default' and 'restore' arguments of ide_unregister() - zeroeing of hwif->{dma,extra}_* fields in ide_unregister() As an added bonus IDE core code size shrinks by ~3kB (x86-32). v2: * fix ide_unregister() arguments in cleanup_module() (Andrew Morton). v3: * fix ide_unregister() arguments in palm_bk3710.c. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- block/compat_ioctl.c | 1 - drivers/ide/arm/bast-ide.c | 2 +- drivers/ide/arm/palm_bk3710.c | 2 +- drivers/ide/arm/rapide.c | 2 +- drivers/ide/ide-pnp.c | 2 +- drivers/ide/ide.c | 199 +------------------------------------- drivers/ide/legacy/ide-cs.c | 4 +- drivers/ide/legacy/ide_platform.c | 2 +- drivers/ide/mips/au1xxx-ide.c | 2 +- drivers/ide/pci/delkin_cb.c | 4 +- drivers/ide/pci/scc_pata.c | 2 +- include/linux/hdreg.h | 4 +- include/linux/ide.h | 2 +- 13 files changed, 19 insertions(+), 209 deletions(-) (limited to 'include/linux') diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index b73373216b0e..c70d0b6f666f 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -624,7 +624,6 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, case HDIO_GET_IDENTITY: case HDIO_DRIVE_TASK: case HDIO_DRIVE_CMD: - case HDIO_SCAN_HWIF: /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ case 0x330: /* 0x02 -- Floppy ioctls */ diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index a22da7ab2b57..d2196436788b 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -48,7 +48,7 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq) i = hwif->index; if (hwif->present) - ide_unregister(i, 0, 0); + ide_unregister(i); else if (!hwif->hold) ide_init_port_data(hwif, i); diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index 0a722503c102..73899ef4ab0d 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -385,7 +385,7 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev) i = hwif->index; if (hwif->present) - ide_unregister(i, 0, 0); + ide_unregister(i); else if (!hwif->hold) ide_init_port_data(hwif, i); diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index efba00d2fc37..b30adcf321c3 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -76,7 +76,7 @@ static void __devexit rapide_remove(struct expansion_card *ec) ecard_set_drvdata(ec, NULL); - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); ecard_release_resources(ec); } diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index c14bb5380c25..34c2ad36ce54 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -62,7 +62,7 @@ static void idepnp_remove(struct pnp_dev * dev) ide_hwif_t *hwif = pnp_get_drvdata(dev); if (hwif) - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); else printk(KERN_ERR "idepnp: Unable to remove device, please report.\n"); } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 7e789c97a8b8..1121d9cb2a9b 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -362,107 +362,6 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) release_region(hwif->io_ports[i], 1); } -/** - * ide_hwif_restore - restore hwif to template - * @hwif: hwif to update - * @tmp_hwif: template - * - * Restore hwif to a previous state by copying most settings - * from the template. - */ - -static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) -{ - hwif->hwgroup = tmp_hwif->hwgroup; - - hwif->gendev.parent = tmp_hwif->gendev.parent; - - hwif->proc = tmp_hwif->proc; - - hwif->major = tmp_hwif->major; - hwif->straight8 = tmp_hwif->straight8; - hwif->bus_state = tmp_hwif->bus_state; - - hwif->host_flags = tmp_hwif->host_flags; - - hwif->pio_mask = tmp_hwif->pio_mask; - - hwif->ultra_mask = tmp_hwif->ultra_mask; - hwif->mwdma_mask = tmp_hwif->mwdma_mask; - hwif->swdma_mask = tmp_hwif->swdma_mask; - - hwif->cbl = tmp_hwif->cbl; - - hwif->chipset = tmp_hwif->chipset; - hwif->hold = tmp_hwif->hold; - - hwif->dev = tmp_hwif->dev; - -#ifdef CONFIG_BLK_DEV_IDEPCI - hwif->cds = tmp_hwif->cds; -#endif - - hwif->set_pio_mode = tmp_hwif->set_pio_mode; - hwif->set_dma_mode = tmp_hwif->set_dma_mode; - hwif->mdma_filter = tmp_hwif->mdma_filter; - hwif->udma_filter = tmp_hwif->udma_filter; - hwif->selectproc = tmp_hwif->selectproc; - hwif->reset_poll = tmp_hwif->reset_poll; - hwif->pre_reset = tmp_hwif->pre_reset; - hwif->resetproc = tmp_hwif->resetproc; - hwif->maskproc = tmp_hwif->maskproc; - hwif->quirkproc = tmp_hwif->quirkproc; - - hwif->ata_input_data = tmp_hwif->ata_input_data; - hwif->ata_output_data = tmp_hwif->ata_output_data; - hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; - hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; - - hwif->dma_host_set = tmp_hwif->dma_host_set; - hwif->dma_setup = tmp_hwif->dma_setup; - hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; - hwif->dma_start = tmp_hwif->dma_start; - hwif->ide_dma_end = tmp_hwif->ide_dma_end; - hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; - hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; - hwif->dma_lost_irq = tmp_hwif->dma_lost_irq; - hwif->dma_timeout = tmp_hwif->dma_timeout; - - hwif->OUTB = tmp_hwif->OUTB; - hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; - hwif->OUTW = tmp_hwif->OUTW; - hwif->OUTSW = tmp_hwif->OUTSW; - hwif->OUTSL = tmp_hwif->OUTSL; - - hwif->INB = tmp_hwif->INB; - hwif->INW = tmp_hwif->INW; - hwif->INSW = tmp_hwif->INSW; - hwif->INSL = tmp_hwif->INSL; - - hwif->sg_max_nents = tmp_hwif->sg_max_nents; - - hwif->mmio = tmp_hwif->mmio; - hwif->rqsize = tmp_hwif->rqsize; - -#ifndef CONFIG_BLK_DEV_IDECS - hwif->irq = tmp_hwif->irq; -#endif - - hwif->dma_base = tmp_hwif->dma_base; - hwif->dma_command = tmp_hwif->dma_command; - hwif->dma_vendor1 = tmp_hwif->dma_vendor1; - hwif->dma_status = tmp_hwif->dma_status; - hwif->dma_vendor3 = tmp_hwif->dma_vendor3; - hwif->dma_prdtable = tmp_hwif->dma_prdtable; - - hwif->config_data = tmp_hwif->config_data; - hwif->select_data = tmp_hwif->select_data; - hwif->extra_base = tmp_hwif->extra_base; - hwif->extra_ports = tmp_hwif->extra_ports; - - hwif->hwif_data = tmp_hwif->hwif_data; -} - void ide_remove_port_from_hwgroup(ide_hwif_t *hwif) { ide_hwgroup_t *hwgroup = hwif->hwgroup; @@ -530,8 +429,6 @@ EXPORT_SYMBOL_GPL(ide_port_unregister_devices); /** * ide_unregister - free an IDE interface * @index: index of interface (will change soon to a pointer) - * @init_default: init default hwif flag - * @restore: restore hwif flag * * Perform the final unregister of an IDE interface. At the moment * we don't refcount interfaces so this will also get split up. @@ -551,10 +448,9 @@ EXPORT_SYMBOL_GPL(ide_port_unregister_devices); * This is raving bonkers. */ -void ide_unregister(unsigned int index, int init_default, int restore) +void ide_unregister(unsigned int index) { ide_hwif_t *hwif, *g; - static ide_hwif_t tmp_hwif; /* protected by ide_cfg_mtx */ ide_hwgroup_t *hwgroup; int irq_count = 0; @@ -601,34 +497,14 @@ void ide_unregister(unsigned int index, int init_default, int restore) unregister_blkdev(hwif->major, hwif->name); spin_lock_irq(&ide_lock); - if (hwif->dma_base) { - (void) ide_release_dma(hwif); - - hwif->dma_base = 0; - hwif->dma_command = 0; - hwif->dma_vendor1 = 0; - hwif->dma_status = 0; - hwif->dma_vendor3 = 0; - hwif->dma_prdtable = 0; - - hwif->extra_base = 0; - hwif->extra_ports = 0; - } + if (hwif->dma_base) + (void)ide_release_dma(hwif); ide_hwif_release_regions(hwif); - /* copy original settings */ - tmp_hwif = *hwif; - /* restore hwif data to pristine status */ ide_init_port_data(hwif, index); - if (init_default) - init_hwif_default(hwif, index); - - if (restore) - ide_hwif_restore(hwif, &tmp_hwif); - abort: spin_unlock_irq(&ide_lock); mutex_unlock(&ide_cfg_mtx); @@ -647,52 +523,6 @@ void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) } EXPORT_SYMBOL_GPL(ide_init_port_hw); -/** - * ide_register_hw - register IDE interface - * @hw: hardware registers - * @quirkproc: quirkproc function - * @hwifp: pointer to returned hwif - * - * Register an IDE interface, specifying exactly the registers etc. - * - * Returns -1 on error. - */ - -static int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), - ide_hwif_t **hwifp) -{ - int index, retry = 1; - ide_hwif_t *hwif; - u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; - - do { - hwif = ide_find_port(hw->io_ports[IDE_DATA_OFFSET]); - if (hwif) - goto found; - for (index = 0; index < MAX_HWIFS; index++) - ide_unregister(index, 1, 1); - } while (retry--); - return -1; -found: - index = hwif->index; - if (hwif->present) - ide_unregister(index, 0, 1); - else if (!hwif->hold) - ide_init_port_data(hwif, index); - - ide_init_port_hw(hwif, hw); - hwif->quirkproc = quirkproc; - - idx[0] = index; - - ide_device_add(idx, NULL); - - if (hwifp) - *hwifp = hwif; - - return hwif->present ? index : -1; -} - /* * Locks for IDE setting functionality */ @@ -995,27 +825,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device if (!capable(CAP_SYS_RAWIO)) return -EACCES; return ide_task_ioctl(drive, cmd, arg); - - case HDIO_SCAN_HWIF: - { - hw_regs_t hw; - int args[3]; - if (!capable(CAP_SYS_RAWIO)) return -EACCES; - if (copy_from_user(args, p, 3 * sizeof(int))) - return -EFAULT; - memset(&hw, 0, sizeof(hw)); - ide_init_hwif_ports(&hw, (unsigned long) args[0], - (unsigned long) args[1], NULL); - hw.irq = args[2]; - if (ide_register_hw(&hw, NULL, NULL) == -1) - return -EIO; - return 0; - } - case HDIO_UNREGISTER_HWIF: - if (!capable(CAP_SYS_RAWIO)) return -EACCES; - /* (arg > MAX_HWIFS) checked in function */ - ide_unregister(arg, 1, 1); - return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) @@ -1648,7 +1457,7 @@ void __exit cleanup_module (void) int index; for (index = 0; index < MAX_HWIFS; ++index) - ide_unregister(index, 0, 0); + ide_unregister(index); proc_ide_destroy(); diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index de2e5944809e..2b0b4958881a 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -163,7 +163,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq i = hwif->index; if (hwif->present) - ide_unregister(i, 0, 0); + ide_unregister(i); else if (!hwif->hold) ide_init_port_data(hwif, i); @@ -360,7 +360,7 @@ void ide_release(struct pcmcia_device *link) if (info->ndev) { /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ - ide_unregister(info->hd, 0, 0); + ide_unregister(info->hd); } info->ndev = 0; diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 688fcae17488..249651e2da42 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -122,7 +122,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev) { ide_hwif_t *hwif = pdev->dev.driver_data; - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); return 0; } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 85c016bdfd38..ee76023f3737 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -673,7 +673,7 @@ static int au_ide_remove(struct device *dev) ide_hwif_t *hwif = dev_get_drvdata(dev); _auide_hwif *ahwif = &auide_hwif; - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); iounmap((void *)ahwif->regbase); diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index e08e13a0bb6e..89570df52f0a 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -85,7 +85,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) i = hwif->index; if (hwif->present) - ide_unregister(i, 0, 0); + ide_unregister(i); else if (!hwif->hold) ide_init_port_data(hwif, i); @@ -120,7 +120,7 @@ delkin_cb_remove (struct pci_dev *dev) ide_hwif_t *hwif = pci_get_drvdata(dev); if (hwif) - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); pci_disable_device(dev); } diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 238e3e181e87..085c1b58a99c 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -736,7 +736,7 @@ static void __devexit scc_remove(struct pci_dev *dev) hwif->dmatable_cpu = NULL; } - ide_unregister(hwif->index, 0, 0); + ide_unregister(hwif->index); hwif->chipset = ide_unknown; iounmap((void*)ports->dma); diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index e38e75967e74..c37e9241fae7 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -422,9 +422,11 @@ struct hd_geometry { #define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ #define HDIO_SET_DMA 0x0326 /* change use-dma flag */ #define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ +#ifndef __KERNEL__ #define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */ -#define HDIO_SET_NICE 0x0329 /* set nice flags */ #define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */ +#endif +#define HDIO_SET_NICE 0x0329 /* set nice flags */ #define HDIO_SET_WCACHE 0x032b /* change write cache enable-disable */ #define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */ #define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 67f83c60845f..478ddf7e21d5 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1191,7 +1191,7 @@ static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {} void ide_remove_port_from_hwgroup(ide_hwif_t *); extern int ide_hwif_request_regions(ide_hwif_t *hwif); extern void ide_hwif_release_regions(ide_hwif_t* hwif); -void ide_unregister(unsigned int, int, int); +void ide_unregister(unsigned int); void ide_register_region(struct gendisk *); void ide_unregister_region(struct gendisk *); -- cgit v1.2.3 From 2304dc6481f9d4fb4f0cb5b72497dfe1694cef9c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:24 +0200 Subject: ide: remove ->hold field from ide_hwif_t (take 2) ->hold is write-only now, remove it. v2: * v1 missed bast-ide, palm_bk3710, ide-cs and delkin_cb host drivers. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/bast-ide.c | 2 +- drivers/ide/arm/palm_bk3710.c | 2 +- drivers/ide/legacy/ide-cs.c | 2 +- drivers/ide/mips/au1xxx-ide.c | 3 --- drivers/ide/pci/delkin_cb.c | 2 +- drivers/ide/ppc/pmac.c | 1 - include/linux/ide.h | 1 - 7 files changed, 4 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index d2196436788b..ec46c44b061c 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -49,7 +49,7 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq) if (hwif->present) ide_unregister(i); - else if (!hwif->hold) + else ide_init_port_data(hwif, i); ide_init_port_hw(hwif, &hw); diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index 73899ef4ab0d..474162cdf665 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -386,7 +386,7 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev) if (hwif->present) ide_unregister(i); - else if (!hwif->hold) + else ide_init_port_data(hwif, i); ide_init_port_hw(hwif, &hw); diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 2b0b4958881a..9a23b94f2939 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -164,7 +164,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq if (hwif->present) ide_unregister(i); - else if (!hwif->hold) + else ide_init_port_data(hwif, i); ide_init_port_hw(hwif, &hw); diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index ee76023f3737..9b628248f2f4 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -613,9 +613,6 @@ static int au_ide_probe(struct device *dev) hwif->dev = dev; - /* hold should be on in all cases */ - hwif->hold = 1; - hwif->mmio = 1; /* If the user has selected DDMA assisted copies, diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 89570df52f0a..961698d655eb 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -86,7 +86,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) if (hwif->present) ide_unregister(i); - else if (!hwif->hold) + else ide_init_port_data(hwif, i); ide_init_port_hw(hwif, &hw); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 7889f5f5c49a..b37dcfbdaad6 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1120,7 +1120,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) hwif->hwif_data = pmif; ide_init_port_hw(hwif, hw); hwif->noprobe = pmif->mediabay; - hwif->hold = pmif->mediabay; hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; hwif->set_pio_mode = pmac_ide_set_pio_mode; if (pmif->kind == controller_un_ata6 diff --git a/include/linux/ide.h b/include/linux/ide.h index 478ddf7e21d5..7744ac9d1ff9 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -571,7 +571,6 @@ typedef struct hwif_s { unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ - unsigned hold : 1; /* this interface is always present */ unsigned serialized : 1; /* serialized all channel operation */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ unsigned reset : 1; /* reset after probe */ -- cgit v1.2.3 From e6bfa38a4803646e212ef542b957344e790c3733 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:25 +0200 Subject: ide: remove ide_init_hwif_ports() ide_init_hwif_ports() is only used by init_ide_data() now, inline it there. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide.c | 11 +++++++++-- include/linux/ide.h | 32 -------------------------------- 2 files changed, 9 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index a60b956db519..9e4d503bc716 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -197,13 +197,20 @@ static void __init init_ide_data (void) /* Initialise all interface structures */ for (index = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; + unsigned long io_addr = ide_default_io_base(index); + unsigned long ctl_addr = ide_default_io_ctl(io_addr); ide_init_port_data(hwif, index); +#ifdef CONFIG_IDE_ARCH_OBSOLETE_INIT memset(&hw, 0, sizeof(hw)); - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, - &hwif->irq); + ide_std_init_ports(&hw, io_addr, ctl_addr); +# ifdef CONFIG_PPC32 + if (ppc_ide_md.ide_init_hwif) + ppc_ide_md.ide_init_hwif(&hw, io_addr, 0, &hwif->irq); +# endif memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); +#endif hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI) hwif->irq = diff --git a/include/linux/ide.h b/include/linux/ide.h index 7744ac9d1ff9..f4c7db572a16 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -215,38 +215,6 @@ static inline void ide_std_init_ports(hw_regs_t *hw, # define ide_init_default_irq(base) (0) #endif -#ifdef CONFIG_IDE_ARCH_OBSOLETE_INIT -static inline void ide_init_hwif_ports(hw_regs_t *hw, - unsigned long io_addr, - unsigned long ctl_addr, - int *irq) -{ - if (!ctl_addr) - ide_std_init_ports(hw, io_addr, ide_default_io_ctl(io_addr)); - else - ide_std_init_ports(hw, io_addr, ctl_addr); - - if (irq) - *irq = 0; - - hw->io_ports[IDE_IRQ_OFFSET] = 0; - -#ifdef CONFIG_PPC32 - if (ppc_ide_md.ide_init_hwif) - ppc_ide_md.ide_init_hwif(hw, io_addr, ctl_addr, irq); -#endif -} -#else -static inline void ide_init_hwif_ports(hw_regs_t *hw, - unsigned long io_addr, - unsigned long ctl_addr, - int *irq) -{ - if (io_addr || ctl_addr) - printk(KERN_WARNING "%s: must not be called\n", __FUNCTION__); -} -#endif /* CONFIG_IDE_ARCH_OBSOLETE_INIT */ - /* Currently only m68k, apus and m8xx need it */ #ifndef IDE_ARCH_ACK_INTR # define ide_ack_intr(hwif) (1) -- cgit v1.2.3 From 7616c0ad2087c7d244b8985390c63059a6223c45 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:26 +0200 Subject: ide: add ide_atapi_{discard_data,write_zeros} inline helpers Add ide_atapi_{discard_data,write_zeros} inline helpers to and use them instead of home-brewn helpers in ide-{floppy,tape,scsi}. There should be no functional changes caused by this patch. Cc: Borislav Petkov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-floppy.c | 24 +++--------------------- drivers/ide/ide-tape.c | 14 ++------------ drivers/scsi/ide-scsi.c | 18 +++--------------- include/linux/ide.h | 22 ++++++++++++++++++++++ 4 files changed, 30 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 973f5f6c815e..170c60d93f55 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -229,23 +229,6 @@ static void ide_floppy_put(struct ide_floppy_obj *floppy) mutex_unlock(&idefloppy_ref_mutex); } -/* - * Too bad. The drive wants to send us data which we are not ready to accept. - * Just throw it away. - */ -static void idefloppy_discard_data(ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - (void) HWIF(drive)->INB(IDE_DATA_REG); -} - -static void idefloppy_write_zeros(ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - HWIF(drive)->OUTB(0, IDE_DATA_REG); -} - - /* * Used to finish servicing a request. For read/write requests, we will call * ide_end_request to pass to the next buffer. @@ -313,10 +296,9 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, idefloppy_pc_t *pc, printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n", drive->name, __func__, bcount); if (direction) - idefloppy_write_zeros(drive, bcount); + ide_atapi_write_zeros(drive, bcount); else - idefloppy_discard_data(drive, bcount); - + ide_atapi_discard_data(drive, bcount); } } @@ -541,7 +523,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); - idefloppy_discard_data(drive, bcount); + ide_atapi_discard_data(drive, bcount); ide_set_handler(drive, &idefloppy_pc_intr, diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 0598ecfd5f37..bfdc4f449797 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -518,16 +518,6 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) return tape; } -/* - * Too bad. The drive wants to send us data which we are not ready to accept. - * Just throw it away. - */ -static void idetape_discard_data(ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - (void) HWIF(drive)->INB(IDE_DATA_REG); -} - static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) { @@ -538,7 +528,7 @@ static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc, if (bh == NULL) { printk(KERN_ERR "ide-tape: bh == NULL in " "idetape_input_buffers\n"); - idetape_discard_data(drive, bcount); + ide_atapi_discard_data(drive, bcount); return; } count = min( @@ -1152,7 +1142,7 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) printk(KERN_ERR "ide-tape: The tape wants to " "send us more data than expected " "- discarding data\n"); - idetape_discard_data(drive, bcount); + ide_atapi_discard_data(drive, bcount); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 68e5c632c5d5..3c3b3502c4d4 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -152,18 +152,6 @@ static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive) */ #define IDESCSI_PC_RQ 90 -static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - (void) HWIF(drive)->INB(IDE_DATA_REG); -} - -static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - HWIF(drive)->OUTB(0, IDE_DATA_REG); -} - /* * PIO data transfer routines using the scatter gather table. */ @@ -200,7 +188,7 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); - idescsi_discard_data (drive, bcount); + ide_atapi_discard_data(drive, bcount); } } @@ -237,7 +225,7 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); - idescsi_output_zeros (drive, bcount); + ide_atapi_write_zeros(drive, bcount); } } @@ -463,7 +451,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) } pc->actually_transferred += temp; pc->current_position += temp; - idescsi_discard_data(drive, bcount - temp); + ide_atapi_discard_data(drive, bcount - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } diff --git a/include/linux/ide.h b/include/linux/ide.h index f4c7db572a16..2eb99cab4a3d 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1297,4 +1297,26 @@ static inline u8 ide_read_error(ide_drive_t *drive) return hwif->INB(hwif->io_ports[IDE_ERROR_OFFSET]); } +/* + * Too bad. The drive wants to send us data which we are not ready to accept. + * Just throw it away. + */ +static inline void ide_atapi_discard_data(ide_drive_t *drive, unsigned bcount) +{ + ide_hwif_t *hwif = drive->hwif; + + /* FIXME: use ->atapi_input_bytes */ + while (bcount--) + (void)hwif->INB(hwif->io_ports[IDE_DATA_OFFSET]); +} + +static inline void ide_atapi_write_zeros(ide_drive_t *drive, unsigned bcount) +{ + ide_hwif_t *hwif = drive->hwif; + + /* FIXME: use ->atapi_output_bytes */ + while (bcount--) + hwif->OUTB(0, hwif->io_ports[IDE_DATA_OFFSET]); +} + #endif /* _IDE_H */ -- cgit v1.2.3 From 23579a2a170265aacf78069f4817a41c1d6e9323 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:26 +0200 Subject: ide: remove IDE_*_REG macros * Add IDE_{ALTSTATUS,IREASON,BCOUNTL,BCOUNTH}_OFFSET defines. * Remove IDE_*_REG macros - this results in more readable and slightly smaller code. There should be no functional changes caused by this patch. Cc: Borislav Petkov Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cris/ide-cris.c | 18 +++++++--- drivers/ide/ide-cd.c | 10 +++--- drivers/ide/ide-floppy.c | 14 ++++---- drivers/ide/ide-io.c | 38 ++++++++++++-------- drivers/ide/ide-iops.c | 86 +++++++++++++++++++++++++------------------- drivers/ide/ide-probe.c | 19 +++++----- drivers/ide/ide-tape.c | 12 +++---- drivers/ide/ide-taskfile.c | 29 ++++++++------- drivers/ide/legacy/ht6560b.c | 13 +++---- drivers/ide/pci/hpt366.c | 2 +- drivers/ide/pci/scc_pata.c | 6 ++-- drivers/ide/pci/sgiioc4.c | 19 +++++----- drivers/ide/ppc/pmac.c | 3 +- drivers/scsi/ide-scsi.c | 15 ++++---- include/linux/ide.h | 29 +++++---------- 15 files changed, 175 insertions(+), 138 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index c8ffbaf29a88..31266d278095 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -228,7 +228,10 @@ cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, in static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len) { - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG); + ide_hwif_t *hwif = drive->hwif; + + reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, + hwif->io_ports[IDE_DATA_OFFSET]); reg_ata_rw_trf_cnt trf_cnt = {0}; mycontext.saved_data = (dma_descr_data*)virt_to_phys(d); @@ -264,8 +267,12 @@ cris_ide_wait_dma(int dir) static int cris_dma_test_irq(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; int intr = REG_RD_INT(ata, regi_ata, r_intr); - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG); + + reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, + hwif->io_ports[IDE_DATA_OFFSET]); + return intr & (1 << ctrl2.sel) ? 1 : 0; } @@ -523,7 +530,8 @@ static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int d IO_STATE(R_ATA_CTRL_DATA, handsh, dma); *R_ATA_CTRL_DATA = cmd | - IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | + IO_FIELD(R_ATA_CTRL_DATA, data, + drive->hwif->io_ports[IDE_DATA_OFFSET]) | IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | IO_STATE(R_ATA_CTRL_DATA, multi, on) | IO_STATE(R_ATA_CTRL_DATA, dma_size, word); @@ -541,7 +549,9 @@ cris_ide_wait_dma(int dir) static int cris_dma_test_irq(ide_drive_t *drive) { int intr = *R_IRQ_MASK0_RD; - int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, IDE_DATA_REG); + int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, + drive->hwif->io_ports[IDE_DATA_OFFSET]); + return intr & (1 << (bus + IO_BITNR(R_IRQ_MASK0_RD, ata_irq0))) ? 1 : 0; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index c8d0e8715997..396000208f81 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -542,7 +542,8 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, /* packet command */ spin_lock_irqsave(&ide_lock, flags); - hwif->OUTBSYNC(drive, WIN_PACKETCMD, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, WIN_PACKETCMD, + hwif->io_ports[IDE_COMMAND_OFFSET]); ndelay(400); spin_unlock_irqrestore(&ide_lock, flags); @@ -992,6 +993,7 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq) static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; struct cdrom_info *info = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; xfer_func_t *xferfunc; @@ -1032,9 +1034,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) /* * ok we fall to pio :/ */ - ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3; - lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); - highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]) & 0x3; + lowcyl = hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]); + highcyl = hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]); len = lowcyl + (256 * highcyl); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 170c60d93f55..4ce67bdb5d5e 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -498,10 +498,10 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Get the number of bytes to transfer */ - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); + bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) | + hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]); /* on this interrupt */ - ireason = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if (ireason & CD) { printk(KERN_ERR "ide-floppy: CoD != 0 in %s\n", __func__); @@ -562,6 +562,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) */ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; ide_startstop_t startstop; idefloppy_floppy_t *floppy = drive->driver_data; u8 ireason; @@ -571,7 +572,7 @@ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive) "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = drive->hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while " "issuing a packet command\n"); @@ -608,6 +609,7 @@ static int idefloppy_transfer_pc2(ide_drive_t *drive) static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; idefloppy_floppy_t *floppy = drive->driver_data; ide_startstop_t startstop; u8 ireason; @@ -617,7 +619,7 @@ static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive) "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = drive->hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) " "while issuing a packet command\n"); @@ -723,7 +725,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive, return ide_started; } else { /* Issue the packet command */ - HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); + hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]); return (*pkt_xfer_routine) (drive); } } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 715379605a7b..31e5afadb7e9 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -301,39 +301,45 @@ void ide_tf_read(ide_drive_t *drive, ide_task_t *task) struct ide_taskfile *tf = &task->tf; if (task->tf_flags & IDE_TFLAG_IN_DATA) { - u16 data = hwif->INW(IDE_DATA_REG); + u16 data = hwif->INW(hwif->io_ports[IDE_DATA_OFFSET]); tf->data = data & 0xff; tf->hob_data = (data >> 8) & 0xff; } /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); + hwif->OUTB(drive->ctl & ~0x80, hwif->io_ports[IDE_CONTROL_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_NSECT) - tf->nsect = hwif->INB(IDE_NSECTOR_REG); + tf->nsect = hwif->INB(hwif->io_ports[IDE_NSECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_LBAL) - tf->lbal = hwif->INB(IDE_SECTOR_REG); + tf->lbal = hwif->INB(hwif->io_ports[IDE_SECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_LBAM) - tf->lbam = hwif->INB(IDE_LCYL_REG); + tf->lbam = hwif->INB(hwif->io_ports[IDE_LCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_LBAH) - tf->lbah = hwif->INB(IDE_HCYL_REG); + tf->lbah = hwif->INB(hwif->io_ports[IDE_HCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_DEVICE) - tf->device = hwif->INB(IDE_SELECT_REG); + tf->device = hwif->INB(hwif->io_ports[IDE_SELECT_OFFSET]); if (task->tf_flags & IDE_TFLAG_LBA48) { - hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG); + hwif->OUTB(drive->ctl | 0x80, + hwif->io_ports[IDE_CONTROL_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = hwif->INB(IDE_FEATURE_REG); + tf->hob_feature = + hwif->INB(hwif->io_ports[IDE_FEATURE_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = hwif->INB(IDE_NSECTOR_REG); + tf->hob_nsect = + hwif->INB(hwif->io_ports[IDE_NSECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = hwif->INB(IDE_SECTOR_REG); + tf->hob_lbal = + hwif->INB(hwif->io_ports[IDE_SECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = hwif->INB(IDE_LCYL_REG); + tf->hob_lbam = + hwif->INB(hwif->io_ports[IDE_LCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = hwif->INB(IDE_HCYL_REG); + tf->hob_lbah = + hwif->INB(hwif->io_ports[IDE_HCYL_OFFSET]); } } @@ -448,7 +454,8 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 if (err == ABRT_ERR) { if (drive->select.b.lba && /* some newer drives don't support WIN_SPECIFY */ - hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY) + hwif->INB(hwif->io_ports[IDE_COMMAND_OFFSET]) == + WIN_SPECIFY) return ide_stopped; } else if ((err & BAD_CRC) == BAD_CRC) { /* UDMA crc error, just retry the operation */ @@ -500,7 +507,8 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); + hwif->OUTB(WIN_IDLEIMMEDIATE, + hwif->io_ports[IDE_COMMAND_OFFSET]); if (rq->errors >= ERROR_MAX) { ide_kill_rq(drive, rq); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index e77cee0e5d65..45944219eea0 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -158,9 +158,12 @@ EXPORT_SYMBOL(default_hwif_mmiops); void SELECT_DRIVE (ide_drive_t *drive) { - if (HWIF(drive)->selectproc) - HWIF(drive)->selectproc(drive); - HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG); + ide_hwif_t *hwif = drive->hwif; + + if (hwif->selectproc) + hwif->selectproc(drive); + + hwif->OUTB(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); } void SELECT_MASK (ide_drive_t *drive, int mask) @@ -194,15 +197,18 @@ static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount) if (io_32bit) { if (io_32bit & 2) { unsigned long flags; + local_irq_save(flags); - ata_vlb_sync(drive, IDE_NSECTOR_REG); - hwif->INSL(IDE_DATA_REG, buffer, wcount); + ata_vlb_sync(drive, hwif->io_ports[IDE_NSECTOR_OFFSET]); + hwif->INSL(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount); local_irq_restore(flags); } else - hwif->INSL(IDE_DATA_REG, buffer, wcount); - } else { - hwif->INSW(IDE_DATA_REG, buffer, wcount<<1); - } + hwif->INSL(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount); + } else + hwif->INSW(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount << 1); } /* @@ -216,15 +222,18 @@ static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount) if (io_32bit) { if (io_32bit & 2) { unsigned long flags; + local_irq_save(flags); - ata_vlb_sync(drive, IDE_NSECTOR_REG); - hwif->OUTSL(IDE_DATA_REG, buffer, wcount); + ata_vlb_sync(drive, hwif->io_ports[IDE_NSECTOR_OFFSET]); + hwif->OUTSL(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount); local_irq_restore(flags); } else - hwif->OUTSL(IDE_DATA_REG, buffer, wcount); - } else { - hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1); - } + hwif->OUTSL(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount); + } else + hwif->OUTSW(hwif->io_ports[IDE_DATA_OFFSET], buffer, + wcount << 1); } /* @@ -243,13 +252,15 @@ static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) #if defined(CONFIG_ATARI) || defined(CONFIG_Q40) if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ - insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); + insw_swapw(hwif->io_ports[IDE_DATA_OFFSET], buffer, + bytecount / 2); return; } #endif /* CONFIG_ATARI || CONFIG_Q40 */ hwif->ata_input_data(drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) - hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1); + hwif->INSW(hwif->io_ports[IDE_DATA_OFFSET], + (u8 *)buffer + (bytecount & ~0x03), 1); } static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) @@ -260,13 +271,15 @@ static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) #if defined(CONFIG_ATARI) || defined(CONFIG_Q40) if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ - outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); + outsw_swapw(hwif->io_ports[IDE_DATA_OFFSET], buffer, + bytecount / 2); return; } #endif /* CONFIG_ATARI || CONFIG_Q40 */ hwif->ata_output_data(drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) - hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1); + hwif->OUTSW(hwif->io_ports[IDE_DATA_OFFSET], + (u8 *)buffer + (bytecount & ~0x03), 1); } void default_hwif_transport(ide_hwif_t *hwif) @@ -429,7 +442,7 @@ int drive_is_ready (ide_drive_t *drive) * an interrupt with another pci card/device. We make no assumptions * about possible isa-pnp and pci-pnp issues yet. */ - if (IDE_CONTROL_REG) + if (hwif->io_ports[IDE_CONTROL_OFFSET]) stat = ide_read_altstatus(drive); else /* Note: this may clear a pending IRQ!! */ @@ -631,7 +644,7 @@ int ide_driveid_update(ide_drive_t *drive) SELECT_MASK(drive, 1); ide_set_irq(drive, 1); msleep(50); - hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG); + hwif->OUTB(WIN_IDENTIFY, hwif->io_ports[IDE_COMMAND_OFFSET]); timeout = jiffies + WAIT_WORSTCASE; do { if (time_after(jiffies, timeout)) { @@ -718,9 +731,10 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) SELECT_MASK(drive, 0); udelay(1); ide_set_irq(drive, 0); - hwif->OUTB(speed, IDE_NSECTOR_REG); - hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); + hwif->OUTB(speed, hwif->io_ports[IDE_NSECTOR_OFFSET]); + hwif->OUTB(SETFEATURES_XFER, hwif->io_ports[IDE_FEATURE_OFFSET]); + hwif->OUTBSYNC(drive, WIN_SETFEATURES, + hwif->io_ports[IDE_COMMAND_OFFSET]); if (drive->quirk_list == 2) ide_set_irq(drive, 1); @@ -828,7 +842,7 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, spin_lock_irqsave(&ide_lock, flags); __ide_set_handler(drive, handler, timeout, expiry); - hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, cmd, hwif->io_ports[IDE_COMMAND_OFFSET]); /* * Drive takes 400nS to respond, we must avoid the IRQ being * serviced before that. @@ -1009,7 +1023,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) unsigned long flags; ide_hwif_t *hwif; ide_hwgroup_t *hwgroup; - + u8 ctl; + spin_lock_irqsave(&ide_lock, flags); hwif = HWIF(drive); hwgroup = HWGROUP(drive); @@ -1023,7 +1038,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) pre_reset(drive); SELECT_DRIVE(drive); udelay (20); - hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, WIN_SRST, + hwif->io_ports[IDE_COMMAND_OFFSET]); ndelay(400); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; hwgroup->polling = 1; @@ -1039,7 +1055,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) for (unit = 0; unit < MAX_DRIVES; ++unit) pre_reset(&hwif->drives[unit]); - if (!IDE_CONTROL_REG) { + if (hwif->io_ports[IDE_CONTROL_OFFSET] == 0) { spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; } @@ -1054,16 +1070,14 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) * recover from reset very quickly, saving us the first 50ms wait time. */ /* set SRST and nIEN */ - hwif->OUTBSYNC(drive, drive->ctl|6,IDE_CONTROL_REG); + hwif->OUTBSYNC(drive, drive->ctl|6, hwif->io_ports[IDE_CONTROL_OFFSET]); /* more than enough time */ udelay(10); - if (drive->quirk_list == 2) { - /* clear SRST and nIEN */ - hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG); - } else { - /* clear SRST, leave nIEN */ - hwif->OUTBSYNC(drive, drive->ctl|2, IDE_CONTROL_REG); - } + if (drive->quirk_list == 2) + ctl = drive->ctl; /* clear SRST and nIEN */ + else + ctl = drive->ctl | 2; /* clear SRST, leave nIEN */ + hwif->OUTBSYNC(drive, ctl, hwif->io_ports[IDE_CONTROL_OFFSET]); /* more than enough time */ udelay(10); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 33cb5e5a249b..10ccf278d5be 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -271,7 +271,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) /* take a deep breath */ msleep(50); - if (IDE_CONTROL_REG) { + if (hwif->io_ports[IDE_CONTROL_OFFSET]) { a = ide_read_altstatus(drive); s = ide_read_status(drive); if ((a ^ s) & ~INDEX_STAT) @@ -289,10 +289,10 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) */ if ((cmd == WIN_PIDENTIFY)) /* disable dma & overlap */ - hwif->OUTB(0, IDE_FEATURE_REG); + hwif->OUTB(0, hwif->io_ports[IDE_FEATURE_OFFSET]); /* ask drive for ID */ - hwif->OUTB(cmd, IDE_COMMAND_REG); + hwif->OUTB(cmd, hwif->io_ports[IDE_COMMAND_OFFSET]); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; @@ -353,7 +353,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) * interrupts during the identify-phase that * the irq handler isn't expecting. */ - if (IDE_CONTROL_REG) { + if (hwif->io_ports[IDE_CONTROL_OFFSET]) { if (!hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); @@ -445,7 +445,8 @@ static int do_probe (ide_drive_t *drive, u8 cmd) msleep(50); SELECT_DRIVE(drive); msleep(50); - if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) { + if (hwif->INB(hwif->io_ports[IDE_SELECT_OFFSET]) != drive->select.all && + !drive->present) { if (drive->select.b.unit != 0) { /* exit with drive0 selected */ SELECT_DRIVE(&hwif->drives[0]); @@ -477,9 +478,11 @@ static int do_probe (ide_drive_t *drive, u8 cmd) printk(KERN_ERR "%s: no response (status = 0x%02x), " "resetting drive\n", drive->name, stat); msleep(50); - hwif->OUTB(drive->select.all, IDE_SELECT_REG); + hwif->OUTB(drive->select.all, + hwif->io_ports[IDE_SELECT_OFFSET]); msleep(50); - hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); + hwif->OUTB(WIN_SRST, + hwif->io_ports[IDE_COMMAND_OFFSET]); (void)ide_busy_sleep(hwif); rc = try_to_identify(drive, cmd); } @@ -515,7 +518,7 @@ static void enable_nest (ide_drive_t *drive) printk("%s: enabling %s -- ", hwif->name, drive->id->model); SELECT_DRIVE(drive); msleep(50); - hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); + hwif->OUTB(EXABYTE_ENABLE_NEST, hwif->io_ports[IDE_COMMAND_OFFSET]); if (ide_busy_sleep(hwif)) { printk(KERN_CONT "failed (timeout)\n"); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index bfdc4f449797..8c39146b6088 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1117,10 +1117,10 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); + bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) | + hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]); - ireason = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if (ireason & CD) { printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__); @@ -1224,12 +1224,12 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) "yet DRQ isn't asserted\n"); return startstop; } - ireason = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n"); udelay(100); - ireason = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if (retries == 0) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " "issuing a packet command, ignoring\n"); @@ -1323,7 +1323,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, idetape_pc_t *pc) IDETAPE_WAIT_CMD, NULL); return ide_started; } else { - hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); + hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]); return idetape_transfer_pc(drive); } } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 4c86a8d84b4c..155cc904f4eb 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -59,32 +59,34 @@ void ide_tf_load(ide_drive_t *drive, ide_task_t *task) SELECT_MASK(drive, 0); if (task->tf_flags & IDE_TFLAG_OUT_DATA) - hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG); + hwif->OUTW((tf->hob_data << 8) | tf->data, + hwif->io_ports[IDE_DATA_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) - hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG); + hwif->OUTB(tf->hob_feature, hwif->io_ports[IDE_FEATURE_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) - hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG); + hwif->OUTB(tf->hob_nsect, hwif->io_ports[IDE_NSECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) - hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG); + hwif->OUTB(tf->hob_lbal, hwif->io_ports[IDE_SECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) - hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG); + hwif->OUTB(tf->hob_lbam, hwif->io_ports[IDE_LCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) - hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG); + hwif->OUTB(tf->hob_lbah, hwif->io_ports[IDE_HCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) - hwif->OUTB(tf->feature, IDE_FEATURE_REG); + hwif->OUTB(tf->feature, hwif->io_ports[IDE_FEATURE_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_NSECT) - hwif->OUTB(tf->nsect, IDE_NSECTOR_REG); + hwif->OUTB(tf->nsect, hwif->io_ports[IDE_NSECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_LBAL) - hwif->OUTB(tf->lbal, IDE_SECTOR_REG); + hwif->OUTB(tf->lbal, hwif->io_ports[IDE_SECTOR_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_LBAM) - hwif->OUTB(tf->lbam, IDE_LCYL_REG); + hwif->OUTB(tf->lbam, hwif->io_ports[IDE_LCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_LBAH) - hwif->OUTB(tf->lbah, IDE_HCYL_REG); + hwif->OUTB(tf->lbah, hwif->io_ports[IDE_HCYL_OFFSET]); if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) - hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG); + hwif->OUTB((tf->device & HIHI) | drive->select.all, + hwif->io_ports[IDE_SELECT_OFFSET]); } int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) @@ -152,7 +154,8 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) switch (task->data_phase) { case TASKFILE_MULTI_OUT: case TASKFILE_OUT: - hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, tf->command, + hwif->io_ports[IDE_COMMAND_OFFSET]); ndelay(400); /* FIXME */ return pre_task_out_intr(drive, task->rq); case TASKFILE_MULTI_IN: diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index 78ca68e60f97..314e6c6aeb6c 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -82,7 +82,7 @@ * out how they setup those cycle time interfacing values, as they at Holtek * call them. IDESETUP.COM that is supplied with the drivers figures out * optimal values and fetches those values to drivers. I found out that - * they use IDE_SELECT_REG to fetch timings to the ide board right after + * they use Select register to fetch timings to the ide board right after * interface switching. After that it was quite easy to add code to * ht6560b.c. * @@ -127,6 +127,7 @@ */ static void ht6560b_selectproc (ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; unsigned long flags; static u8 current_select = 0; static u8 current_timing = 0; @@ -155,8 +156,8 @@ static void ht6560b_selectproc (ide_drive_t *drive) /* * Set timing for this drive: */ - outb(timing, IDE_SELECT_REG); - (void)inb(IDE_STATUS_REG); + outb(timing, hwif->io_ports[IDE_SELECT_OFFSET]); + (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]); #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); @@ -193,9 +194,9 @@ static int __init try_to_init_ht6560b(void) * Ht6560b autodetected */ outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); - outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ - (void) inb(0x1f7); /* IDE_STATUS_REG */ - + outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */ + (void)inb(0x1f7); /* Status register */ + printk("ht6560b " HT6560B_VERSION ": chipset detected and initialized" #ifdef DEBUG diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index d03a231d965e..82d0e318a1fe 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -760,7 +760,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask) } } else outb(mask ? (drive->ctl | 2) : (drive->ctl & ~2), - IDE_CONTROL_REG); + hwif->io_ports[IDE_CONTROL_OFFSET]); } /* diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 1a560dc1eac1..ef07c7a8b97a 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -334,7 +334,8 @@ static int scc_ide_dma_end(ide_drive_t * drive) /* errata A308 workaround: Step5 (check data loss) */ /* We don't check non ide_disk because it is limited to UDMA4 */ - if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) && + if (!(in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET]) + & ERR_STAT) && drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) { reg = in_be32((void __iomem *)intsts_port); if (!(reg & INTSTS_ACTEINT)) { @@ -437,7 +438,8 @@ static int scc_dma_test_irq(ide_drive_t *drive) u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014); /* SCC errata A252,A308 workaround: Step4 */ - if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) && + if ((in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET]) + & ERR_STAT) && (int_stat & INTSTS_INTRQ)) return 1; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 9046a69117ff..9d1a3038af9b 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -112,10 +112,9 @@ static void sgiioc4_maskproc(ide_drive_t * drive, int mask) { writeb(mask ? (drive->ctl | 2) : (drive->ctl & ~2), - (void __iomem *)IDE_CONTROL_REG); + (void __iomem *)drive->hwif->io_ports[IDE_CONTROL_OFFSET]); } - static int sgiioc4_checkirq(ide_hwif_t * hwif) { @@ -142,18 +141,18 @@ sgiioc4_clearirq(ide_drive_t * drive) intr_reg = readl((void __iomem *)other_ir); if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ /* - * Using sgiioc4_INB to read the IDE_STATUS_REG has a side effect - * of clearing the interrupt. The first read should clear it - * if it is set. The second read should return a "clear" status - * if it got cleared. If not, then spin for a bit trying to - * clear it. + * Using sgiioc4_INB to read the Status register has a side + * effect of clearing the interrupt. The first read should + * clear it if it is set. The second read should return + * a "clear" status if it got cleared. If not, then spin + * for a bit trying to clear it. */ - u8 stat = sgiioc4_INB(IDE_STATUS_REG); + u8 stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]); int count = 0; - stat = sgiioc4_INB(IDE_STATUS_REG); + stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]); while ((stat & 0x80) && (count++ < 100)) { udelay(1); - stat = sgiioc4_INB(IDE_STATUS_REG); + stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]); } if (intr_reg & 0x02) { diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index b37dcfbdaad6..03a77713caf2 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -450,7 +450,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw, hw->dev = &pmac_ide[ix].mdev->ofdev.dev; } -#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x))) +#define PMAC_IDE_REG(x) \ + ((void __iomem *)((drive)->hwif->io_ports[IDE_DATA_OFFSET] + (x))) /* * Apply the timings of the proper unit (master/slave) to the shared diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 3c3b3502c4d4..7fea769cf291 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -275,9 +275,12 @@ static int idescsi_end_request(ide_drive_t *, int, int); static ide_startstop_t idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) { + ide_hwif_t *hwif = drive->hwif; + if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + hwif->OUTB(WIN_IDLEIMMEDIATE, + hwif->io_ports[IDE_COMMAND_OFFSET]); rq->errors++; @@ -423,9 +426,9 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) idescsi_end_request (drive, 1, 0); return ide_stopped; } - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); - ireason = hwif->INB(IDE_IREASON_REG); + bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) | + hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if (ireason & CD) { printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n"); @@ -497,7 +500,7 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while " "issuing a packet command\n"); @@ -587,7 +590,7 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) return ide_started; } else { /* Issue the packet command */ - HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); + hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]); return idescsi_transfer_pc(drive); } } diff --git a/include/linux/ide.h b/include/linux/ide.h index 2eb99cab4a3d..3b691cce00e1 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -82,24 +82,10 @@ typedef unsigned char byte; /* used everywhere */ #define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET #define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -#define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET]) -#define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET]) -#define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET]) -#define IDE_SECTOR_REG (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET]) -#define IDE_LCYL_REG (HWIF(drive)->io_ports[IDE_LCYL_OFFSET]) -#define IDE_HCYL_REG (HWIF(drive)->io_ports[IDE_HCYL_OFFSET]) -#define IDE_SELECT_REG (HWIF(drive)->io_ports[IDE_SELECT_OFFSET]) -#define IDE_STATUS_REG (HWIF(drive)->io_ports[IDE_STATUS_OFFSET]) -#define IDE_CONTROL_REG (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]) -#define IDE_IRQ_REG (HWIF(drive)->io_ports[IDE_IRQ_OFFSET]) - -#define IDE_FEATURE_REG IDE_ERROR_REG -#define IDE_COMMAND_REG IDE_STATUS_REG -#define IDE_ALTSTATUS_REG IDE_CONTROL_REG -#define IDE_IREASON_REG IDE_NSECTOR_REG -#define IDE_BCOUNTL_REG IDE_LCYL_REG -#define IDE_BCOUNTH_REG IDE_HCYL_REG +#define IDE_ALTSTATUS_OFFSET IDE_CONTROL_OFFSET +#define IDE_IREASON_OFFSET IDE_NSECTOR_OFFSET +#define IDE_BCOUNTL_OFFSET IDE_LCYL_OFFSET +#define IDE_BCOUNTH_OFFSET IDE_HCYL_OFFSET #define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) #define BAD_R_STAT (BUSY_STAT | ERR_STAT) @@ -369,7 +355,7 @@ typedef struct ide_drive_s { u8 wcache; /* status of write cache */ u8 acoustic; /* acoustic management */ u8 media; /* disk, cdrom, tape, floppy, ... */ - u8 ctl; /* "normal" value for IDE_CONTROL_REG */ + u8 ctl; /* "normal" value for Control register */ u8 ready_stat; /* min status value for drive ready */ u8 mult_count; /* current multiple sector setting */ u8 mult_req; /* requested multiple sector setting */ @@ -1273,7 +1259,10 @@ static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive) static inline void ide_set_irq(ide_drive_t *drive, int on) { - drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG); + ide_hwif_t *hwif = drive->hwif; + + hwif->OUTB(drive->ctl | (on ? 0 : 2), + hwif->io_ports[IDE_CONTROL_OFFSET]); } static inline u8 ide_read_status(ide_drive_t *drive) -- cgit v1.2.3 From 8303b46e18b58b2d0257e6842e60b50ac880a6d1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 18 Apr 2008 00:46:26 +0200 Subject: ide: add generic packet command representation ide_atapi_pc This new struct unifies ide{-floppy,-tape,-scsi}'s view of a packet command. For now, it represents the common denominator between the three drivers while adding driver- specific members at the end of the struct which will be merged/simplified into the generic ATAPI handling code in later steps, or removed completely. Bart: - move struct ide_atapi_pc outside of #ifdef/#endif CONFIG_IDE_PROC_FS Signed-off-by: Borislav Petkov Signed-off-by: Bartlomiej Zolnierkiewicz --- include/linux/ide.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ide.h b/include/linux/ide.h index 3b691cce00e1..e9b1def1e66a 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -595,6 +595,53 @@ int set_io_32bit(ide_drive_t *, int); int set_pio_mode(ide_drive_t *, int); int set_using_dma(ide_drive_t *, int); +struct ide_atapi_pc { + /* actual packet bytes */ + u8 c[12]; + /* incremented on each retry */ + int retries; + int error; + + /* bytes to transfer */ + int req_xfer; + /* bytes actually transferred */ + int xferred; + + /* data buffer */ + u8 *buf; + /* current buffer position */ + u8 *cur_pos; + int buf_size; + /* missing/available data on the current buffer */ + int b_count; + + /* the corresponding request */ + struct request *rq; + + unsigned long flags; + + /* + * those are more or less driver-specific and some of them are subject + * to change/removal later. + */ + u8 pc_buf[256]; + void (*idefloppy_callback) (ide_drive_t *); + ide_startstop_t (*idetape_callback) (ide_drive_t *); + + /* idetape only */ + struct idetape_bh *bh; + char *b_data; + + /* idescsi only for now */ + struct scatterlist *sg; + unsigned int sg_cnt; + + struct scsi_cmnd *scsi_cmd; + void (*done) (struct scsi_cmnd *); + + unsigned long timeout; +}; + #ifdef CONFIG_IDE_PROC_FS /* * configurable drive settings -- cgit v1.2.3 From eaec3e7ded9dbc88bad393c076b65f4b7b11d30d Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 18 Apr 2008 00:46:27 +0200 Subject: ide: use generic ATAPI packet command flags in ide-{floppy,tape} Signed-off-by: Borislav Petkov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-floppy.c | 14 -------------- drivers/ide/ide-tape.c | 16 ---------------- include/linux/ide.h | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index bf1ef60a5a07..5f133dfb541c 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -78,20 +78,6 @@ */ #define IDEFLOPPY_PC_STACK (10 + IDEFLOPPY_MAX_PC_RETRIES) -/* Packet command flag bits. */ -enum { - /* 1 when we prefer to use DMA if possible */ - PC_FLAG_DMA_RECOMMENDED = (1 << 0), - /* 1 while DMA in progress */ - PC_FLAG_DMA_IN_PROGRESS = (1 << 1), - /* 1 when encountered problem during DMA */ - PC_FLAG_DMA_ERROR = (1 << 2), - /* Data direction */ - PC_FLAG_WRITING = (1 << 3), - /* Suppress error reporting */ - PC_FLAG_SUPPRESS_ERROR = (1 << 4), -}; - /* format capacities descriptor codes */ #define CAPACITY_INVALID 0x00 #define CAPACITY_UNFORMATTED 0x01 diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 3f9dcca6f092..f43fd070f1b6 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -181,22 +181,6 @@ struct idetape_bh { char *b_data; }; -/* Packet command flag bits. */ -enum { - /* Set when an error is considered normal - We won't retry */ - PC_FLAG_ABORT = (1 << 0), - /* 1 When polling for DSC on a media access command */ - PC_FLAG_WAIT_FOR_DSC = (1 << 1), - /* 1 when we prefer to use DMA if possible */ - PC_FLAG_DMA_RECOMMENDED = (1 << 2), - /* 1 while DMA in progress */ - PC_FLAG_DMA_IN_PROGRESS = (1 << 3), - /* 1 when encountered problem during DMA */ - PC_FLAG_DMA_ERROR = (1 << 4), - /* Data direction */ - PC_FLAG_WRITING = (1 << 5), -}; - /* Tape door status */ #define DOOR_UNLOCKED 0 #define DOOR_LOCKED 1 diff --git a/include/linux/ide.h b/include/linux/ide.h index e9b1def1e66a..65445b7efc63 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -595,6 +595,21 @@ int set_io_32bit(ide_drive_t *, int); int set_pio_mode(ide_drive_t *, int); int set_using_dma(ide_drive_t *, int); +/* ATAPI packet command flags */ +enum { + /* set when an error is considered normal - no retry (ide-tape) */ + PC_FLAG_ABORT = (1 << 0), + PC_FLAG_SUPPRESS_ERROR = (1 << 1), + PC_FLAG_WAIT_FOR_DSC = (1 << 2), + PC_FLAG_DMA_OK = (1 << 3), + PC_FLAG_DMA_RECOMMENDED = (1 << 4), + PC_FLAG_DMA_IN_PROGRESS = (1 << 5), + PC_FLAG_DMA_ERROR = (1 << 6), + PC_FLAG_WRITING = (1 << 7), + /* command timed out */ + PC_FLAG_TIMEDOUT = (1 << 8), +}; + struct ide_atapi_pc { /* actual packet bytes */ u8 c[12]; -- cgit v1.2.3 From 0e33555fffdc8490630d98070e76e5fe031bcac2 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Apr 2008 00:46:33 +0200 Subject: ide: add CONFIG_IDE_ARCH_OBSOLETE_DEFAULTS (take 2) * Add CONFIG_IDE_ARCH_OBSOLETE_DEFAULTS to drivers/ide/Kconfig and use it instead of defining IDE_ARCH_OBSOLETE_DEFAULTS in . v2: * Define ide_default_irq() in ide-probe.c/ns87415.c if not already defined and drop defining ide_default_irq() for CONFIG_IDE_ARCH_OBSOLETE_DEFAULTS=n. [ Thanks to Stephen Rothwell and David Miller for noticing the problem. ] Cc: Stephen Rothwell Cc: David Miller Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 3 +++ drivers/ide/ide-probe.c | 4 ++++ drivers/ide/ide.c | 4 ++++ drivers/ide/pci/ns87415.c | 4 ++++ include/asm-alpha/ide.h | 3 --- include/asm-ia64/ide.h | 2 -- include/asm-m32r/ide.h | 2 -- include/asm-mips/mach-generic/ide.h | 2 -- include/asm-powerpc/ide.h | 2 -- include/asm-x86/ide.h | 2 -- include/linux/ide.h | 7 ------- 11 files changed, 15 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 4dc2761e9704..a57893c03b7a 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1092,6 +1092,9 @@ config BLK_DEV_IDEDMA config IDE_ARCH_OBSOLETE_INIT def_bool ALPHA || (ARM && !ARCH_L7200) || BLACKFIN || X86 || IA64 || M32R || MIPS || PARISC || PPC || (SUPERH64 && BLK_DEV_IDEPCI) || SPARC +config IDE_ARCH_OBSOLETE_DEFAULTS + def_bool ALPHA || X86 || IA64 || M32R || MIPS || PPC32 + endif config BLK_DEV_HD_ONLY diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 10ccf278d5be..6a196c27b0aa 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1233,6 +1233,10 @@ static void drive_release_dev (struct device *dev) complete(&drive->gendev_rel_comp); } +#ifndef ide_default_irq +#define ide_default_irq(irq) 0 +#endif + static int hwif_init(ide_hwif_t *hwif) { int old_irq; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index c2fb5c964a51..a1a02c74d77f 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -165,6 +165,10 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) } } +#ifndef CONFIG_IDE_ARCH_OBSOLETE_DEFAULTS +# define ide_default_io_base(index) (0) +# define ide_init_default_irq(base) (0) +#endif /* * init_ide_data() sets reasonable default values into all fields diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index bf0d3b2931f1..75513320aad9 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -181,6 +181,10 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive) return 1; } +#ifndef ide_default_irq +#define ide_default_irq(irq) 0 +#endif + static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h index b7bf68d0407b..a2feed30bb68 100644 --- a/include/asm-alpha/ide.h +++ b/include/asm-alpha/ide.h @@ -13,9 +13,6 @@ #ifdef __KERNEL__ - -#define IDE_ARCH_OBSOLETE_DEFAULTS - static inline int ide_default_irq(unsigned long base) { switch (base) { diff --git a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h index 1ccf23809329..09c2a05e1c8a 100644 --- a/include/asm-ia64/ide.h +++ b/include/asm-ia64/ide.h @@ -16,8 +16,6 @@ #include -#define IDE_ARCH_OBSOLETE_DEFAULTS - static inline int ide_default_irq(unsigned long base) { switch (base) { diff --git a/include/asm-m32r/ide.h b/include/asm-m32r/ide.h index 5d2044e529ab..feb7f0d7aca9 100644 --- a/include/asm-m32r/ide.h +++ b/include/asm-m32r/ide.h @@ -23,8 +23,6 @@ # endif #endif -#define IDE_ARCH_OBSOLETE_DEFAULTS - static __inline__ int ide_default_irq(unsigned long base) { switch (base) { diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h index 4ec2b930dfbb..45e24474cf43 100644 --- a/include/asm-mips/mach-generic/ide.h +++ b/include/asm-mips/mach-generic/ide.h @@ -27,8 +27,6 @@ # endif #endif -#define IDE_ARCH_OBSOLETE_DEFAULTS - static __inline__ int ide_probe_legacy(void) { #ifdef CONFIG_PCI diff --git a/include/asm-powerpc/ide.h b/include/asm-powerpc/ide.h index 06549456c953..fef2ef1dbe86 100644 --- a/include/asm-powerpc/ide.h +++ b/include/asm-powerpc/ide.h @@ -31,8 +31,6 @@ #include #include -#define IDE_ARCH_OBSOLETE_DEFAULTS - /* FIXME: use ide_platform host driver */ static __inline__ int ide_default_irq(unsigned long base) { diff --git a/include/asm-x86/ide.h b/include/asm-x86/ide.h index c2552d8bebf7..58080a7111de 100644 --- a/include/asm-x86/ide.h +++ b/include/asm-x86/ide.h @@ -20,8 +20,6 @@ # endif #endif -#define IDE_ARCH_OBSOLETE_DEFAULTS - static __inline__ int ide_default_irq(unsigned long base) { switch (base) { diff --git a/include/linux/ide.h b/include/linux/ide.h index 65445b7efc63..6c39482fd1a1 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -194,13 +194,6 @@ static inline void ide_std_init_ports(hw_regs_t *hw, #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS #endif -/* needed on alpha, x86/x86_64, ia64, mips, ppc32 and sh */ -#ifndef IDE_ARCH_OBSOLETE_DEFAULTS -# define ide_default_io_base(index) (0) -# define ide_default_irq(base) (0) -# define ide_init_default_irq(base) (0) -#endif - /* Currently only m68k, apus and m8xx need it */ #ifndef IDE_ARCH_ACK_INTR # define ide_ack_intr(hwif) (1) -- cgit v1.2.3 From 8a076191f373abaeb4aa5f6755d22e49db98940f Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sat, 1 Mar 2008 21:51:09 +0200 Subject: LSM: Introduce inode_getsecid and ipc_getsecid hooks Introduce inode_getsecid(inode, secid) and ipc_getsecid(ipcp, secid) LSM hooks. These hooks will be used instead of similar exported SELinux interfaces. Let {inode,ipc,task}_getsecid hooks set the secid to 0 by default if CONFIG_SECURITY is not defined or if the hook is set to NULL (dummy). This is done to notify the caller that no valid secid exists. Signed-off-by: Casey Schaufler Signed-off-by: Ahmed S. Darwish Acked-by: James Morris Reviewed-by: Paul Moore --- include/linux/security.h | 30 +++++++++++++++++++++++++++++- security/dummy.c | 16 +++++++++++++++- security/security.c | 10 ++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index c673dfd4dffc..45717d9d9656 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -468,6 +468,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @dentry is the dentry being changed. * Return 0 on success. If error is returned, then the operation * causing setuid bit removal is failed. + * @inode_getsecid: + * Get the secid associated with the node. + * @inode contains a pointer to the inode. + * @secid contains a pointer to the location where result will be saved. + * In case of failure, @secid will be set to zero. * * Security hooks for file operations * @@ -636,6 +641,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @task_getsecid: * Retrieve the security identifier of the process @p. * @p contains the task_struct for the process and place is into @secid. + * In case of failure, @secid will be set to zero. + * * @task_setgroups: * Check permission before setting the supplementary group set of the * current process. @@ -997,6 +1004,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @ipcp contains the kernel IPC permission structure * @flag contains the desired (requested) permission set * Return 0 if permission is granted. + * @ipc_getsecid: + * Get the secid associated with the ipc object. + * @ipcp contains the kernel IPC permission structure. + * @secid contains a pointer to the location where result will be saved. + * In case of failure, @secid will be set to zero. * * Security hooks for individual messages held in System V IPC message queues * @msg_msg_alloc_security: @@ -1317,6 +1329,7 @@ struct security_operations { int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc); int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); + void (*inode_getsecid)(const struct inode *inode, u32 *secid); int (*file_permission) (struct file * file, int mask); int (*file_alloc_security) (struct file * file); @@ -1369,6 +1382,7 @@ struct security_operations { void (*task_to_inode)(struct task_struct *p, struct inode *inode); int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag); + void (*ipc_getsecid) (struct kern_ipc_perm *ipcp, u32 *secid); int (*msg_msg_alloc_security) (struct msg_msg * msg); void (*msg_msg_free_security) (struct msg_msg * msg); @@ -1578,6 +1592,7 @@ int security_inode_killpriv(struct dentry *dentry); int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc); int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size); +void security_inode_getsecid(const struct inode *inode, u32 *secid); int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -1622,6 +1637,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, void security_task_reparent_to_init(struct task_struct *p); void security_task_to_inode(struct task_struct *p, struct inode *inode); int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); +void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid); int security_msg_msg_alloc(struct msg_msg *msg); void security_msg_msg_free(struct msg_msg *msg); int security_msg_queue_alloc(struct msg_queue *msq); @@ -2022,6 +2038,11 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer, return 0; } +static inline void security_inode_getsecid(const struct inode *inode, u32 *secid) +{ + *secid = 0; +} + static inline int security_file_permission (struct file *file, int mask) { return 0; @@ -2137,7 +2158,9 @@ static inline int security_task_getsid (struct task_struct *p) } static inline void security_task_getsecid (struct task_struct *p, u32 *secid) -{ } +{ + *secid = 0; +} static inline int security_task_setgroups (struct group_info *group_info) { @@ -2216,6 +2239,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp, return 0; } +static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + *secid = 0; +} + static inline int security_msg_msg_alloc (struct msg_msg * msg) { return 0; diff --git a/security/dummy.c b/security/dummy.c index 78d8f92310a4..fb2e942efbb6 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -424,6 +424,11 @@ static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t bu return 0; } +static void dummy_inode_getsecid(const struct inode *inode, u32 *secid) +{ + *secid = 0; +} + static int dummy_file_permission (struct file *file, int mask) { return 0; @@ -542,7 +547,9 @@ static int dummy_task_getsid (struct task_struct *p) } static void dummy_task_getsecid (struct task_struct *p, u32 *secid) -{ } +{ + *secid = 0; +} static int dummy_task_setgroups (struct group_info *group_info) { @@ -616,6 +623,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag) return 0; } +static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + *secid = 0; +} + static int dummy_msg_msg_alloc_security (struct msg_msg *msg) { return 0; @@ -1058,6 +1070,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, inode_getsecurity); set_to_dummy_if_null(ops, inode_setsecurity); set_to_dummy_if_null(ops, inode_listsecurity); + set_to_dummy_if_null(ops, inode_getsecid); set_to_dummy_if_null(ops, file_permission); set_to_dummy_if_null(ops, file_alloc_security); set_to_dummy_if_null(ops, file_free_security); @@ -1094,6 +1107,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, task_reparent_to_init); set_to_dummy_if_null(ops, task_to_inode); set_to_dummy_if_null(ops, ipc_permission); + set_to_dummy_if_null(ops, ipc_getsecid); set_to_dummy_if_null(ops, msg_msg_alloc_security); set_to_dummy_if_null(ops, msg_msg_free_security); set_to_dummy_if_null(ops, msg_queue_alloc_security); diff --git a/security/security.c b/security/security.c index 9beecac933b4..290482bdbbb0 100644 --- a/security/security.c +++ b/security/security.c @@ -523,6 +523,11 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer return security_ops->inode_listsecurity(inode, buffer, buffer_size); } +void security_inode_getsecid(const struct inode *inode, u32 *secid) +{ + security_ops->inode_getsecid(inode, secid); +} + int security_file_permission(struct file *file, int mask) { return security_ops->file_permission(file, mask); @@ -712,6 +717,11 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) return security_ops->ipc_permission(ipcp, flag); } +void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + security_ops->ipc_getsecid(ipcp, secid); +} + int security_msg_msg_alloc(struct msg_msg *msg) { return security_ops->msg_msg_alloc_security(msg); -- cgit v1.2.3 From 6b89a74be0fbbc6cc639d5cf7dcf8e6ee0f120a7 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sat, 1 Mar 2008 21:58:32 +0200 Subject: SELinux: remove redundant exports Remove the following exported SELinux interfaces: selinux_get_inode_sid(inode, sid) selinux_get_ipc_sid(ipcp, sid) selinux_get_task_sid(tsk, sid) selinux_sid_to_string(sid, ctx, len) They can be substitued with the following generic equivalents respectively: new LSM hook, inode_getsecid(inode, secid) new LSM hook, ipc_getsecid*(ipcp, secid) LSM hook, task_getsecid(tsk, secid) LSM hook, sid_to_secctx(sid, ctx, len) Signed-off-by: Casey Schaufler Signed-off-by: Ahmed S. Darwish Acked-by: James Morris Reviewed-by: Paul Moore --- include/linux/selinux.h | 62 ---------------------------------------------- security/selinux/exports.c | 42 ------------------------------- 2 files changed, 104 deletions(-) (limited to 'include/linux') diff --git a/include/linux/selinux.h b/include/linux/selinux.h index 8c2cc4c02526..24b0af1c4cac 100644 --- a/include/linux/selinux.h +++ b/include/linux/selinux.h @@ -16,7 +16,6 @@ struct selinux_audit_rule; struct audit_context; -struct inode; struct kern_ipc_perm; #ifdef CONFIG_SECURITY_SELINUX @@ -69,45 +68,6 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, */ void selinux_audit_set_callback(int (*callback)(void)); -/** - * selinux_sid_to_string - map a security context ID to a string - * @sid: security context ID to be converted. - * @ctx: address of context string to be returned - * @ctxlen: length of returned context string. - * - * Returns 0 if successful, -errno if not. On success, the context - * string will be allocated internally, and the caller must call - * kfree() on it after use. - */ -int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen); - -/** - * selinux_get_inode_sid - get the inode's security context ID - * @inode: inode structure to get the sid from. - * @sid: pointer to security context ID to be filled in. - * - * Returns nothing - */ -void selinux_get_inode_sid(const struct inode *inode, u32 *sid); - -/** - * selinux_get_ipc_sid - get the ipc security context ID - * @ipcp: ipc structure to get the sid from. - * @sid: pointer to security context ID to be filled in. - * - * Returns nothing - */ -void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid); - -/** - * selinux_get_task_sid - return the SID of task - * @tsk: the task whose SID will be returned - * @sid: pointer to security context ID to be filled in. - * - * Returns nothing - */ -void selinux_get_task_sid(struct task_struct *tsk, u32 *sid); - /** * selinux_string_to_sid - map a security context string to a security ID * @str: the security context string to be mapped @@ -175,28 +135,6 @@ static inline void selinux_audit_set_callback(int (*callback)(void)) return; } -static inline int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen) -{ - *ctx = NULL; - *ctxlen = 0; - return 0; -} - -static inline void selinux_get_inode_sid(const struct inode *inode, u32 *sid) -{ - *sid = 0; -} - -static inline void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid) -{ - *sid = 0; -} - -static inline void selinux_get_task_sid(struct task_struct *tsk, u32 *sid) -{ - *sid = 0; -} - static inline int selinux_string_to_sid(const char *str, u32 *sid) { *sid = 0; diff --git a/security/selinux/exports.c b/security/selinux/exports.c index 87d2bb3ea355..64af2d3409ef 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -25,48 +25,6 @@ /* SECMARK reference count */ extern atomic_t selinux_secmark_refcount; -int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen) -{ - if (selinux_enabled) - return security_sid_to_context(sid, ctx, ctxlen); - else { - *ctx = NULL; - *ctxlen = 0; - } - - return 0; -} - -void selinux_get_inode_sid(const struct inode *inode, u32 *sid) -{ - if (selinux_enabled) { - struct inode_security_struct *isec = inode->i_security; - *sid = isec->sid; - return; - } - *sid = 0; -} - -void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid) -{ - if (selinux_enabled) { - struct ipc_security_struct *isec = ipcp->security; - *sid = isec->sid; - return; - } - *sid = 0; -} - -void selinux_get_task_sid(struct task_struct *tsk, u32 *sid) -{ - if (selinux_enabled) { - struct task_security_struct *tsec = tsk->security; - *sid = tsec->sid; - return; - } - *sid = 0; -} - int selinux_string_to_sid(char *str, u32 *sid) { if (selinux_enabled) -- cgit v1.2.3 From 03d37d25e0f91b28c4b6d002be6221f1af4b19d8 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sat, 1 Mar 2008 22:00:05 +0200 Subject: LSM/Audit: Introduce generic Audit LSM hooks Introduce a generic Audit interface for security modules by adding the following new LSM hooks: audit_rule_init(field, op, rulestr, lsmrule) audit_rule_known(krule) audit_rule_match(secid, field, op, rule, actx) audit_rule_free(rule) Those hooks are only available if CONFIG_AUDIT is enabled. Signed-off-by: Casey Schaufler Signed-off-by: Ahmed S. Darwish Acked-by: James Morris Reviewed-by: Paul Moore --- include/linux/security.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ security/dummy.c | 31 ++++++++++++++++++++- security/security.c | 25 +++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index 45717d9d9656..697f228daf19 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -37,6 +37,7 @@ extern unsigned securebits; struct ctl_table; +struct audit_krule; /* * These functions are in security/capability.c and are used @@ -1235,6 +1236,37 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @secdata contains the security context. * @seclen contains the length of the security context. * + * Security hooks for Audit + * + * @audit_rule_init: + * Allocate and initialize an LSM audit rule structure. + * @field contains the required Audit action. Fields flags are defined in include/linux/audit.h + * @op contains the operator the rule uses. + * @rulestr contains the context where the rule will be applied to. + * @lsmrule contains a pointer to receive the result. + * Return 0 if @lsmrule has been successfully set, + * -EINVAL in case of an invalid rule. + * + * @audit_rule_known: + * Specifies whether given @rule contains any fields related to current LSM. + * @rule contains the audit rule of interest. + * Return 1 in case of relation found, 0 otherwise. + * + * @audit_rule_match: + * Determine if given @secid matches a rule previously approved + * by @audit_rule_known. + * @secid contains the security id in question. + * @field contains the field which relates to current LSM. + * @op contains the operator that will be used for matching. + * @rule points to the audit rule that will be checked against. + * @actx points to the audit context associated with the check. + * Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure. + * + * @audit_rule_free: + * Deallocate the LSM audit rule structure previously allocated by + * audit_rule_init. + * @rule contains the allocated rule + * * This is the main security structure. */ struct security_operations { @@ -1494,6 +1526,13 @@ struct security_operations { #endif /* CONFIG_KEYS */ +#ifdef CONFIG_AUDIT + int (*audit_rule_init)(u32 field, u32 op, char *rulestr, void **lsmrule); + int (*audit_rule_known)(struct audit_krule *krule); + int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule, + struct audit_context *actx); + void (*audit_rule_free)(void *lsmrule); +#endif /* CONFIG_AUDIT */ }; /* prototypes */ @@ -2700,5 +2739,38 @@ static inline int security_key_permission(key_ref_t key_ref, #endif #endif /* CONFIG_KEYS */ +#ifdef CONFIG_AUDIT +#ifdef CONFIG_SECURITY +int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule); +int security_audit_rule_known(struct audit_krule *krule); +int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, + struct audit_context *actx); +void security_audit_rule_free(void *lsmrule); + +#else + +static inline int security_audit_rule_init(u32 field, u32 op, char *rulestr, + void **lsmrule) +{ + return 0; +} + +static inline int security_audit_rule_known(struct audit_krule *krule) +{ + return 0; +} + +static inline int security_audit_rule_match(u32 secid, u32 field, u32 op, + void *lsmrule, struct audit_context *actx) +{ + return 0; +} + +static inline void security_audit_rule_free(void *lsmrule) +{ } + +#endif /* CONFIG_SECURITY */ +#endif /* CONFIG_AUDIT */ + #endif /* ! __LINUX_SECURITY_H */ diff --git a/security/dummy.c b/security/dummy.c index fb2e942efbb6..1ac9f8e66aa2 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -993,6 +993,30 @@ static inline int dummy_key_permission(key_ref_t key_ref, } #endif /* CONFIG_KEYS */ +#ifdef CONFIG_AUDIT +static inline int dummy_audit_rule_init(u32 field, u32 op, char *rulestr, + void **lsmrule) +{ + return 0; +} + +static inline int dummy_audit_rule_known(struct audit_krule *krule) +{ + return 0; +} + +static inline int dummy_audit_rule_match(u32 secid, u32 field, u32 op, + void *lsmrule, + struct audit_context *actx) +{ + return 0; +} + +static inline void dummy_audit_rule_free(void *lsmrule) +{ } + +#endif /* CONFIG_AUDIT */ + struct security_operations dummy_security_ops; #define set_to_dummy_if_null(ops, function) \ @@ -1182,6 +1206,11 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, key_free); set_to_dummy_if_null(ops, key_permission); #endif /* CONFIG_KEYS */ - +#ifdef CONFIG_AUDIT + set_to_dummy_if_null(ops, audit_rule_init); + set_to_dummy_if_null(ops, audit_rule_known); + set_to_dummy_if_null(ops, audit_rule_match); + set_to_dummy_if_null(ops, audit_rule_free); +#endif } diff --git a/security/security.c b/security/security.c index 290482bdbbb0..2ef593ec70f3 100644 --- a/security/security.c +++ b/security/security.c @@ -1120,3 +1120,28 @@ int security_key_permission(key_ref_t key_ref, } #endif /* CONFIG_KEYS */ + +#ifdef CONFIG_AUDIT + +int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule) +{ + return security_ops->audit_rule_init(field, op, rulestr, lsmrule); +} + +int security_audit_rule_known(struct audit_krule *krule) +{ + return security_ops->audit_rule_known(krule); +} + +void security_audit_rule_free(void *lsmrule) +{ + security_ops->audit_rule_free(lsmrule); +} + +int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, + struct audit_context *actx) +{ + return security_ops->audit_rule_match(secid, field, op, lsmrule, actx); +} + +#endif /* CONFIG_AUDIT */ -- cgit v1.2.3 From 9d57a7f9e23dc30783d245280fc9907cf2c87837 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sat, 1 Mar 2008 22:03:14 +0200 Subject: SELinux: use new audit hooks, remove redundant exports Setup the new Audit LSM hooks for SELinux. Remove the now redundant exported SELinux Audit interface. Audit: Export 'audit_krule' and 'audit_field' to the public since their internals are needed by the implementation of the new LSM hook 'audit_rule_known'. Signed-off-by: Casey Schaufler Signed-off-by: Ahmed S. Darwish Acked-by: James Morris --- include/linux/audit.h | 29 +++++++++++++++++ include/linux/selinux.h | 72 ------------------------------------------ kernel/audit.h | 25 --------------- security/selinux/hooks.c | 8 +++++ security/selinux/ss/services.c | 45 +++++++++++++++++++------- 5 files changed, 71 insertions(+), 108 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index 2af9ec025015..04869c96016b 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -353,6 +353,33 @@ struct netlink_skb_parms; struct linux_binprm; struct mq_attr; struct mqstat; +struct audit_watch; +struct audit_tree; + +struct audit_krule { + int vers_ops; + u32 flags; + u32 listnr; + u32 action; + u32 mask[AUDIT_BITMASK_SIZE]; + u32 buflen; /* for data alloc on list rules */ + u32 field_count; + char *filterkey; /* ties events to rules */ + struct audit_field *fields; + struct audit_field *arch_f; /* quick access to arch field */ + struct audit_field *inode_f; /* quick access to an inode field */ + struct audit_watch *watch; /* associated watch */ + struct audit_tree *tree; /* associated watched tree */ + struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ +}; + +struct audit_field { + u32 type; + u32 val; + u32 op; + char *se_str; + void *se_rule; +}; #define AUDITSC_INVALID 0 #define AUDITSC_SUCCESS 1 @@ -536,6 +563,8 @@ extern void audit_log_d_path(struct audit_buffer *ab, const char *prefix, struct path *path); extern void audit_log_lost(const char *message); +extern int audit_update_lsm_rules(void); + /* Private API (for audit.c only) */ extern int audit_filter_user(struct netlink_skb_parms *cb, int type); extern int audit_filter_type(int type); diff --git a/include/linux/selinux.h b/include/linux/selinux.h index 24b0af1c4cac..20f965d4b041 100644 --- a/include/linux/selinux.h +++ b/include/linux/selinux.h @@ -20,54 +20,6 @@ struct kern_ipc_perm; #ifdef CONFIG_SECURITY_SELINUX -/** - * selinux_audit_rule_init - alloc/init an selinux audit rule structure. - * @field: the field this rule refers to - * @op: the operater the rule uses - * @rulestr: the text "target" of the rule - * @rule: pointer to the new rule structure returned via this - * - * Returns 0 if successful, -errno if not. On success, the rule structure - * will be allocated internally. The caller must free this structure with - * selinux_audit_rule_free() after use. - */ -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, - struct selinux_audit_rule **rule); - -/** - * selinux_audit_rule_free - free an selinux audit rule structure. - * @rule: pointer to the audit rule to be freed - * - * This will free all memory associated with the given rule. - * If @rule is NULL, no operation is performed. - */ -void selinux_audit_rule_free(struct selinux_audit_rule *rule); - -/** - * selinux_audit_rule_match - determine if a context ID matches a rule. - * @sid: the context ID to check - * @field: the field this rule refers to - * @op: the operater the rule uses - * @rule: pointer to the audit rule to check against - * @actx: the audit context (can be NULL) associated with the check - * - * Returns 1 if the context id matches the rule, 0 if it does not, and - * -errno on failure. - */ -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, - struct selinux_audit_rule *rule, - struct audit_context *actx); - -/** - * selinux_audit_set_callback - set the callback for policy reloads. - * @callback: the function to call when the policy is reloaded - * - * This sets the function callback function that will update the rules - * upon policy reloads. This callback should rebuild all existing rules - * using selinux_audit_rule_init(). - */ -void selinux_audit_set_callback(int (*callback)(void)); - /** * selinux_string_to_sid - map a security context string to a security ID * @str: the security context string to be mapped @@ -111,30 +63,6 @@ void selinux_secmark_refcount_inc(void); void selinux_secmark_refcount_dec(void); #else -static inline int selinux_audit_rule_init(u32 field, u32 op, - char *rulestr, - struct selinux_audit_rule **rule) -{ - return -EOPNOTSUPP; -} - -static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule) -{ - return; -} - -static inline int selinux_audit_rule_match(u32 sid, u32 field, u32 op, - struct selinux_audit_rule *rule, - struct audit_context *actx) -{ - return 0; -} - -static inline void selinux_audit_set_callback(int (*callback)(void)) -{ - return; -} - static inline int selinux_string_to_sid(const char *str, u32 *sid) { *sid = 0; diff --git a/kernel/audit.h b/kernel/audit.h index 2554bd524fd1..3cfc54ee3e1f 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -65,34 +65,9 @@ struct audit_watch { struct list_head rules; /* associated rules */ }; -struct audit_field { - u32 type; - u32 val; - u32 op; - char *se_str; - struct selinux_audit_rule *se_rule; -}; - struct audit_tree; struct audit_chunk; -struct audit_krule { - int vers_ops; - u32 flags; - u32 listnr; - u32 action; - u32 mask[AUDIT_BITMASK_SIZE]; - u32 buflen; /* for data alloc on list rules */ - u32 field_count; - char *filterkey; /* ties events to rules */ - struct audit_field *fields; - struct audit_field *arch_f; /* quick access to arch field */ - struct audit_field *inode_f; /* quick access to an inode field */ - struct audit_watch *watch; /* associated watch */ - struct audit_tree *tree; /* associated watched tree */ - struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ -}; - struct audit_entry { struct list_head list; struct rcu_head rcu; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bfffaa52e0cb..a2f7e9cf78c5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -83,6 +83,7 @@ #include "netport.h" #include "xfrm.h" #include "netlabel.h" +#include "audit.h" #define XATTR_SELINUX_SUFFIX "selinux" #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX @@ -5478,6 +5479,13 @@ static struct security_operations selinux_ops = { .key_free = selinux_key_free, .key_permission = selinux_key_permission, #endif + +#ifdef CONFIG_AUDIT + .audit_rule_init = selinux_audit_rule_init, + .audit_rule_known = selinux_audit_rule_known, + .audit_rule_match = selinux_audit_rule_match, + .audit_rule_free = selinux_audit_rule_free, +#endif }; static __init int selinux_init(void) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d75050819b06..1e0df5ec1bcd 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -57,6 +57,7 @@ #include "netlabel.h" #include "xfrm.h" #include "ebitmap.h" +#include "audit.h" extern void selnl_notify_policyload(u32 seqno); unsigned int policydb_loaded_version; @@ -2296,21 +2297,23 @@ struct selinux_audit_rule { struct context au_ctxt; }; -void selinux_audit_rule_free(struct selinux_audit_rule *rule) +void selinux_audit_rule_free(void *vrule) { + struct selinux_audit_rule *rule = vrule; + if (rule) { context_destroy(&rule->au_ctxt); kfree(rule); } } -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, - struct selinux_audit_rule **rule) +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) { struct selinux_audit_rule *tmprule; struct role_datum *roledatum; struct type_datum *typedatum; struct user_datum *userdatum; + struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; int rc = 0; *rule = NULL; @@ -2397,12 +2400,37 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, return rc; } -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, - struct selinux_audit_rule *rule, +/* Check to see if the rule contains any selinux fields */ +int selinux_audit_rule_known(struct audit_krule *rule) +{ + int i; + + for (i = 0; i < rule->field_count; i++) { + struct audit_field *f = &rule->fields[i]; + switch (f->type) { + case AUDIT_SUBJ_USER: + case AUDIT_SUBJ_ROLE: + case AUDIT_SUBJ_TYPE: + case AUDIT_SUBJ_SEN: + case AUDIT_SUBJ_CLR: + case AUDIT_OBJ_USER: + case AUDIT_OBJ_ROLE: + case AUDIT_OBJ_TYPE: + case AUDIT_OBJ_LEV_LOW: + case AUDIT_OBJ_LEV_HIGH: + return 1; + } + } + + return 0; +} + +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, struct audit_context *actx) { struct context *ctxt; struct mls_level *level; + struct selinux_audit_rule *rule = vrule; int match = 0; if (!rule) { @@ -2509,7 +2537,7 @@ out: return match; } -static int (*aurule_callback)(void) = NULL; +static int (*aurule_callback)(void) = audit_update_lsm_rules; static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, u16 class, u32 perms, u32 *retained) @@ -2534,11 +2562,6 @@ static int __init aurule_init(void) } __initcall(aurule_init); -void selinux_audit_set_callback(int (*callback)(void)) -{ - aurule_callback = callback; -} - #ifdef CONFIG_NETLABEL /** * security_netlbl_cache_add - Add an entry to the NetLabel cache -- cgit v1.2.3 From 04305e4aff8b0533dc05f9f6f1a34d0796bd985f Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sat, 19 Apr 2008 09:59:43 +1000 Subject: Audit: Final renamings and cleanup Rename the se_str and se_rule audit fields elements to lsm_str and lsm_rule to avoid confusion. Signed-off-by: Casey Schaufler Signed-off-by: Ahmed S. Darwish Acked-by: James Morris --- include/linux/audit.h | 4 +-- kernel/auditfilter.c | 40 ++++++++++++------------- kernel/auditsc.c | 12 ++++---- security/selinux/include/audit.h | 65 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 security/selinux/include/audit.h (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index 04869c96016b..4ccb048cae1d 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -377,8 +377,8 @@ struct audit_field { u32 type; u32 val; u32 op; - char *se_str; - void *se_rule; + char *lsm_str; + void *lsm_rule; }; #define AUDITSC_INVALID 0 diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 7c69cb5e44fb..28fef6bf8534 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -139,8 +139,8 @@ static inline void audit_free_rule(struct audit_entry *e) if (e->rule.fields) for (i = 0; i < e->rule.field_count; i++) { struct audit_field *f = &e->rule.fields[i]; - kfree(f->se_str); - security_audit_rule_free(f->se_rule); + kfree(f->lsm_str); + security_audit_rule_free(f->lsm_rule); } kfree(e->rule.fields); kfree(e->rule.filterkey); @@ -554,8 +554,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, f->op = data->fieldflags[i] & AUDIT_OPERATORS; f->type = data->fields[i]; f->val = data->values[i]; - f->se_str = NULL; - f->se_rule = NULL; + f->lsm_str = NULL; + f->lsm_rule = NULL; switch(f->type) { case AUDIT_PID: case AUDIT_UID: @@ -598,7 +598,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, entry->rule.buflen += f->val; err = security_audit_rule_init(f->type, f->op, str, - (void **)&f->se_rule); + (void **)&f->lsm_rule); /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (err == -EINVAL) { @@ -610,7 +610,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, kfree(str); goto exit_free; } else - f->se_str = str; + f->lsm_str = str; break; case AUDIT_WATCH: str = audit_unpack_string(&bufp, &remain, f->val); @@ -754,7 +754,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule) case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: data->buflen += data->values[i] = - audit_pack_string(&bufp, f->se_str); + audit_pack_string(&bufp, f->lsm_str); break; case AUDIT_WATCH: data->buflen += data->values[i] = @@ -806,7 +806,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b) case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: - if (strcmp(a->fields[i].se_str, b->fields[i].se_str)) + if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str)) return 1; break; case AUDIT_WATCH: @@ -862,28 +862,28 @@ out: return new; } -/* Duplicate LSM field information. The se_rule is opaque, so must be +/* Duplicate LSM field information. The lsm_rule is opaque, so must be * re-initialized. */ static inline int audit_dupe_lsm_field(struct audit_field *df, struct audit_field *sf) { int ret = 0; - char *se_str; + char *lsm_str; - /* our own copy of se_str */ - se_str = kstrdup(sf->se_str, GFP_KERNEL); - if (unlikely(!se_str)) + /* our own copy of lsm_str */ + lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL); + if (unlikely(!lsm_str)) return -ENOMEM; - df->se_str = se_str; + df->lsm_str = lsm_str; - /* our own (refreshed) copy of se_rule */ - ret = security_audit_rule_init(df->type, df->op, df->se_str, - (void **)&df->se_rule); + /* our own (refreshed) copy of lsm_rule */ + ret = security_audit_rule_init(df->type, df->op, df->lsm_str, + (void **)&df->lsm_rule); /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (ret == -EINVAL) { printk(KERN_WARNING "audit rule for LSM \'%s\' is " - "invalid\n", df->se_str); + "invalid\n", df->lsm_str); ret = 0; } @@ -930,7 +930,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old, new->tree = old->tree; memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount); - /* deep copy this information, updating the se_rule fields, because + /* deep copy this information, updating the lsm_rule fields, because * the originals will all be freed when the old rule is freed. */ for (i = 0; i < fcount; i++) { switch (new->fields[i].type) { @@ -1762,7 +1762,7 @@ unlock_and_return: return result; } -/* This function will re-initialize the se_rule field of all applicable rules. +/* This function will re-initialize the lsm_rule field of all applicable rules. * It will traverse the filter lists serarching for rules that contain LSM * specific filter fields. When such a rule is found, it is copied, the * LSM field is re-initialized, and the old rule is replaced with the diff --git a/kernel/auditsc.c b/kernel/auditsc.c index c0700535e5c5..56e56ed594a8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -527,14 +527,14 @@ static int audit_filter_rules(struct task_struct *tsk, match for now to avoid losing information that may be wanted. An error message will also be logged upon error */ - if (f->se_rule) { + if (f->lsm_rule) { if (need_sid) { security_task_getsecid(tsk, &sid); need_sid = 0; } result = security_audit_rule_match(sid, f->type, f->op, - f->se_rule, + f->lsm_rule, ctx); } break; @@ -545,18 +545,18 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_OBJ_LEV_HIGH: /* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR also applies here */ - if (f->se_rule) { + if (f->lsm_rule) { /* Find files that match */ if (name) { result = security_audit_rule_match( name->osid, f->type, f->op, - f->se_rule, ctx); + f->lsm_rule, ctx); } else if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (security_audit_rule_match( ctx->names[j].osid, f->type, f->op, - f->se_rule, ctx)) { + f->lsm_rule, ctx)) { ++result; break; } @@ -569,7 +569,7 @@ static int audit_filter_rules(struct task_struct *tsk, aux = aux->next) { if (aux->type == AUDIT_IPC) { struct audit_aux_data_ipcctl *axi = (void *)aux; - if (security_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) { + if (security_audit_rule_match(axi->osid, f->type, f->op, f->lsm_rule, ctx)) { ++result; break; } diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h new file mode 100644 index 000000000000..6c8b9ef15579 --- /dev/null +++ b/security/selinux/include/audit.h @@ -0,0 +1,65 @@ +/* + * SELinux support for the Audit LSM hooks + * + * Most of below header was moved from include/linux/selinux.h which + * is released under below copyrights: + * + * Author: James Morris + * + * Copyright (C) 2005 Red Hat, Inc., James Morris + * Copyright (C) 2006 Trusted Computer Solutions, Inc. + * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez + * + * 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. + */ + +#ifndef _SELINUX_AUDIT_H +#define _SELINUX_AUDIT_H + +/** + * selinux_audit_rule_init - alloc/init an selinux audit rule structure. + * @field: the field this rule refers to + * @op: the operater the rule uses + * @rulestr: the text "target" of the rule + * @rule: pointer to the new rule structure returned via this + * + * Returns 0 if successful, -errno if not. On success, the rule structure + * will be allocated internally. The caller must free this structure with + * selinux_audit_rule_free() after use. + */ +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule); + +/** + * selinux_audit_rule_free - free an selinux audit rule structure. + * @rule: pointer to the audit rule to be freed + * + * This will free all memory associated with the given rule. + * If @rule is NULL, no operation is performed. + */ +void selinux_audit_rule_free(void *rule); + +/** + * selinux_audit_rule_match - determine if a context ID matches a rule. + * @sid: the context ID to check + * @field: the field this rule refers to + * @op: the operater the rule uses + * @rule: pointer to the audit rule to check against + * @actx: the audit context (can be NULL) associated with the check + * + * Returns 1 if the context id matches the rule, 0 if it does not, and + * -errno on failure. + */ +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, + struct audit_context *actx); + +/** + * selinux_audit_rule_known - check to see if rule contains selinux fields. + * @rule: rule to be checked + * Returns 1 if there are selinux fields specified in the rule, 0 otherwise. + */ +int selinux_audit_rule_known(struct audit_krule *krule); + +#endif /* _SELINUX_AUDIT_H */ + -- cgit v1.2.3 From 076c54c5bcaed2081c0cba94a6f77c4d470236ad Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Thu, 6 Mar 2008 18:09:10 +0200 Subject: Security: Introduce security= boot parameter Add the security= boot parameter. This is done to avoid LSM registration clashes in case of more than one bult-in module. User can choose a security module to enable at boot. If no security= boot parameter is specified, only the first LSM asking for registration will be loaded. An invalid security module name will be treated as if no module has been chosen. LSM modules must check now if they are allowed to register by calling security_module_enable(ops) first. Modify SELinux and SMACK to do so. Do not let SMACK register smackfs if it was not chosen on boot. Smackfs assumes that smack hooks are registered and the initial task security setup (swapper->security) is done. Signed-off-by: Ahmed S. Darwish Acked-by: James Morris --- Documentation/kernel-parameters.txt | 6 ++++++ include/linux/security.h | 12 ++++++++++++ security/dummy.c | 4 +++- security/security.c | 38 ++++++++++++++++++++++++++++++++++++- security/selinux/hooks.c | 7 +++++++ security/smack/smack.h | 2 ++ security/smack/smack_lsm.c | 7 ++++++- security/smack/smackfs.c | 11 ++++++++++- 8 files changed, 83 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 256a2162503c..4b0f1ae31a4c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -366,6 +366,12 @@ and is between 256 and 4096 characters. It is defined in the file possible to determine what the correct size should be. This option provides an override for these situations. + security= [SECURITY] Choose a security module to enable at boot. + If this boot parameter is not specified, only the first + security module asking for security registration will be + loaded. An invalid security module name will be treated + as if no module has been chosen. + capability.disable= [SECURITY] Disable capabilities. This would normally be used only if an alternative security model is to be diff --git a/include/linux/security.h b/include/linux/security.h index 697f228daf19..f4116d6ed64b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -36,6 +36,9 @@ extern unsigned securebits; +/* Maximum number of letters for an LSM name string */ +#define SECURITY_NAME_MAX 10 + struct ctl_table; struct audit_krule; @@ -137,6 +140,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) /** * struct security_operations - main security structure * + * Security module identifier. + * + * @name: + * A string that acts as a unique identifeir for the LSM with max number + * of characters = SECURITY_NAME_MAX. + * * Security hooks for program execution operations. * * @bprm_alloc_security: @@ -1270,6 +1279,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * This is the main security structure. */ struct security_operations { + char name[SECURITY_NAME_MAX + 1]; + int (*ptrace) (struct task_struct * parent, struct task_struct * child); int (*capget) (struct task_struct * target, kernel_cap_t * effective, @@ -1537,6 +1548,7 @@ struct security_operations { /* prototypes */ extern int security_init (void); +extern int security_module_enable(struct security_operations *ops); extern int register_security (struct security_operations *ops); extern int mod_reg_security (const char *name, struct security_operations *ops); extern struct dentry *securityfs_create_file(const char *name, mode_t mode, diff --git a/security/dummy.c b/security/dummy.c index 1ac9f8e66aa2..d797a4196b89 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -1017,7 +1017,9 @@ static inline void dummy_audit_rule_free(void *lsmrule) #endif /* CONFIG_AUDIT */ -struct security_operations dummy_security_ops; +struct security_operations dummy_security_ops = { + .name = "dummy", +}; #define set_to_dummy_if_null(ops, function) \ do { \ diff --git a/security/security.c b/security/security.c index 2ef593ec70f3..dd0c6baed494 100644 --- a/security/security.c +++ b/security/security.c @@ -17,6 +17,8 @@ #include #include +/* Boot-time LSM user choice */ +static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1]; /* things that live in dummy.c */ extern struct security_operations dummy_security_ops; @@ -67,13 +69,47 @@ int __init security_init(void) return 0; } +/* Save user chosen LSM */ +static int __init choose_lsm(char *str) +{ + strncpy(chosen_lsm, str, SECURITY_NAME_MAX); + return 1; +} +__setup("security=", choose_lsm); + +/** + * security_module_enable - Load given security module on boot ? + * @ops: a pointer to the struct security_operations that is to be checked. + * + * Each LSM must pass this method before registering its own operations + * to avoid security registration races. This method may also be used + * to check if your LSM is currently loaded. + * + * Return true if: + * -The passed LSM is the one chosen by user at boot time, + * -or user didsn't specify a specific LSM and we're the first to ask + * for registeration permissoin, + * -or the passed LSM is currently loaded. + * Otherwise, return false. + */ +int __init security_module_enable(struct security_operations *ops) +{ + if (!*chosen_lsm) + strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX); + else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX)) + return 0; + + return 1; +} + /** * register_security - registers a security framework with the kernel * @ops: a pointer to the struct security_options that is to be registered * * This function is to allow a security module to register itself with the * kernel security subsystem. Some rudimentary checking is done on the @ops - * value passed to this function. + * value passed to this function. You'll need to check first if your LSM + * is allowed to register its @ops by calling security_module_enable(@ops). * * If there is already a security module registered with the kernel, * an error will be returned. Otherwise 0 is returned on success. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a2f7e9cf78c5..f9927f02bc3d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5295,6 +5295,8 @@ static int selinux_key_permission(key_ref_t key_ref, #endif static struct security_operations selinux_ops = { + .name = "selinux", + .ptrace = selinux_ptrace, .capget = selinux_capget, .capset_check = selinux_capset_check, @@ -5492,6 +5494,11 @@ static __init int selinux_init(void) { struct task_security_struct *tsec; + if (!security_module_enable(&selinux_ops)) { + selinux_enabled = 0; + return 0; + } + if (!selinux_enabled) { printk(KERN_INFO "SELinux: Disabled at boot.\n"); return 0; diff --git a/security/smack/smack.h b/security/smack/smack.h index 62c1e982849d..4a4477f5afdc 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -15,6 +15,7 @@ #include #include +#include #include /* @@ -187,6 +188,7 @@ extern struct smack_known smack_known_star; extern struct smack_known smack_known_unset; extern struct smk_list_entry *smack_list; +extern struct security_operations smack_ops; /* * Stricly for CIPSO level manipulation. diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 732ba27923c4..904bdc01a12b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2424,7 +2424,9 @@ static void smack_release_secctx(char *secdata, u32 seclen) { } -static struct security_operations smack_ops = { +struct security_operations smack_ops = { + .name = "smack", + .ptrace = smack_ptrace, .capget = cap_capget, .capset_check = cap_capset_check, @@ -2557,6 +2559,9 @@ static struct security_operations smack_ops = { */ static __init int smack_init(void) { + if (!security_module_enable(&smack_ops)) + return 0; + printk(KERN_INFO "Smack: Initializing.\n"); /* diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index cfae8afcc262..6ba283783b70 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -965,12 +965,21 @@ static struct vfsmount *smackfs_mount; * * register the smackfs * - * Returns 0 unless the registration fails. + * Do not register smackfs if Smack wasn't enabled + * on boot. We can not put this method normally under the + * smack_init() code path since the security subsystem get + * initialized before the vfs caches. + * + * Returns true if we were not chosen on boot or if + * we were chosen and filesystem registration succeeded. */ static int __init init_smk_fs(void) { int err; + if (!security_module_enable(&smack_ops)) + return 0; + err = register_filesystem(&smk_fs_type); if (!err) { smackfs_mount = kern_mount(&smk_fs_type); -- cgit v1.2.3