From 58a7ce64426394a46e80cdc9440cc1e7c195e85d Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Thu, 30 Mar 2006 17:01:53 +0200 Subject: [PATCH] Goramo PCI200SYN WAN driver subsystem ID patch Goramo finally got PCI subsystem ID for their PCI200SYN card. The attached patch adds support for it - cards with old EEPROM data will emit a warning with URL for update tool. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 870fe38378b1..6a1ef8b635c5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -930,6 +930,7 @@ #define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 #define PCI_DEVICE_ID_PLX_R753 0x1152 #define PCI_DEVICE_ID_PLX_OLITEC 0x1187 +#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196 #define PCI_DEVICE_ID_PLX_9050 0x9050 #define PCI_DEVICE_ID_PLX_9080 0x9080 #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 -- cgit v1.2.3 From ea2841521a7e061b772d6cee03f5b23c58a58284 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 13 Apr 2006 17:17:06 +0800 Subject: [PATCH] ieee80211: Fix TKIP MIC calculation for QoS frames Fix TKIP MIC verification failure when receiving QoS frames from AP. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- include/net/ieee80211.h | 3 +++ net/ieee80211/ieee80211_crypt_tkip.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4725ff861c57..66dc136588a9 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -104,6 +104,9 @@ #define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_SEQ 0xFFF0 +/* QOS control */ +#define IEEE80211_QCTL_TID 0x000F + /* debug macros */ #ifdef CONFIG_IEEE80211_DEBUG diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 93def94c1b32..3fa5df2e1f0b 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -501,8 +501,11 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) { struct ieee80211_hdr_4addr *hdr11; + u16 stype; hdr11 = (struct ieee80211_hdr_4addr *)skb->data; + stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl)); + switch (le16_to_cpu(hdr11->frame_ctl) & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_TODS: @@ -523,7 +526,13 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) break; } - hdr[12] = 0; /* priority */ + if (stype & IEEE80211_STYPE_QOS_DATA) { + const struct ieee80211_hdr_3addrqos *qoshdr = + (struct ieee80211_hdr_3addrqos *)skb->data; + hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID; + } else + hdr[12] = 0; /* priority */ + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ } -- cgit v1.2.3 From 73858062b66c07d71bce47a0e4798dd3ce604590 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 13 Apr 2006 17:17:17 +0800 Subject: [PATCH] ieee80211: Fix TX code doesn't enable QoS when using WPA + QoS Fix ieee80211 TX code when using WPA+QOS. TKIP/CCMP will use the TID field of qos_ctl in 802.11 frame header to do encryption. We cannot ignore this field when doing host encryption and add the qos_ctl field later. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- include/net/ieee80211.h | 1 + net/ieee80211/ieee80211_tx.c | 63 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 66dc136588a9..bc6bdd62c150 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -1076,6 +1076,7 @@ struct ieee80211_device { int (*handle_management) (struct net_device * dev, struct ieee80211_network * network, u16 type); + int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); /* Typical STA methods */ int (*handle_auth) (struct net_device * dev, diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 8b4332f53394..233d527c6953 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -220,13 +220,43 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } +static int ieee80211_classify(struct sk_buff *skb) +{ + struct ethhdr *eth; + struct iphdr *ip; + + eth = (struct ethhdr *)skb->data; + if (eth->h_proto != __constant_htons(ETH_P_IP)) + return 0; + + ip = skb->nh.iph; + switch (ip->tos & 0xfc) { + case 0x20: + return 2; + case 0x40: + return 1; + case 0x60: + return 3; + case 0x80: + return 4; + case 0xa0: + return 5; + case 0xc0: + return 6; + case 0xe0: + return 7; + default: + return 0; + } +} + /* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_txb *txb = NULL; - struct ieee80211_hdr_3addr *frag_hdr; + struct ieee80211_hdr_3addrqos *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, rts_required; unsigned long flags; @@ -234,9 +264,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; int bytes, fc, hdr_len; struct sk_buff *skb_frag; - struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ + struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ .duration_id = 0, - .seq_ctl = 0 + .seq_ctl = 0, + .qos_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; struct ieee80211_crypt_data *crypt; @@ -282,12 +313,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(dest, skb->data, ETH_ALEN); memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); - /* Advance the SKB to the start of the payload */ - skb_pull(skb, sizeof(struct ethhdr)); - - /* Determine total amount of storage required for TXB packets */ - bytes = skb->len + SNAP_SIZE + sizeof(u16); - if (host_encrypt || host_build_iv) fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_PROTECTED; @@ -306,9 +331,23 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN); } - header.frame_ctl = cpu_to_le16(fc); hdr_len = IEEE80211_3ADDR_LEN; + if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { + fc |= IEEE80211_STYPE_QOS_DATA; + hdr_len += 2; + + skb->priority = ieee80211_classify(skb); + header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID; + } + header.frame_ctl = cpu_to_le16(fc); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + /* Encrypt msdu first on the whole data packet. */ if ((host_encrypt || host_encrypt_msdu) && crypt && crypt->ops && crypt->ops->encrypt_msdu) { @@ -402,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (rts_required) { skb_frag = txb->fragments[0]; frag_hdr = - (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); + (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); /* * Set header frame_ctl to the RTS. @@ -433,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) crypt->ops->extra_mpdu_prefix_len); frag_hdr = - (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); + (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); memcpy(frag_hdr, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS -- cgit v1.2.3 From 45a62ab3d6f9d5963cb7c01fa76c950e42d037c2 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 13 Apr 2006 17:17:54 +0800 Subject: [PATCH] ieee80211: update version stamp to 1.1.13 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- include/net/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index bc6bdd62c150..4087dfc47094 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -29,7 +29,7 @@ #include /* ARRAY_SIZE */ #include -#define IEEE80211_VERSION "git-1.1.7" +#define IEEE80211_VERSION "git-1.1.13" #define IEEE80211_DATA_LEN 2304 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section -- cgit v1.2.3 From 9a1771e86756212041b32d80b850cc4c8063360a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Apr 2006 20:02:02 +0200 Subject: [PATCH] softmac: add SIOCSIWMLME This patch adds the SIOCSIWMLME wext to softmac, this functionality appears to be used by wpa_supplicant and is softmac-specific. Signed-off-by: Johannes Berg Cc: Jouni Malinen Signed-off-by: John W. Linville --- include/net/ieee80211softmac_wx.h | 5 ++++ net/ieee80211/softmac/ieee80211softmac_assoc.c | 2 +- net/ieee80211/softmac/ieee80211softmac_priv.h | 1 + net/ieee80211/softmac/ieee80211softmac_wx.c | 32 ++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/ieee80211softmac_wx.h b/include/net/ieee80211softmac_wx.h index 3e0be453ecea..4ee3ad57283f 100644 --- a/include/net/ieee80211softmac_wx.h +++ b/include/net/ieee80211softmac_wx.h @@ -91,4 +91,9 @@ ieee80211softmac_wx_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); +extern int +ieee80211softmac_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra); #endif /* _IEEE80211SOFTMAC_WX */ diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index fb79ce7d6439..ea9f5aacce85 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -82,7 +82,7 @@ ieee80211softmac_assoc_timeout(void *d) } /* Sends out a disassociation request to the desired AP */ -static void +void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) { unsigned long flags; diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index 65d9816c8ecc..8c95b3abe0cc 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -150,6 +150,7 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev, int ieee80211softmac_handle_reassoc_req(struct net_device * dev, struct ieee80211_reassoc_request * reassoc); void ieee80211softmac_assoc_timeout(void *d); +void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason); /* some helper functions */ static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 27edb2b5581a..8d0c22641ca8 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -431,3 +431,35 @@ ieee80211softmac_wx_get_genie(struct net_device *dev, } EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); +int +ieee80211softmac_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct ieee80211softmac_device *mac = ieee80211_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + u16 reason = cpu_to_le16(mlme->reason_code); + struct ieee80211softmac_network *net; + + if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) { + printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n"); + return -EINVAL; + } + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data); + if (!net) { + printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n"); + return -EINVAL; + } + return ieee80211softmac_deauth_req(mac, net, reason); + case IW_MLME_DISASSOC: + ieee80211softmac_disassoc(mac, reason); + return 0; + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme); -- cgit v1.2.3 From 8462fe3cd9ec8951871a20a4dfe36321ab075964 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 1 May 2006 22:45:50 +0100 Subject: [PATCH] softmac: suggest per-frame-type TX rate This patch is the first step towards rate control inside softmac. The txrates substructure has been extended to provide different fields for different types of packets (management/data, unicast/multicast). These fields are updated on association to values compatible with the access point we are associating to. Drivers can then use the new ieee80211softmac_suggest_txrate() function call when deciding which rate to transmit each frame at. This is immensely useful for ZD1211, and bcm can use it too. The user can still specify a rate through iwconfig, which is matched for all transmissions (assuming the rate they have specified is in the rate set required by the AP). At a later date, we can incorporate automatic rate management into the ieee80211softmac_recalc_txrates() function. This patch also removes the mcast_fallback field. Sam Leffler pointed out that this field is meaningless, because no driver will ever be retransmitting mcast frames (they are not acked). Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/ieee80211softmac.h | 38 +++++++- net/ieee80211/softmac/ieee80211softmac_assoc.c | 19 ++-- net/ieee80211/softmac/ieee80211softmac_module.c | 117 +++++++++++++++++++----- net/ieee80211/softmac/ieee80211softmac_priv.h | 3 + net/ieee80211/softmac/ieee80211softmac_wx.c | 4 +- 5 files changed, 141 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index 052ed596a4e4..703463a8828b 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -86,6 +86,9 @@ struct ieee80211softmac_assoc_info { /* BSSID we're trying to associate to */ char bssid[ETH_ALEN]; + + /* Rates supported by the network */ + struct ieee80211softmac_ratesinfo supported_rates; /* some flags. * static_essid is valid if the essid is constant, @@ -132,23 +135,26 @@ enum { struct ieee80211softmac_txrates { /* The Bit-Rate to be used for multicast frames. */ u8 mcast_rate; - /* The Bit-Rate to be used for multicast fallback - * (If the device supports fallback and hardware-retry) - */ - u8 mcast_fallback; + + /* The Bit-Rate to be used for multicast management frames. */ + u8 mgt_mcast_rate; + /* The Bit-Rate to be used for any other (normal) data packet. */ u8 default_rate; /* The Bit-Rate to be used for default fallback * (If the device supports fallback and hardware-retry) */ u8 default_fallback; + + /* This is the rate that the user asked for */ + u8 user_rate; }; /* Bits for txrates_change callback. */ #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */ #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */ #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ -#define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK (1 << 3) /* mcast_fallback */ +#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */ struct ieee80211softmac_device { /* 802.11 structure for data stuff */ @@ -250,6 +256,28 @@ extern void ieee80211softmac_fragment_lost(struct net_device *dev, * Note that the rates need to be sorted. */ extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates); +/* Helper function which advises you the rate at which a frame should be + * transmitted at. */ +static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac, + int is_multicast, + int is_mgt) +{ + struct ieee80211softmac_txrates *txrates = &mac->txrates; + + if (!mac->associated) + return txrates->mgt_mcast_rate; + + /* We are associated, sending unicast frame */ + if (!is_multicast) + return txrates->default_rate; + + /* We are associated, sending multicast frame */ + if (is_mgt) + return txrates->mgt_mcast_rate; + else + return txrates->mcast_rate; +} + /* Start the SoftMAC. Call this after you initialized the device * and it is ready to run. */ diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 01f21334767c..5d90b9a6ee50 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -96,6 +96,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac) mac->associated = 0; mac->associnfo.bssvalid = 0; mac->associnfo.associating = 0; + ieee80211softmac_init_txrates(mac); ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); spin_unlock_irqrestore(&mac->lock, flags); } @@ -118,24 +119,15 @@ ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reas static inline int we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) { - int idx, search, found; - u8 rate, search_rate; + int idx; + u8 rate; for (idx = 0; idx < (from_len); idx++) { rate = (from)[idx]; if (!(rate & IEEE80211_BASIC_RATE_MASK)) continue; - found = 0; rate &= ~IEEE80211_BASIC_RATE_MASK; - for (search = 0; search < mac->ratesinfo.count; search++) { - search_rate = mac->ratesinfo.rates[search]; - search_rate &= ~IEEE80211_BASIC_RATE_MASK; - if (rate == search_rate) { - found = 1; - break; - } - } - if (!found) + if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) return 0; } return 1; @@ -310,6 +302,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) { mac->associnfo.associating = 0; + mac->associnfo.supported_rates = net->supported_rates; + ieee80211softmac_recalc_txrates(mac); + mac->associated = 1; if (mac->set_bssid_filter) mac->set_bssid_filter(mac->dev, net->bssid); diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index 6252be2c0db9..4b2e57d12418 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -26,6 +26,7 @@ #include "ieee80211softmac_priv.h" #include +#include struct net_device *alloc_ieee80211softmac(int sizeof_priv) { @@ -61,14 +62,6 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv) softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; softmac->stop_scan = ieee80211softmac_stop_scan_implementation; - //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...) - // It has to be set to the highest rate all stations in the current network can handle. - softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB; - softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB; - /* This is reassigned in ieee80211softmac_start to sane values. */ - softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB; - softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB; - /* to start with, we can't send anything ... */ netif_carrier_off(dev); @@ -170,15 +163,82 @@ static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *m } } -void ieee80211softmac_start(struct net_device *dev) +int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate) +{ + int search; + u8 search_rate; + + for (search = 0; search < ri->count; search++) { + search_rate = ri->rates[search]; + search_rate &= ~IEEE80211_BASIC_RATE_MASK; + if (rate == search_rate) + return 1; + } + + return 0; +} + +/* Finds the highest rate which is: + * 1. Present in ri (optionally a basic rate) + * 2. Supported by the device + * 3. Less than or equal to the user-defined rate + */ +static u8 highest_supported_rate(struct ieee80211softmac_device *mac, + struct ieee80211softmac_ratesinfo *ri, int basic_only) +{ + u8 user_rate = mac->txrates.user_rate; + int i; + + if (ri->count == 0) { + dprintk(KERN_ERR PFX "empty ratesinfo?\n"); + return IEEE80211_CCK_RATE_1MB; + } + + for (i = ri->count - 1; i >= 0; i--) { + u8 rate = ri->rates[i]; + if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK)) + continue; + rate &= ~IEEE80211_BASIC_RATE_MASK; + if (rate > user_rate) + continue; + if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) + return rate; + } + + /* If we haven't found a suitable rate by now, just trust the user */ + return user_rate; +} + +void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac) +{ + struct ieee80211softmac_txrates *txrates = &mac->txrates; + struct ieee80211softmac_txrates oldrates; + u32 change = 0; + + if (mac->txrates_change) + oldrates = mac->txrates; + + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; + txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0); + + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + txrates->default_fallback = lower_rate(mac, txrates->default_rate); + + change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; + txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1); + + if (mac->txrates_change) + mac->txrates_change(mac->dev, change, &oldrates); + +} + +void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac) { - struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211_device *ieee = mac->ieee; u32 change = 0; + struct ieee80211softmac_txrates *txrates = &mac->txrates; struct ieee80211softmac_txrates oldrates; - ieee80211softmac_start_check_rates(mac); - /* TODO: We need some kind of state machine to lower the default rates * if we loose too many packets. */ @@ -193,22 +253,37 @@ void ieee80211softmac_start(struct net_device *dev) more reliable. Note similar logic in ieee80211softmac_wx_set_rate() */ if (ieee->modulation & IEEE80211_CCK_MODULATION) { - mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + txrates->user_rate = IEEE80211_CCK_RATE_11MB; } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { - mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + txrates->user_rate = IEEE80211_OFDM_RATE_54MB; } else assert(0); + + txrates->default_rate = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; + + txrates->default_fallback = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + + txrates->mcast_rate = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; + + txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; + if (mac->txrates_change) - mac->txrates_change(dev, change, &oldrates); + mac->txrates_change(mac->dev, change, &oldrates); mac->running = 1; } + +void ieee80211softmac_start(struct net_device *dev) +{ + struct ieee80211softmac_device *mac = ieee80211_priv(dev); + + ieee80211softmac_start_check_rates(mac); + ieee80211softmac_init_txrates(mac); +} EXPORT_SYMBOL_GPL(ieee80211softmac_start); void ieee80211softmac_stop(struct net_device *dev) diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index 5de0abf157e3..fa1f8e3acfc0 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid); /* Rates related */ +int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate); u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); +void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac); +void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac); static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { return ieee80211softmac_lower_rate_delta(mac, rate, 1); } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index b7d83cd4d56c..22aa6199185b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -211,8 +211,8 @@ ieee80211softmac_wx_set_rate(struct net_device *net_dev, if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) goto out_unlock; - mac->txrates.default_rate = rate; - mac->txrates.default_fallback = lower_rate(mac, rate); + mac->txrates.user_rate = rate; + ieee80211softmac_recalc_txrates(mac); err = 0; out_unlock: -- cgit v1.2.3 From 3a720d726a6aa0a7cd9190f694587adf7bafdf4f Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 23 May 2006 06:10:01 -0400 Subject: [PATCH] Revive pci_find_ext_capability This patch revives pci_find_ext_capability (has been disabled a couple month ago since it was not used anywhere. See http://lkml.org/lkml/2006/1/20/247). It will now be used by the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: Andrew J. Gallatin drivers/pci/pci.c | 3 +-- include/linux/pci.h | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) Signed-off-by: Jeff Garzik --- drivers/pci/pci.c | 3 +-- include/linux/pci.h | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2329f941a0dc..8d107c6c2c70 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -164,7 +164,6 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap); } -#if 0 /** * pci_find_ext_capability - Find an extended capability * @dev: PCI device to query @@ -212,7 +211,7 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) return 0; } -#endif /* 0 */ +EXPORT_SYMBOL_GPL(pci_find_ext_capability); /** * pci_find_parent_resource - return resource region of parent bus of given region diff --git a/include/linux/pci.h b/include/linux/pci.h index 3a6a4e37a482..6fd36cb09160 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -442,6 +442,7 @@ struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int devic struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); +int pci_find_ext_capability (struct pci_dev *dev, int cap); struct pci_bus * pci_find_next_bus(const struct pci_bus *from); struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); @@ -662,6 +663,7 @@ static inline int pci_register_driver(struct pci_driver *drv) { return 0;} static inline void pci_unregister_driver(struct pci_driver *drv) { } static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; } +static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; } static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } /* Power management related routines */ -- cgit v1.2.3 From 0da34b6dfe55810ae60db57e08e2af8a808c0a55 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 23 May 2006 06:10:15 -0400 Subject: [PATCH] Add Myri-10G Ethernet driver Signed-off-by: Brice Goglin Signed-off-by: Andrew J. Gallatin drivers/net/Kconfig | 17 drivers/net/Makefile | 1 drivers/net/myri10ge/Makefile | 5 drivers/net/myri10ge/myri10ge.c | 2851 +++++++++++++++ drivers/net/myri10ge/myri10ge_mcp.h | 205 + drivers/net/myri10ge/myri10ge_mcp_gen_header.h | 58 include/linux/pci_ids.h | 1 7 files changed, 3138 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 17 + drivers/net/Makefile | 1 + drivers/net/myri10ge/Makefile | 5 + drivers/net/myri10ge/myri10ge.c | 2851 ++++++++++++++++++++++++ drivers/net/myri10ge/myri10ge_mcp.h | 205 ++ drivers/net/myri10ge/myri10ge_mcp_gen_header.h | 58 + include/linux/pci_ids.h | 1 + 7 files changed, 3138 insertions(+) create mode 100644 drivers/net/myri10ge/Makefile create mode 100644 drivers/net/myri10ge/myri10ge.c create mode 100644 drivers/net/myri10ge/myri10ge_mcp.h create mode 100644 drivers/net/myri10ge/myri10ge_mcp_gen_header.h (limited to 'include') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 68bc073b8b31..f499a3bc629f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2327,6 +2327,23 @@ config S2IO_NAPI If in doubt, say N. +config MYRI10GE + tristate "Myricom Myri-10G Ethernet support" + depends on PCI + select FW_LOADER + select CRC32 + ---help--- + This driver supports Myricom Myri-10G Dual Protocol interface in + Ethernet mode. If the eeprom on your board is not recent enough, + you will need a newer firmware image. + You may get this image or more information, at: + + + + To compile this driver as a module, choose M here and read + . The module + will be called myri10ge. + endmenu source "drivers/net/tokenring/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b01cc9a3cb10..1eced3287507 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -192,6 +192,7 @@ obj-$(CONFIG_R8169) += r8169.o obj-$(CONFIG_AMD8111_ETH) += amd8111e.o obj-$(CONFIG_IBMVETH) += ibmveth.o obj-$(CONFIG_S2IO) += s2io.o +obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_DM9000) += dm9000.o diff --git a/drivers/net/myri10ge/Makefile b/drivers/net/myri10ge/Makefile new file mode 100644 index 000000000000..5df891647aee --- /dev/null +++ b/drivers/net/myri10ge/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Myricom Myri-10G ethernet driver +# + +obj-$(CONFIG_MYRI10GE) += myri10ge.o diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c new file mode 100644 index 000000000000..87933cba7e22 --- /dev/null +++ b/drivers/net/myri10ge/myri10ge.c @@ -0,0 +1,2851 @@ +/************************************************************************* + * myri10ge.c: Myricom Myri-10G Ethernet driver. + * + * Copyright (C) 2005, 2006 Myricom, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Myricom, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * If the eeprom on your board is not recent enough, you will need to get a + * newer firmware image at: + * http://www.myri.com/scs/download-Myri10GE.html + * + * Contact Information: + * + * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006 + *************************************************************************/ + +#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 +#ifdef CONFIG_MTRR +#include +#endif + +#include "myri10ge_mcp.h" +#include "myri10ge_mcp_gen_header.h" + +#define MYRI10GE_VERSION_STR "0.9.0" + +MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); +MODULE_AUTHOR("Maintainer: help@myri.com"); +MODULE_VERSION(MYRI10GE_VERSION_STR); +MODULE_LICENSE("Dual BSD/GPL"); + +#define MYRI10GE_MAX_ETHER_MTU 9014 + +#define MYRI10GE_ETH_STOPPED 0 +#define MYRI10GE_ETH_STOPPING 1 +#define MYRI10GE_ETH_STARTING 2 +#define MYRI10GE_ETH_RUNNING 3 +#define MYRI10GE_ETH_OPEN_FAILED 4 + +#define MYRI10GE_EEPROM_STRINGS_SIZE 256 +#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) + +#define MYRI10GE_NO_CONFIRM_DATA 0xffffffff +#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff + +struct myri10ge_rx_buffer_state { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(bus) + DECLARE_PCI_UNMAP_LEN(len) +}; + +struct myri10ge_tx_buffer_state { + struct sk_buff *skb; + int last; + DECLARE_PCI_UNMAP_ADDR(bus) + DECLARE_PCI_UNMAP_LEN(len) +}; + +struct myri10ge_cmd { + u32 data0; + u32 data1; + u32 data2; +}; + +struct myri10ge_rx_buf { + struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */ + u8 __iomem *wc_fifo; /* w/c rx dma addr fifo address */ + struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */ + struct myri10ge_rx_buffer_state *info; + int cnt; + int alloc_fail; + int mask; /* number of rx slots -1 */ +}; + +struct myri10ge_tx_buf { + struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */ + u8 __iomem *wc_fifo; /* w/c send fifo address */ + struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */ + char *req_bytes; + struct myri10ge_tx_buffer_state *info; + int mask; /* number of transmit slots -1 */ + int boundary; /* boundary transmits cannot cross */ + int req ____cacheline_aligned; /* transmit slots submitted */ + int pkt_start; /* packets started */ + int done ____cacheline_aligned; /* transmit slots completed */ + int pkt_done; /* packets completed */ +}; + +struct myri10ge_rx_done { + struct mcp_slot *entry; + dma_addr_t bus; + int cnt; + int idx; +}; + +struct myri10ge_priv { + int running; /* running? */ + int csum_flag; /* rx_csums? */ + struct myri10ge_tx_buf tx; /* transmit ring */ + struct myri10ge_rx_buf rx_small; + struct myri10ge_rx_buf rx_big; + struct myri10ge_rx_done rx_done; + int small_bytes; + struct net_device *dev; + struct net_device_stats stats; + u8 __iomem *sram; + int sram_size; + unsigned long board_span; + unsigned long iomem_base; + u32 __iomem *irq_claim; + u32 __iomem *irq_deassert; + char *mac_addr_string; + struct mcp_cmd_response *cmd; + dma_addr_t cmd_bus; + struct mcp_irq_data *fw_stats; + dma_addr_t fw_stats_bus; + struct pci_dev *pdev; + int msi_enabled; + unsigned int link_state; + unsigned int rdma_tags_available; + int intr_coal_delay; + u32 __iomem *intr_coal_delay_ptr; + int mtrr; + int wake_queue; + int stop_queue; + int down_cnt; + wait_queue_head_t down_wq; + struct work_struct watchdog_work; + struct timer_list watchdog_timer; + int watchdog_tx_done; + int watchdog_resets; + int tx_linearized; + int pause; + char *fw_name; + char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; + char fw_version[128]; + u8 mac_addr[6]; /* eeprom mac address */ + unsigned long serial_number; + int vendor_specific_offset; + u32 devctl; + u16 msi_flags; + u32 pm_state[16]; + u32 read_dma; + u32 write_dma; + u32 read_write_dma; +}; + +static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; +static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat"; + +static char *myri10ge_fw_name = NULL; +module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name\n"); + +static int myri10ge_ecrc_enable = 1; +module_param(myri10ge_ecrc_enable, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E\n"); + +static int myri10ge_max_intr_slots = 1024; +module_param(myri10ge_max_intr_slots, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_max_intr_slots, "Interrupt queue slots\n"); + +static int myri10ge_small_bytes = -1; /* -1 == auto */ +module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n"); + +static int myri10ge_msi = 1; /* enable msi by default */ +module_param(myri10ge_msi, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n"); + +static int myri10ge_intr_coal_delay = 25; +module_param(myri10ge_intr_coal_delay, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay\n"); + +static int myri10ge_flow_control = 1; +module_param(myri10ge_flow_control, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter\n"); + +static int myri10ge_deassert_wait = 1; +module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(myri10ge_deassert_wait, + "Wait when deasserting legacy interrupts\n"); + +static int myri10ge_force_firmware = 0; +module_param(myri10ge_force_firmware, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_force_firmware, + "Force firmware to assume aligned completions\n"); + +static int myri10ge_skb_cross_4k = 0; +module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(myri10ge_skb_cross_4k, + "Can a small skb cross a 4KB boundary?\n"); + +static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; +module_param(myri10ge_initial_mtu, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n"); + +static int myri10ge_napi_weight = 64; +module_param(myri10ge_napi_weight, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight\n"); + +static int myri10ge_watchdog_timeout = 1; +module_param(myri10ge_watchdog_timeout, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout\n"); + +static int myri10ge_max_irq_loops = 1048576; +module_param(myri10ge_max_irq_loops, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_max_irq_loops, + "Set stuck legacy IRQ detection threshold\n"); + +#define MYRI10GE_FW_OFFSET 1024*1024 +#define MYRI10GE_HIGHPART_TO_U32(X) \ +(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) +#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X)) + +#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) + +static int +myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, + struct myri10ge_cmd *data, int atomic) +{ + struct mcp_cmd *buf; + char buf_bytes[sizeof(*buf) + 8]; + struct mcp_cmd_response *response = mgp->cmd; + char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET; + u32 dma_low, dma_high, result, value; + int sleep_total = 0; + + /* ensure buf is aligned to 8 bytes */ + buf = (struct mcp_cmd *)ALIGN((unsigned long)buf_bytes, 8); + + buf->data0 = htonl(data->data0); + buf->data1 = htonl(data->data1); + buf->data2 = htonl(data->data2); + buf->cmd = htonl(cmd); + dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); + dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); + + buf->response_addr.low = htonl(dma_low); + buf->response_addr.high = htonl(dma_high); + response->result = MYRI10GE_NO_RESPONSE_RESULT; + mb(); + myri10ge_pio_copy(cmd_addr, buf, sizeof(*buf)); + + /* wait up to 15ms. Longest command is the DMA benchmark, + * which is capped at 5ms, but runs from a timeout handler + * that runs every 7.8ms. So a 15ms timeout leaves us with + * a 2.2ms margin + */ + if (atomic) { + /* if atomic is set, do not sleep, + * and try to get the completion quickly + * (1ms will be enough for those commands) */ + for (sleep_total = 0; + sleep_total < 1000 + && response->result == MYRI10GE_NO_RESPONSE_RESULT; + sleep_total += 10) + udelay(10); + } else { + /* use msleep for most command */ + for (sleep_total = 0; + sleep_total < 15 + && response->result == MYRI10GE_NO_RESPONSE_RESULT; + sleep_total++) + msleep(1); + } + + result = ntohl(response->result); + value = ntohl(response->data); + if (result != MYRI10GE_NO_RESPONSE_RESULT) { + if (result == 0) { + data->data0 = value; + return 0; + } else { + dev_err(&mgp->pdev->dev, + "command %d failed, result = %d\n", + cmd, result); + return -ENXIO; + } + } + + dev_err(&mgp->pdev->dev, "command %d timed out, result = %d\n", + cmd, result); + return -EAGAIN; +} + +/* + * The eeprom strings on the lanaiX have the format + * SN=x\0 + * MAC=x:x:x:x:x:x\0 + * PT:ddd mmm xx xx:xx:xx xx\0 + * PV:ddd mmm xx xx:xx:xx xx\0 + */ +static int myri10ge_read_mac_addr(struct myri10ge_priv *mgp) +{ + char *ptr, *limit; + int i; + + ptr = mgp->eeprom_strings; + limit = mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE; + + while (*ptr != '\0' && ptr < limit) { + if (memcmp(ptr, "MAC=", 4) == 0) { + ptr += 4; + mgp->mac_addr_string = ptr; + for (i = 0; i < 6; i++) { + if ((ptr + 2) > limit) + goto abort; + mgp->mac_addr[i] = + simple_strtoul(ptr, &ptr, 16); + ptr += 1; + } + } + if (memcmp((const void *)ptr, "SN=", 3) == 0) { + ptr += 3; + mgp->serial_number = simple_strtoul(ptr, &ptr, 10); + } + while (ptr < limit && *ptr++) ; + } + + return 0; + +abort: + dev_err(&mgp->pdev->dev, "failed to parse eeprom_strings\n"); + return -ENXIO; +} + +/* + * Enable or disable periodic RDMAs from the host to make certain + * chipsets resend dropped PCIe messages + */ + +static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable) +{ + char __iomem *submit; + u32 buf[16]; + u32 dma_low, dma_high; + int i; + + /* clear confirmation addr */ + mgp->cmd->data = 0; + mb(); + + /* send a rdma command to the PCIe engine, and wait for the + * response in the confirmation address. The firmware should + * write a -1 there to indicate it is alive and well + */ + dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); + dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); + + buf[0] = htonl(dma_high); /* confirm addr MSW */ + buf[1] = htonl(dma_low); /* confirm addr LSW */ + buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */ + buf[3] = htonl(dma_high); /* dummy addr MSW */ + buf[4] = htonl(dma_low); /* dummy addr LSW */ + buf[5] = htonl(enable); /* enable? */ + + submit = mgp->sram + 0xfc01c0; + + myri10ge_pio_copy(submit, &buf, sizeof(buf)); + for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++) + msleep(1); + if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) + dev_err(&mgp->pdev->dev, "dummy rdma %s failed\n", + (enable ? "enable" : "disable")); +} + +static int +myri10ge_validate_firmware(struct myri10ge_priv *mgp, + struct mcp_gen_header *hdr) +{ + struct device *dev = &mgp->pdev->dev; + int major, minor; + + /* check firmware type */ + if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) { + dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type)); + return -EINVAL; + } + + /* save firmware version for ethtool */ + strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version)); + + sscanf(mgp->fw_version, "%d.%d", &major, &minor); + + if (!(major == MXGEFW_VERSION_MAJOR && minor == MXGEFW_VERSION_MINOR)) { + dev_err(dev, "Found firmware version %s\n", mgp->fw_version); + dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR, + MXGEFW_VERSION_MINOR); + return -EINVAL; + } + return 0; +} + +static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size) +{ + unsigned crc, reread_crc; + const struct firmware *fw; + struct device *dev = &mgp->pdev->dev; + struct mcp_gen_header *hdr; + size_t hdr_offset; + int status; + + if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) { + dev_err(dev, "Unable to load %s firmware image via hotplug\n", + mgp->fw_name); + status = -EINVAL; + goto abort_with_nothing; + } + + /* check size */ + + if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET || + fw->size < MCP_HEADER_PTR_OFFSET + 4) { + dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size); + status = -EINVAL; + goto abort_with_fw; + } + + /* check id */ + hdr_offset = ntohl(*(u32 *) (fw->data + MCP_HEADER_PTR_OFFSET)); + if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) { + dev_err(dev, "Bad firmware file\n"); + status = -EINVAL; + goto abort_with_fw; + } + hdr = (void *)(fw->data + hdr_offset); + + status = myri10ge_validate_firmware(mgp, hdr); + if (status != 0) + goto abort_with_fw; + + crc = crc32(~0, fw->data, fw->size); + memcpy_toio(mgp->sram + MYRI10GE_FW_OFFSET, fw->data, fw->size); + /* corruption checking is good for parity recovery and buggy chipset */ + memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size); + reread_crc = crc32(~0, fw->data, fw->size); + if (crc != reread_crc) { + dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n", + (unsigned)fw->size, reread_crc, crc); + status = -EIO; + goto abort_with_fw; + } + *size = (u32) fw->size; + +abort_with_fw: + release_firmware(fw); + +abort_with_nothing: + return status; +} + +static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp) +{ + struct mcp_gen_header *hdr; + struct device *dev = &mgp->pdev->dev; + const size_t bytes = sizeof(struct mcp_gen_header); + size_t hdr_offset; + int status; + + /* find running firmware header */ + hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET)); + + if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) { + dev_err(dev, "Running firmware has bad header offset (%d)\n", + (int)hdr_offset); + return -EIO; + } + + /* copy header of running firmware from SRAM to host memory to + * validate firmware */ + hdr = kmalloc(bytes, GFP_KERNEL); + if (hdr == NULL) { + dev_err(dev, "could not malloc firmware hdr\n"); + return -ENOMEM; + } + memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes); + status = myri10ge_validate_firmware(mgp, hdr); + kfree(hdr); + return status; +} + +static int myri10ge_load_firmware(struct myri10ge_priv *mgp) +{ + char __iomem *submit; + u32 buf[16]; + u32 dma_low, dma_high, size; + int status, i; + + status = myri10ge_load_hotplug_firmware(mgp, &size); + if (status) { + dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n"); + + /* Do not attempt to adopt firmware if there + * was a bad crc */ + if (status == -EIO) + return status; + + status = myri10ge_adopt_running_firmware(mgp); + if (status != 0) { + dev_err(&mgp->pdev->dev, + "failed to adopt running firmware\n"); + return status; + } + dev_info(&mgp->pdev->dev, + "Successfully adopted running firmware\n"); + if (mgp->tx.boundary == 4096) { + dev_warn(&mgp->pdev->dev, + "Using firmware currently running on NIC" + ". For optimal\n"); + dev_warn(&mgp->pdev->dev, + "performance consider loading optimized " + "firmware\n"); + dev_warn(&mgp->pdev->dev, "via hotplug\n"); + } + + mgp->fw_name = "adopted"; + mgp->tx.boundary = 2048; + return status; + } + + /* clear confirmation addr */ + mgp->cmd->data = 0; + mb(); + + /* send a reload command to the bootstrap MCP, and wait for the + * response in the confirmation address. The firmware should + * write a -1 there to indicate it is alive and well + */ + dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); + dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); + + buf[0] = htonl(dma_high); /* confirm addr MSW */ + buf[1] = htonl(dma_low); /* confirm addr LSW */ + buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */ + + /* FIX: All newest firmware should un-protect the bottom of + * the sram before handoff. However, the very first interfaces + * do not. Therefore the handoff copy must skip the first 8 bytes + */ + buf[3] = htonl(MYRI10GE_FW_OFFSET + 8); /* where the code starts */ + buf[4] = htonl(size - 8); /* length of code */ + buf[5] = htonl(8); /* where to copy to */ + buf[6] = htonl(0); /* where to jump to */ + + submit = mgp->sram + 0xfc0000; + + myri10ge_pio_copy(submit, &buf, sizeof(buf)); + mb(); + msleep(1); + mb(); + i = 0; + while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20) { + msleep(1); + i++; + } + if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) { + dev_err(&mgp->pdev->dev, "handoff failed\n"); + return -ENXIO; + } + dev_info(&mgp->pdev->dev, "handoff confirmed\n"); + myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096); + + return 0; +} + +static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr) +{ + struct myri10ge_cmd cmd; + int status; + + cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) + | (addr[2] << 8) | addr[3]); + + cmd.data1 = ((addr[4] << 8) | (addr[5])); + + status = myri10ge_send_cmd(mgp, MXGEFW_SET_MAC_ADDRESS, &cmd, 0); + return status; +} + +static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause) +{ + struct myri10ge_cmd cmd; + int status, ctl; + + ctl = pause ? MXGEFW_ENABLE_FLOW_CONTROL : MXGEFW_DISABLE_FLOW_CONTROL; + status = myri10ge_send_cmd(mgp, ctl, &cmd, 0); + + if (status) { + printk(KERN_ERR + "myri10ge: %s: Failed to set flow control mode\n", + mgp->dev->name); + return status; + } + mgp->pause = pause; + return 0; +} + +static void +myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic) +{ + struct myri10ge_cmd cmd; + int status, ctl; + + ctl = promisc ? MXGEFW_ENABLE_PROMISC : MXGEFW_DISABLE_PROMISC; + status = myri10ge_send_cmd(mgp, ctl, &cmd, atomic); + if (status) + printk(KERN_ERR "myri10ge: %s: Failed to set promisc mode\n", + mgp->dev->name); +} + +static int myri10ge_reset(struct myri10ge_priv *mgp) +{ + struct myri10ge_cmd cmd; + int status; + size_t bytes; + u32 len; + + /* try to send a reset command to the card to see if it + * is alive */ + memset(&cmd, 0, sizeof(cmd)); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed reset\n"); + return -ENXIO; + } + + /* Now exchange information about interrupts */ + + bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry); + memset(mgp->rx_done.entry, 0, bytes); + cmd.data0 = (u32) bytes; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0); + + status |= + myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); + mgp->irq_claim = (__iomem u32 *) (mgp->sram + cmd.data0); + if (!mgp->msi_enabled) { + status |= myri10ge_send_cmd + (mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0); + mgp->irq_deassert = (__iomem u32 *) (mgp->sram + cmd.data0); + + } + status |= myri10ge_send_cmd + (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0); + mgp->intr_coal_delay_ptr = (__iomem u32 *) (mgp->sram + cmd.data0); + if (status != 0) { + dev_err(&mgp->pdev->dev, "failed set interrupt parameters\n"); + return status; + } + __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); + + /* Run a small DMA test. + * The magic multipliers to the length tell the firmware + * to do DMA read, write, or read+write tests. The + * results are returned in cmd.data0. The upper 16 + * bits or the return is the number of transfers completed. + * The lower 16 bits is the time in 0.5us ticks that the + * transfers took to complete. + */ + + len = mgp->tx.boundary; + + cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data2 = len * 0x10000; + status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); + if (status == 0) + mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / + (cmd.data0 & 0xffff); + else + dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n", + status); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data2 = len * 0x1; + status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); + if (status == 0) + mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / + (cmd.data0 & 0xffff); + else + dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n", + status); + + cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data2 = len * 0x10001; + status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); + if (status == 0) + mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) / + (cmd.data0 & 0xffff); + else + dev_warn(&mgp->pdev->dev, + "DMA read/write benchmark failed: %d\n", status); + + memset(mgp->rx_done.entry, 0, bytes); + + /* reset mcp/driver shared state back to 0 */ + mgp->tx.req = 0; + mgp->tx.done = 0; + mgp->tx.pkt_start = 0; + mgp->tx.pkt_done = 0; + mgp->rx_big.cnt = 0; + mgp->rx_small.cnt = 0; + mgp->rx_done.idx = 0; + mgp->rx_done.cnt = 0; + status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); + myri10ge_change_promisc(mgp, 0, 0); + myri10ge_change_pause(mgp, mgp->pause); + return status; +} + +static inline void +myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, + struct mcp_kreq_ether_recv *src) +{ + u32 low; + + low = src->addr_low; + src->addr_low = DMA_32BIT_MASK; + myri10ge_pio_copy(dst, src, 8 * sizeof(*src)); + mb(); + src->addr_low = low; + __raw_writel(low, &dst->addr_low); + mb(); +} + +/* + * Set of routunes to get a new receive buffer. Any buffer which + * crosses a 4KB boundary must start on a 4KB boundary due to PCIe + * wdma restrictions. We also try to align any smaller allocation to + * at least a 16 byte boundary for efficiency. We assume the linux + * memory allocator works by powers of 2, and will not return memory + * smaller than 2KB which crosses a 4KB boundary. If it does, we fall + * back to allocating 2x as much space as required. + * + * We intend to replace large (>4KB) skb allocations by using + * pages directly and building a fraglist in the near future. + */ + +static inline struct sk_buff *myri10ge_alloc_big(int bytes) +{ + struct sk_buff *skb; + unsigned long data, roundup; + + skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD); + if (skb == NULL) + return NULL; + + /* Correct skb->truesize so that socket buffer + * accounting is not confused the rounding we must + * do to satisfy alignment constraints. + */ + skb->truesize -= 4096; + + data = (unsigned long)(skb->data); + roundup = (-data) & (4095); + skb_reserve(skb, roundup); + return skb; +} + +/* Allocate 2x as much space as required and use whichever portion + * does not cross a 4KB boundary */ +static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes) +{ + struct sk_buff *skb; + unsigned long data, boundary; + + skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1); + if (unlikely(skb == NULL)) + return NULL; + + /* Correct skb->truesize so that socket buffer + * accounting is not confused the rounding we must + * do to satisfy alignment constraints. + */ + skb->truesize -= bytes + MXGEFW_PAD; + + data = (unsigned long)(skb->data); + boundary = (data + 4095UL) & ~4095UL; + if ((boundary - data) >= (bytes + MXGEFW_PAD)) + return skb; + + skb_reserve(skb, boundary - data); + return skb; +} + +/* Allocate just enough space, and verify that the allocated + * space does not cross a 4KB boundary */ +static inline struct sk_buff *myri10ge_alloc_small(int bytes) +{ + struct sk_buff *skb; + unsigned long roundup, data, end; + + skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD); + if (unlikely(skb == NULL)) + return NULL; + + /* Round allocated buffer to 16 byte boundary */ + data = (unsigned long)(skb->data); + roundup = (-data) & 15UL; + skb_reserve(skb, roundup); + /* Verify that the data buffer does not cross a page boundary */ + data = (unsigned long)(skb->data); + end = data + bytes + MXGEFW_PAD - 1; + if (unlikely(((end >> 12) != (data >> 12)) && (data & 4095UL))) { + printk(KERN_NOTICE + "myri10ge_alloc_small: small skb crossed 4KB boundary\n"); + myri10ge_skb_cross_4k = 1; + dev_kfree_skb_any(skb); + skb = myri10ge_alloc_small_safe(bytes); + } + return skb; +} + +static inline int +myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes, + int idx) +{ + struct sk_buff *skb; + dma_addr_t bus; + int len, retval = 0; + + bytes += VLAN_HLEN; /* account for 802.1q vlan tag */ + + if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ ) + skb = myri10ge_alloc_big(bytes); + else if (myri10ge_skb_cross_4k) + skb = myri10ge_alloc_small_safe(bytes); + else + skb = myri10ge_alloc_small(bytes); + + if (unlikely(skb == NULL)) { + rx->alloc_fail++; + retval = -ENOBUFS; + goto done; + } + + /* set len so that it only covers the area we + * need mapped for DMA */ + len = bytes + MXGEFW_PAD; + + bus = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE); + rx->info[idx].skb = skb; + pci_unmap_addr_set(&rx->info[idx], bus, bus); + pci_unmap_len_set(&rx->info[idx], len, len); + rx->shadow[idx].addr_low = htonl(MYRI10GE_LOWPART_TO_U32(bus)); + rx->shadow[idx].addr_high = htonl(MYRI10GE_HIGHPART_TO_U32(bus)); + +done: + /* copy 8 descriptors (64-bytes) to the mcp at a time */ + if ((idx & 7) == 7) { + if (rx->wc_fifo == NULL) + myri10ge_submit_8rx(&rx->lanai[idx - 7], + &rx->shadow[idx - 7]); + else { + mb(); + myri10ge_pio_copy(rx->wc_fifo, + &rx->shadow[idx - 7], 64); + } + } + return retval; +} + +static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum) +{ + struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data); + + if ((skb->protocol == ntohs(ETH_P_8021Q)) && + (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) || + vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) { + skb->csum = hw_csum; + skb->ip_summed = CHECKSUM_HW; + } +} + +static inline unsigned long +myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, + int bytes, int len, int csum) +{ + dma_addr_t bus; + struct sk_buff *skb; + int idx, unmap_len; + + idx = rx->cnt & rx->mask; + rx->cnt++; + + /* save a pointer to the received skb */ + skb = rx->info[idx].skb; + bus = pci_unmap_addr(&rx->info[idx], bus); + unmap_len = pci_unmap_len(&rx->info[idx], len); + + /* try to replace the received skb */ + if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) { + /* drop the frame -- the old skbuf is re-cycled */ + mgp->stats.rx_dropped += 1; + return 0; + } + + /* unmap the recvd skb */ + pci_unmap_single(mgp->pdev, bus, unmap_len, PCI_DMA_FROMDEVICE); + + /* mcp implicitly skips 1st bytes so that packet is properly + * aligned */ + skb_reserve(skb, MXGEFW_PAD); + + /* set the length of the frame */ + skb_put(skb, len); + + skb->protocol = eth_type_trans(skb, mgp->dev); + skb->dev = mgp->dev; + if (mgp->csum_flag) { + if ((skb->protocol == ntohs(ETH_P_IP)) || + (skb->protocol == ntohs(ETH_P_IPV6))) { + skb->csum = ntohs((u16) csum); + skb->ip_summed = CHECKSUM_HW; + } else + myri10ge_vlan_ip_csum(skb, ntohs((u16) csum)); + } + + netif_receive_skb(skb); + mgp->dev->last_rx = jiffies; + return 1; +} + +static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index) +{ + struct pci_dev *pdev = mgp->pdev; + struct myri10ge_tx_buf *tx = &mgp->tx; + struct sk_buff *skb; + int idx, len; + int limit = 0; + + while (tx->pkt_done != mcp_index) { + idx = tx->done & tx->mask; + skb = tx->info[idx].skb; + + /* Mark as free */ + tx->info[idx].skb = NULL; + if (tx->info[idx].last) { + tx->pkt_done++; + tx->info[idx].last = 0; + } + tx->done++; + len = pci_unmap_len(&tx->info[idx], len); + pci_unmap_len_set(&tx->info[idx], len, 0); + if (skb) { + mgp->stats.tx_bytes += skb->len; + mgp->stats.tx_packets++; + dev_kfree_skb_irq(skb); + if (len) + pci_unmap_single(pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + } else { + if (len) + pci_unmap_page(pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + } + + /* limit potential for livelock by only handling + * 2 full tx rings per call */ + if (unlikely(++limit > 2 * tx->mask)) + break; + } + /* start the queue if we've stopped it */ + if (netif_queue_stopped(mgp->dev) + && tx->req - tx->done < (tx->mask >> 1)) { + mgp->wake_queue++; + netif_wake_queue(mgp->dev); + } +} + +static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) +{ + struct myri10ge_rx_done *rx_done = &mgp->rx_done; + unsigned long rx_bytes = 0; + unsigned long rx_packets = 0; + unsigned long rx_ok; + + int idx = rx_done->idx; + int cnt = rx_done->cnt; + u16 length; + u16 checksum; + + while (rx_done->entry[idx].length != 0 && *limit != 0) { + length = ntohs(rx_done->entry[idx].length); + rx_done->entry[idx].length = 0; + checksum = ntohs(rx_done->entry[idx].checksum); + if (length <= mgp->small_bytes) + rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small, + mgp->small_bytes, + length, checksum); + else + rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big, + mgp->dev->mtu + ETH_HLEN, + length, checksum); + rx_packets += rx_ok; + rx_bytes += rx_ok * (unsigned long)length; + cnt++; + idx = cnt & (myri10ge_max_intr_slots - 1); + + /* limit potential for livelock by only handling a + * limited number of frames. */ + (*limit)--; + } + rx_done->idx = idx; + rx_done->cnt = cnt; + mgp->stats.rx_packets += rx_packets; + mgp->stats.rx_bytes += rx_bytes; +} + +static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) +{ + struct mcp_irq_data *stats = mgp->fw_stats; + + if (unlikely(stats->stats_updated)) { + if (mgp->link_state != stats->link_up) { + mgp->link_state = stats->link_up; + if (mgp->link_state) { + printk(KERN_INFO "myri10ge: %s: link up\n", + mgp->dev->name); + netif_carrier_on(mgp->dev); + } else { + printk(KERN_INFO "myri10ge: %s: link down\n", + mgp->dev->name); + netif_carrier_off(mgp->dev); + } + } + if (mgp->rdma_tags_available != + ntohl(mgp->fw_stats->rdma_tags_available)) { + mgp->rdma_tags_available = + ntohl(mgp->fw_stats->rdma_tags_available); + printk(KERN_WARNING "myri10ge: %s: RDMA timed out! " + "%d tags left\n", mgp->dev->name, + mgp->rdma_tags_available); + } + mgp->down_cnt += stats->link_down; + if (stats->link_down) + wake_up(&mgp->down_wq); + } +} + +static int myri10ge_poll(struct net_device *netdev, int *budget) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + struct myri10ge_rx_done *rx_done = &mgp->rx_done; + int limit, orig_limit, work_done; + + /* process as many rx events as NAPI will allow */ + limit = min(*budget, netdev->quota); + orig_limit = limit; + myri10ge_clean_rx_done(mgp, &limit); + work_done = orig_limit - limit; + *budget -= work_done; + netdev->quota -= work_done; + + if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) { + netif_rx_complete(netdev); + __raw_writel(htonl(3), mgp->irq_claim); + return 0; + } + return 1; +} + +static irqreturn_t myri10ge_intr(int irq, void *arg, struct pt_regs *regs) +{ + struct myri10ge_priv *mgp = arg; + struct mcp_irq_data *stats = mgp->fw_stats; + struct myri10ge_tx_buf *tx = &mgp->tx; + u32 send_done_count; + int i; + + /* make sure it is our IRQ, and that the DMA has finished */ + if (unlikely(!stats->valid)) + return (IRQ_NONE); + + /* low bit indicates receives are present, so schedule + * napi poll handler */ + if (stats->valid & 1) + netif_rx_schedule(mgp->dev); + + if (!mgp->msi_enabled) { + __raw_writel(0, mgp->irq_deassert); + if (!myri10ge_deassert_wait) + stats->valid = 0; + mb(); + } else + stats->valid = 0; + + /* Wait for IRQ line to go low, if using INTx */ + i = 0; + while (1) { + i++; + /* check for transmit completes and receives */ + send_done_count = ntohl(stats->send_done_count); + if (send_done_count != tx->pkt_done) + myri10ge_tx_done(mgp, (int)send_done_count); + if (unlikely(i > myri10ge_max_irq_loops)) { + printk(KERN_WARNING "myri10ge: %s: irq stuck?\n", + mgp->dev->name); + stats->valid = 0; + schedule_work(&mgp->watchdog_work); + } + if (likely(stats->valid == 0)) + break; + cpu_relax(); + barrier(); + } + + myri10ge_check_statblock(mgp); + + __raw_writel(htonl(3), mgp->irq_claim + 1); + return (IRQ_HANDLED); +} + +static int +myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + cmd->autoneg = AUTONEG_DISABLE; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + return 0; +} + +static void +myri10ge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + + strlcpy(info->driver, "myri10ge", sizeof(info->driver)); + strlcpy(info->version, MYRI10GE_VERSION_STR, sizeof(info->version)); + strlcpy(info->fw_version, mgp->fw_version, sizeof(info->fw_version)); + strlcpy(info->bus_info, pci_name(mgp->pdev), sizeof(info->bus_info)); +} + +static int +myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + coal->rx_coalesce_usecs = mgp->intr_coal_delay; + return 0; +} + +static int +myri10ge_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + + mgp->intr_coal_delay = coal->rx_coalesce_usecs; + __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); + return 0; +} + +static void +myri10ge_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + + pause->autoneg = 0; + pause->rx_pause = mgp->pause; + pause->tx_pause = mgp->pause; +} + +static int +myri10ge_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + + if (pause->tx_pause != mgp->pause) + return myri10ge_change_pause(mgp, pause->tx_pause); + if (pause->rx_pause != mgp->pause) + return myri10ge_change_pause(mgp, pause->tx_pause); + if (pause->autoneg != 0) + return -EINVAL; + return 0; +} + +static void +myri10ge_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + + ring->rx_mini_max_pending = mgp->rx_small.mask + 1; + ring->rx_max_pending = mgp->rx_big.mask + 1; + ring->rx_jumbo_max_pending = 0; + ring->tx_max_pending = mgp->rx_small.mask + 1; + ring->rx_mini_pending = ring->rx_mini_max_pending; + ring->rx_pending = ring->rx_max_pending; + ring->rx_jumbo_pending = ring->rx_jumbo_max_pending; + ring->tx_pending = ring->tx_max_pending; +} + +static u32 myri10ge_get_rx_csum(struct net_device *netdev) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + if (mgp->csum_flag) + return 1; + else + return 0; +} + +static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + if (csum_enabled) + mgp->csum_flag = MXGEFW_FLAGS_CKSUM; + else + mgp->csum_flag = 0; + return 0; +} + +static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + /* device-specific stats */ + "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", + "serial_number", "tx_pkt_start", "tx_pkt_done", + "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt", + "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized", + "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered", + "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", + "dropped_no_big_buffer" +}; + +#define MYRI10GE_NET_STATS_LEN 21 +#define MYRI10GE_STATS_LEN sizeof(myri10ge_gstrings_stats) / ETH_GSTRING_LEN + +static void +myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *myri10ge_gstrings_stats, + sizeof(myri10ge_gstrings_stats)); + break; + } +} + +static int myri10ge_get_stats_count(struct net_device *netdev) +{ + return MYRI10GE_STATS_LEN; +} + +static void +myri10ge_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 * data) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + int i; + + for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&mgp->stats)[i]; + + data[i++] = (unsigned int)mgp->read_dma; + data[i++] = (unsigned int)mgp->write_dma; + data[i++] = (unsigned int)mgp->read_write_dma; + data[i++] = (unsigned int)mgp->serial_number; + data[i++] = (unsigned int)mgp->tx.pkt_start; + data[i++] = (unsigned int)mgp->tx.pkt_done; + data[i++] = (unsigned int)mgp->tx.req; + data[i++] = (unsigned int)mgp->tx.done; + data[i++] = (unsigned int)mgp->rx_small.cnt; + data[i++] = (unsigned int)mgp->rx_big.cnt; + data[i++] = (unsigned int)mgp->wake_queue; + data[i++] = (unsigned int)mgp->stop_queue; + data[i++] = (unsigned int)mgp->watchdog_resets; + data[i++] = (unsigned int)mgp->tx_linearized; + data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow); + data[i++] = + (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer); +} + +static struct ethtool_ops myri10ge_ethtool_ops = { + .get_settings = myri10ge_get_settings, + .get_drvinfo = myri10ge_get_drvinfo, + .get_coalesce = myri10ge_get_coalesce, + .set_coalesce = myri10ge_set_coalesce, + .get_pauseparam = myri10ge_get_pauseparam, + .set_pauseparam = myri10ge_set_pauseparam, + .get_ringparam = myri10ge_get_ringparam, + .get_rx_csum = myri10ge_get_rx_csum, + .set_rx_csum = myri10ge_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +#ifdef NETIF_F_TSO + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +#endif + .get_strings = myri10ge_get_strings, + .get_stats_count = myri10ge_get_stats_count, + .get_ethtool_stats = myri10ge_get_ethtool_stats +}; + +static int myri10ge_allocate_rings(struct net_device *dev) +{ + struct myri10ge_priv *mgp; + struct myri10ge_cmd cmd; + int tx_ring_size, rx_ring_size; + int tx_ring_entries, rx_ring_entries; + int i, status; + size_t bytes; + + mgp = netdev_priv(dev); + + /* get ring sizes */ + + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0); + tx_ring_size = cmd.data0; + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); + rx_ring_size = cmd.data0; + + tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send); + rx_ring_entries = rx_ring_size / sizeof(struct mcp_dma_addr); + mgp->tx.mask = tx_ring_entries - 1; + mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1; + + /* allocate the host shadow rings */ + + bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4) + * sizeof(*mgp->tx.req_list); + mgp->tx.req_bytes = kzalloc(bytes, GFP_KERNEL); + if (mgp->tx.req_bytes == NULL) + goto abort_with_nothing; + + /* ensure req_list entries are aligned to 8 bytes */ + mgp->tx.req_list = (struct mcp_kreq_ether_send *) + ALIGN((unsigned long)mgp->tx.req_bytes, 8); + + bytes = rx_ring_entries * sizeof(*mgp->rx_small.shadow); + mgp->rx_small.shadow = kzalloc(bytes, GFP_KERNEL); + if (mgp->rx_small.shadow == NULL) + goto abort_with_tx_req_bytes; + + bytes = rx_ring_entries * sizeof(*mgp->rx_big.shadow); + mgp->rx_big.shadow = kzalloc(bytes, GFP_KERNEL); + if (mgp->rx_big.shadow == NULL) + goto abort_with_rx_small_shadow; + + /* allocate the host info rings */ + + bytes = tx_ring_entries * sizeof(*mgp->tx.info); + mgp->tx.info = kzalloc(bytes, GFP_KERNEL); + if (mgp->tx.info == NULL) + goto abort_with_rx_big_shadow; + + bytes = rx_ring_entries * sizeof(*mgp->rx_small.info); + mgp->rx_small.info = kzalloc(bytes, GFP_KERNEL); + if (mgp->rx_small.info == NULL) + goto abort_with_tx_info; + + bytes = rx_ring_entries * sizeof(*mgp->rx_big.info); + mgp->rx_big.info = kzalloc(bytes, GFP_KERNEL); + if (mgp->rx_big.info == NULL) + goto abort_with_rx_small_info; + + /* Fill the receive rings */ + + for (i = 0; i <= mgp->rx_small.mask; i++) { + status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev, + mgp->small_bytes, i); + if (status) { + printk(KERN_ERR + "myri10ge: %s: alloced only %d small bufs\n", + dev->name, i); + goto abort_with_rx_small_ring; + } + } + + for (i = 0; i <= mgp->rx_big.mask; i++) { + status = + myri10ge_getbuf(&mgp->rx_big, mgp->pdev, + dev->mtu + ETH_HLEN, i); + if (status) { + printk(KERN_ERR + "myri10ge: %s: alloced only %d big bufs\n", + dev->name, i); + goto abort_with_rx_big_ring; + } + } + + return 0; + +abort_with_rx_big_ring: + for (i = 0; i <= mgp->rx_big.mask; i++) { + if (mgp->rx_big.info[i].skb != NULL) + dev_kfree_skb_any(mgp->rx_big.info[i].skb); + if (pci_unmap_len(&mgp->rx_big.info[i], len)) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&mgp->rx_big.info[i], + bus), + pci_unmap_len(&mgp->rx_big.info[i], + len), + PCI_DMA_FROMDEVICE); + } + +abort_with_rx_small_ring: + for (i = 0; i <= mgp->rx_small.mask; i++) { + if (mgp->rx_small.info[i].skb != NULL) + dev_kfree_skb_any(mgp->rx_small.info[i].skb); + if (pci_unmap_len(&mgp->rx_small.info[i], len)) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&mgp->rx_small.info[i], + bus), + pci_unmap_len(&mgp->rx_small.info[i], + len), + PCI_DMA_FROMDEVICE); + } + kfree(mgp->rx_big.info); + +abort_with_rx_small_info: + kfree(mgp->rx_small.info); + +abort_with_tx_info: + kfree(mgp->tx.info); + +abort_with_rx_big_shadow: + kfree(mgp->rx_big.shadow); + +abort_with_rx_small_shadow: + kfree(mgp->rx_small.shadow); + +abort_with_tx_req_bytes: + kfree(mgp->tx.req_bytes); + mgp->tx.req_bytes = NULL; + mgp->tx.req_list = NULL; + +abort_with_nothing: + return status; +} + +static void myri10ge_free_rings(struct net_device *dev) +{ + struct myri10ge_priv *mgp; + struct sk_buff *skb; + struct myri10ge_tx_buf *tx; + int i, len, idx; + + mgp = netdev_priv(dev); + + for (i = 0; i <= mgp->rx_big.mask; i++) { + if (mgp->rx_big.info[i].skb != NULL) + dev_kfree_skb_any(mgp->rx_big.info[i].skb); + if (pci_unmap_len(&mgp->rx_big.info[i], len)) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&mgp->rx_big.info[i], + bus), + pci_unmap_len(&mgp->rx_big.info[i], + len), + PCI_DMA_FROMDEVICE); + } + + for (i = 0; i <= mgp->rx_small.mask; i++) { + if (mgp->rx_small.info[i].skb != NULL) + dev_kfree_skb_any(mgp->rx_small.info[i].skb); + if (pci_unmap_len(&mgp->rx_small.info[i], len)) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&mgp->rx_small.info[i], + bus), + pci_unmap_len(&mgp->rx_small.info[i], + len), + PCI_DMA_FROMDEVICE); + } + + tx = &mgp->tx; + while (tx->done != tx->req) { + idx = tx->done & tx->mask; + skb = tx->info[idx].skb; + + /* Mark as free */ + tx->info[idx].skb = NULL; + tx->done++; + len = pci_unmap_len(&tx->info[idx], len); + pci_unmap_len_set(&tx->info[idx], len, 0); + if (skb) { + mgp->stats.tx_dropped++; + dev_kfree_skb_any(skb); + if (len) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + } else { + if (len) + pci_unmap_page(mgp->pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + } + } + kfree(mgp->rx_big.info); + + kfree(mgp->rx_small.info); + + kfree(mgp->tx.info); + + kfree(mgp->rx_big.shadow); + + kfree(mgp->rx_small.shadow); + + kfree(mgp->tx.req_bytes); + mgp->tx.req_bytes = NULL; + mgp->tx.req_list = NULL; +} + +static int myri10ge_open(struct net_device *dev) +{ + struct myri10ge_priv *mgp; + struct myri10ge_cmd cmd; + int status, big_pow2; + + mgp = netdev_priv(dev); + + if (mgp->running != MYRI10GE_ETH_STOPPED) + return -EBUSY; + + mgp->running = MYRI10GE_ETH_STARTING; + status = myri10ge_reset(mgp); + if (status != 0) { + printk(KERN_ERR "myri10ge: %s: failed reset\n", dev->name); + mgp->running = MYRI10GE_ETH_STOPPED; + return -ENXIO; + } + + /* decide what small buffer size to use. For good TCP rx + * performance, it is important to not receive 1514 byte + * frames into jumbo buffers, as it confuses the socket buffer + * accounting code, leading to drops and erratic performance. + */ + + if (dev->mtu <= ETH_DATA_LEN) + mgp->small_bytes = 128; /* enough for a TCP header */ + else + mgp->small_bytes = ETH_FRAME_LEN; /* enough for an ETH_DATA_LEN frame */ + + /* Override the small buffer size? */ + if (myri10ge_small_bytes > 0) + mgp->small_bytes = myri10ge_small_bytes; + + /* If the user sets an obscenely small MTU, adjust the small + * bytes down to nearly nothing */ + if (mgp->small_bytes >= (dev->mtu + ETH_HLEN)) + mgp->small_bytes = 64; + + /* get the lanai pointers to the send and receive rings */ + + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0); + mgp->tx.lanai = + (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0); + + status |= + myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0); + mgp->rx_small.lanai = + (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); + + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); + mgp->rx_big.lanai = + (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0); + + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: failed to get ring sizes or locations\n", + dev->name); + mgp->running = MYRI10GE_ETH_STOPPED; + return -ENXIO; + } + + if (mgp->mtrr >= 0) { + mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000; + mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000; + mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000; + } else { + mgp->tx.wc_fifo = NULL; + mgp->rx_small.wc_fifo = NULL; + mgp->rx_big.wc_fifo = NULL; + } + + status = myri10ge_allocate_rings(dev); + if (status != 0) + goto abort_with_nothing; + + /* Firmware needs the big buff size as a power of 2. Lie and + * tell him the buffer is larger, because we only use 1 + * buffer/pkt, and the mtu will prevent overruns. + */ + big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD; + while ((big_pow2 & (big_pow2 - 1)) != 0) + big_pow2++; + + /* now give firmware buffers sizes, and MTU */ + cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_MTU, &cmd, 0); + cmd.data0 = mgp->small_bytes; + status |= + myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd, 0); + cmd.data0 = big_pow2; + status |= + myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd, 0); + if (status) { + printk(KERN_ERR "myri10ge: %s: Couldn't set buffer sizes\n", + dev->name); + goto abort_with_rings; + } + + cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0); + if (status) { + printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n", + dev->name); + goto abort_with_rings; + } + + mgp->link_state = -1; + mgp->rdma_tags_available = 15; + + netif_poll_enable(mgp->dev); /* must happen prior to any irq */ + + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); + if (status) { + printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n", + dev->name); + goto abort_with_rings; + } + + mgp->wake_queue = 0; + mgp->stop_queue = 0; + mgp->running = MYRI10GE_ETH_RUNNING; + mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ; + add_timer(&mgp->watchdog_timer); + netif_wake_queue(dev); + return 0; + +abort_with_rings: + myri10ge_free_rings(dev); + +abort_with_nothing: + mgp->running = MYRI10GE_ETH_STOPPED; + return -ENOMEM; +} + +static int myri10ge_close(struct net_device *dev) +{ + struct myri10ge_priv *mgp; + struct myri10ge_cmd cmd; + int status, old_down_cnt; + + mgp = netdev_priv(dev); + + if (mgp->running != MYRI10GE_ETH_RUNNING) + return 0; + + if (mgp->tx.req_bytes == NULL) + return 0; + + del_timer_sync(&mgp->watchdog_timer); + mgp->running = MYRI10GE_ETH_STOPPING; + netif_poll_disable(mgp->dev); + netif_carrier_off(dev); + netif_stop_queue(dev); + old_down_cnt = mgp->down_cnt; + mb(); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); + if (status) + printk(KERN_ERR "myri10ge: %s: Couldn't bring down link\n", + dev->name); + + wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, HZ); + if (old_down_cnt == mgp->down_cnt) + printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name); + + netif_tx_disable(dev); + + myri10ge_free_rings(dev); + + mgp->running = MYRI10GE_ETH_STOPPED; + return 0; +} + +/* copy an array of struct mcp_kreq_ether_send's to the mcp. Copy + * backwards one at a time and handle ring wraps */ + +static inline void +myri10ge_submit_req_backwards(struct myri10ge_tx_buf *tx, + struct mcp_kreq_ether_send *src, int cnt) +{ + int idx, starting_slot; + starting_slot = tx->req; + while (cnt > 1) { + cnt--; + idx = (starting_slot + cnt) & tx->mask; + myri10ge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); + mb(); + } +} + +/* + * copy an array of struct mcp_kreq_ether_send's to the mcp. Copy + * at most 32 bytes at a time, so as to avoid involving the software + * pio handler in the nic. We re-write the first segment's flags + * to mark them valid only after writing the entire chain. + */ + +static inline void +myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, + int cnt) +{ + int idx, i; + struct mcp_kreq_ether_send __iomem *dstp, *dst; + struct mcp_kreq_ether_send *srcp; + u8 last_flags; + + idx = tx->req & tx->mask; + + last_flags = src->flags; + src->flags = 0; + mb(); + dst = dstp = &tx->lanai[idx]; + srcp = src; + + if ((idx + cnt) < tx->mask) { + for (i = 0; i < (cnt - 1); i += 2) { + myri10ge_pio_copy(dstp, srcp, 2 * sizeof(*src)); + mb(); /* force write every 32 bytes */ + srcp += 2; + dstp += 2; + } + } else { + /* submit all but the first request, and ensure + * that it is submitted below */ + myri10ge_submit_req_backwards(tx, src, cnt); + i = 0; + } + if (i < cnt) { + /* submit the first request */ + myri10ge_pio_copy(dstp, srcp, sizeof(*src)); + mb(); /* barrier before setting valid flag */ + } + + /* re-write the last 32-bits with the valid flags */ + src->flags = last_flags; + __raw_writel(*((u32 *) src + 3), (u32 __iomem *) dst + 3); + tx->req += cnt; + mb(); +} + +static inline void +myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx, + struct mcp_kreq_ether_send *src, int cnt) +{ + tx->req += cnt; + mb(); + while (cnt >= 4) { + myri10ge_pio_copy(tx->wc_fifo, src, 64); + mb(); + src += 4; + cnt -= 4; + } + if (cnt > 0) { + /* pad it to 64 bytes. The src is 64 bytes bigger than it + * needs to be so that we don't overrun it */ + myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64); + mb(); + } +} + +/* + * Transmit a packet. We need to split the packet so that a single + * segment does not cross myri10ge->tx.boundary, so this makes segment + * counting tricky. So rather than try to count segments up front, we + * just give up if there are too few segments to hold a reasonably + * fragmented packet currently available. If we run + * out of segments while preparing a packet for DMA, we just linearize + * it and try again. + */ + +static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct myri10ge_priv *mgp = netdev_priv(dev); + struct mcp_kreq_ether_send *req; + struct myri10ge_tx_buf *tx = &mgp->tx; + struct skb_frag_struct *frag; + dma_addr_t bus; + u32 low, high_swapped; + unsigned int len; + int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments; + u16 pseudo_hdr_offset, cksum_offset; + int cum_len, seglen, boundary, rdma_count; + u8 flags, odd_flag; + +again: + req = tx->req_list; + avail = tx->mask - 1 - (tx->req - tx->done); + + mss = 0; + max_segments = MXGEFW_MAX_SEND_DESC; + +#ifdef NETIF_F_TSO + if (skb->len > (dev->mtu + ETH_HLEN)) { + mss = skb_shinfo(skb)->tso_size; + if (mss != 0) + max_segments = MYRI10GE_MAX_SEND_DESC_TSO; + } +#endif /*NETIF_F_TSO */ + + if ((unlikely(avail < max_segments))) { + /* we are out of transmit resources */ + mgp->stop_queue++; + netif_stop_queue(dev); + return 1; + } + + /* Setup checksum offloading, if needed */ + cksum_offset = 0; + pseudo_hdr_offset = 0; + odd_flag = 0; + flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); + if (likely(skb->ip_summed == CHECKSUM_HW)) { + cksum_offset = (skb->h.raw - skb->data); + pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data; + /* If the headers are excessively large, then we must + * fall back to a software checksum */ + if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { + if (skb_checksum_help(skb, 0)) + goto drop; + cksum_offset = 0; + pseudo_hdr_offset = 0; + } else { + pseudo_hdr_offset = htons(pseudo_hdr_offset); + odd_flag = MXGEFW_FLAGS_ALIGN_ODD; + flags |= MXGEFW_FLAGS_CKSUM; + } + } + + cum_len = 0; + +#ifdef NETIF_F_TSO + if (mss) { /* TSO */ + /* this removes any CKSUM flag from before */ + flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST); + + /* negative cum_len signifies to the + * send loop that we are still in the + * header portion of the TSO packet. + * TSO header must be at most 134 bytes long */ + cum_len = -((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + + /* for TSO, pseudo_hdr_offset holds mss. + * The firmware figures out where to put + * the checksum by parsing the header. */ + pseudo_hdr_offset = htons(mss); + } else +#endif /*NETIF_F_TSO */ + /* Mark small packets, and pad out tiny packets */ + if (skb->len <= MXGEFW_SEND_SMALL_SIZE) { + flags |= MXGEFW_FLAGS_SMALL; + + /* pad frames to at least ETH_ZLEN bytes */ + if (unlikely(skb->len < ETH_ZLEN)) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) { + /* The packet is gone, so we must + * return 0 */ + mgp->stats.tx_dropped += 1; + return 0; + } + /* adjust the len to account for the zero pad + * so that the nic can know how long it is */ + skb->len = ETH_ZLEN; + } + } + + /* map the skb for DMA */ + len = skb->len - skb->data_len; + idx = tx->req & tx->mask; + tx->info[idx].skb = skb; + bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE); + pci_unmap_addr_set(&tx->info[idx], bus, bus); + pci_unmap_len_set(&tx->info[idx], len, len); + + frag_cnt = skb_shinfo(skb)->nr_frags; + frag_idx = 0; + count = 0; + rdma_count = 0; + + /* "rdma_count" is the number of RDMAs belonging to the + * current packet BEFORE the current send request. For + * non-TSO packets, this is equal to "count". + * For TSO packets, rdma_count needs to be reset + * to 0 after a segment cut. + * + * The rdma_count field of the send request is + * the number of RDMAs of the packet starting at + * that request. For TSO send requests with one ore more cuts + * in the middle, this is the number of RDMAs starting + * after the last cut in the request. All previous + * segments before the last cut implicitly have 1 RDMA. + * + * Since the number of RDMAs is not known beforehand, + * it must be filled-in retroactively - after each + * segmentation cut or at the end of the entire packet. + */ + + while (1) { + /* Break the SKB or Fragment up into pieces which + * do not cross mgp->tx.boundary */ + low = MYRI10GE_LOWPART_TO_U32(bus); + high_swapped = htonl(MYRI10GE_HIGHPART_TO_U32(bus)); + while (len) { + u8 flags_next; + int cum_len_next; + + if (unlikely(count == max_segments)) + goto abort_linearize; + + boundary = (low + tx->boundary) & ~(tx->boundary - 1); + seglen = boundary - low; + if (seglen > len) + seglen = len; + flags_next = flags & ~MXGEFW_FLAGS_FIRST; + cum_len_next = cum_len + seglen; +#ifdef NETIF_F_TSO + if (mss) { /* TSO */ + (req - rdma_count)->rdma_count = rdma_count + 1; + + if (likely(cum_len >= 0)) { /* payload */ + int next_is_first, chop; + + chop = (cum_len_next > mss); + cum_len_next = cum_len_next % mss; + next_is_first = (cum_len_next == 0); + flags |= chop * MXGEFW_FLAGS_TSO_CHOP; + flags_next |= next_is_first * + MXGEFW_FLAGS_FIRST; + rdma_count |= -(chop | next_is_first); + rdma_count += chop & !next_is_first; + } else if (likely(cum_len_next >= 0)) { /* header ends */ + int small; + + rdma_count = -1; + cum_len_next = 0; + seglen = -cum_len; + small = (mss <= MXGEFW_SEND_SMALL_SIZE); + flags_next = MXGEFW_FLAGS_TSO_PLD | + MXGEFW_FLAGS_FIRST | + (small * MXGEFW_FLAGS_SMALL); + } + } +#endif /* NETIF_F_TSO */ + req->addr_high = high_swapped; + req->addr_low = htonl(low); + req->pseudo_hdr_offset = pseudo_hdr_offset; + req->pad = 0; /* complete solid 16-byte block; does this matter? */ + req->rdma_count = 1; + req->length = htons(seglen); + req->cksum_offset = cksum_offset; + req->flags = flags | ((cum_len & 1) * odd_flag); + + low += seglen; + len -= seglen; + cum_len = cum_len_next; + flags = flags_next; + req++; + count++; + rdma_count++; + if (unlikely(cksum_offset > seglen)) + cksum_offset -= seglen; + else + cksum_offset = 0; + } + if (frag_idx == frag_cnt) + break; + + /* map next fragment for DMA */ + idx = (count + tx->req) & tx->mask; + frag = &skb_shinfo(skb)->frags[frag_idx]; + frag_idx++; + len = frag->size; + bus = pci_map_page(mgp->pdev, frag->page, frag->page_offset, + len, PCI_DMA_TODEVICE); + pci_unmap_addr_set(&tx->info[idx], bus, bus); + pci_unmap_len_set(&tx->info[idx], len, len); + } + + (req - rdma_count)->rdma_count = rdma_count; +#ifdef NETIF_F_TSO + if (mss) + do { + req--; + req->flags |= MXGEFW_FLAGS_TSO_LAST; + } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | + MXGEFW_FLAGS_FIRST))); +#endif + idx = ((count - 1) + tx->req) & tx->mask; + tx->info[idx].last = 1; + if (tx->wc_fifo == NULL) + myri10ge_submit_req(tx, tx->req_list, count); + else + myri10ge_submit_req_wc(tx, tx->req_list, count); + tx->pkt_start++; + if ((avail - count) < MXGEFW_MAX_SEND_DESC) { + mgp->stop_queue++; + netif_stop_queue(dev); + } + dev->trans_start = jiffies; + return 0; + +abort_linearize: + /* Free any DMA resources we've alloced and clear out the skb + * slot so as to not trip up assertions, and to avoid a + * double-free if linearizing fails */ + + last_idx = (idx + 1) & tx->mask; + idx = tx->req & tx->mask; + tx->info[idx].skb = NULL; + do { + len = pci_unmap_len(&tx->info[idx], len); + if (len) { + if (tx->info[idx].skb != NULL) + pci_unmap_single(mgp->pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(mgp->pdev, + pci_unmap_addr(&tx->info[idx], + bus), len, + PCI_DMA_TODEVICE); + pci_unmap_len_set(&tx->info[idx], len, 0); + tx->info[idx].skb = NULL; + } + idx = (idx + 1) & tx->mask; + } while (idx != last_idx); + if (skb_shinfo(skb)->tso_size) { + printk(KERN_ERR + "myri10ge: %s: TSO but wanted to linearize?!?!?\n", + mgp->dev->name); + goto drop; + } + + if (skb_linearize(skb, GFP_ATOMIC)) + goto drop; + + mgp->tx_linearized++; + goto again; + +drop: + dev_kfree_skb_any(skb); + mgp->stats.tx_dropped += 1; + return 0; + +} + +static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) +{ + struct myri10ge_priv *mgp = netdev_priv(dev); + return &mgp->stats; +} + +static void myri10ge_set_multicast_list(struct net_device *dev) +{ + /* can be called from atomic contexts, + * pass 1 to force atomicity in myri10ge_send_cmd() */ + myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1); +} + +static int myri10ge_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + struct myri10ge_priv *mgp = netdev_priv(dev); + int status; + + if (!is_valid_ether_addr(sa->sa_data)) + return -EADDRNOTAVAIL; + + status = myri10ge_update_mac_address(mgp, sa->sa_data); + if (status != 0) { + printk(KERN_ERR + "myri10ge: %s: changing mac address failed with %d\n", + dev->name, status); + return status; + } + + /* change the dev structure */ + memcpy(dev->dev_addr, sa->sa_data, 6); + return 0; +} + +static int myri10ge_change_mtu(struct net_device *dev, int new_mtu) +{ + struct myri10ge_priv *mgp = netdev_priv(dev); + int error = 0; + + if ((new_mtu < 68) || (ETH_HLEN + new_mtu > MYRI10GE_MAX_ETHER_MTU)) { + printk(KERN_ERR "myri10ge: %s: new mtu (%d) is not valid\n", + dev->name, new_mtu); + return -EINVAL; + } + printk(KERN_INFO "%s: changing mtu from %d to %d\n", + dev->name, dev->mtu, new_mtu); + if (mgp->running) { + /* if we change the mtu on an active device, we must + * reset the device so the firmware sees the change */ + myri10ge_close(dev); + dev->mtu = new_mtu; + myri10ge_open(dev); + } else + dev->mtu = new_mtu; + + return error; +} + +/* + * Enable ECRC to align PCI-E Completion packets on an 8-byte boundary. + * Only do it if the bridge is a root port since we don't want to disturb + * any other device, except if forced with myri10ge_ecrc_enable > 1. + */ + +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d + +static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) +{ + struct pci_dev *bridge = mgp->pdev->bus->self; + struct device *dev = &mgp->pdev->dev; + unsigned cap; + unsigned err_cap; + u16 val; + u8 ext_type; + int ret; + + if (!myri10ge_ecrc_enable || !bridge) + return; + + /* check that the bridge is a root port */ + cap = pci_find_capability(bridge, PCI_CAP_ID_EXP); + pci_read_config_word(bridge, cap + PCI_CAP_FLAGS, &val); + ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4; + if (ext_type != PCI_EXP_TYPE_ROOT_PORT) { + if (myri10ge_ecrc_enable > 1) { + struct pci_dev *old_bridge = bridge; + + /* Walk the hierarchy up to the root port + * where ECRC has to be enabled */ + do { + bridge = bridge->bus->self; + if (!bridge) { + dev_err(dev, + "Failed to find root port" + " to force ECRC\n"); + return; + } + cap = + pci_find_capability(bridge, PCI_CAP_ID_EXP); + pci_read_config_word(bridge, + cap + PCI_CAP_FLAGS, &val); + ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4; + } while (ext_type != PCI_EXP_TYPE_ROOT_PORT); + + dev_info(dev, + "Forcing ECRC on non-root port %s" + " (enabling on root port %s)\n", + pci_name(old_bridge), pci_name(bridge)); + } else { + dev_err(dev, + "Not enabling ECRC on non-root port %s\n", + pci_name(bridge)); + return; + } + } + + cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR); + /* nvidia ext cap is not always linked in ext cap chain */ + if (!cap + && bridge->vendor == PCI_VENDOR_ID_NVIDIA + && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE) + cap = 0x160; + + if (!cap) + return; + + ret = pci_read_config_dword(bridge, cap + PCI_ERR_CAP, &err_cap); + if (ret) { + dev_err(dev, "failed reading ext-conf-space of %s\n", + pci_name(bridge)); + dev_err(dev, "\t pci=nommconf in use? " + "or buggy/incomplete/absent ACPI MCFG attr?\n"); + return; + } + if (!(err_cap & PCI_ERR_CAP_ECRC_GENC)) + return; + + err_cap |= PCI_ERR_CAP_ECRC_GENE; + pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap); + dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge)); + mgp->tx.boundary = 4096; + mgp->fw_name = myri10ge_fw_aligned; +} + +/* + * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput + * when the PCI-E Completion packets are aligned on an 8-byte + * boundary. Some PCI-E chip sets always align Completion packets; on + * the ones that do not, the alignment can be enforced by enabling + * ECRC generation (if supported). + * + * When PCI-E Completion packets are not aligned, it is actually more + * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. + * + * If the driver can neither enable ECRC nor verify that it has + * already been enabled, then it must use a firmware image which works + * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it + * should also ensure that it never gives the device a Read-DMA which is + * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is + * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat) + * firmware image, and set tx.boundary to 4KB. + */ + +#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 + +static void myri10ge_select_firmware(struct myri10ge_priv *mgp) +{ + struct pci_dev *bridge = mgp->pdev->bus->self; + + mgp->tx.boundary = 2048; + mgp->fw_name = myri10ge_fw_unaligned; + + if (myri10ge_force_firmware == 0) { + myri10ge_enable_ecrc(mgp); + + /* Check to see if the upstream bridge is known to + * provide aligned completions */ + if (bridge + /* ServerWorks HT2000/HT1000 */ + && bridge->vendor == PCI_VENDOR_ID_SERVERWORKS + && bridge->device == + PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE) { + dev_info(&mgp->pdev->dev, + "Assuming aligned completions (0x%x:0x%x)\n", + bridge->vendor, bridge->device); + mgp->tx.boundary = 4096; + mgp->fw_name = myri10ge_fw_aligned; + } + } else { + if (myri10ge_force_firmware == 1) { + dev_info(&mgp->pdev->dev, + "Assuming aligned completions (forced)\n"); + mgp->tx.boundary = 4096; + mgp->fw_name = myri10ge_fw_aligned; + } else { + dev_info(&mgp->pdev->dev, + "Assuming unaligned completions (forced)\n"); + mgp->tx.boundary = 2048; + mgp->fw_name = myri10ge_fw_unaligned; + } + } + if (myri10ge_fw_name != NULL) { + dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", + myri10ge_fw_name); + mgp->fw_name = myri10ge_fw_name; + } +} + +static void myri10ge_save_state(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int cap; + + pci_save_state(pdev); + /* now save PCIe and MSI state that Linux will not + * save for us */ + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, &mgp->devctl); + cap = pci_find_capability(pdev, PCI_CAP_ID_MSI); + pci_read_config_word(pdev, cap + PCI_MSI_FLAGS, &mgp->msi_flags); +} + +static void myri10ge_restore_state(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int cap; + + /* restore PCIe and MSI state that linux will not */ + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_write_config_dword(pdev, cap + PCI_CAP_ID_EXP, mgp->devctl); + cap = pci_find_capability(pdev, PCI_CAP_ID_MSI); + pci_write_config_word(pdev, cap + PCI_MSI_FLAGS, mgp->msi_flags); + + pci_restore_state(pdev); +} + +#ifdef CONFIG_PM + +static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct myri10ge_priv *mgp; + struct net_device *netdev; + + mgp = pci_get_drvdata(pdev); + if (mgp == NULL) + return -EINVAL; + netdev = mgp->dev; + + netif_device_detach(netdev); + if (netif_running(netdev)) { + printk(KERN_INFO "myri10ge: closing %s\n", netdev->name); + rtnl_lock(); + myri10ge_close(netdev); + rtnl_unlock(); + } + myri10ge_dummy_rdma(mgp, 0); + free_irq(pdev->irq, mgp); + myri10ge_save_state(mgp); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int myri10ge_resume(struct pci_dev *pdev) +{ + struct myri10ge_priv *mgp; + struct net_device *netdev; + int status; + u16 vendor; + + mgp = pci_get_drvdata(pdev); + if (mgp == NULL) + return -EINVAL; + netdev = mgp->dev; + pci_set_power_state(pdev, 0); /* zeros conf space as a side effect */ + msleep(5); /* give card time to respond */ + pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor); + if (vendor == 0xffff) { + printk(KERN_ERR "myri10ge: %s: device disappeared!\n", + mgp->dev->name); + return -EIO; + } + myri10ge_restore_state(mgp); + pci_enable_device(pdev); + pci_set_master(pdev); + + status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ, + netdev->name, mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to allocate IRQ\n"); + goto abort_with_msi; + } + + myri10ge_reset(mgp); + myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096); + + /* Save configuration space to be restored if the + * nic resets due to a parity error */ + myri10ge_save_state(mgp); + + if (netif_running(netdev)) { + rtnl_lock(); + myri10ge_open(netdev); + rtnl_unlock(); + } + netif_device_attach(netdev); + + return 0; + +abort_with_msi: + return -EIO; + +} + +#endif /* CONFIG_PM */ + +static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int vs = mgp->vendor_specific_offset; + u32 reboot; + + /*enter read32 mode */ + pci_write_config_byte(pdev, vs + 0x10, 0x3); + + /*read REBOOT_STATUS (0xfffffff0) */ + pci_write_config_dword(pdev, vs + 0x18, 0xfffffff0); + pci_read_config_dword(pdev, vs + 0x14, &reboot); + return reboot; +} + +/* + * This watchdog is used to check whether the board has suffered + * from a parity error and needs to be recovered. + */ +static void myri10ge_watchdog(void *arg) +{ + struct myri10ge_priv *mgp = arg; + u32 reboot; + int status; + u16 cmd, vendor; + + mgp->watchdog_resets++; + pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_MASTER) == 0) { + /* Bus master DMA disabled? Check to see + * if the card rebooted due to a parity error + * For now, just report it */ + reboot = myri10ge_read_reboot(mgp); + printk(KERN_ERR + "myri10ge: %s: NIC rebooted (0x%x), resetting\n", + mgp->dev->name, reboot); + /* + * A rebooted nic will come back with config space as + * it was after power was applied to PCIe bus. + * Attempt to restore config space which was saved + * when the driver was loaded, or the last time the + * nic was resumed from power saving mode. + */ + myri10ge_restore_state(mgp); + } else { + /* if we get back -1's from our slot, perhaps somebody + * powered off our card. Don't try to reset it in + * this case */ + if (cmd == 0xffff) { + pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor); + if (vendor == 0xffff) { + printk(KERN_ERR + "myri10ge: %s: device disappeared!\n", + mgp->dev->name); + return; + } + } + /* Perhaps it is a software error. Try to reset */ + + printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n", + mgp->dev->name); + printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", + mgp->dev->name, mgp->tx.req, mgp->tx.done, + mgp->tx.pkt_start, mgp->tx.pkt_done, + (int)ntohl(mgp->fw_stats->send_done_count)); + msleep(2000); + printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n", + mgp->dev->name, mgp->tx.req, mgp->tx.done, + mgp->tx.pkt_start, mgp->tx.pkt_done, + (int)ntohl(mgp->fw_stats->send_done_count)); + } + rtnl_lock(); + myri10ge_close(mgp->dev); + status = myri10ge_load_firmware(mgp); + if (status != 0) + printk(KERN_ERR "myri10ge: %s: failed to load firmware\n", + mgp->dev->name); + else + myri10ge_open(mgp->dev); + rtnl_unlock(); +} + +/* + * We use our own timer routine rather than relying upon + * netdev->tx_timeout because we have a very large hardware transmit + * queue. Due to the large queue, the netdev->tx_timeout function + * cannot detect a NIC with a parity error in a timely fashion if the + * NIC is lightly loaded. + */ +static void myri10ge_watchdog_timer(unsigned long arg) +{ + struct myri10ge_priv *mgp; + + mgp = (struct myri10ge_priv *)arg; + if (mgp->tx.req != mgp->tx.done && + mgp->tx.done == mgp->watchdog_tx_done) + /* nic seems like it might be stuck.. */ + schedule_work(&mgp->watchdog_work); + else + /* rearm timer */ + mod_timer(&mgp->watchdog_timer, + jiffies + myri10ge_watchdog_timeout * HZ); + + mgp->watchdog_tx_done = mgp->tx.done; +} + +static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct myri10ge_priv *mgp; + struct device *dev = &pdev->dev; + size_t bytes; + int i; + int status = -ENXIO; + int cap; + int dac_enabled; + u16 val; + + netdev = alloc_etherdev(sizeof(*mgp)); + if (netdev == NULL) { + dev_err(dev, "Could not allocate ethernet device\n"); + return -ENOMEM; + } + + mgp = netdev_priv(netdev); + memset(mgp, 0, sizeof(*mgp)); + mgp->dev = netdev; + mgp->pdev = pdev; + mgp->csum_flag = MXGEFW_FLAGS_CKSUM; + mgp->pause = myri10ge_flow_control; + mgp->intr_coal_delay = myri10ge_intr_coal_delay; + init_waitqueue_head(&mgp->down_wq); + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "pci_enable_device call failed\n"); + status = -ENODEV; + goto abort_with_netdev; + } + myri10ge_select_firmware(mgp); + + /* Find the vendor-specific cap so we can check + * the reboot register later on */ + mgp->vendor_specific_offset + = pci_find_capability(pdev, PCI_CAP_ID_VNDR); + + /* Set our max read request to 4KB */ + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap < 64) { + dev_err(&pdev->dev, "Bad PCI_CAP_ID_EXP location %d\n", cap); + goto abort_with_netdev; + } + status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val); + if (status != 0) { + dev_err(&pdev->dev, "Error %d reading PCI_EXP_DEVCTL\n", + status); + goto abort_with_netdev; + } + val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); + status = pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, val); + if (status != 0) { + dev_err(&pdev->dev, "Error %d writing PCI_EXP_DEVCTL\n", + status); + goto abort_with_netdev; + } + + pci_set_master(pdev); + dac_enabled = 1; + status = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (status != 0) { + dac_enabled = 0; + dev_err(&pdev->dev, + "64-bit pci address mask was refused, trying 32-bit"); + status = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + } + if (status != 0) { + dev_err(&pdev->dev, "Error %d setting DMA mask\n", status); + goto abort_with_netdev; + } + mgp->cmd = pci_alloc_consistent(pdev, sizeof(*mgp->cmd), &mgp->cmd_bus); + if (mgp->cmd == NULL) + goto abort_with_netdev; + + mgp->fw_stats = pci_alloc_consistent(pdev, sizeof(*mgp->fw_stats), + &mgp->fw_stats_bus); + if (mgp->fw_stats == NULL) + goto abort_with_cmd; + + mgp->board_span = pci_resource_len(pdev, 0); + mgp->iomem_base = pci_resource_start(pdev, 0); + mgp->mtrr = -1; +#ifdef CONFIG_MTRR + mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span, + MTRR_TYPE_WRCOMB, 1); +#endif + /* Hack. need to get rid of these magic numbers */ + mgp->sram_size = + 2 * 1024 * 1024 - (2 * (48 * 1024) + (32 * 1024)) - 0x100; + if (mgp->sram_size > mgp->board_span) { + dev_err(&pdev->dev, "board span %ld bytes too small\n", + mgp->board_span); + goto abort_with_wc; + } + mgp->sram = ioremap(mgp->iomem_base, mgp->board_span); + if (mgp->sram == NULL) { + dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n", + mgp->board_span, mgp->iomem_base); + status = -ENXIO; + goto abort_with_wc; + } + memcpy_fromio(mgp->eeprom_strings, + mgp->sram + mgp->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE, + MYRI10GE_EEPROM_STRINGS_SIZE); + memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2); + status = myri10ge_read_mac_addr(mgp); + if (status) + goto abort_with_ioremap; + + for (i = 0; i < ETH_ALEN; i++) + netdev->dev_addr[i] = mgp->mac_addr[i]; + + /* allocate rx done ring */ + bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry); + mgp->rx_done.entry = + pci_alloc_consistent(pdev, bytes, &mgp->rx_done.bus); + if (mgp->rx_done.entry == NULL) + goto abort_with_ioremap; + memset(mgp->rx_done.entry, 0, bytes); + + status = myri10ge_load_firmware(mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to load firmware\n"); + goto abort_with_rx_done; + } + + status = myri10ge_reset(mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed reset\n"); + goto abort_with_firmware; + } + + if (myri10ge_msi) { + status = pci_enable_msi(pdev); + if (status != 0) + dev_err(&pdev->dev, + "Error %d setting up MSI; falling back to xPIC\n", + status); + else + mgp->msi_enabled = 1; + } + + status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ, + netdev->name, mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to allocate IRQ\n"); + goto abort_with_firmware; + } + + pci_set_drvdata(pdev, mgp); + if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) + myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; + if ((myri10ge_initial_mtu + ETH_HLEN) < 68) + myri10ge_initial_mtu = 68; + netdev->mtu = myri10ge_initial_mtu; + netdev->open = myri10ge_open; + netdev->stop = myri10ge_close; + netdev->hard_start_xmit = myri10ge_xmit; + netdev->get_stats = myri10ge_get_stats; + netdev->base_addr = mgp->iomem_base; + netdev->irq = pdev->irq; + netdev->change_mtu = myri10ge_change_mtu; + netdev->set_multicast_list = myri10ge_set_multicast_list; + netdev->set_mac_address = myri10ge_set_mac_address; + netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; + if (dac_enabled) + netdev->features |= NETIF_F_HIGHDMA; + netdev->poll = myri10ge_poll; + netdev->weight = myri10ge_napi_weight; + + /* Save configuration space to be restored if the + * nic resets due to a parity error */ + myri10ge_save_state(mgp); + /* Restore state immediately since pci_save_msi_state disables MSI */ + myri10ge_restore_state(mgp); + + /* Setup the watchdog timer */ + setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, + (unsigned long)mgp); + + SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops); + INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog, mgp); + status = register_netdev(netdev); + if (status != 0) { + dev_err(&pdev->dev, "register_netdev failed: %d\n", status); + goto abort_with_irq; + } + + printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n", + netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"), + pdev->irq, mgp->tx.boundary, mgp->fw_name, + (mgp->mtrr >= 0 ? "Enabled" : "Disabled")); + + return 0; + +abort_with_irq: + free_irq(pdev->irq, mgp); + if (mgp->msi_enabled) + pci_disable_msi(pdev); + +abort_with_firmware: + myri10ge_dummy_rdma(mgp, 0); + +abort_with_rx_done: + bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry); + pci_free_consistent(pdev, bytes, mgp->rx_done.entry, mgp->rx_done.bus); + +abort_with_ioremap: + iounmap(mgp->sram); + +abort_with_wc: +#ifdef CONFIG_MTRR + if (mgp->mtrr >= 0) + mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); +#endif + pci_free_consistent(pdev, sizeof(*mgp->fw_stats), + mgp->fw_stats, mgp->fw_stats_bus); + +abort_with_cmd: + pci_free_consistent(pdev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); + +abort_with_netdev: + + free_netdev(netdev); + return status; +} + +/* + * myri10ge_remove + * + * Does what is necessary to shutdown one Myrinet device. Called + * once for each Myrinet card by the kernel when a module is + * unloaded. + */ +static void myri10ge_remove(struct pci_dev *pdev) +{ + struct myri10ge_priv *mgp; + struct net_device *netdev; + size_t bytes; + + mgp = pci_get_drvdata(pdev); + if (mgp == NULL) + return; + + flush_scheduled_work(); + netdev = mgp->dev; + unregister_netdev(netdev); + free_irq(pdev->irq, mgp); + if (mgp->msi_enabled) + pci_disable_msi(pdev); + + myri10ge_dummy_rdma(mgp, 0); + + bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry); + pci_free_consistent(pdev, bytes, mgp->rx_done.entry, mgp->rx_done.bus); + + iounmap(mgp->sram); + +#ifdef CONFIG_MTRR + if (mgp->mtrr >= 0) + mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); +#endif + pci_free_consistent(pdev, sizeof(*mgp->fw_stats), + mgp->fw_stats, mgp->fw_stats_bus); + + pci_free_consistent(pdev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); + + free_netdev(netdev); + pci_set_drvdata(pdev, NULL); +} + +#define PCI_DEVICE_ID_MYIRCOM_MYRI10GE_Z8E 0x0008 + +static struct pci_device_id myri10ge_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYIRCOM_MYRI10GE_Z8E)}, + {0}, +}; + +static struct pci_driver myri10ge_driver = { + .name = "myri10ge", + .probe = myri10ge_probe, + .remove = myri10ge_remove, + .id_table = myri10ge_pci_tbl, +#ifdef CONFIG_PM + .suspend = myri10ge_suspend, + .resume = myri10ge_resume, +#endif +}; + +static __init int myri10ge_init_module(void) +{ + printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, + MYRI10GE_VERSION_STR); + return pci_register_driver(&myri10ge_driver); +} + +module_init(myri10ge_init_module); + +static __exit void myri10ge_cleanup_module(void) +{ + pci_unregister_driver(&myri10ge_driver); +} + +module_exit(myri10ge_cleanup_module); diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h new file mode 100644 index 000000000000..ac23e18db63d --- /dev/null +++ b/drivers/net/myri10ge/myri10ge_mcp.h @@ -0,0 +1,205 @@ +#ifndef __MYRI10GE_MCP_H__ +#define __MYRI10GE_MCP_H__ + +#define MXGEFW_VERSION_MAJOR 1 +#define MXGEFW_VERSION_MINOR 4 + +/* 8 Bytes */ +struct mcp_dma_addr { + u32 high; + u32 low; +}; + +/* 4 Bytes */ +struct mcp_slot { + u16 checksum; + u16 length; +}; + +/* 64 Bytes */ +struct mcp_cmd { + u32 cmd; + u32 data0; /* will be low portion if data > 32 bits */ + /* 8 */ + u32 data1; /* will be high portion if data > 32 bits */ + u32 data2; /* currently unused.. */ + /* 16 */ + struct mcp_dma_addr response_addr; + /* 24 */ + u8 pad[40]; +}; + +/* 8 Bytes */ +struct mcp_cmd_response { + u32 data; + u32 result; +}; + +/* + * flags used in mcp_kreq_ether_send_t: + * + * The SMALL flag is only needed in the first segment. It is raised + * for packets that are total less or equal 512 bytes. + * + * The CKSUM flag must be set in all segments. + * + * The PADDED flags is set if the packet needs to be padded, and it + * must be set for all segments. + * + * The MXGEFW_FLAGS_ALIGN_ODD must be set if the cumulative + * length of all previous segments was odd. + */ + +#define MXGEFW_FLAGS_SMALL 0x1 +#define MXGEFW_FLAGS_TSO_HDR 0x1 +#define MXGEFW_FLAGS_FIRST 0x2 +#define MXGEFW_FLAGS_ALIGN_ODD 0x4 +#define MXGEFW_FLAGS_CKSUM 0x8 +#define MXGEFW_FLAGS_TSO_LAST 0x8 +#define MXGEFW_FLAGS_NO_TSO 0x10 +#define MXGEFW_FLAGS_TSO_CHOP 0x10 +#define MXGEFW_FLAGS_TSO_PLD 0x20 + +#define MXGEFW_SEND_SMALL_SIZE 1520 +#define MXGEFW_MAX_MTU 9400 + +union mcp_pso_or_cumlen { + u16 pseudo_hdr_offset; + u16 cum_len; +}; + +#define MXGEFW_MAX_SEND_DESC 12 +#define MXGEFW_PAD 2 + +/* 16 Bytes */ +struct mcp_kreq_ether_send { + u32 addr_high; + u32 addr_low; + u16 pseudo_hdr_offset; + u16 length; + u8 pad; + u8 rdma_count; + u8 cksum_offset; /* where to start computing cksum */ + u8 flags; /* as defined above */ +}; + +/* 8 Bytes */ +struct mcp_kreq_ether_recv { + u32 addr_high; + u32 addr_low; +}; + +/* Commands */ + +#define MXGEFW_CMD_OFFSET 0xf80000 + +enum myri10ge_mcp_cmd_type { + MXGEFW_CMD_NONE = 0, + /* Reset the mcp, it is left in a safe state, waiting + * for the driver to set all its parameters */ + MXGEFW_CMD_RESET, + + /* get the version number of the current firmware.. + * (may be available in the eeprom strings..? */ + MXGEFW_GET_MCP_VERSION, + + /* Parameters which must be set by the driver before it can + * issue MXGEFW_CMD_ETHERNET_UP. They persist until the next + * MXGEFW_CMD_RESET is issued */ + + MXGEFW_CMD_SET_INTRQ_DMA, + MXGEFW_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */ + MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */ + + /* Parameters which refer to lanai SRAM addresses where the + * driver must issue PIO writes for various things */ + + MXGEFW_CMD_GET_SEND_OFFSET, + MXGEFW_CMD_GET_SMALL_RX_OFFSET, + MXGEFW_CMD_GET_BIG_RX_OFFSET, + MXGEFW_CMD_GET_IRQ_ACK_OFFSET, + MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, + + /* Parameters which refer to rings stored on the MCP, + * and whose size is controlled by the mcp */ + + MXGEFW_CMD_GET_SEND_RING_SIZE, /* in bytes */ + MXGEFW_CMD_GET_RX_RING_SIZE, /* in bytes */ + + /* Parameters which refer to rings stored in the host, + * and whose size is controlled by the host. Note that + * all must be physically contiguous and must contain + * a power of 2 number of entries. */ + + MXGEFW_CMD_SET_INTRQ_SIZE, /* in bytes */ + + /* command to bring ethernet interface up. Above parameters + * (plus mtu & mac address) must have been exchanged prior + * to issuing this command */ + MXGEFW_CMD_ETHERNET_UP, + + /* command to bring ethernet interface down. No further sends + * or receives may be processed until an MXGEFW_CMD_ETHERNET_UP + * is issued, and all interrupt queues must be flushed prior + * to ack'ing this command */ + + MXGEFW_CMD_ETHERNET_DOWN, + + /* commands the driver may issue live, without resetting + * the nic. Note that increasing the mtu "live" should + * only be done if the driver has already supplied buffers + * sufficiently large to handle the new mtu. Decreasing + * the mtu live is safe */ + + MXGEFW_CMD_SET_MTU, + MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ + MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ + MXGEFW_CMD_SET_STATS_DMA, + + MXGEFW_ENABLE_PROMISC, + MXGEFW_DISABLE_PROMISC, + MXGEFW_SET_MAC_ADDRESS, + + MXGEFW_ENABLE_FLOW_CONTROL, + MXGEFW_DISABLE_FLOW_CONTROL, + + /* do a DMA test + * data0,data1 = DMA address + * data2 = RDMA length (MSH), WDMA length (LSH) + * command return data = repetitions (MSH), 0.5-ms ticks (LSH) + */ + MXGEFW_DMA_TEST +}; + +enum myri10ge_mcp_cmd_status { + MXGEFW_CMD_OK = 0, + MXGEFW_CMD_UNKNOWN, + MXGEFW_CMD_ERROR_RANGE, + MXGEFW_CMD_ERROR_BUSY, + MXGEFW_CMD_ERROR_EMPTY, + MXGEFW_CMD_ERROR_CLOSED, + MXGEFW_CMD_ERROR_HASH_ERROR, + MXGEFW_CMD_ERROR_BAD_PORT, + MXGEFW_CMD_ERROR_RESOURCES +}; + +/* 40 Bytes */ +struct mcp_irq_data { + u32 send_done_count; + + u32 link_up; + u32 dropped_link_overflow; + u32 dropped_link_error_or_filtered; + u32 dropped_runt; + u32 dropped_overrun; + u32 dropped_no_small_buffer; + u32 dropped_no_big_buffer; + u32 rdma_tags_available; + + u8 tx_stopped; + u8 link_down; + u8 stats_updated; + u8 valid; +}; + +#endif /* __MYRI10GE_MCP_H__ */ diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h new file mode 100644 index 000000000000..1d3a35f10789 --- /dev/null +++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h @@ -0,0 +1,58 @@ +#ifndef __MYRI10GE_MCP_GEN_HEADER_H__ +#define __MYRI10GE_MCP_GEN_HEADER_H__ + +/* this file define a standard header used as a first entry point to + * exchange information between firmware/driver and driver. The + * header structure can be anywhere in the mcp. It will usually be in + * the .data section, because some fields needs to be initialized at + * compile time. + * The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must + * contains the location of the header. + * + * Typically a MCP will start with the following: + * .text + * .space 52 ! to help catch MEMORY_INT errors + * bt start ! jump to real code + * nop + * .long _gen_mcp_header + * + * The source will have a definition like: + * + * mcp_gen_header_t gen_mcp_header = { + * .header_length = sizeof(mcp_gen_header_t), + * .mcp_type = MCP_TYPE_XXX, + * .version = "something $Id: mcp_gen_header.h,v 1.2 2006/05/13 10:04:35 bgoglin Exp $", + * .mcp_globals = (unsigned)&Globals + * }; + */ + +#define MCP_HEADER_PTR_OFFSET 0x3c + +#define MCP_TYPE_MX 0x4d582020 /* "MX " */ +#define MCP_TYPE_PCIE 0x70636965 /* "PCIE" pcie-only MCP */ +#define MCP_TYPE_ETH 0x45544820 /* "ETH " */ +#define MCP_TYPE_MCP0 0x4d435030 /* "MCP0" */ + +struct mcp_gen_header { + /* the first 4 fields are filled at compile time */ + unsigned header_length; + unsigned mcp_type; + char version[128]; + unsigned mcp_globals; /* pointer to mcp-type specific structure */ + + /* filled by the MCP at run-time */ + unsigned sram_size; + unsigned string_specs; /* either the original STRING_SPECS or a superset */ + unsigned string_specs_len; + + /* Fields above this comment are guaranteed to be present. + * + * Fields below this comment are extensions added in later versions + * of this struct, drivers should compare the header_length against + * offsetof(field) to check wether a given MCP implements them. + * + * Never remove any field. Keep everything naturally align. + */ +}; + +#endif /* __MYRI10GE_MCP_GEN_HEADER_H__ */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 563eeadbea46..151549a69ee0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1827,6 +1827,7 @@ #define PCI_VENDOR_ID_SAMSUNG 0x144d +#define PCI_VENDOR_ID_MYRICOM 0x14c1 #define PCI_VENDOR_ID_TITAN 0x14D2 #define PCI_DEVICE_ID_TITAN_010L 0x8001 -- cgit v1.2.3 From 4c0c2fd486b6598e37c77b5d81a08bc2d948aa7b Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 25 May 2006 13:10:38 -0400 Subject: [PATCH] pci_ids: add new device ids This patch adds new device ids for MCP61 and MCP65 chips. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 151549a69ee0..dce2534ab7dc 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1183,6 +1183,14 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E #define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372 #define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 +#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6 +#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE +#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF +#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450 +#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 +#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 +#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_TT128 0x9128 -- cgit v1.2.3 From 76ea4c7f4cd319dee35934ecab57745feae58fa5 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 1 Jun 2006 15:34:26 +0100 Subject: [PATCH] softmac: complete shared key authentication This patch finishes of the partially-complete shared key authentication implementation in softmac. The complication here is that we need to encrypt a management frame during the authentication process. I don't think there are any other scenarios where this would have to happen. To get around this without causing too many headaches, we decided to just use software encryption for this frame. The softmac config option now selects IEEE80211_CRYPT_WEP so that we can ensure this available. This also involved a modification to some otherwise unused ieee80211 API. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/ieee80211.h | 3 ++- net/ieee80211/ieee80211_tx.c | 25 ++++++++++++----- net/ieee80211/softmac/Kconfig | 1 + net/ieee80211/softmac/ieee80211softmac_auth.c | 12 +++++---- net/ieee80211/softmac/ieee80211softmac_io.c | 39 +++++++++++++++------------ 5 files changed, 51 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 293e920ca59d..d5147770ad47 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -1247,7 +1247,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee); extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); extern int ieee80211_tx_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *frame, int len); + struct ieee80211_hdr *frame, int hdr_len, + int total_len, int encrypt_mpdu); /* ieee80211_rx.c */ extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 233d527c6953..6a5de1b84459 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -555,7 +555,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Incoming 802.11 strucure is converted to a TXB * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_tx_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *frame, int len) + struct ieee80211_hdr *frame, int hdr_len, int total_len, + int encrypt_mpdu) { struct ieee80211_txb *txb = NULL; unsigned long flags; @@ -565,6 +566,9 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, spin_lock_irqsave(&ieee->lock, flags); + if (encrypt_mpdu && !ieee->sec.encrypt) + encrypt_mpdu = 0; + /* If there is no driver handler to take the TXB, dont' bother * creating it... */ if (!ieee->hard_start_xmit) { @@ -572,32 +576,41 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, goto success; } - if (unlikely(len < 24)) { + if (unlikely(total_len < 24)) { printk(KERN_WARNING "%s: skb too small (%d).\n", - ieee->dev->name, len); + ieee->dev->name, total_len); goto success; } + if (encrypt_mpdu) + frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(1, len, ieee->tx_headroom, GFP_ATOMIC); + txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC); if (unlikely(!txb)) { printk(KERN_WARNING "%s: Could not allocate TXB\n", ieee->dev->name); goto failed; } txb->encrypted = 0; - txb->payload_size = len; + txb->payload_size = total_len; skb_frag = txb->fragments[0]; - memcpy(skb_put(skb_frag, len), frame, len); + memcpy(skb_put(skb_frag, total_len), frame, total_len); if (ieee->config & (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) skb_put(skb_frag, 4); + /* To avoid overcomplicating things, we do the corner-case frame + * encryption in software. The only real situation where encryption is + * needed here is during software-based shared key authentication. */ + if (encrypt_mpdu) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + success: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig index f2a27cc6ecb1..2811651cb134 100644 --- a/net/ieee80211/softmac/Kconfig +++ b/net/ieee80211/softmac/Kconfig @@ -2,6 +2,7 @@ config IEEE80211_SOFTMAC tristate "Software MAC add-on to the IEEE 802.11 networking stack" depends on IEEE80211 && EXPERIMENTAL select WIRELESS_EXT + select IEEE80211_CRYPT_WEP ---help--- This option enables the hardware independent software MAC addon for the IEEE 802.11 networking stack. diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 084b6211f293..90b8484e509b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -107,6 +107,7 @@ ieee80211softmac_auth_queue(void *data) printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); /* Remove this item from the queue */ spin_lock_irqsave(&mac->lock, flags); + net->authenticating = 0; ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); cancel_delayed_work(&auth->work); /* just to make sure... */ list_del(&auth->list); @@ -212,13 +213,13 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; spin_unlock_irqrestore(&mac->lock, flags); - /* Switch to correct channel for this network */ - mac->set_channel(mac->dev, net->channel); - - /* Send our response (How to encrypt?) */ + /* Send our response */ ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); - break; + return 0; case IEEE80211SOFTMAC_AUTH_SHARED_PASS: + kfree(net->challenge); + net->challenge = NULL; + net->challenge_len = 0; /* Check the status code of the response */ switch(auth->status) { case WLAN_STATUS_SUCCESS: @@ -229,6 +230,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) spin_unlock_irqrestore(&mac->lock, flags); printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid)); + ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); break; default: printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c index 7b9e78d39598..44f51175a2fc 100644 --- a/net/ieee80211/softmac/ieee80211softmac_io.c +++ b/net/ieee80211/softmac/ieee80211softmac_io.c @@ -268,26 +268,27 @@ ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt, static u32 ieee80211softmac_auth(struct ieee80211_auth **pkt, struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, - u16 transaction, u16 status) + u16 transaction, u16 status, int *encrypt_mpdu) { u8 *data; + int auth_mode = mac->ieee->sec.auth_mode; + int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY + && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE); + /* Allocate Packet */ (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( 2 + /* Auth Algorithm */ 2 + /* Auth Transaction Seq */ 2 + /* Status Code */ /* Challenge Text IE */ - mac->ieee->open_wep ? 0 : - 1 + 1 + WLAN_AUTH_CHALLENGE_LEN - ); + is_shared_response ? 0 : 1 + 1 + net->challenge_len + ); if (unlikely((*pkt) == NULL)) return 0; ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); /* Algorithm */ - (*pkt)->algorithm = mac->ieee->open_wep ? - cpu_to_le16(WLAN_AUTH_OPEN) : - cpu_to_le16(WLAN_AUTH_SHARED_KEY); + (*pkt)->algorithm = cpu_to_le16(auth_mode); /* Transaction */ (*pkt)->transaction = cpu_to_le16(transaction); /* Status */ @@ -295,18 +296,20 @@ ieee80211softmac_auth(struct ieee80211_auth **pkt, data = (u8 *)(*pkt)->info_element; /* Challenge Text */ - if(!mac->ieee->open_wep){ + if (is_shared_response) { *data = MFIE_TYPE_CHALLENGE; data++; /* Copy the challenge in */ - // *data = challenge length - // data += sizeof(u16); - // memcpy(data, challenge, challenge length); - // data += challenge length; - - /* Add the full size to the packet length */ - } + *data = net->challenge_len; + data++; + memcpy(data, net->challenge, net->challenge_len); + data += net->challenge_len; + + /* Make sure this frame gets encrypted with the shared key */ + *encrypt_mpdu = 1; + } else + *encrypt_mpdu = 0; /* Return the packet size */ return (data - (u8 *)(*pkt)); @@ -396,6 +399,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, { void *pkt = NULL; u32 pkt_size = 0; + int encrypt_mpdu = 0; switch(type) { case IEEE80211_STYPE_ASSOC_REQ: @@ -405,7 +409,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); break; case IEEE80211_STYPE_AUTH: - pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16)); + pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu); break; case IEEE80211_STYPE_DISASSOC: case IEEE80211_STYPE_DEAUTH: @@ -434,7 +438,8 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, * or get rid of it alltogether? * Does this work for you now? */ - ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size); + ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, + IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu); kfree(pkt); return 0; -- cgit v1.2.3 From 6ae15df16ef3dc3f5f043e94bb2cd4aa6c7f2aa8 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 1 Jun 2006 15:37:22 +0100 Subject: [PATCH] softmac: Fix handling of authentication failure My router blew up earlier, but exhibited some interesting behaviour during its dying moments. It was broadcasting beacons but wouldn't respond to any authentication requests. I noticed that softmac wasn't playing nice with this, as I couldn't make it try to connect to other networks after it had timed out authenticating to my ill router. To resolve this, I modified the softmac event/notify API to pass the event code to the callback, so that callbacks being notified from IEEE80211SOFTMAC_EVENT_ANY masks can make some judgement. In this case, the ieee80211softmac_assoc callback needs to make a decision based upon whether the association passed or failed. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/ieee80211softmac.h | 2 +- net/ieee80211/softmac/ieee80211softmac_assoc.c | 22 +++++++++++++++++++--- net/ieee80211/softmac/ieee80211softmac_event.c | 5 ++++- 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index 703463a8828b..7a483ab4022f 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -310,7 +310,7 @@ extern void ieee80211softmac_stop(struct net_device *dev); * - context set to the context data you want passed * The return value is 0, or an error. */ -typedef void (*notify_function_ptr)(struct net_device *dev, void *context); +typedef void (*notify_function_ptr)(struct net_device *dev, int event_type, void *context); #define ieee80211softmac_notify(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_KERNEL); #define ieee80211softmac_notify_atomic(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_ATOMIC); diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 5d90b9a6ee50..5e9a90651d04 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -164,12 +164,28 @@ network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_ne } static void -ieee80211softmac_assoc_notify(struct net_device *dev, void *context) +ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context) { struct ieee80211softmac_device *mac = ieee80211_priv(dev); ieee80211softmac_assoc_work((void*)mac); } +static void +ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context) +{ + struct ieee80211softmac_device *mac = ieee80211_priv(dev); + + switch (event_type) { + case IEEE80211SOFTMAC_EVENT_AUTHENTICATED: + ieee80211softmac_assoc_work((void*)mac); + break; + case IEEE80211SOFTMAC_EVENT_AUTH_FAILED: + case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT: + ieee80211softmac_disassoc(mac); + break; + } +} + /* This function is called to handle userspace requests (asynchronously) */ void ieee80211softmac_assoc_work(void *d) @@ -249,7 +265,7 @@ ieee80211softmac_assoc_work(void *d) * Maybe we can hope to have more memory after scanning finishes ;) */ dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); - ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL); + ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL); if (ieee80211softmac_start_scan(mac)) dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); return; @@ -284,7 +300,7 @@ ieee80211softmac_assoc_work(void *d) * otherwise adding the notification would be racy. */ if (!ieee80211softmac_auth_req(mac, found)) { dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); - ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL); + ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); } else { printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index 4b153f7cc96c..f34fa2ef666b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c @@ -78,7 +78,7 @@ ieee80211softmac_notify_callback(void *d) struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; kfree(d); - event.fun(event.mac->dev, event.context); + event.fun(event.mac->dev, event.event_type, event.context); } int @@ -167,6 +167,9 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve if ((eventptr->event_type == event || eventptr->event_type == -1) && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { list_del(&eventptr->list); + /* User may have subscribed to ANY event, so + * we tell them which event triggered it. */ + eventptr->event_type = event; schedule_work(&eventptr->work); } } -- cgit v1.2.3 From 0c27c5d5b93339df4def7ced77ea5be26df4d84b Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 8 Jun 2006 22:44:07 +0100 Subject: [ARM] 3547/1: PXA-OHCI: Allow platforms to specify a power budget Patch from Richard Purdie Add a power budget variable to the PXA OHCI platform data and add a default value for the spitz platform(s) which prevents known failures with certain USB devices. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/spitz.c | 1 + drivers/usb/host/ohci-pxa27x.c | 3 +++ include/asm-arm/arch-pxa/ohci.h | 2 ++ 3 files changed, 6 insertions(+) (limited to 'include') diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 19b372df544a..44bcb8097c7a 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -371,6 +371,7 @@ static int spitz_ohci_init(struct device *dev) static struct pxaohci_platform_data spitz_ohci_platform_data = { .port_mode = PMM_NPS_MODE, .init = spitz_ohci_init, + .power_budget = 150, }; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index acde8868da21..fafe7c1265b3 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -185,6 +185,9 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device /* Select Power Management Mode */ pxa27x_ohci_select_pmm(inf->port_mode); + if (inf->power_budget) + hcd->power_budget = inf->power_budget; + ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); diff --git a/include/asm-arm/arch-pxa/ohci.h b/include/asm-arm/arch-pxa/ohci.h index 7da89569061e..e848a47128cd 100644 --- a/include/asm-arm/arch-pxa/ohci.h +++ b/include/asm-arm/arch-pxa/ohci.h @@ -11,6 +11,8 @@ struct pxaohci_platform_data { #define PMM_NPS_MODE 1 #define PMM_GLOBAL_MODE 2 #define PMM_PERPORT_MODE 3 + + int power_budget; }; extern void pxa_set_ohci_info(struct pxaohci_platform_data *info); -- cgit v1.2.3 From 57a62fed871eb2a95f296fe6c5c250ce21b81a79 Mon Sep 17 00:00:00 2001 From: Markus Lidel Date: Sat, 10 Jun 2006 09:54:14 -0700 Subject: [PATCH] I2O: Bugfixes to get I2O working again From: Markus Lidel - Fixed locking of struct i2o_exec_wait in Executive-OSM - Removed LCT Notify in i2o_exec_probe() which caused freeing memory and accessing freed memory during first enumeration of I2O devices - Added missing locking in i2o_exec_lct_notify() - removed put_device() of I2O controller in i2o_iop_remove() which caused the controller structure get freed to early - Fixed size of mempool in i2o_iop_alloc() - Fixed access to freed memory in i2o_msg_get() See http://bugzilla.kernel.org/show_bug.cgi?id=6561 Signed-off-by: Markus Lidel Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/message/i2o/exec-osm.c | 72 ++++++++++++++++++++++-------------------- drivers/message/i2o/iop.c | 4 +-- include/linux/i2o.h | 5 ++- 3 files changed, 42 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 5ea133c59afb..7bd4d85d0b42 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -55,6 +55,7 @@ struct i2o_exec_wait { u32 m; /* message id */ struct i2o_message *msg; /* pointer to the reply message */ struct list_head list; /* node in global wait list */ + spinlock_t lock; /* lock before modifying */ }; /* Work struct needed to handle LCT NOTIFY replies */ @@ -87,6 +88,7 @@ static struct i2o_exec_wait *i2o_exec_wait_alloc(void) return NULL; INIT_LIST_HEAD(&wait->list); + spin_lock_init(&wait->lock); return wait; }; @@ -125,6 +127,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, DECLARE_WAIT_QUEUE_HEAD(wq); struct i2o_exec_wait *wait; static u32 tcntxt = 0x80000000; + long flags; int rc = 0; wait = i2o_exec_wait_alloc(); @@ -146,33 +149,28 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, wait->tcntxt = tcntxt++; msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt); + wait->wq = &wq; + /* + * we add elements to the head, because if a entry in the list will + * never be removed, we have to iterate over it every time + */ + list_add(&wait->list, &i2o_exec_wait_list); + /* * Post the message to the controller. At some point later it will * return. If we time out before it returns then complete will be zero. */ i2o_msg_post(c, msg); - if (!wait->complete) { - wait->wq = &wq; - /* - * we add elements add the head, because if a entry in the list - * will never be removed, we have to iterate over it every time - */ - list_add(&wait->list, &i2o_exec_wait_list); - - wait_event_interruptible_timeout(wq, wait->complete, - timeout * HZ); + wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ); - wait->wq = NULL; - } + spin_lock_irqsave(&wait->lock, flags); - barrier(); + wait->wq = NULL; - if (wait->complete) { + if (wait->complete) rc = le32_to_cpu(wait->msg->body[0]) >> 24; - i2o_flush_reply(c, wait->m); - i2o_exec_wait_free(wait); - } else { + else { /* * We cannot remove it now. This is important. When it does * terminate (which it must do if the controller has not @@ -186,6 +184,13 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, rc = -ETIMEDOUT; } + spin_unlock_irqrestore(&wait->lock, flags); + + if (rc != -ETIMEDOUT) { + i2o_flush_reply(c, wait->m); + i2o_exec_wait_free(wait); + } + return rc; }; @@ -213,7 +218,6 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, { struct i2o_exec_wait *wait, *tmp; unsigned long flags; - static spinlock_t lock = SPIN_LOCK_UNLOCKED; int rc = 1; /* @@ -223,23 +227,24 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, * already expired. Not much we can do about that except log it for * debug purposes, increase timeout, and recompile. */ - spin_lock_irqsave(&lock, flags); list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { if (wait->tcntxt == context) { - list_del(&wait->list); + spin_lock_irqsave(&wait->lock, flags); - spin_unlock_irqrestore(&lock, flags); + list_del(&wait->list); wait->m = m; wait->msg = msg; wait->complete = 1; - barrier(); - - if (wait->wq) { - wake_up_interruptible(wait->wq); + if (wait->wq) rc = 0; - } else { + else + rc = -1; + + spin_unlock_irqrestore(&wait->lock, flags); + + if (rc) { struct device *dev; dev = &c->pdev->dev; @@ -248,15 +253,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, c->name); i2o_dma_free(dev, &wait->dma); i2o_exec_wait_free(wait); - rc = -1; - } + } else + wake_up_interruptible(wait->wq); return rc; } } - spin_unlock_irqrestore(&lock, flags); - osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, context); @@ -322,14 +325,9 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL); static int i2o_exec_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(dev); - struct i2o_controller *c = i2o_dev->iop; i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); - c->exec = i2o_dev; - - i2o_exec_lct_notify(c, c->lct->change_ind + 1); - device_create_file(dev, &dev_attr_vendor_id); device_create_file(dev, &dev_attr_product_id); @@ -523,6 +521,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) struct device *dev; struct i2o_message *msg; + down(&c->lct_lock); + dev = &c->pdev->dev; if (i2o_dma_realloc @@ -545,6 +545,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) i2o_msg_post(c, msg); + up(&c->lct_lock); + return 0; }; diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 492167446936..febbdd4e0605 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -804,8 +804,6 @@ void i2o_iop_remove(struct i2o_controller *c) /* Ask the IOP to switch to RESET state */ i2o_iop_reset(c); - - put_device(&c->device); } /** @@ -1059,7 +1057,7 @@ struct i2o_controller *i2o_iop_alloc(void) snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name); if (i2o_pool_alloc - (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4, + (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32), I2O_MSG_INPOOL_MIN)) { kfree(c); return ERR_PTR(-ENOMEM); diff --git a/include/linux/i2o.h b/include/linux/i2o.h index dd7d627bf66f..c115e9e840b4 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -1114,8 +1114,11 @@ static inline struct i2o_message *i2o_msg_get(struct i2o_controller *c) mmsg->mfa = readl(c->in_port); if (unlikely(mmsg->mfa >= c->in_queue.len)) { + u32 mfa = mmsg->mfa; + mempool_free(mmsg, c->in_msg.mempool); - if(mmsg->mfa == I2O_QUEUE_EMPTY) + + if (mfa == I2O_QUEUE_EMPTY) return ERR_PTR(-EBUSY); return ERR_PTR(-EFAULT); } -- cgit v1.2.3 From 0ce030395b92270567423d57d9d432eb77df32f2 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sat, 13 May 2006 08:30:52 -0700 Subject: [PATCH] PCI: fix pciehp compile issue when CONFIG_ACPI is not enabled Fix build error when CONFIG_ACPI not defined Signed-off-by: Kristen Carlson Accardi Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/pci-acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 4877e35ae202..936ef82ed76a 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -50,7 +50,7 @@ extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags); extern acpi_status pci_osc_support_set(u32 flags); #else -#if !defined(acpi_status) +#if !defined(AE_ERROR) typedef u32 acpi_status; #define AE_ERROR (acpi_status) (0x0001) #endif -- cgit v1.2.3 From ce221982e0bef039d7047b0f667bb414efece5af Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Jun 2006 15:09:16 +0200 Subject: [PATCH] powerpc: enable CPU_FTR_CI_LARGE_PAGE for cell Reflect the fact that the Cell Broadband Engine supports 64k pages by adding the bit to the CPU features. Signed-off-by: Arnd Bergmann Signed-off-by: Linus Torvalds --- include/asm-powerpc/cputable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 9fcf0162d859..f6265c2a0dd2 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -329,7 +329,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO) + CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE) #define CPU_FTRS_COMPATIBLE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2) #endif -- cgit v1.2.3 From 6a9af2e18a5c6ebcf8283309d20ac0e9fa35e346 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:27 -0700 Subject: IB: common handling for marshalling parameters to/from userspace Provide common handling for marshalling data between userspace clients and kernel InfiniBand drivers. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/Makefile | 3 +- drivers/infiniband/core/ucm.c | 131 +++------------------------- drivers/infiniband/core/uverbs_marshall.c | 138 ++++++++++++++++++++++++++++++ include/rdma/ib_marshall.h | 50 +++++++++++ include/rdma/ib_user_cm.h | 84 ++---------------- include/rdma/ib_user_sa.h | 60 +++++++++++++ include/rdma/ib_user_verbs.h | 80 ++++++++++++----- 7 files changed, 328 insertions(+), 218 deletions(-) create mode 100644 drivers/infiniband/core/uverbs_marshall.c create mode 100644 include/rdma/ib_marshall.h create mode 100644 include/rdma/ib_user_sa.h (limited to 'include') diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index ec3353f24b27..a56bf9c994f6 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -16,4 +16,5 @@ ib_umad-y := user_mad.o ib_ucm-y := ucm.o -ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o +ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o \ + uverbs_marshall.o diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 9164a09b6ccd..b396bf703f80 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -30,7 +30,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ + * $Id: ucm.c 4311 2005-12-05 18:42:01Z sean.hefty $ */ #include @@ -50,6 +50,7 @@ #include #include +#include MODULE_AUTHOR("Libor Michalek"); MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); @@ -205,36 +206,6 @@ error: return NULL; } -static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, - struct ib_sa_path_rec *kpath) -{ - if (!kpath || !upath) - return; - - memcpy(upath->dgid, kpath->dgid.raw, sizeof *upath->dgid); - memcpy(upath->sgid, kpath->sgid.raw, sizeof *upath->sgid); - - upath->dlid = kpath->dlid; - upath->slid = kpath->slid; - upath->raw_traffic = kpath->raw_traffic; - upath->flow_label = kpath->flow_label; - upath->hop_limit = kpath->hop_limit; - upath->traffic_class = kpath->traffic_class; - upath->reversible = kpath->reversible; - upath->numb_path = kpath->numb_path; - upath->pkey = kpath->pkey; - upath->sl = kpath->sl; - upath->mtu_selector = kpath->mtu_selector; - upath->mtu = kpath->mtu; - upath->rate_selector = kpath->rate_selector; - upath->rate = kpath->rate; - upath->packet_life_time = kpath->packet_life_time; - upath->preference = kpath->preference; - - upath->packet_life_time_selector = - kpath->packet_life_time_selector; -} - static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, struct ib_cm_req_event_param *kreq) { @@ -253,8 +224,10 @@ static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, ureq->srq = kreq->srq; ureq->port = kreq->port; - ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path); - ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path); + ib_copy_path_rec_to_user(&ureq->primary_path, kreq->primary_path); + if (kreq->alternate_path) + ib_copy_path_rec_to_user(&ureq->alternate_path, + kreq->alternate_path); } static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, @@ -324,8 +297,8 @@ static int ib_ucm_event_process(struct ib_cm_event *evt, info = evt->param.rej_rcvd.ari; break; case IB_CM_LAP_RECEIVED: - ib_ucm_event_path_get(&uvt->resp.u.lap_resp.path, - evt->param.lap_rcvd.alternate_path); + ib_copy_path_rec_to_user(&uvt->resp.u.lap_resp.path, + evt->param.lap_rcvd.alternate_path); uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE; uvt->resp.present = IB_UCM_PRES_ALTERNATE; break; @@ -637,65 +610,11 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, return result; } -static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr, - struct ib_ah_attr *src_attr) -{ - memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw, - sizeof src_attr->grh.dgid); - dest_attr->grh_flow_label = src_attr->grh.flow_label; - dest_attr->grh_sgid_index = src_attr->grh.sgid_index; - dest_attr->grh_hop_limit = src_attr->grh.hop_limit; - dest_attr->grh_traffic_class = src_attr->grh.traffic_class; - - dest_attr->dlid = src_attr->dlid; - dest_attr->sl = src_attr->sl; - dest_attr->src_path_bits = src_attr->src_path_bits; - dest_attr->static_rate = src_attr->static_rate; - dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH); - dest_attr->port_num = src_attr->port_num; -} - -static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr, - struct ib_qp_attr *src_attr) -{ - dest_attr->cur_qp_state = src_attr->cur_qp_state; - dest_attr->path_mtu = src_attr->path_mtu; - dest_attr->path_mig_state = src_attr->path_mig_state; - dest_attr->qkey = src_attr->qkey; - dest_attr->rq_psn = src_attr->rq_psn; - dest_attr->sq_psn = src_attr->sq_psn; - dest_attr->dest_qp_num = src_attr->dest_qp_num; - dest_attr->qp_access_flags = src_attr->qp_access_flags; - - dest_attr->max_send_wr = src_attr->cap.max_send_wr; - dest_attr->max_recv_wr = src_attr->cap.max_recv_wr; - dest_attr->max_send_sge = src_attr->cap.max_send_sge; - dest_attr->max_recv_sge = src_attr->cap.max_recv_sge; - dest_attr->max_inline_data = src_attr->cap.max_inline_data; - - ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr); - ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr); - - dest_attr->pkey_index = src_attr->pkey_index; - dest_attr->alt_pkey_index = src_attr->alt_pkey_index; - dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify; - dest_attr->sq_draining = src_attr->sq_draining; - dest_attr->max_rd_atomic = src_attr->max_rd_atomic; - dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic; - dest_attr->min_rnr_timer = src_attr->min_rnr_timer; - dest_attr->port_num = src_attr->port_num; - dest_attr->timeout = src_attr->timeout; - dest_attr->retry_cnt = src_attr->retry_cnt; - dest_attr->rnr_retry = src_attr->rnr_retry; - dest_attr->alt_port_num = src_attr->alt_port_num; - dest_attr->alt_timeout = src_attr->alt_timeout; -} - static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, const char __user *inbuf, int in_len, int out_len) { - struct ib_ucm_init_qp_attr_resp resp; + struct ib_uverbs_qp_attr resp; struct ib_ucm_init_qp_attr cmd; struct ib_ucm_context *ctx; struct ib_qp_attr qp_attr; @@ -718,7 +637,7 @@ static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, if (result) goto out; - ib_ucm_copy_qp_attr(&resp, &qp_attr); + ib_copy_qp_attr_to_user(&resp, &qp_attr); if (copy_to_user((void __user *)(unsigned long)cmd.response, &resp, sizeof(resp))) @@ -793,7 +712,7 @@ static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len) static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) { - struct ib_ucm_path_rec ucm_path; + struct ib_user_path_rec upath; struct ib_sa_path_rec *sa_path; *path = NULL; @@ -805,36 +724,14 @@ static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) if (!sa_path) return -ENOMEM; - if (copy_from_user(&ucm_path, (void __user *)(unsigned long)src, - sizeof(ucm_path))) { + if (copy_from_user(&upath, (void __user *)(unsigned long)src, + sizeof(upath))) { kfree(sa_path); return -EFAULT; } - memcpy(sa_path->dgid.raw, ucm_path.dgid, sizeof sa_path->dgid); - memcpy(sa_path->sgid.raw, ucm_path.sgid, sizeof sa_path->sgid); - - sa_path->dlid = ucm_path.dlid; - sa_path->slid = ucm_path.slid; - sa_path->raw_traffic = ucm_path.raw_traffic; - sa_path->flow_label = ucm_path.flow_label; - sa_path->hop_limit = ucm_path.hop_limit; - sa_path->traffic_class = ucm_path.traffic_class; - sa_path->reversible = ucm_path.reversible; - sa_path->numb_path = ucm_path.numb_path; - sa_path->pkey = ucm_path.pkey; - sa_path->sl = ucm_path.sl; - sa_path->mtu_selector = ucm_path.mtu_selector; - sa_path->mtu = ucm_path.mtu; - sa_path->rate_selector = ucm_path.rate_selector; - sa_path->rate = ucm_path.rate; - sa_path->packet_life_time = ucm_path.packet_life_time; - sa_path->preference = ucm_path.preference; - - sa_path->packet_life_time_selector = - ucm_path.packet_life_time_selector; - + ib_copy_path_rec_from_user(sa_path, &upath); *path = sa_path; return 0; } diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c new file mode 100644 index 000000000000..ce46b13ae02b --- /dev/null +++ b/drivers/infiniband/core/uverbs_marshall.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +static void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, + struct ib_ah_attr *src) +{ + memcpy(dst->grh.dgid, src->grh.dgid.raw, sizeof src->grh.dgid); + dst->grh.flow_label = src->grh.flow_label; + dst->grh.sgid_index = src->grh.sgid_index; + dst->grh.hop_limit = src->grh.hop_limit; + dst->grh.traffic_class = src->grh.traffic_class; + dst->dlid = src->dlid; + dst->sl = src->sl; + dst->src_path_bits = src->src_path_bits; + dst->static_rate = src->static_rate; + dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0; + dst->port_num = src->port_num; +} + +void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, + struct ib_qp_attr *src) +{ + dst->cur_qp_state = src->cur_qp_state; + dst->path_mtu = src->path_mtu; + dst->path_mig_state = src->path_mig_state; + dst->qkey = src->qkey; + dst->rq_psn = src->rq_psn; + dst->sq_psn = src->sq_psn; + dst->dest_qp_num = src->dest_qp_num; + dst->qp_access_flags = src->qp_access_flags; + + dst->max_send_wr = src->cap.max_send_wr; + dst->max_recv_wr = src->cap.max_recv_wr; + dst->max_send_sge = src->cap.max_send_sge; + dst->max_recv_sge = src->cap.max_recv_sge; + dst->max_inline_data = src->cap.max_inline_data; + + ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr); + ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr); + + dst->pkey_index = src->pkey_index; + dst->alt_pkey_index = src->alt_pkey_index; + dst->en_sqd_async_notify = src->en_sqd_async_notify; + dst->sq_draining = src->sq_draining; + dst->max_rd_atomic = src->max_rd_atomic; + dst->max_dest_rd_atomic = src->max_dest_rd_atomic; + dst->min_rnr_timer = src->min_rnr_timer; + dst->port_num = src->port_num; + dst->timeout = src->timeout; + dst->retry_cnt = src->retry_cnt; + dst->rnr_retry = src->rnr_retry; + dst->alt_port_num = src->alt_port_num; + dst->alt_timeout = src->alt_timeout; +} +EXPORT_SYMBOL(ib_copy_qp_attr_to_user); + +void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst, + struct ib_sa_path_rec *src) +{ + memcpy(dst->dgid, src->dgid.raw, sizeof src->dgid); + memcpy(dst->sgid, src->sgid.raw, sizeof src->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} +EXPORT_SYMBOL(ib_copy_path_rec_to_user); + +void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst, + struct ib_user_path_rec *src) +{ + memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid); + memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} +EXPORT_SYMBOL(ib_copy_path_rec_from_user); diff --git a/include/rdma/ib_marshall.h b/include/rdma/ib_marshall.h new file mode 100644 index 000000000000..66bf4d7d0dfb --- /dev/null +++ b/include/rdma/ib_marshall.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_USER_MARSHALL_H) +#define IB_USER_MARSHALL_H + +#include +#include +#include +#include + +void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, + struct ib_qp_attr *src); + +void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst, + struct ib_sa_path_rec *src); + +void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst, + struct ib_user_path_rec *src); + +#endif /* IB_USER_MARSHALL_H */ diff --git a/include/rdma/ib_user_cm.h b/include/rdma/ib_user_cm.h index 19be116047f6..a9e1b22d245c 100644 --- a/include/rdma/ib_user_cm.h +++ b/include/rdma/ib_user_cm.h @@ -30,13 +30,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: ib_user_cm.h 2576 2005-06-09 17:00:30Z libor $ + * $Id: ib_user_cm.h 4019 2005-11-11 00:33:09Z sean.hefty $ */ #ifndef IB_USER_CM_H #define IB_USER_CM_H -#include +#include #define IB_USER_CM_ABI_VERSION 4 @@ -110,58 +110,6 @@ struct ib_ucm_init_qp_attr { __u32 qp_state; }; -struct ib_ucm_ah_attr { - __u8 grh_dgid[16]; - __u32 grh_flow_label; - __u16 dlid; - __u16 reserved; - __u8 grh_sgid_index; - __u8 grh_hop_limit; - __u8 grh_traffic_class; - __u8 sl; - __u8 src_path_bits; - __u8 static_rate; - __u8 is_global; - __u8 port_num; -}; - -struct ib_ucm_init_qp_attr_resp { - __u32 qp_attr_mask; - __u32 qp_state; - __u32 cur_qp_state; - __u32 path_mtu; - __u32 path_mig_state; - __u32 qkey; - __u32 rq_psn; - __u32 sq_psn; - __u32 dest_qp_num; - __u32 qp_access_flags; - - struct ib_ucm_ah_attr ah_attr; - struct ib_ucm_ah_attr alt_ah_attr; - - /* ib_qp_cap */ - __u32 max_send_wr; - __u32 max_recv_wr; - __u32 max_send_sge; - __u32 max_recv_sge; - __u32 max_inline_data; - - __u16 pkey_index; - __u16 alt_pkey_index; - __u8 en_sqd_async_notify; - __u8 sq_draining; - __u8 max_rd_atomic; - __u8 max_dest_rd_atomic; - __u8 min_rnr_timer; - __u8 port_num; - __u8 timeout; - __u8 retry_cnt; - __u8 rnr_retry; - __u8 alt_port_num; - __u8 alt_timeout; -}; - struct ib_ucm_listen { __be64 service_id; __be64 service_mask; @@ -180,28 +128,6 @@ struct ib_ucm_private_data { __u8 reserved[3]; }; -struct ib_ucm_path_rec { - __u8 dgid[16]; - __u8 sgid[16]; - __be16 dlid; - __be16 slid; - __u32 raw_traffic; - __be32 flow_label; - __u32 reversible; - __u32 mtu; - __be16 pkey; - __u8 hop_limit; - __u8 traffic_class; - __u8 numb_path; - __u8 sl; - __u8 mtu_selector; - __u8 rate_selector; - __u8 rate; - __u8 packet_life_time_selector; - __u8 packet_life_time; - __u8 preference; -}; - struct ib_ucm_req { __u32 id; __u32 qpn; @@ -304,8 +230,8 @@ struct ib_ucm_event_get { }; struct ib_ucm_req_event_resp { - struct ib_ucm_path_rec primary_path; - struct ib_ucm_path_rec alternate_path; + struct ib_user_path_rec primary_path; + struct ib_user_path_rec alternate_path; __be64 remote_ca_guid; __u32 remote_qkey; __u32 remote_qpn; @@ -349,7 +275,7 @@ struct ib_ucm_mra_event_resp { }; struct ib_ucm_lap_event_resp { - struct ib_ucm_path_rec path; + struct ib_user_path_rec path; }; struct ib_ucm_apr_event_resp { diff --git a/include/rdma/ib_user_sa.h b/include/rdma/ib_user_sa.h new file mode 100644 index 000000000000..659120157e14 --- /dev/null +++ b/include/rdma/ib_user_sa.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_USER_SA_H +#define IB_USER_SA_H + +#include + +struct ib_user_path_rec { + __u8 dgid[16]; + __u8 sgid[16]; + __be16 dlid; + __be16 slid; + __u32 raw_traffic; + __be32 flow_label; + __u32 reversible; + __u32 mtu; + __be16 pkey; + __u8 hop_limit; + __u8 traffic_class; + __u8 numb_path; + __u8 sl; + __u8 mtu_selector; + __u8 rate_selector; + __u8 rate; + __u8 packet_life_time_selector; + __u8 packet_life_time; + __u8 preference; +}; + +#endif /* IB_USER_SA_H */ diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 338ed4333063..7b5372010f4b 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h @@ -32,7 +32,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: ib_user_verbs.h 2708 2005-06-24 17:27:21Z roland $ + * $Id: ib_user_verbs.h 4019 2005-11-11 00:33:09Z sean.hefty $ */ #ifndef IB_USER_VERBS_H @@ -323,6 +323,64 @@ struct ib_uverbs_destroy_cq_resp { __u32 async_events_reported; }; +struct ib_uverbs_global_route { + __u8 dgid[16]; + __u32 flow_label; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 reserved; +}; + +struct ib_uverbs_ah_attr { + struct ib_uverbs_global_route grh; + __u16 dlid; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; + __u8 reserved; +}; + +struct ib_uverbs_qp_attr { + __u32 qp_attr_mask; + __u32 qp_state; + __u32 cur_qp_state; + __u32 path_mtu; + __u32 path_mig_state; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + + struct ib_uverbs_ah_attr ah_attr; + struct ib_uverbs_ah_attr alt_ah_attr; + + /* ib_qp_cap */ + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 en_sqd_async_notify; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[5]; +}; + struct ib_uverbs_create_qp { __u64 response; __u64 user_handle; @@ -541,26 +599,6 @@ struct ib_uverbs_post_srq_recv_resp { __u32 bad_wr; }; -struct ib_uverbs_global_route { - __u8 dgid[16]; - __u32 flow_label; - __u8 sgid_index; - __u8 hop_limit; - __u8 traffic_class; - __u8 reserved; -}; - -struct ib_uverbs_ah_attr { - struct ib_uverbs_global_route grh; - __u16 dlid; - __u8 sl; - __u8 src_path_bits; - __u8 static_rate; - __u8 is_global; - __u8 port_num; - __u8 reserved; -}; - struct ib_uverbs_create_ah { __u64 response; __u64 user_handle; -- cgit v1.2.3 From 6e61d04f2d8c7ac4f67e1f498ed2a2a3ad8edaa3 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:28 -0700 Subject: IB/cm: Match connection requests based on private data Extend matching connection requests to listens in the InfiniBand CM to include private data checks. This allows applications to listen on the same service identifier, with private data directing the request to the appropriate application. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 91 +++++++++++++++++++++++++++++++++++++------ drivers/infiniband/core/ucm.c | 19 ++++++++- include/rdma/ib_cm.h | 23 ++++++++--- 3 files changed, 114 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 86fee43502cd..490fd03766db 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -32,7 +32,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ + * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $ */ #include @@ -132,6 +132,7 @@ struct cm_id_private { /* todo: use alternate port on send failure */ struct cm_av av; struct cm_av alt_av; + struct ib_cm_compare_data *compare_data; void *private_data; __be64 tid; @@ -357,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) return cm_id_priv; } +static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) +{ + int i; + + for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) + ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & + ((unsigned long *) mask)[i]; +} + +static int cm_compare_data(struct ib_cm_compare_data *src_data, + struct ib_cm_compare_data *dst_data) +{ + u8 src[IB_CM_COMPARE_SIZE]; + u8 dst[IB_CM_COMPARE_SIZE]; + + if (!src_data || !dst_data) + return 0; + + cm_mask_copy(src, src_data->data, dst_data->mask); + cm_mask_copy(dst, dst_data->data, src_data->mask); + return memcmp(src, dst, IB_CM_COMPARE_SIZE); +} + +static int cm_compare_private_data(u8 *private_data, + struct ib_cm_compare_data *dst_data) +{ + u8 src[IB_CM_COMPARE_SIZE]; + + if (!dst_data) + return 0; + + cm_mask_copy(src, private_data, dst_data->mask); + return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); +} + static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) { struct rb_node **link = &cm.listen_service_table.rb_node; @@ -364,14 +400,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) struct cm_id_private *cur_cm_id_priv; __be64 service_id = cm_id_priv->id.service_id; __be64 service_mask = cm_id_priv->id.service_mask; + int data_cmp; while (*link) { parent = *link; cur_cm_id_priv = rb_entry(parent, struct cm_id_private, service_node); + data_cmp = cm_compare_data(cm_id_priv->compare_data, + cur_cm_id_priv->compare_data); if ((cur_cm_id_priv->id.service_mask & service_id) == (service_mask & cur_cm_id_priv->id.service_id) && - (cm_id_priv->id.device == cur_cm_id_priv->id.device)) + (cm_id_priv->id.device == cur_cm_id_priv->id.device) && + !data_cmp) return cur_cm_id_priv; if (cm_id_priv->id.device < cur_cm_id_priv->id.device) @@ -380,6 +420,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) link = &(*link)->rb_right; else if (service_id < cur_cm_id_priv->id.service_id) link = &(*link)->rb_left; + else if (service_id > cur_cm_id_priv->id.service_id) + link = &(*link)->rb_right; + else if (data_cmp < 0) + link = &(*link)->rb_left; else link = &(*link)->rb_right; } @@ -389,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) } static struct cm_id_private * cm_find_listen(struct ib_device *device, - __be64 service_id) + __be64 service_id, + u8 *private_data) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; + int data_cmp; while (node) { cm_id_priv = rb_entry(node, struct cm_id_private, service_node); + data_cmp = cm_compare_private_data(private_data, + cm_id_priv->compare_data); if ((cm_id_priv->id.service_mask & service_id) == cm_id_priv->id.service_id && - (cm_id_priv->id.device == device)) + (cm_id_priv->id.device == device) && !data_cmp) return cm_id_priv; if (device < cm_id_priv->id.device) @@ -407,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device, node = node->rb_right; else if (service_id < cm_id_priv->id.service_id) node = node->rb_left; + else if (service_id > cm_id_priv->id.service_id) + node = node->rb_right; + else if (data_cmp < 0) + node = node->rb_left; else node = node->rb_right; } @@ -730,15 +782,14 @@ retest: wait_for_completion(&cm_id_priv->comp); while ((work = cm_dequeue_work(cm_id_priv)) != NULL) cm_free_work(work); - if (cm_id_priv->private_data && cm_id_priv->private_data_len) - kfree(cm_id_priv->private_data); + kfree(cm_id_priv->compare_data); + kfree(cm_id_priv->private_data); kfree(cm_id_priv); } EXPORT_SYMBOL(ib_destroy_cm_id); -int ib_cm_listen(struct ib_cm_id *cm_id, - __be64 service_id, - __be64 service_mask) +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, + struct ib_cm_compare_data *compare_data) { struct cm_id_private *cm_id_priv, *cur_cm_id_priv; unsigned long flags; @@ -752,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id, return -EINVAL; cm_id_priv = container_of(cm_id, struct cm_id_private, id); - BUG_ON(cm_id->state != IB_CM_IDLE); + if (cm_id->state != IB_CM_IDLE) + return -EINVAL; + + if (compare_data) { + cm_id_priv->compare_data = kzalloc(sizeof *compare_data, + GFP_KERNEL); + if (!cm_id_priv->compare_data) + return -ENOMEM; + cm_mask_copy(cm_id_priv->compare_data->data, + compare_data->data, compare_data->mask); + memcpy(cm_id_priv->compare_data->mask, compare_data->mask, + IB_CM_COMPARE_SIZE); + } cm_id->state = IB_CM_LISTEN; @@ -769,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id, if (cur_cm_id_priv) { cm_id->state = IB_CM_IDLE; + kfree(cm_id_priv->compare_data); + cm_id_priv->compare_data = NULL; ret = -EBUSY; } return ret; @@ -1241,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, /* Find matching listen request. */ listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, - req_msg->service_id); + req_msg->service_id, + req_msg->private_data); if (!listen_cm_id_priv) { spin_unlock_irqrestore(&cm.lock, flags); cm_issue_rej(work->port, work->mad_recv_wc, @@ -2654,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work) goto out; /* Duplicate message. */ } cur_cm_id_priv = cm_find_listen(cm_id->device, - sidr_req_msg->service_id); + sidr_req_msg->service_id, + sidr_req_msg->private_data); if (!cur_cm_id_priv) { rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); spin_unlock_irqrestore(&cm.lock, flags); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index b396bf703f80..0136aee0faa7 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -648,6 +648,17 @@ out: return result; } +static int ucm_validate_listen(__be64 service_id, __be64 service_mask) +{ + service_id &= service_mask; + + if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) || + ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID)) + return -EINVAL; + + return 0; +} + static ssize_t ib_ucm_listen(struct ib_ucm_file *file, const char __user *inbuf, int in_len, int out_len) @@ -663,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file, if (IS_ERR(ctx)) return PTR_ERR(ctx); - result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); + result = ucm_validate_listen(cmd.service_id, cmd.service_mask); + if (result) + goto out; + + result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask, + NULL); +out: ib_ucm_ctx_put(ctx); return result; } diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 0a9fcd59eb43..8f394f035684 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -32,7 +32,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: ib_cm.h 2730 2005-06-28 16:43:03Z sean.hefty $ + * $Id: ib_cm.h 4311 2005-12-05 18:42:01Z sean.hefty $ */ #if !defined(IB_CM_H) #define IB_CM_H @@ -102,7 +102,8 @@ enum ib_cm_data_size { IB_CM_APR_INFO_LENGTH = 72, IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, - IB_CM_SIDR_REP_INFO_LENGTH = 72 + IB_CM_SIDR_REP_INFO_LENGTH = 72, + IB_CM_COMPARE_SIZE = 64 }; struct ib_cm_id; @@ -238,7 +239,6 @@ struct ib_cm_sidr_rep_event_param { u32 qpn; void *info; u8 info_len; - }; struct ib_cm_event { @@ -317,6 +317,15 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); #define IB_SERVICE_ID_AGN_MASK __constant_cpu_to_be64(0xFF00000000000000ULL) #define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL) +#define IB_CMA_SERVICE_ID __constant_cpu_to_be64(0x0000000001000000ULL) +#define IB_CMA_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFF000000ULL) +#define IB_SDP_SERVICE_ID __constant_cpu_to_be64(0x0000000000010000ULL) +#define IB_SDP_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFFFF0000ULL) + +struct ib_cm_compare_data { + u8 data[IB_CM_COMPARE_SIZE]; + u8 mask[IB_CM_COMPARE_SIZE]; +}; /** * ib_cm_listen - Initiates listening on the specified service ID for @@ -330,10 +339,12 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); * range of service IDs. If set to 0, the service ID is matched * exactly. This parameter is ignored if %service_id is set to * IB_CM_ASSIGN_SERVICE_ID. + * @compare_data: This parameter is optional. It specifies data that must + * appear in the private data of a connection request for the specified + * listen request. */ -int ib_cm_listen(struct ib_cm_id *cm_id, - __be64 service_id, - __be64 service_mask); +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, + struct ib_cm_compare_data *compare_data); struct ib_cm_req_param { struct ib_sa_path_rec *primary_path; -- cgit v1.2.3 From 7025fcd36bd62af2c6ca0ea3490c00b216c4d168 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:28 -0700 Subject: IB: address translation to map IP toIB addresses (GIDs) Add an address translation service that maps IP addresses to InfiniBand GID addresses using IPoIB. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/Kconfig | 5 + drivers/infiniband/core/Makefile | 6 +- drivers/infiniband/core/addr.c | 367 +++++++++++++++++++++++++++++++++++++++ include/rdma/ib_addr.h | 114 ++++++++++++ 4 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/core/addr.c create mode 100644 include/rdma/ib_addr.h (limited to 'include') diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index afc612b8577d..ba2d6505e9a4 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -29,6 +29,11 @@ config INFINIBAND_USER_ACCESS libibverbs, libibcm and a hardware driver library from . +config INFINIBAND_ADDR_TRANS + bool + depends on INFINIBAND && INET + default y + source "drivers/infiniband/hw/mthca/Kconfig" source "drivers/infiniband/hw/ipath/Kconfig" diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index a56bf9c994f6..05095919d168 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -1,5 +1,7 @@ +addr_trans-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o + obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ - ib_cm.o + ib_cm.o $(addr_trans-y) obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o @@ -12,6 +14,8 @@ ib_sa-y := sa_query.o ib_cm-y := cm.o +ib_addr-y := addr.o + ib_umad-y := user_mad.o ib_ucm-y := ucm.o diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c new file mode 100644 index 000000000000..d294bbc42f09 --- /dev/null +++ b/drivers/infiniband/core/addr.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("IB Address Translation"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct addr_req { + struct list_head list; + struct sockaddr src_addr; + struct sockaddr dst_addr; + struct rdma_dev_addr *addr; + void *context; + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context); + unsigned long timeout; + int status; +}; + +static void process_req(void *data); + +static DEFINE_MUTEX(lock); +static LIST_HEAD(req_list); +static DECLARE_WORK(work, process_req, NULL); +static struct workqueue_struct *addr_wq; + +static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, + unsigned char *dst_dev_addr) +{ + switch (dev->type) { + case ARPHRD_INFINIBAND: + dev_addr->dev_type = IB_NODE_CA; + break; + default: + return -EADDRNOTAVAIL; + } + + memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); + if (dst_dev_addr) + memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); + return 0; +} + +int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) +{ + struct net_device *dev; + u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + int ret; + + dev = ip_dev_find(ip); + if (!dev) + return -EADDRNOTAVAIL; + + ret = copy_addr(dev_addr, dev, NULL); + dev_put(dev); + return ret; +} +EXPORT_SYMBOL(rdma_translate_ip); + +static void set_timeout(unsigned long time) +{ + unsigned long delay; + + cancel_delayed_work(&work); + + delay = time - jiffies; + if ((long)delay <= 0) + delay = 1; + + queue_delayed_work(addr_wq, &work, delay); +} + +static void queue_req(struct addr_req *req) +{ + struct addr_req *temp_req; + + mutex_lock(&lock); + list_for_each_entry_reverse(temp_req, &req_list, list) { + if (time_after(req->timeout, temp_req->timeout)) + break; + } + + list_add(&req->list, &temp_req->list); + + if (req_list.next == &req->list) + set_timeout(req->timeout); + mutex_unlock(&lock); +} + +static void addr_send_arp(struct sockaddr_in *dst_in) +{ + struct rtable *rt; + struct flowi fl; + u32 dst_ip = dst_in->sin_addr.s_addr; + + memset(&fl, 0, sizeof fl); + fl.nl_u.ip4_u.daddr = dst_ip; + if (ip_route_output_key(&rt, &fl)) + return; + + arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev, + rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL); + ip_rt_put(rt); +} + +static int addr_resolve_remote(struct sockaddr_in *src_in, + struct sockaddr_in *dst_in, + struct rdma_dev_addr *addr) +{ + u32 src_ip = src_in->sin_addr.s_addr; + u32 dst_ip = dst_in->sin_addr.s_addr; + struct flowi fl; + struct rtable *rt; + struct neighbour *neigh; + int ret; + + memset(&fl, 0, sizeof fl); + fl.nl_u.ip4_u.daddr = dst_ip; + fl.nl_u.ip4_u.saddr = src_ip; + ret = ip_route_output_key(&rt, &fl); + if (ret) + goto out; + + /* If the device does ARP internally, return 'done' */ + if (rt->idev->dev->flags & IFF_NOARP) { + copy_addr(addr, rt->idev->dev, NULL); + goto put; + } + + neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); + if (!neigh) { + ret = -ENODATA; + goto put; + } + + if (!(neigh->nud_state & NUD_VALID)) { + ret = -ENODATA; + goto release; + } + + if (!src_ip) { + src_in->sin_family = dst_in->sin_family; + src_in->sin_addr.s_addr = rt->rt_src; + } + + ret = copy_addr(addr, neigh->dev, neigh->ha); +release: + neigh_release(neigh); +put: + ip_rt_put(rt); +out: + return ret; +} + +static void process_req(void *data) +{ + struct addr_req *req, *temp_req; + struct sockaddr_in *src_in, *dst_in; + struct list_head done_list; + + INIT_LIST_HEAD(&done_list); + + mutex_lock(&lock); + list_for_each_entry_safe(req, temp_req, &req_list, list) { + if (req->status) { + src_in = (struct sockaddr_in *) &req->src_addr; + dst_in = (struct sockaddr_in *) &req->dst_addr; + req->status = addr_resolve_remote(src_in, dst_in, + req->addr); + } + if (req->status && time_after(jiffies, req->timeout)) + req->status = -ETIMEDOUT; + else if (req->status == -ENODATA) + continue; + + list_del(&req->list); + list_add_tail(&req->list, &done_list); + } + + if (!list_empty(&req_list)) { + req = list_entry(req_list.next, struct addr_req, list); + set_timeout(req->timeout); + } + mutex_unlock(&lock); + + list_for_each_entry_safe(req, temp_req, &done_list, list) { + list_del(&req->list); + req->callback(req->status, &req->src_addr, req->addr, + req->context); + kfree(req); + } +} + +static int addr_resolve_local(struct sockaddr_in *src_in, + struct sockaddr_in *dst_in, + struct rdma_dev_addr *addr) +{ + struct net_device *dev; + u32 src_ip = src_in->sin_addr.s_addr; + u32 dst_ip = dst_in->sin_addr.s_addr; + int ret; + + dev = ip_dev_find(dst_ip); + if (!dev) + return -EADDRNOTAVAIL; + + if (ZERONET(src_ip)) { + src_in->sin_family = dst_in->sin_family; + src_in->sin_addr.s_addr = dst_ip; + ret = copy_addr(addr, dev, dev->dev_addr); + } else if (LOOPBACK(src_ip)) { + ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } else { + ret = rdma_translate_ip((struct sockaddr *)src_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } + + dev_put(dev); + return ret; +} + +int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, + struct rdma_dev_addr *addr, int timeout_ms, + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context), + void *context) +{ + struct sockaddr_in *src_in, *dst_in; + struct addr_req *req; + int ret = 0; + + req = kmalloc(sizeof *req, GFP_KERNEL); + if (!req) + return -ENOMEM; + memset(req, 0, sizeof *req); + + if (src_addr) + memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); + memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr)); + req->addr = addr; + req->callback = callback; + req->context = context; + + src_in = (struct sockaddr_in *) &req->src_addr; + dst_in = (struct sockaddr_in *) &req->dst_addr; + + req->status = addr_resolve_local(src_in, dst_in, addr); + if (req->status == -EADDRNOTAVAIL) + req->status = addr_resolve_remote(src_in, dst_in, addr); + + switch (req->status) { + case 0: + req->timeout = jiffies; + queue_req(req); + break; + case -ENODATA: + req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; + queue_req(req); + addr_send_arp(dst_in); + break; + default: + ret = req->status; + kfree(req); + break; + } + return ret; +} +EXPORT_SYMBOL(rdma_resolve_ip); + +void rdma_addr_cancel(struct rdma_dev_addr *addr) +{ + struct addr_req *req, *temp_req; + + mutex_lock(&lock); + list_for_each_entry_safe(req, temp_req, &req_list, list) { + if (req->addr == addr) { + req->status = -ECANCELED; + req->timeout = jiffies; + list_del(&req->list); + list_add(&req->list, &req_list); + set_timeout(req->timeout); + break; + } + } + mutex_unlock(&lock); +} +EXPORT_SYMBOL(rdma_addr_cancel); + +static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pkt, struct net_device *orig_dev) +{ + struct arphdr *arp_hdr; + + arp_hdr = (struct arphdr *) skb->nh.raw; + + if (arp_hdr->ar_op == htons(ARPOP_REQUEST) || + arp_hdr->ar_op == htons(ARPOP_REPLY)) + set_timeout(jiffies); + + kfree_skb(skb); + return 0; +} + +static struct packet_type addr_arp = { + .type = __constant_htons(ETH_P_ARP), + .func = addr_arp_recv, + .af_packet_priv = (void*) 1, +}; + +static int addr_init(void) +{ + addr_wq = create_singlethread_workqueue("ib_addr_wq"); + if (!addr_wq) + return -ENOMEM; + + dev_add_pack(&addr_arp); + return 0; +} + +static void addr_cleanup(void) +{ + dev_remove_pack(&addr_arp); + destroy_workqueue(addr_wq); +} + +module_init(addr_init); +module_exit(addr_cleanup); diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h new file mode 100644 index 000000000000..fcb5ba87dcc5 --- /dev/null +++ b/include/rdma/ib_addr.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + * + */ + +#if !defined(IB_ADDR_H) +#define IB_ADDR_H + +#include +#include +#include +#include +#include + +struct rdma_dev_addr { + unsigned char src_dev_addr[MAX_ADDR_LEN]; + unsigned char dst_dev_addr[MAX_ADDR_LEN]; + unsigned char broadcast[MAX_ADDR_LEN]; + enum ib_node_type dev_type; +}; + +/** + * rdma_translate_ip - Translate a local IP address to an RDMA hardware + * address. + */ +int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr); + +/** + * rdma_resolve_ip - Resolve source and destination IP addresses to + * RDMA hardware addresses. + * @src_addr: An optional source address to use in the resolution. If a + * source address is not provided, a usable address will be returned via + * the callback. + * @dst_addr: The destination address to resolve. + * @addr: A reference to a data location that will receive the resolved + * addresses. The data location must remain valid until the callback has + * been invoked. + * @timeout_ms: Amount of time to wait for the address resolution to complete. + * @callback: Call invoked once address resolution has completed, timed out, + * or been canceled. A status of 0 indicates success. + * @context: User-specified context associated with the call. + */ +int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, + struct rdma_dev_addr *addr, int timeout_ms, + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context), + void *context); + +void rdma_addr_cancel(struct rdma_dev_addr *addr); + +static inline int ip_addr_size(struct sockaddr *addr) +{ + return addr->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); +} + +static inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) +{ + return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; +} + +static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) +{ + dev_addr->broadcast[8] = pkey >> 8; + dev_addr->broadcast[9] = (unsigned char) pkey; +} + +static inline union ib_gid *ib_addr_get_sgid(struct rdma_dev_addr *dev_addr) +{ + return (union ib_gid *) (dev_addr->src_dev_addr + 4); +} + +static inline void ib_addr_set_sgid(struct rdma_dev_addr *dev_addr, + union ib_gid *gid) +{ + memcpy(dev_addr->src_dev_addr + 4, gid, sizeof *gid); +} + +static inline union ib_gid *ib_addr_get_dgid(struct rdma_dev_addr *dev_addr) +{ + return (union ib_gid *) (dev_addr->dst_dev_addr + 4); +} + +static inline void ib_addr_set_dgid(struct rdma_dev_addr *dev_addr, + union ib_gid *gid) +{ + memcpy(dev_addr->dst_dev_addr + 4, gid, sizeof *gid); +} + +#endif /* IB_ADDR_H */ -- cgit v1.2.3 From e51060f08a61965c4dd91516d82fe90617152590 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:29 -0700 Subject: IB: IP address based RDMA connection manager Kernel connection management agent over InfiniBand that connects based on IP addresses. The agent defines a generic RDMA connection abstraction to support clients wanting to connect over different RDMA devices. The agent also handles RDMA device hotplug events on behalf of clients. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/Makefile | 6 +- drivers/infiniband/core/cma.c | 1927 ++++++++++++++++++++++++++++++++++++++ include/rdma/rdma_cm.h | 256 +++++ include/rdma/rdma_cm_ib.h | 47 + 4 files changed, 2234 insertions(+), 2 deletions(-) create mode 100644 drivers/infiniband/core/cma.c create mode 100644 include/rdma/rdma_cm.h create mode 100644 include/rdma/rdma_cm_ib.h (limited to 'include') diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 05095919d168..68e73ec2d1f8 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -1,7 +1,7 @@ -addr_trans-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o +infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ - ib_cm.o $(addr_trans-y) + ib_cm.o $(infiniband-y) obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o @@ -14,6 +14,8 @@ ib_sa-y := sa_query.o ib_cm-y := cm.o +rdma_cm-y := cma.o + ib_addr-y := addr.o ib_umad-y := user_mad.o diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c new file mode 100644 index 000000000000..a76834edf608 --- /dev/null +++ b/drivers/infiniband/core/cma.c @@ -0,0 +1,1927 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("Generic RDMA CM Agent"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define CMA_CM_RESPONSE_TIMEOUT 20 +#define CMA_MAX_CM_RETRIES 3 + +static void cma_add_one(struct ib_device *device); +static void cma_remove_one(struct ib_device *device); + +static struct ib_client cma_client = { + .name = "cma", + .add = cma_add_one, + .remove = cma_remove_one +}; + +static LIST_HEAD(dev_list); +static LIST_HEAD(listen_any_list); +static DEFINE_MUTEX(lock); +static struct workqueue_struct *cma_wq; +static DEFINE_IDR(sdp_ps); +static DEFINE_IDR(tcp_ps); + +struct cma_device { + struct list_head list; + struct ib_device *device; + __be64 node_guid; + struct completion comp; + atomic_t refcount; + struct list_head id_list; +}; + +enum cma_state { + CMA_IDLE, + CMA_ADDR_QUERY, + CMA_ADDR_RESOLVED, + CMA_ROUTE_QUERY, + CMA_ROUTE_RESOLVED, + CMA_CONNECT, + CMA_DISCONNECT, + CMA_ADDR_BOUND, + CMA_LISTEN, + CMA_DEVICE_REMOVAL, + CMA_DESTROYING +}; + +struct rdma_bind_list { + struct idr *ps; + struct hlist_head owners; + unsigned short port; +}; + +/* + * Device removal can occur at anytime, so we need extra handling to + * serialize notifying the user of device removal with other callbacks. + * We do this by disabling removal notification while a callback is in process, + * and reporting it after the callback completes. + */ +struct rdma_id_private { + struct rdma_cm_id id; + + struct rdma_bind_list *bind_list; + struct hlist_node node; + struct list_head list; + struct list_head listen_list; + struct cma_device *cma_dev; + + enum cma_state state; + spinlock_t lock; + struct completion comp; + atomic_t refcount; + wait_queue_head_t wait_remove; + atomic_t dev_remove; + + int backlog; + int timeout_ms; + struct ib_sa_query *query; + int query_id; + union { + struct ib_cm_id *ib; + } cm_id; + + u32 seq_num; + u32 qp_num; + enum ib_qp_type qp_type; + u8 srq; +}; + +struct cma_work { + struct work_struct work; + struct rdma_id_private *id; + enum cma_state old_state; + enum cma_state new_state; + struct rdma_cm_event event; +}; + +union cma_ip_addr { + struct in6_addr ip6; + struct { + __u32 pad[3]; + __u32 addr; + } ip4; +}; + +struct cma_hdr { + u8 cma_version; + u8 ip_version; /* IP version: 7:4 */ + __u16 port; + union cma_ip_addr src_addr; + union cma_ip_addr dst_addr; +}; + +struct sdp_hh { + u8 bsdh[16]; + u8 sdp_version; /* Major version: 7:4 */ + u8 ip_version; /* IP version: 7:4 */ + u8 sdp_specific1[10]; + __u16 port; + __u16 sdp_specific2; + union cma_ip_addr src_addr; + union cma_ip_addr dst_addr; +}; + +struct sdp_hah { + u8 bsdh[16]; + u8 sdp_version; +}; + +#define CMA_VERSION 0x00 +#define SDP_MAJ_VERSION 0x2 + +static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&id_priv->lock, flags); + ret = (id_priv->state == comp); + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} + +static int cma_comp_exch(struct rdma_id_private *id_priv, + enum cma_state comp, enum cma_state exch) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&id_priv->lock, flags); + if ((ret = (id_priv->state == comp))) + id_priv->state = exch; + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} + +static enum cma_state cma_exch(struct rdma_id_private *id_priv, + enum cma_state exch) +{ + unsigned long flags; + enum cma_state old; + + spin_lock_irqsave(&id_priv->lock, flags); + old = id_priv->state; + id_priv->state = exch; + spin_unlock_irqrestore(&id_priv->lock, flags); + return old; +} + +static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) +{ + return hdr->ip_version >> 4; +} + +static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) +{ + hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); +} + +static inline u8 sdp_get_majv(u8 sdp_version) +{ + return sdp_version >> 4; +} + +static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) +{ + return hh->ip_version >> 4; +} + +static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) +{ + hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); +} + +static void cma_attach_to_dev(struct rdma_id_private *id_priv, + struct cma_device *cma_dev) +{ + atomic_inc(&cma_dev->refcount); + id_priv->cma_dev = cma_dev; + id_priv->id.device = cma_dev->device; + list_add_tail(&id_priv->list, &cma_dev->id_list); +} + +static inline void cma_deref_dev(struct cma_device *cma_dev) +{ + if (atomic_dec_and_test(&cma_dev->refcount)) + complete(&cma_dev->comp); +} + +static void cma_detach_from_dev(struct rdma_id_private *id_priv) +{ + list_del(&id_priv->list); + cma_deref_dev(id_priv->cma_dev); + id_priv->cma_dev = NULL; +} + +static int cma_acquire_ib_dev(struct rdma_id_private *id_priv) +{ + struct cma_device *cma_dev; + union ib_gid *gid; + int ret = -ENODEV; + + gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) { + ret = ib_find_cached_gid(cma_dev->device, gid, + &id_priv->id.port_num, NULL); + if (!ret) { + cma_attach_to_dev(id_priv, cma_dev); + break; + } + } + mutex_unlock(&lock); + return ret; +} + +static int cma_acquire_dev(struct rdma_id_private *id_priv) +{ + switch (id_priv->id.route.addr.dev_addr.dev_type) { + case IB_NODE_CA: + return cma_acquire_ib_dev(id_priv); + default: + return -ENODEV; + } +} + +static void cma_deref_id(struct rdma_id_private *id_priv) +{ + if (atomic_dec_and_test(&id_priv->refcount)) + complete(&id_priv->comp); +} + +static void cma_release_remove(struct rdma_id_private *id_priv) +{ + if (atomic_dec_and_test(&id_priv->dev_remove)) + wake_up(&id_priv->wait_remove); +} + +struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, + void *context, enum rdma_port_space ps) +{ + struct rdma_id_private *id_priv; + + id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); + if (!id_priv) + return ERR_PTR(-ENOMEM); + + id_priv->state = CMA_IDLE; + id_priv->id.context = context; + id_priv->id.event_handler = event_handler; + id_priv->id.ps = ps; + spin_lock_init(&id_priv->lock); + init_completion(&id_priv->comp); + atomic_set(&id_priv->refcount, 1); + init_waitqueue_head(&id_priv->wait_remove); + atomic_set(&id_priv->dev_remove, 0); + INIT_LIST_HEAD(&id_priv->listen_list); + get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); + + return &id_priv->id; +} +EXPORT_SYMBOL(rdma_create_id); + +static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + struct rdma_dev_addr *dev_addr; + int ret; + + dev_addr = &id_priv->id.route.addr.dev_addr; + ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, + ib_addr_get_pkey(dev_addr), + &qp_attr.pkey_index); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_INIT; + qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; + qp_attr.port_num = id_priv->id.port_num; + return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | IB_QP_PORT); +} + +int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr) +{ + struct rdma_id_private *id_priv; + struct ib_qp *qp; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id->device != pd->device) + return -EINVAL; + + qp = ib_create_qp(pd, qp_init_attr); + if (IS_ERR(qp)) + return PTR_ERR(qp); + + switch (id->device->node_type) { + case IB_NODE_CA: + ret = cma_init_ib_qp(id_priv, qp); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) + goto err; + + id->qp = qp; + id_priv->qp_num = qp->qp_num; + id_priv->qp_type = qp->qp_type; + id_priv->srq = (qp->srq != NULL); + return 0; +err: + ib_destroy_qp(qp); + return ret; +} +EXPORT_SYMBOL(rdma_create_qp); + +void rdma_destroy_qp(struct rdma_cm_id *id) +{ + ib_destroy_qp(id->qp); +} +EXPORT_SYMBOL(rdma_destroy_qp); + +static int cma_modify_qp_rtr(struct rdma_cm_id *id) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + if (!id->qp) + return 0; + + /* Need to update QP attributes from default values. */ + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTR; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); +} + +static int cma_modify_qp_rts(struct rdma_cm_id *id) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + if (!id->qp) + return 0; + + qp_attr.qp_state = IB_QPS_RTS; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); +} + +static int cma_modify_qp_err(struct rdma_cm_id *id) +{ + struct ib_qp_attr qp_attr; + + if (!id->qp) + return 0; + + qp_attr.qp_state = IB_QPS_ERR; + return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE); +} + +int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + switch (id_priv->id.device->node_type) { + case IB_NODE_CA: + ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, + qp_attr_mask); + if (qp_attr->qp_state == IB_QPS_RTR) + qp_attr->rq_psn = id_priv->seq_num; + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} +EXPORT_SYMBOL(rdma_init_qp_attr); + +static inline int cma_zero_addr(struct sockaddr *addr) +{ + struct in6_addr *ip6; + + if (addr->sa_family == AF_INET) + return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr); + else { + ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; + return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | + ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0; + } +} + +static inline int cma_loopback_addr(struct sockaddr *addr) +{ + return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr); +} + +static inline int cma_any_addr(struct sockaddr *addr) +{ + return cma_zero_addr(addr) || cma_loopback_addr(addr); +} + +static inline int cma_any_port(struct sockaddr *addr) +{ + return !((struct sockaddr_in *) addr)->sin_port; +} + +static int cma_get_net_info(void *hdr, enum rdma_port_space ps, + u8 *ip_ver, __u16 *port, + union cma_ip_addr **src, union cma_ip_addr **dst) +{ + switch (ps) { + case RDMA_PS_SDP: + if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != + SDP_MAJ_VERSION) + return -EINVAL; + + *ip_ver = sdp_get_ip_ver(hdr); + *port = ((struct sdp_hh *) hdr)->port; + *src = &((struct sdp_hh *) hdr)->src_addr; + *dst = &((struct sdp_hh *) hdr)->dst_addr; + break; + default: + if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) + return -EINVAL; + + *ip_ver = cma_get_ip_ver(hdr); + *port = ((struct cma_hdr *) hdr)->port; + *src = &((struct cma_hdr *) hdr)->src_addr; + *dst = &((struct cma_hdr *) hdr)->dst_addr; + break; + } + + if (*ip_ver != 4 && *ip_ver != 6) + return -EINVAL; + return 0; +} + +static void cma_save_net_info(struct rdma_addr *addr, + struct rdma_addr *listen_addr, + u8 ip_ver, __u16 port, + union cma_ip_addr *src, union cma_ip_addr *dst) +{ + struct sockaddr_in *listen4, *ip4; + struct sockaddr_in6 *listen6, *ip6; + + switch (ip_ver) { + case 4: + listen4 = (struct sockaddr_in *) &listen_addr->src_addr; + ip4 = (struct sockaddr_in *) &addr->src_addr; + ip4->sin_family = listen4->sin_family; + ip4->sin_addr.s_addr = dst->ip4.addr; + ip4->sin_port = listen4->sin_port; + + ip4 = (struct sockaddr_in *) &addr->dst_addr; + ip4->sin_family = listen4->sin_family; + ip4->sin_addr.s_addr = src->ip4.addr; + ip4->sin_port = port; + break; + case 6: + listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; + ip6 = (struct sockaddr_in6 *) &addr->src_addr; + ip6->sin6_family = listen6->sin6_family; + ip6->sin6_addr = dst->ip6; + ip6->sin6_port = listen6->sin6_port; + + ip6 = (struct sockaddr_in6 *) &addr->dst_addr; + ip6->sin6_family = listen6->sin6_family; + ip6->sin6_addr = src->ip6; + ip6->sin6_port = port; + break; + default: + break; + } +} + +static inline int cma_user_data_offset(enum rdma_port_space ps) +{ + switch (ps) { + case RDMA_PS_SDP: + return 0; + default: + return sizeof(struct cma_hdr); + } +} + +static int cma_notify_user(struct rdma_id_private *id_priv, + enum rdma_cm_event_type type, int status, + void *data, u8 data_len) +{ + struct rdma_cm_event event; + + event.event = type; + event.status = status; + event.private_data = data; + event.private_data_len = data_len; + + return id_priv->id.event_handler(&id_priv->id, &event); +} + +static void cma_cancel_route(struct rdma_id_private *id_priv) +{ + switch (id_priv->id.device->node_type) { + case IB_NODE_CA: + if (id_priv->query) + ib_sa_cancel_query(id_priv->query_id, id_priv->query); + break; + default: + break; + } +} + +static inline int cma_internal_listen(struct rdma_id_private *id_priv) +{ + return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev && + cma_any_addr(&id_priv->id.route.addr.src_addr); +} + +static void cma_destroy_listen(struct rdma_id_private *id_priv) +{ + cma_exch(id_priv, CMA_DESTROYING); + + if (id_priv->cma_dev) { + switch (id_priv->id.device->node_type) { + case IB_NODE_CA: + if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) + ib_destroy_cm_id(id_priv->cm_id.ib); + break; + default: + break; + } + cma_detach_from_dev(id_priv); + } + list_del(&id_priv->listen_list); + + cma_deref_id(id_priv); + wait_for_completion(&id_priv->comp); + + kfree(id_priv); +} + +static void cma_cancel_listens(struct rdma_id_private *id_priv) +{ + struct rdma_id_private *dev_id_priv; + + mutex_lock(&lock); + list_del(&id_priv->list); + + while (!list_empty(&id_priv->listen_list)) { + dev_id_priv = list_entry(id_priv->listen_list.next, + struct rdma_id_private, listen_list); + cma_destroy_listen(dev_id_priv); + } + mutex_unlock(&lock); +} + +static void cma_cancel_operation(struct rdma_id_private *id_priv, + enum cma_state state) +{ + switch (state) { + case CMA_ADDR_QUERY: + rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); + break; + case CMA_ROUTE_QUERY: + cma_cancel_route(id_priv); + break; + case CMA_LISTEN: + if (cma_any_addr(&id_priv->id.route.addr.src_addr) && + !id_priv->cma_dev) + cma_cancel_listens(id_priv); + break; + default: + break; + } +} + +static void cma_release_port(struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list = id_priv->bind_list; + + if (!bind_list) + return; + + mutex_lock(&lock); + hlist_del(&id_priv->node); + if (hlist_empty(&bind_list->owners)) { + idr_remove(bind_list->ps, bind_list->port); + kfree(bind_list); + } + mutex_unlock(&lock); +} + +void rdma_destroy_id(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv; + enum cma_state state; + + id_priv = container_of(id, struct rdma_id_private, id); + state = cma_exch(id_priv, CMA_DESTROYING); + cma_cancel_operation(id_priv, state); + + if (id_priv->cma_dev) { + switch (id->device->node_type) { + case IB_NODE_CA: + if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) + ib_destroy_cm_id(id_priv->cm_id.ib); + break; + default: + break; + } + mutex_lock(&lock); + cma_detach_from_dev(id_priv); + mutex_unlock(&lock); + } + + cma_release_port(id_priv); + cma_deref_id(id_priv); + wait_for_completion(&id_priv->comp); + + kfree(id_priv->id.route.path_rec); + kfree(id_priv); +} +EXPORT_SYMBOL(rdma_destroy_id); + +static int cma_rep_recv(struct rdma_id_private *id_priv) +{ + int ret; + + ret = cma_modify_qp_rtr(&id_priv->id); + if (ret) + goto reject; + + ret = cma_modify_qp_rts(&id_priv->id); + if (ret) + goto reject; + + ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); + if (ret) + goto reject; + + return 0; +reject: + cma_modify_qp_err(&id_priv->id); + ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + return ret; +} + +static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) +{ + if (id_priv->id.ps == RDMA_PS_SDP && + sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != + SDP_MAJ_VERSION) + return -EINVAL; + + return 0; +} + +static int cma_rtu_recv(struct rdma_id_private *id_priv) +{ + int ret; + + ret = cma_modify_qp_rts(&id_priv->id); + if (ret) + goto reject; + + return 0; +reject: + cma_modify_qp_err(&id_priv->id); + ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + return ret; +} + +static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv = cm_id->context; + enum rdma_cm_event_type event; + u8 private_data_len = 0; + int ret = 0, status = 0; + + atomic_inc(&id_priv->dev_remove); + if (!cma_comp(id_priv, CMA_CONNECT)) + goto out; + + switch (ib_event->event) { + case IB_CM_REQ_ERROR: + case IB_CM_REP_ERROR: + event = RDMA_CM_EVENT_UNREACHABLE; + status = -ETIMEDOUT; + break; + case IB_CM_REP_RECEIVED: + status = cma_verify_rep(id_priv, ib_event->private_data); + if (status) + event = RDMA_CM_EVENT_CONNECT_ERROR; + else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { + status = cma_rep_recv(id_priv); + event = status ? RDMA_CM_EVENT_CONNECT_ERROR : + RDMA_CM_EVENT_ESTABLISHED; + } else + event = RDMA_CM_EVENT_CONNECT_RESPONSE; + private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; + break; + case IB_CM_RTU_RECEIVED: + status = cma_rtu_recv(id_priv); + event = status ? RDMA_CM_EVENT_CONNECT_ERROR : + RDMA_CM_EVENT_ESTABLISHED; + break; + case IB_CM_DREQ_ERROR: + status = -ETIMEDOUT; /* fall through */ + case IB_CM_DREQ_RECEIVED: + case IB_CM_DREP_RECEIVED: + if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) + goto out; + event = RDMA_CM_EVENT_DISCONNECTED; + break; + case IB_CM_TIMEWAIT_EXIT: + case IB_CM_MRA_RECEIVED: + /* ignore event */ + goto out; + case IB_CM_REJ_RECEIVED: + cma_modify_qp_err(&id_priv->id); + status = ib_event->param.rej_rcvd.reason; + event = RDMA_CM_EVENT_REJECTED; + break; + default: + printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d", + ib_event->event); + goto out; + } + + ret = cma_notify_user(id_priv, event, status, ib_event->private_data, + private_data_len); + if (ret) { + /* Destroy the CM ID by returning a non-zero value. */ + id_priv->cm_id.ib = NULL; + cma_exch(id_priv, CMA_DESTROYING); + cma_release_remove(id_priv); + rdma_destroy_id(&id_priv->id); + return ret; + } +out: + cma_release_remove(id_priv); + return ret; +} + +static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id, + struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv; + struct rdma_cm_id *id; + struct rdma_route *rt; + union cma_ip_addr *src, *dst; + __u16 port; + u8 ip_ver; + + id = rdma_create_id(listen_id->event_handler, listen_id->context, + listen_id->ps); + if (IS_ERR(id)) + return NULL; + + rt = &id->route; + rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; + rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL); + if (!rt->path_rec) + goto err; + + if (cma_get_net_info(ib_event->private_data, listen_id->ps, + &ip_ver, &port, &src, &dst)) + goto err; + + cma_save_net_info(&id->route.addr, &listen_id->route.addr, + ip_ver, port, src, dst); + rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; + if (rt->num_paths == 2) + rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; + + ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); + ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); + ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); + rt->addr.dev_addr.dev_type = IB_NODE_CA; + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->state = CMA_CONNECT; + return id_priv; +err: + rdma_destroy_id(id); + return NULL; +} + +static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) +{ + struct rdma_id_private *listen_id, *conn_id; + int offset, ret; + + listen_id = cm_id->context; + atomic_inc(&listen_id->dev_remove); + if (!cma_comp(listen_id, CMA_LISTEN)) { + ret = -ECONNABORTED; + goto out; + } + + conn_id = cma_new_id(&listen_id->id, ib_event); + if (!conn_id) { + ret = -ENOMEM; + goto out; + } + + atomic_inc(&conn_id->dev_remove); + ret = cma_acquire_ib_dev(conn_id); + if (ret) { + ret = -ENODEV; + cma_release_remove(conn_id); + rdma_destroy_id(&conn_id->id); + goto out; + } + + conn_id->cm_id.ib = cm_id; + cm_id->context = conn_id; + cm_id->cm_handler = cma_ib_handler; + + offset = cma_user_data_offset(listen_id->id.ps); + ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0, + ib_event->private_data + offset, + IB_CM_REQ_PRIVATE_DATA_SIZE - offset); + if (ret) { + /* Destroy the CM ID by returning a non-zero value. */ + conn_id->cm_id.ib = NULL; + cma_exch(conn_id, CMA_DESTROYING); + cma_release_remove(conn_id); + rdma_destroy_id(&conn_id->id); + } +out: + cma_release_remove(listen_id); + return ret; +} + +static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) +{ + return cpu_to_be64(((u64)ps << 16) + + be16_to_cpu(((struct sockaddr_in *) addr)->sin_port)); +} + +static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, + struct ib_cm_compare_data *compare) +{ + struct cma_hdr *cma_data, *cma_mask; + struct sdp_hh *sdp_data, *sdp_mask; + __u32 ip4_addr; + struct in6_addr ip6_addr; + + memset(compare, 0, sizeof *compare); + cma_data = (void *) compare->data; + cma_mask = (void *) compare->mask; + sdp_data = (void *) compare->data; + sdp_mask = (void *) compare->mask; + + switch (addr->sa_family) { + case AF_INET: + ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + if (ps == RDMA_PS_SDP) { + sdp_set_ip_ver(sdp_data, 4); + sdp_set_ip_ver(sdp_mask, 0xF); + sdp_data->dst_addr.ip4.addr = ip4_addr; + sdp_mask->dst_addr.ip4.addr = ~0; + } else { + cma_set_ip_ver(cma_data, 4); + cma_set_ip_ver(cma_mask, 0xF); + cma_data->dst_addr.ip4.addr = ip4_addr; + cma_mask->dst_addr.ip4.addr = ~0; + } + break; + case AF_INET6: + ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; + if (ps == RDMA_PS_SDP) { + sdp_set_ip_ver(sdp_data, 6); + sdp_set_ip_ver(sdp_mask, 0xF); + sdp_data->dst_addr.ip6 = ip6_addr; + memset(&sdp_mask->dst_addr.ip6, 0xFF, + sizeof sdp_mask->dst_addr.ip6); + } else { + cma_set_ip_ver(cma_data, 6); + cma_set_ip_ver(cma_mask, 0xF); + cma_data->dst_addr.ip6 = ip6_addr; + memset(&cma_mask->dst_addr.ip6, 0xFF, + sizeof cma_mask->dst_addr.ip6); + } + break; + default: + break; + } +} + +static int cma_ib_listen(struct rdma_id_private *id_priv) +{ + struct ib_cm_compare_data compare_data; + struct sockaddr *addr; + __be64 svc_id; + int ret; + + id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, + id_priv); + if (IS_ERR(id_priv->cm_id.ib)) + return PTR_ERR(id_priv->cm_id.ib); + + addr = &id_priv->id.route.addr.src_addr; + svc_id = cma_get_service_id(id_priv->id.ps, addr); + if (cma_any_addr(addr)) + ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); + else { + cma_set_compare_data(id_priv->id.ps, addr, &compare_data); + ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); + } + + if (ret) { + ib_destroy_cm_id(id_priv->cm_id.ib); + id_priv->cm_id.ib = NULL; + } + + return ret; +} + +static int cma_listen_handler(struct rdma_cm_id *id, + struct rdma_cm_event *event) +{ + struct rdma_id_private *id_priv = id->context; + + id->context = id_priv->id.context; + id->event_handler = id_priv->id.event_handler; + return id_priv->id.event_handler(id, event); +} + +static void cma_listen_on_dev(struct rdma_id_private *id_priv, + struct cma_device *cma_dev) +{ + struct rdma_id_private *dev_id_priv; + struct rdma_cm_id *id; + int ret; + + id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); + if (IS_ERR(id)) + return; + + dev_id_priv = container_of(id, struct rdma_id_private, id); + + dev_id_priv->state = CMA_ADDR_BOUND; + memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, + ip_addr_size(&id_priv->id.route.addr.src_addr)); + + cma_attach_to_dev(dev_id_priv, cma_dev); + list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); + + ret = rdma_listen(id, id_priv->backlog); + if (ret) + goto err; + + return; +err: + cma_destroy_listen(dev_id_priv); +} + +static void cma_listen_on_all(struct rdma_id_private *id_priv) +{ + struct cma_device *cma_dev; + + mutex_lock(&lock); + list_add_tail(&id_priv->list, &listen_any_list); + list_for_each_entry(cma_dev, &dev_list, list) + cma_listen_on_dev(id_priv, cma_dev); + mutex_unlock(&lock); +} + +static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) +{ + struct sockaddr_in addr_in; + + memset(&addr_in, 0, sizeof addr_in); + addr_in.sin_family = af; + return rdma_bind_addr(id, (struct sockaddr *) &addr_in); +} + +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ret = cma_bind_any(id, AF_INET); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) + return -EINVAL; + + id_priv->backlog = backlog; + if (id->device) { + switch (id->device->node_type) { + case IB_NODE_CA: + ret = cma_ib_listen(id_priv); + if (ret) + goto err; + break; + default: + ret = -ENOSYS; + goto err; + } + } else + cma_listen_on_all(id_priv); + + return 0; +err: + id_priv->backlog = 0; + cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); + return ret; +} +EXPORT_SYMBOL(rdma_listen); + +static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, + void *context) +{ + struct cma_work *work = context; + struct rdma_route *route; + + route = &work->id->id.route; + + if (!status) { + route->num_paths = 1; + *route->path_rec = *path_rec; + } else { + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ADDR_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; + } + + queue_work(cma_wq, &work->work); +} + +static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, + struct cma_work *work) +{ + struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr; + struct ib_sa_path_rec path_rec; + + memset(&path_rec, 0, sizeof path_rec); + path_rec.sgid = *ib_addr_get_sgid(addr); + path_rec.dgid = *ib_addr_get_dgid(addr); + path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); + path_rec.numb_path = 1; + + id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device, + id_priv->id.port_num, &path_rec, + IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | + IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH, + timeout_ms, GFP_KERNEL, + cma_query_handler, work, &id_priv->query); + + return (id_priv->query_id < 0) ? id_priv->query_id : 0; +} + +static void cma_work_handler(void *data) +{ + struct cma_work *work = data; + struct rdma_id_private *id_priv = work->id; + int destroy = 0; + + atomic_inc(&id_priv->dev_remove); + if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) + goto out; + + if (id_priv->id.event_handler(&id_priv->id, &work->event)) { + cma_exch(id_priv, CMA_DESTROYING); + destroy = 1; + } +out: + cma_release_remove(id_priv); + cma_deref_id(id_priv); + if (destroy) + rdma_destroy_id(&id_priv->id); + kfree(work); +} + +static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) +{ + struct rdma_route *route = &id_priv->id.route; + struct cma_work *work; + int ret; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler, work); + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ROUTE_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + + route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); + if (!route->path_rec) { + ret = -ENOMEM; + goto err1; + } + + ret = cma_query_ib_route(id_priv, timeout_ms, work); + if (ret) + goto err2; + + return 0; +err2: + kfree(route->path_rec); + route->path_rec = NULL; +err1: + kfree(work); + return ret; +} + +int rdma_set_ib_paths(struct rdma_cm_id *id, + struct ib_sa_path_rec *path_rec, int num_paths) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) + return -EINVAL; + + id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); + if (!id->route.path_rec) { + ret = -ENOMEM; + goto err; + } + + memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); + return 0; +err: + cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); + return ret; +} +EXPORT_SYMBOL(rdma_set_ib_paths); + +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) + return -EINVAL; + + atomic_inc(&id_priv->refcount); + switch (id->device->node_type) { + case IB_NODE_CA: + ret = cma_resolve_ib_route(id_priv, timeout_ms); + break; + default: + ret = -ENOSYS; + break; + } + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); + cma_deref_id(id_priv); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_route); + +static int cma_bind_loopback(struct rdma_id_private *id_priv) +{ + struct cma_device *cma_dev; + struct ib_port_attr port_attr; + union ib_gid *gid; + u16 pkey; + int ret; + u8 p; + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) + for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) + if (!ib_query_port (cma_dev->device, p, &port_attr) && + port_attr.state == IB_PORT_ACTIVE) + goto port_found; + + if (!list_empty(&dev_list)) { + p = 1; + cma_dev = list_entry(dev_list.next, struct cma_device, list); + } else { + ret = -ENODEV; + goto out; + } + +port_found: + gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); + ret = ib_get_cached_gid(cma_dev->device, p, 0, gid); + if (ret) + goto out; + + ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); + if (ret) + goto out; + + ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); + id_priv->id.port_num = p; + cma_attach_to_dev(id_priv, cma_dev); +out: + mutex_unlock(&lock); + return ret; +} + +static void addr_handler(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *dev_addr, void *context) +{ + struct rdma_id_private *id_priv = context; + enum rdma_cm_event_type event; + + atomic_inc(&id_priv->dev_remove); + if (!id_priv->cma_dev && !status) + status = cma_acquire_dev(id_priv); + + if (status) { + if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND)) + goto out; + event = RDMA_CM_EVENT_ADDR_ERROR; + } else { + if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) + goto out; + memcpy(&id_priv->id.route.addr.src_addr, src_addr, + ip_addr_size(src_addr)); + event = RDMA_CM_EVENT_ADDR_RESOLVED; + } + + if (cma_notify_user(id_priv, event, status, NULL, 0)) { + cma_exch(id_priv, CMA_DESTROYING); + cma_release_remove(id_priv); + cma_deref_id(id_priv); + rdma_destroy_id(&id_priv->id); + return; + } +out: + cma_release_remove(id_priv); + cma_deref_id(id_priv); +} + +static int cma_resolve_loopback(struct rdma_id_private *id_priv) +{ + struct cma_work *work; + struct sockaddr_in *src_in, *dst_in; + int ret; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + if (!id_priv->cma_dev) { + ret = cma_bind_loopback(id_priv); + if (ret) + goto err; + } + + ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, + ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr)); + + if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) { + src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; + dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; + src_in->sin_family = dst_in->sin_family; + src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr; + } + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler, work); + work->old_state = CMA_ADDR_QUERY; + work->new_state = CMA_ADDR_RESOLVED; + work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; + queue_work(cma_wq, &work->work); + return 0; +err: + kfree(work); + return ret; +} + +static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr) +{ + if (src_addr && src_addr->sa_family) + return rdma_bind_addr(id, src_addr); + else + return cma_bind_any(id, dst_addr->sa_family); +} + +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ret = cma_bind_addr(id, src_addr, dst_addr); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) + return -EINVAL; + + atomic_inc(&id_priv->refcount); + memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); + if (cma_any_addr(dst_addr)) + ret = cma_resolve_loopback(id_priv); + else + ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, + &id->route.addr.dev_addr, + timeout_ms, addr_handler, id_priv); + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); + cma_deref_id(id_priv); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_addr); + +static void cma_bind_port(struct rdma_bind_list *bind_list, + struct rdma_id_private *id_priv) +{ + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + sin->sin_port = htons(bind_list->port); + id_priv->bind_list = bind_list; + hlist_add_head(&id_priv->node, &bind_list->owners); +} + +static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, + unsigned short snum) +{ + struct rdma_bind_list *bind_list; + int port, start, ret; + + bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + if (!bind_list) + return -ENOMEM; + + start = snum ? snum : sysctl_local_port_range[0]; + + do { + ret = idr_get_new_above(ps, bind_list, start, &port); + } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); + + if (ret) + goto err; + + if ((snum && port != snum) || + (!snum && port > sysctl_local_port_range[1])) { + idr_remove(ps, port); + ret = -EADDRNOTAVAIL; + goto err; + } + + bind_list->ps = ps; + bind_list->port = (unsigned short) port; + cma_bind_port(bind_list, id_priv); + return 0; +err: + kfree(bind_list); + return ret; +} + +static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_id_private *cur_id; + struct sockaddr_in *sin, *cur_sin; + struct rdma_bind_list *bind_list; + struct hlist_node *node; + unsigned short snum; + + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + snum = ntohs(sin->sin_port); + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + bind_list = idr_find(ps, snum); + if (!bind_list) + return cma_alloc_port(ps, id_priv, snum); + + /* + * We don't support binding to any address if anyone is bound to + * a specific address on the same port. + */ + if (cma_any_addr(&id_priv->id.route.addr.src_addr)) + return -EADDRNOTAVAIL; + + hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { + if (cma_any_addr(&cur_id->id.route.addr.src_addr)) + return -EADDRNOTAVAIL; + + cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; + if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) + return -EADDRINUSE; + } + + cma_bind_port(bind_list, id_priv); + return 0; +} + +static int cma_get_port(struct rdma_id_private *id_priv) +{ + struct idr *ps; + int ret; + + switch (id_priv->id.ps) { + case RDMA_PS_SDP: + ps = &sdp_ps; + break; + case RDMA_PS_TCP: + ps = &tcp_ps; + break; + default: + return -EPROTONOSUPPORT; + } + + mutex_lock(&lock); + if (cma_any_port(&id_priv->id.route.addr.src_addr)) + ret = cma_alloc_port(ps, id_priv, 0); + else + ret = cma_use_port(ps, id_priv); + mutex_unlock(&lock); + + return ret; +} + +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct rdma_id_private *id_priv; + int ret; + + if (addr->sa_family != AF_INET) + return -EAFNOSUPPORT; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) + return -EINVAL; + + if (!cma_any_addr(addr)) { + ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); + if (!ret) + ret = cma_acquire_dev(id_priv); + if (ret) + goto err; + } + + memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); + ret = cma_get_port(id_priv); + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); + return ret; +} +EXPORT_SYMBOL(rdma_bind_addr); + +static int cma_format_hdr(void *hdr, enum rdma_port_space ps, + struct rdma_route *route) +{ + struct sockaddr_in *src4, *dst4; + struct cma_hdr *cma_hdr; + struct sdp_hh *sdp_hdr; + + src4 = (struct sockaddr_in *) &route->addr.src_addr; + dst4 = (struct sockaddr_in *) &route->addr.dst_addr; + + switch (ps) { + case RDMA_PS_SDP: + sdp_hdr = hdr; + if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) + return -EINVAL; + sdp_set_ip_ver(sdp_hdr, 4); + sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + sdp_hdr->port = src4->sin_port; + break; + default: + cma_hdr = hdr; + cma_hdr->cma_version = CMA_VERSION; + cma_set_ip_ver(cma_hdr, 4); + cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + cma_hdr->port = src4->sin_port; + break; + } + return 0; +} + +static int cma_connect_ib(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_cm_req_param req; + struct rdma_route *route; + void *private_data; + int offset, ret; + + memset(&req, 0, sizeof req); + offset = cma_user_data_offset(id_priv->id.ps); + req.private_data_len = offset + conn_param->private_data_len; + private_data = kzalloc(req.private_data_len, GFP_ATOMIC); + if (!private_data) + return -ENOMEM; + + if (conn_param->private_data && conn_param->private_data_len) + memcpy(private_data + offset, conn_param->private_data, + conn_param->private_data_len); + + id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, + id_priv); + if (IS_ERR(id_priv->cm_id.ib)) { + ret = PTR_ERR(id_priv->cm_id.ib); + goto out; + } + + route = &id_priv->id.route; + ret = cma_format_hdr(private_data, id_priv->id.ps, route); + if (ret) + goto out; + req.private_data = private_data; + + req.primary_path = &route->path_rec[0]; + if (route->num_paths == 2) + req.alternate_path = &route->path_rec[1]; + + req.service_id = cma_get_service_id(id_priv->id.ps, + &route->addr.dst_addr); + req.qp_num = id_priv->qp_num; + req.qp_type = id_priv->qp_type; + req.starting_psn = id_priv->seq_num; + req.responder_resources = conn_param->responder_resources; + req.initiator_depth = conn_param->initiator_depth; + req.flow_control = conn_param->flow_control; + req.retry_count = conn_param->retry_count; + req.rnr_retry_count = conn_param->rnr_retry_count; + req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; + req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; + req.max_cm_retries = CMA_MAX_CM_RETRIES; + req.srq = id_priv->srq ? 1 : 0; + + ret = ib_send_cm_req(id_priv->cm_id.ib, &req); +out: + kfree(private_data); + return ret; +} + +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) + return -EINVAL; + + if (!id->qp) { + id_priv->qp_num = conn_param->qp_num; + id_priv->qp_type = conn_param->qp_type; + id_priv->srq = conn_param->srq; + } + + switch (id->device->node_type) { + case IB_NODE_CA: + ret = cma_connect_ib(id_priv, conn_param); + break; + default: + ret = -ENOSYS; + break; + } + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); + return ret; +} +EXPORT_SYMBOL(rdma_connect); + +static int cma_accept_ib(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_cm_rep_param rep; + int ret; + + ret = cma_modify_qp_rtr(&id_priv->id); + if (ret) + return ret; + + memset(&rep, 0, sizeof rep); + rep.qp_num = id_priv->qp_num; + rep.starting_psn = id_priv->seq_num; + rep.private_data = conn_param->private_data; + rep.private_data_len = conn_param->private_data_len; + rep.responder_resources = conn_param->responder_resources; + rep.initiator_depth = conn_param->initiator_depth; + rep.target_ack_delay = CMA_CM_RESPONSE_TIMEOUT; + rep.failover_accepted = 0; + rep.flow_control = conn_param->flow_control; + rep.rnr_retry_count = conn_param->rnr_retry_count; + rep.srq = id_priv->srq ? 1 : 0; + + return ib_send_cm_rep(id_priv->cm_id.ib, &rep); +} + +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_CONNECT)) + return -EINVAL; + + if (!id->qp && conn_param) { + id_priv->qp_num = conn_param->qp_num; + id_priv->qp_type = conn_param->qp_type; + id_priv->srq = conn_param->srq; + } + + switch (id->device->node_type) { + case IB_NODE_CA: + if (conn_param) + ret = cma_accept_ib(id_priv, conn_param); + else + ret = cma_rep_recv(id_priv); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) + goto reject; + + return 0; +reject: + cma_modify_qp_err(id); + rdma_reject(id, NULL, 0); + return ret; +} +EXPORT_SYMBOL(rdma_accept); + +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + u8 private_data_len) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_CONNECT)) + return -EINVAL; + + switch (id->device->node_type) { + case IB_NODE_CA: + ret = ib_send_cm_rej(id_priv->cm_id.ib, + IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, + private_data, private_data_len); + break; + default: + ret = -ENOSYS; + break; + } + return ret; +} +EXPORT_SYMBOL(rdma_reject); + +int rdma_disconnect(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_CONNECT) && + !cma_comp(id_priv, CMA_DISCONNECT)) + return -EINVAL; + + ret = cma_modify_qp_err(id); + if (ret) + goto out; + + switch (id->device->node_type) { + case IB_NODE_CA: + /* Initiate or respond to a disconnect. */ + if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) + ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); + break; + default: + break; + } +out: + return ret; +} +EXPORT_SYMBOL(rdma_disconnect); + +static void cma_add_one(struct ib_device *device) +{ + struct cma_device *cma_dev; + struct rdma_id_private *id_priv; + + cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); + if (!cma_dev) + return; + + cma_dev->device = device; + cma_dev->node_guid = device->node_guid; + if (!cma_dev->node_guid) + goto err; + + init_completion(&cma_dev->comp); + atomic_set(&cma_dev->refcount, 1); + INIT_LIST_HEAD(&cma_dev->id_list); + ib_set_client_data(device, &cma_client, cma_dev); + + mutex_lock(&lock); + list_add_tail(&cma_dev->list, &dev_list); + list_for_each_entry(id_priv, &listen_any_list, list) + cma_listen_on_dev(id_priv, cma_dev); + mutex_unlock(&lock); + return; +err: + kfree(cma_dev); +} + +static int cma_remove_id_dev(struct rdma_id_private *id_priv) +{ + enum cma_state state; + + /* Record that we want to remove the device */ + state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); + if (state == CMA_DESTROYING) + return 0; + + cma_cancel_operation(id_priv, state); + wait_event(id_priv->wait_remove, !atomic_read(&id_priv->dev_remove)); + + /* Check for destruction from another callback. */ + if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) + return 0; + + return cma_notify_user(id_priv, RDMA_CM_EVENT_DEVICE_REMOVAL, + 0, NULL, 0); +} + +static void cma_process_remove(struct cma_device *cma_dev) +{ + struct list_head remove_list; + struct rdma_id_private *id_priv; + int ret; + + INIT_LIST_HEAD(&remove_list); + + mutex_lock(&lock); + while (!list_empty(&cma_dev->id_list)) { + id_priv = list_entry(cma_dev->id_list.next, + struct rdma_id_private, list); + + if (cma_internal_listen(id_priv)) { + cma_destroy_listen(id_priv); + continue; + } + + list_del(&id_priv->list); + list_add_tail(&id_priv->list, &remove_list); + atomic_inc(&id_priv->refcount); + mutex_unlock(&lock); + + ret = cma_remove_id_dev(id_priv); + cma_deref_id(id_priv); + if (ret) + rdma_destroy_id(&id_priv->id); + + mutex_lock(&lock); + } + mutex_unlock(&lock); + + cma_deref_dev(cma_dev); + wait_for_completion(&cma_dev->comp); +} + +static void cma_remove_one(struct ib_device *device) +{ + struct cma_device *cma_dev; + + cma_dev = ib_get_client_data(device, &cma_client); + if (!cma_dev) + return; + + mutex_lock(&lock); + list_del(&cma_dev->list); + mutex_unlock(&lock); + + cma_process_remove(cma_dev); + kfree(cma_dev); +} + +static int cma_init(void) +{ + int ret; + + cma_wq = create_singlethread_workqueue("rdma_cm_wq"); + if (!cma_wq) + return -ENOMEM; + + ret = ib_register_client(&cma_client); + if (ret) + goto err; + return 0; + +err: + destroy_workqueue(cma_wq); + return ret; +} + +static void cma_cleanup(void) +{ + ib_unregister_client(&cma_client); + destroy_workqueue(cma_wq); + idr_destroy(&sdp_ps); + idr_destroy(&tcp_ps); +} + +module_init(cma_init); +module_exit(cma_cleanup); diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h new file mode 100644 index 000000000000..402c63d7226b --- /dev/null +++ b/include/rdma/rdma_cm.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + * + */ + +#if !defined(RDMA_CM_H) +#define RDMA_CM_H + +#include +#include +#include +#include + +/* + * Upon receiving a device removal event, users must destroy the associated + * RDMA identifier and release all resources allocated with the device. + */ +enum rdma_cm_event_type { + RDMA_CM_EVENT_ADDR_RESOLVED, + RDMA_CM_EVENT_ADDR_ERROR, + RDMA_CM_EVENT_ROUTE_RESOLVED, + RDMA_CM_EVENT_ROUTE_ERROR, + RDMA_CM_EVENT_CONNECT_REQUEST, + RDMA_CM_EVENT_CONNECT_RESPONSE, + RDMA_CM_EVENT_CONNECT_ERROR, + RDMA_CM_EVENT_UNREACHABLE, + RDMA_CM_EVENT_REJECTED, + RDMA_CM_EVENT_ESTABLISHED, + RDMA_CM_EVENT_DISCONNECTED, + RDMA_CM_EVENT_DEVICE_REMOVAL, +}; + +enum rdma_port_space { + RDMA_PS_SDP = 0x0001, + RDMA_PS_TCP = 0x0106, + RDMA_PS_UDP = 0x0111, + RDMA_PS_SCTP = 0x0183 +}; + +struct rdma_addr { + struct sockaddr src_addr; + u8 src_pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; + struct sockaddr dst_addr; + u8 dst_pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; + struct rdma_dev_addr dev_addr; +}; + +struct rdma_route { + struct rdma_addr addr; + struct ib_sa_path_rec *path_rec; + int num_paths; +}; + +struct rdma_cm_event { + enum rdma_cm_event_type event; + int status; + void *private_data; + u8 private_data_len; +}; + +struct rdma_cm_id; + +/** + * rdma_cm_event_handler - Callback used to report user events. + * + * Notes: Users may not call rdma_destroy_id from this callback to destroy + * the passed in id, or a corresponding listen id. Returning a + * non-zero value from the callback will destroy the passed in id. + */ +typedef int (*rdma_cm_event_handler)(struct rdma_cm_id *id, + struct rdma_cm_event *event); + +struct rdma_cm_id { + struct ib_device *device; + void *context; + struct ib_qp *qp; + rdma_cm_event_handler event_handler; + struct rdma_route route; + enum rdma_port_space ps; + u8 port_num; +}; + +/** + * rdma_create_id - Create an RDMA identifier. + * + * @event_handler: User callback invoked to report events associated with the + * returned rdma_id. + * @context: User specified context associated with the id. + * @ps: RDMA port space. + */ +struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, + void *context, enum rdma_port_space ps); + +void rdma_destroy_id(struct rdma_cm_id *id); + +/** + * rdma_bind_addr - Bind an RDMA identifier to a source address and + * associated RDMA device, if needed. + * + * @id: RDMA identifier. + * @addr: Local address information. Wildcard values are permitted. + * + * This associates a source address with the RDMA identifier before calling + * rdma_listen. If a specific local address is given, the RDMA identifier will + * be bound to a local RDMA device. + */ +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_resolve_addr - Resolve destination and optional source addresses + * from IP addresses to an RDMA address. If successful, the specified + * rdma_cm_id will be bound to a local device. + * + * @id: RDMA identifier. + * @src_addr: Source address information. This parameter may be NULL. + * @dst_addr: Destination address information. + * @timeout_ms: Time to wait for resolution to complete. + */ +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms); + +/** + * rdma_resolve_route - Resolve the RDMA address bound to the RDMA identifier + * into route information needed to establish a connection. + * + * This is called on the client side of a connection. + * Users must have first called rdma_resolve_addr to resolve a dst_addr + * into an RDMA address before calling this routine. + */ +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms); + +/** + * rdma_create_qp - Allocate a QP and associate it with the specified RDMA + * identifier. + * + * QPs allocated to an rdma_cm_id will automatically be transitioned by the CMA + * through their states. + */ +int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr); + +/** + * rdma_destroy_qp - Deallocate the QP associated with the specified RDMA + * identifier. + * + * Users must destroy any QP associated with an RDMA identifier before + * destroying the RDMA ID. + */ +void rdma_destroy_qp(struct rdma_cm_id *id); + +/** + * rdma_init_qp_attr - Initializes the QP attributes for use in transitioning + * to a specified QP state. + * @id: Communication identifier associated with the QP attributes to + * initialize. + * @qp_attr: On input, specifies the desired QP state. On output, the + * mandatory and desired optional attributes will be set in order to + * modify the QP to the specified state. + * @qp_attr_mask: The QP attribute mask that may be used to transition the + * QP to the specified state. + * + * Users must set the @qp_attr->qp_state to the desired QP state. This call + * will set all required attributes for the given transition, along with + * known optional attributes. Users may override the attributes returned from + * this call before calling ib_modify_qp. + * + * Users that wish to have their QP automatically transitioned through its + * states can associate a QP with the rdma_cm_id by calling rdma_create_qp(). + */ +int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, + int *qp_attr_mask); + +struct rdma_conn_param { + const void *private_data; + u8 private_data_len; + u8 responder_resources; + u8 initiator_depth; + u8 flow_control; + u8 retry_count; /* ignored when accepting */ + u8 rnr_retry_count; + /* Fields below ignored if a QP is created on the rdma_cm_id. */ + u8 srq; + u32 qp_num; + enum ib_qp_type qp_type; +}; + +/** + * rdma_connect - Initiate an active connection request. + * + * Users must have resolved a route for the rdma_cm_id to connect with + * by having called rdma_resolve_route before calling this routine. + */ +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_listen - This function is called by the passive side to + * listen for incoming connection requests. + * + * Users must have bound the rdma_cm_id to a local address by calling + * rdma_bind_addr before calling this routine. + */ +int rdma_listen(struct rdma_cm_id *id, int backlog); + +/** + * rdma_accept - Called to accept a connection request or response. + * @id: Connection identifier associated with the request. + * @conn_param: Information needed to establish the connection. This must be + * provided if accepting a connection request. If accepting a connection + * response, this parameter must be NULL. + * + * Typically, this routine is only called by the listener to accept a connection + * request. It must also be called on the active side of a connection if the + * user is performing their own QP transitions. + */ +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_reject - Called to reject a connection request or response. + */ +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + u8 private_data_len); + +/** + * rdma_disconnect - This function disconnects the associated QP and + * transitions it into the error state. + */ +int rdma_disconnect(struct rdma_cm_id *id); + +#endif /* RDMA_CM_H */ + diff --git a/include/rdma/rdma_cm_ib.h b/include/rdma/rdma_cm_ib.h new file mode 100644 index 000000000000..e8c3af1804d4 --- /dev/null +++ b/include/rdma/rdma_cm_ib.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + * + */ + +#if !defined(RDMA_CM_IB_H) +#define RDMA_CM_IB_H + +#include + +/** + * rdma_set_ib_paths - Manually sets the path records used to establish a + * connection. + * @id: Connection identifier associated with the request. + * @path_rec: Reference to the path record + * + * This call permits a user to specify routing information for rdma_cm_id's + * bound to Infiniband devices. It is called on the client side of a + * connection and replaces the call to rdma_resolve_route. + */ +int rdma_set_ib_paths(struct rdma_cm_id *id, + struct ib_sa_path_rec *path_rec, int num_paths); + +#endif /* RDMA_CM_IB_H */ -- cgit v1.2.3 From 6fb9cdbf2cdb2ea187e57ec2e16cc59df2adf86a Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 17 Jun 2006 20:37:34 -0700 Subject: IB: Add caching of ports' LMC Add an LMC cache to struct ib_device, and add a function ib_get_cached_lmc() to query the cache. Signed-off-by: Jack Morgenstein Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cache.c | 30 +++++++++++++++++++++++++++++- include/rdma/ib_cache.h | 13 +++++++++++++ include/rdma/ib_verbs.h | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 50364c0b090c..e05ca2cdc73f 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -191,6 +191,24 @@ int ib_find_cached_pkey(struct ib_device *device, } EXPORT_SYMBOL(ib_find_cached_pkey); +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc) +{ + unsigned long flags; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, flags); + *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_lmc); + static void ib_cache_update(struct ib_device *device, u8 port) { @@ -251,6 +269,8 @@ static void ib_cache_update(struct ib_device *device, device->cache.pkey_cache[port - start_port(device)] = pkey_cache; device->cache.gid_cache [port - start_port(device)] = gid_cache; + device->cache.lmc_cache[port - start_port(device)] = tprops->lmc; + write_unlock_irq(&device->cache.lock); kfree(old_pkey_cache); @@ -305,7 +325,13 @@ static void ib_cache_setup_one(struct ib_device *device) kmalloc(sizeof *device->cache.gid_cache * (end_port(device) - start_port(device) + 1), GFP_KERNEL); - if (!device->cache.pkey_cache || !device->cache.gid_cache) { + device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * + (end_port(device) - + start_port(device) + 1), + GFP_KERNEL); + + if (!device->cache.pkey_cache || !device->cache.gid_cache || + !device->cache.lmc_cache) { printk(KERN_WARNING "Couldn't allocate cache " "for %s\n", device->name); goto err; @@ -333,6 +359,7 @@ err_cache: err: kfree(device->cache.pkey_cache); kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); } static void ib_cache_cleanup_one(struct ib_device *device) @@ -349,6 +376,7 @@ static void ib_cache_cleanup_one(struct ib_device *device) kfree(device->cache.pkey_cache); kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); } static struct ib_client cache_client = { diff --git a/include/rdma/ib_cache.h b/include/rdma/ib_cache.h index 5bf9834f7dca..f179d233ffc3 100644 --- a/include/rdma/ib_cache.h +++ b/include/rdma/ib_cache.h @@ -102,4 +102,17 @@ int ib_find_cached_pkey(struct ib_device *device, u16 pkey, u16 *index); +/** + * ib_get_cached_lmc - Returns a cached lmc table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @lmc: The lmc value for the specified port for that device. + * + * ib_get_cached_lmc() fetches the specified lmc table entry stored in + * the local software cache. + */ +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc); + #endif /* _IB_CACHE_H */ diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6bbf1b364400..aeb4fcd86a9e 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -827,6 +827,7 @@ struct ib_cache { struct ib_event_handler event_handler; struct ib_pkey_cache **pkey_cache; struct ib_gid_cache **gid_cache; + u8 *lmc_cache; }; struct ib_device { -- cgit v1.2.3 From 63942c9a981ecfa2aabfb27ff1a87b88f2ee9f5b Mon Sep 17 00:00:00 2001 From: Leonid Arsh Date: Sat, 17 Jun 2006 20:37:35 -0700 Subject: IB: Add client reregister event type Add IB_EVENT_CLIENT_REREGISTER to enum so low-level drivers can generate "client reregister" events. Signed-off-by: Leonid Arsh Signed-off-by: Roland Dreier --- include/rdma/ib_verbs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index aeb4fcd86a9e..10a6268c2cc2 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -260,7 +260,8 @@ enum ib_event_type { IB_EVENT_SM_CHANGE, IB_EVENT_SRQ_ERR, IB_EVENT_SRQ_LIMIT_REACHED, - IB_EVENT_QP_LAST_WQE_REACHED + IB_EVENT_QP_LAST_WQE_REACHED, + IB_EVENT_CLIENT_REREGISTER }; struct ib_event { -- cgit v1.2.3 From da2ab62ab5e430e6ffafc2d0e6046dcd2780f570 Mon Sep 17 00:00:00 2001 From: Leonid Arsh Date: Sat, 17 Jun 2006 20:37:36 -0700 Subject: IB: Move struct port_info from ipath to Move ipath's struct port_info into , so that it can be used by mthca to implement client reregister support. Remove the __attribute__((packed)) because all the members of the struct are naturally aligned anyway. Signed-off-by: Leonid Arsh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_mad.c | 40 ++------------------------------- include/rdma/ib_smi.h | 36 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index f7f8391fe43f..49acd1e15707 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -137,47 +137,11 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp, return reply(smp); } -struct port_info { - __be64 mkey; - __be64 gid_prefix; - __be16 lid; - __be16 sm_lid; - __be32 cap_mask; - __be16 diag_code; - __be16 mkey_lease_period; - u8 local_port_num; - u8 link_width_enabled; - u8 link_width_supported; - u8 link_width_active; - u8 linkspeed_portstate; /* 4 bits, 4 bits */ - u8 portphysstate_linkdown; /* 4 bits, 4 bits */ - u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ - u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ - u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ - u8 vlcap_inittype; /* 4 bits, 4 bits */ - u8 vl_high_limit; - u8 vl_arb_high_cap; - u8 vl_arb_low_cap; - u8 inittypereply_mtucap; /* 4 bits, 4 bits */ - u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ - u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ - __be16 mkey_violations; - __be16 pkey_violations; - __be16 qkey_violations; - u8 guid_cap; - u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ - u8 resv_resptimevalue; /* 3 bits, 5 bits */ - u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ - __be16 max_credit_hint; - u8 resv; - u8 link_roundtrip_latency[3]; -} __attribute__ ((packed)); - static int recv_subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev, u8 port) { struct ipath_ibdev *dev; - struct port_info *pip = (struct port_info *)smp->data; + struct ib_port_info *pip = (struct ib_port_info *)smp->data; u16 lid; u8 ibcstat; u8 mtu; @@ -312,7 +276,7 @@ static int recv_subn_set_guidinfo(struct ib_smp *smp, static int recv_subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, u8 port) { - struct port_info *pip = (struct port_info *)smp->data; + struct ib_port_info *pip = (struct ib_port_info *)smp->data; struct ib_event event; struct ipath_ibdev *dev; u32 flags; diff --git a/include/rdma/ib_smi.h b/include/rdma/ib_smi.h index 87f60737f695..f29af135ba83 100644 --- a/include/rdma/ib_smi.h +++ b/include/rdma/ib_smi.h @@ -85,6 +85,42 @@ struct ib_smp { #define IB_SMP_ATTR_LED_INFO __constant_htons(0x0031) #define IB_SMP_ATTR_VENDOR_MASK __constant_htons(0xFF00) +struct ib_port_info { + __be64 mkey; + __be64 gid_prefix; + __be16 lid; + __be16 sm_lid; + __be32 cap_mask; + __be16 diag_code; + __be16 mkey_lease_period; + u8 local_port_num; + u8 link_width_enabled; + u8 link_width_supported; + u8 link_width_active; + u8 linkspeed_portstate; /* 4 bits, 4 bits */ + u8 portphysstate_linkdown; /* 4 bits, 4 bits */ + u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ + u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ + u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ + u8 vlcap_inittype; /* 4 bits, 4 bits */ + u8 vl_high_limit; + u8 vl_arb_high_cap; + u8 vl_arb_low_cap; + u8 inittypereply_mtucap; /* 4 bits, 4 bits */ + u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ + u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ + __be16 mkey_violations; + __be16 pkey_violations; + __be16 qkey_violations; + u8 guid_cap; + u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ + u8 resv_resptimevalue; /* 3 bits, 5 bits */ + u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ + __be16 max_credit_hint; + u8 resv; + u8 link_roundtrip_latency[3]; +}; + static inline u8 ib_get_smp_direction(struct ib_smp *smp) { -- cgit v1.2.3 From 73c0996b1ca60338fa50e42acfcebd32b7636a8b Mon Sep 17 00:00:00 2001 From: Ramachandra K Date: Sat, 17 Jun 2006 20:37:38 -0700 Subject: [SCSI] srp.h: Add I/O Class values Add enum values for I/O Class values from rev. 10 and rev. 16a SRP drafts. The values are used to detect targets that implement obsolete revisions of SRP, so that the initiator can use the old format for port identifier when connecting to them. Signed-off-by: Ramachandra K Signed-off-by: Roland Dreier --- include/scsi/srp.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/scsi/srp.h b/include/scsi/srp.h index 637f77eccf0c..ad178fa78f66 100644 --- a/include/scsi/srp.h +++ b/include/scsi/srp.h @@ -87,6 +87,11 @@ enum srp_login_rej_reason { SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006 }; +enum { + SRP_REV10_IB_IO_CLASS = 0xff00, + SRP_REV16A_IB_IO_CLASS = 0x0100 +}; + struct srp_direct_buf { __be64 va; __be32 key; -- cgit v1.2.3 From 75af9088514432ef0c1052ba3767ceb0beb6f101 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:39 -0700 Subject: IB/ucm: Get rid of duplicate P_Key parameter The P_Key is provided into a SIDR REQ in two places, once as a parameter, and again in the path record. Remove the P_Key as a parameter and always use the one given in the path record. This change has no practical effect on ABI functionality. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 2 +- drivers/infiniband/core/ucm.c | 1 - include/rdma/ib_cm.h | 3 +-- include/rdma/ib_user_cm.h | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 1c7463b7c5fd..629ed26a0176 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -2615,7 +2615,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg, cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); sidr_req_msg->request_id = cm_id_priv->id.local_id; - sidr_req_msg->pkey = cpu_to_be16(param->pkey); + sidr_req_msg->pkey = cpu_to_be16(param->path->pkey); sidr_req_msg->service_id = param->service_id; if (param->private_data && param->private_data_len) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 67caf36504ee..c1c6fda9452c 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1044,7 +1044,6 @@ static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file, param.service_id = cmd.sid; param.timeout_ms = cmd.timeout; param.max_cm_retries = cmd.max_cm_retries; - param.pkey = cmd.pkey; ctx = ib_ucm_ctx_get(file, cmd.id); if (!IS_ERR(ctx)) { diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 8f394f035684..c9b4738be9d6 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -546,7 +546,6 @@ struct ib_cm_sidr_req_param { const void *private_data; u8 private_data_len; u8 max_cm_retries; - u16 pkey; }; /** @@ -570,7 +569,7 @@ struct ib_cm_sidr_rep_param { }; /** - * ib_send_cm_sidr_rep - Sends a service ID resolution request to the + * ib_send_cm_sidr_rep - Sends a service ID resolution reply to the * remote node. * @cm_id: Communication identifier associated with the received service ID * resolution request. diff --git a/include/rdma/ib_user_cm.h b/include/rdma/ib_user_cm.h index a9e1b22d245c..066c20b7cdfb 100644 --- a/include/rdma/ib_user_cm.h +++ b/include/rdma/ib_user_cm.h @@ -200,7 +200,7 @@ struct ib_ucm_sidr_req { __be64 sid; __u64 data; __u64 path; - __u16 pkey; + __u16 reserved_pkey; __u8 len; __u8 max_cm_retries; __u8 reserved[4]; -- cgit v1.2.3 From 4e00d69454a8747798de11dc4eeef1edeee5ce98 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:39 -0700 Subject: IB: Add ib_init_ah_from_wc() Add a function to initialize address handle attributes from a work completion. This functionality is duplicated by both verbs and the CM. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/verbs.c | 44 ++++++++++++++++++++++++++--------------- include/rdma/ib_verbs.h | 14 +++++++++++++ 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index b78e7dc69330..468999c38803 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -125,35 +125,47 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) } EXPORT_SYMBOL(ib_create_ah); -struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, - struct ib_grh *grh, u8 port_num) +int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, + struct ib_grh *grh, struct ib_ah_attr *ah_attr) { - struct ib_ah_attr ah_attr; u32 flow_class; u16 gid_index; int ret; - memset(&ah_attr, 0, sizeof ah_attr); - ah_attr.dlid = wc->slid; - ah_attr.sl = wc->sl; - ah_attr.src_path_bits = wc->dlid_path_bits; - ah_attr.port_num = port_num; + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = wc->slid; + ah_attr->sl = wc->sl; + ah_attr->src_path_bits = wc->dlid_path_bits; + ah_attr->port_num = port_num; if (wc->wc_flags & IB_WC_GRH) { - ah_attr.ah_flags = IB_AH_GRH; - ah_attr.grh.dgid = grh->sgid; + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = grh->sgid; - ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num, + ret = ib_find_cached_gid(device, &grh->dgid, &port_num, &gid_index); if (ret) - return ERR_PTR(ret); + return ret; - ah_attr.grh.sgid_index = (u8) gid_index; + ah_attr->grh.sgid_index = (u8) gid_index; flow_class = be32_to_cpu(grh->version_tclass_flow); - ah_attr.grh.flow_label = flow_class & 0xFFFFF; - ah_attr.grh.traffic_class = (flow_class >> 20) & 0xFF; - ah_attr.grh.hop_limit = grh->hop_limit; + ah_attr->grh.flow_label = flow_class & 0xFFFFF; + ah_attr->grh.hop_limit = grh->hop_limit; + ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; } + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_wc); + +struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, + struct ib_grh *grh, u8 port_num) +{ + struct ib_ah_attr ah_attr; + int ret; + + ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr); + if (ret) + return ERR_PTR(ret); return ib_create_ah(pd, &ah_attr); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 10a6268c2cc2..7ced208edacf 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1087,6 +1087,20 @@ int ib_dealloc_pd(struct ib_pd *pd); */ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +/** + * ib_init_ah_from_wc - Initializes address handle attributes from a + * work completion. + * @device: Device on which the received message arrived. + * @port_num: Port on which the received message arrived. + * @wc: Work completion associated with the received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @ah_attr: Returned attributes that can be used when creating an address + * handle for replying to the message. + */ +int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, + struct ib_grh *grh, struct ib_ah_attr *ah_attr); + /** * ib_create_ah_from_wc - Creates an address handle associated with the * sender of the specified work completion. -- cgit v1.2.3 From 6d969a471ba107d94cf03dab3c69f45b9733f500 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Sat, 17 Jun 2006 20:37:39 -0700 Subject: IB/sa: Add ib_init_ah_from_path() Add a call to initialize address handle attributes given a path record. This is used by the CM, and would be useful for users of UD QPs. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 31 +++++++++++++++++++++++++++++++ include/rdma/ib_sa.h | 7 +++++++ 2 files changed, 38 insertions(+) (limited to 'include') diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 501cc054cb3b..08d9dd5e0487 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -47,6 +47,7 @@ #include #include +#include MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand subnet administration query support"); @@ -441,6 +442,36 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) } EXPORT_SYMBOL(ib_sa_cancel_query); +int ib_init_ah_from_path(struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr) +{ + int ret; + u16 gid_index; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(rec->dlid); + ah_attr->sl = rec->sl; + ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; + ah_attr->port_num = port_num; + + if (rec->hop_limit > 1) { + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = rec->dgid; + + ret = ib_find_cached_gid(device, &rec->sgid, &port_num, + &gid_index); + if (ret) + return ret; + + ah_attr->grh.sgid_index = gid_index; + ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); + ah_attr->grh.hop_limit = rec->hop_limit; + ah_attr->grh.traffic_class = rec->traffic_class; + } + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_path); + static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) { unsigned long flags; diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index ad63c215efe5..c99e4420fd7e 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -370,5 +370,12 @@ ib_sa_mcmember_rec_delete(struct ib_device *device, u8 port_num, context, query); } +/** + * ib_init_ah_from_path - Initialize address handle attributes based on an SA + * path record. + */ +int ib_init_ah_from_path(struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + struct ib_ah_attr *ah_attr); #endif /* IB_SA_H */ -- cgit v1.2.3 From 9ead190bfde2a434c74ea604382d08acb2eceef5 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 17 Jun 2006 20:44:49 -0700 Subject: IB/uverbs: Don't serialize with ib_uverbs_idr_mutex Currently, all userspace verbs operations that call into the kernel are serialized by ib_uverbs_idr_mutex. This can be a scalability issue for some workloads, especially for devices driven by the ipath driver, which needs to call into the kernel even for datapath operations. Fix this by adding reference counts to the userspace objects, and then converting ib_uverbs_idr_mutex into a spinlock that only protects the idrs long enough to take a reference on the object being looked up. Because remove operations may fail, we have to do a slightly funky two-step deletion, which is described in the comments at the top of uverbs_cmd.c. This also still leaves ib_uverbs_idr_lock as a single lock that is possibly subject to contention. However, the lock hold time will only be a single idr operation, so multiple threads should still be able to make progress, even if ib_uverbs_idr_lock is being ping-ponged. Surprisingly, these changes even shrink the object code: add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60) Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 4 +- drivers/infiniband/core/uverbs_cmd.c | 890 ++++++++++++++++++++-------------- drivers/infiniband/core/uverbs_main.c | 35 +- include/rdma/ib_verbs.h | 4 + 4 files changed, 557 insertions(+), 376 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 3372d67ff139..bb9bee56a824 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -132,7 +132,7 @@ struct ib_ucq_object { u32 async_events_reported; }; -extern struct mutex ib_uverbs_idr_mutex; +extern spinlock_t ib_uverbs_idr_lock; extern struct idr ib_uverbs_pd_idr; extern struct idr ib_uverbs_mr_idr; extern struct idr ib_uverbs_mw_idr; @@ -141,6 +141,8 @@ extern struct idr ib_uverbs_cq_idr; extern struct idr ib_uverbs_qp_idr; extern struct idr ib_uverbs_srq_idr; +void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); + struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async, int *fd); void ib_uverbs_release_event_file(struct kref *ref); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 403dd811ec7f..76bf61e9b552 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -50,7 +50,64 @@ (udata)->outlen = (olen); \ } while (0) -static int idr_add_uobj(struct idr *idr, void *obj, struct ib_uobject *uobj) +/* + * The ib_uobject locking scheme is as follows: + * + * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it + * needs to be held during all idr operations. When an object is + * looked up, a reference must be taken on the object's kref before + * dropping this lock. + * + * - Each object also has an rwsem. This rwsem must be held for + * reading while an operation that uses the object is performed. + * For example, while registering an MR, the associated PD's + * uobject.mutex must be held for reading. The rwsem must be held + * for writing while initializing or destroying an object. + * + * - In addition, each object has a "live" flag. If this flag is not + * set, then lookups of the object will fail even if it is found in + * the idr. This handles a reader that blocks and does not acquire + * the rwsem until after the object is destroyed. The destroy + * operation will set the live flag to 0 and then drop the rwsem; + * this will allow the reader to acquire the rwsem, see that the + * live flag is 0, and then drop the rwsem and its reference to + * object. The underlying storage will not be freed until the last + * reference to the object is dropped. + */ + +static void init_uobj(struct ib_uobject *uobj, u64 user_handle, + struct ib_ucontext *context) +{ + uobj->user_handle = user_handle; + uobj->context = context; + kref_init(&uobj->ref); + init_rwsem(&uobj->mutex); + uobj->live = 0; +} + +static void release_uobj(struct kref *kref) +{ + kfree(container_of(kref, struct ib_uobject, ref)); +} + +static void put_uobj(struct ib_uobject *uobj) +{ + kref_put(&uobj->ref, release_uobj); +} + +static void put_uobj_read(struct ib_uobject *uobj) +{ + up_read(&uobj->mutex); + put_uobj(uobj); +} + +static void put_uobj_write(struct ib_uobject *uobj) +{ + up_write(&uobj->mutex); + put_uobj(uobj); +} + +static int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj) { int ret; @@ -58,7 +115,9 @@ retry: if (!idr_pre_get(idr, GFP_KERNEL)) return -ENOMEM; + spin_lock(&ib_uverbs_idr_lock); ret = idr_get_new(idr, uobj, &uobj->id); + spin_unlock(&ib_uverbs_idr_lock); if (ret == -EAGAIN) goto retry; @@ -66,6 +125,121 @@ retry: return ret; } +void idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj) +{ + spin_lock(&ib_uverbs_idr_lock); + idr_remove(idr, uobj->id); + spin_unlock(&ib_uverbs_idr_lock); +} + +static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + spin_lock(&ib_uverbs_idr_lock); + uobj = idr_find(idr, id); + if (uobj) + kref_get(&uobj->ref); + spin_unlock(&ib_uverbs_idr_lock); + + return uobj; +} + +static struct ib_uobject *idr_read_uobj(struct idr *idr, int id, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + uobj = __idr_get_uobj(idr, id, context); + if (!uobj) + return NULL; + + down_read(&uobj->mutex); + if (!uobj->live) { + put_uobj_read(uobj); + return NULL; + } + + return uobj; +} + +static struct ib_uobject *idr_write_uobj(struct idr *idr, int id, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + uobj = __idr_get_uobj(idr, id, context); + if (!uobj) + return NULL; + + down_write(&uobj->mutex); + if (!uobj->live) { + put_uobj_write(uobj); + return NULL; + } + + return uobj; +} + +static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + uobj = idr_read_uobj(idr, id, context); + return uobj ? uobj->object : NULL; +} + +static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context); +} + +static void put_pd_read(struct ib_pd *pd) +{ + put_uobj_read(pd->uobject); +} + +static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context); +} + +static void put_cq_read(struct ib_cq *cq) +{ + put_uobj_read(cq->uobject); +} + +static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context); +} + +static void put_ah_read(struct ib_ah *ah) +{ + put_uobj_read(ah->uobject); +} + +static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context); +} + +static void put_qp_read(struct ib_qp *qp) +{ + put_uobj_read(qp->uobject); +} + +static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context); +} + +static void put_srq_read(struct ib_srq *srq) +{ + put_uobj_read(srq->uobject); +} + ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -296,7 +470,8 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, if (!uobj) return -ENOMEM; - uobj->context = file->ucontext; + init_uobj(uobj, 0, file->ucontext); + down_write(&uobj->mutex); pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, file->ucontext, &udata); @@ -309,11 +484,10 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, pd->uobject = uobj; atomic_set(&pd->usecnt, 0); - mutex_lock(&ib_uverbs_idr_mutex); - - ret = idr_add_uobj(&ib_uverbs_pd_idr, pd, uobj); + uobj->object = pd; + ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj); if (ret) - goto err_up; + goto err_idr; memset(&resp, 0, sizeof resp); resp.pd_handle = uobj->id; @@ -321,26 +495,27 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } mutex_lock(&file->mutex); list_add_tail(&uobj->list, &file->ucontext->pd_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + uobj->live = 1; + + up_write(&uobj->mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_pd_idr, uobj->id); +err_copy: + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); +err_idr: ib_dealloc_pd(pd); err: - kfree(uobj); + put_uobj_write(uobj); return ret; } @@ -349,37 +524,34 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, int in_len, int out_len) { struct ib_uverbs_dealloc_pd cmd; - struct ib_pd *pd; struct ib_uobject *uobj; - int ret = -EINVAL; + int ret; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); + uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext); + if (!uobj) + return -EINVAL; - pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); - if (!pd || pd->uobject->context != file->ucontext) - goto out; + ret = ib_dealloc_pd(uobj->object); + if (!ret) + uobj->live = 0; - uobj = pd->uobject; + put_uobj_write(uobj); - ret = ib_dealloc_pd(pd); if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); mutex_lock(&file->mutex); list_del(&uobj->list); mutex_unlock(&file->mutex); - kfree(uobj); + put_uobj(uobj); -out: - mutex_unlock(&ib_uverbs_idr_mutex); - - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, @@ -419,7 +591,8 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, if (!obj) return -ENOMEM; - obj->uobject.context = file->ucontext; + init_uobj(&obj->uobject, 0, file->ucontext); + down_write(&obj->uobject.mutex); /* * We ask for writable memory if any access flags other than @@ -436,23 +609,14 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, obj->umem.virt_base = cmd.hca_va; - mutex_lock(&ib_uverbs_idr_mutex); - - pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); - if (!pd || pd->uobject->context != file->ucontext) { - ret = -EINVAL; - goto err_up; - } - - if (!pd->device->reg_user_mr) { - ret = -ENOSYS; - goto err_up; - } + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) + goto err_release; mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); if (IS_ERR(mr)) { ret = PTR_ERR(mr); - goto err_up; + goto err_put; } mr->device = pd->device; @@ -461,43 +625,48 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, atomic_inc(&pd->usecnt); atomic_set(&mr->usecnt, 0); - memset(&resp, 0, sizeof resp); - resp.lkey = mr->lkey; - resp.rkey = mr->rkey; - - ret = idr_add_uobj(&ib_uverbs_mr_idr, mr, &obj->uobject); + obj->uobject.object = mr; + ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uobject); if (ret) goto err_unreg; + memset(&resp, 0, sizeof resp); + resp.lkey = mr->lkey; + resp.rkey = mr->rkey; resp.mr_handle = obj->uobject.id; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } + put_pd_read(pd); + mutex_lock(&file->mutex); list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_mr_idr, obj->uobject.id); +err_copy: + idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uobject); err_unreg: ib_dereg_mr(mr); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); +err_put: + put_pd_read(pd); +err_release: ib_umem_release(file->device->ib_dev, &obj->umem); err_free: - kfree(obj); + put_uobj_write(&obj->uobject); return ret; } @@ -507,37 +676,40 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, { struct ib_uverbs_dereg_mr cmd; struct ib_mr *mr; + struct ib_uobject *uobj; struct ib_umem_object *memobj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - - mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle); - if (!mr || mr->uobject->context != file->ucontext) - goto out; + uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext); + if (!uobj) + return -EINVAL; - memobj = container_of(mr->uobject, struct ib_umem_object, uobject); + memobj = container_of(uobj, struct ib_umem_object, uobject); + mr = uobj->object; ret = ib_dereg_mr(mr); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); + idr_remove_uobj(&ib_uverbs_mr_idr, uobj); mutex_lock(&file->mutex); - list_del(&memobj->uobject.list); + list_del(&uobj->list); mutex_unlock(&file->mutex); ib_umem_release(file->device->ib_dev, &memobj->umem); - kfree(memobj); -out: - mutex_unlock(&ib_uverbs_idr_mutex); + put_uobj(uobj); - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, @@ -576,7 +748,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, struct ib_uverbs_create_cq cmd; struct ib_uverbs_create_cq_resp resp; struct ib_udata udata; - struct ib_ucq_object *uobj; + struct ib_ucq_object *obj; struct ib_uverbs_event_file *ev_file = NULL; struct ib_cq *cq; int ret; @@ -594,10 +766,13 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, if (cmd.comp_vector >= file->device->num_comp_vectors) return -EINVAL; - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); - if (!uobj) + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) return -ENOMEM; + init_uobj(&obj->uobject, cmd.user_handle, file->ucontext); + down_write(&obj->uobject.mutex); + if (cmd.comp_channel >= 0) { ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); if (!ev_file) { @@ -606,63 +781,64 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, } } - uobj->uobject.user_handle = cmd.user_handle; - uobj->uobject.context = file->ucontext; - uobj->uverbs_file = file; - uobj->comp_events_reported = 0; - uobj->async_events_reported = 0; - INIT_LIST_HEAD(&uobj->comp_list); - INIT_LIST_HEAD(&uobj->async_list); + obj->uverbs_file = file; + obj->comp_events_reported = 0; + obj->async_events_reported = 0; + INIT_LIST_HEAD(&obj->comp_list); + INIT_LIST_HEAD(&obj->async_list); cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, file->ucontext, &udata); if (IS_ERR(cq)) { ret = PTR_ERR(cq); - goto err; + goto err_file; } cq->device = file->device->ib_dev; - cq->uobject = &uobj->uobject; + cq->uobject = &obj->uobject; cq->comp_handler = ib_uverbs_comp_handler; cq->event_handler = ib_uverbs_cq_event_handler; cq->cq_context = ev_file; atomic_set(&cq->usecnt, 0); - mutex_lock(&ib_uverbs_idr_mutex); - - ret = idr_add_uobj(&ib_uverbs_cq_idr, cq, &uobj->uobject); + obj->uobject.object = cq; + ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject); if (ret) - goto err_up; + goto err_free; memset(&resp, 0, sizeof resp); - resp.cq_handle = uobj->uobject.id; + resp.cq_handle = obj->uobject.id; resp.cqe = cq->cqe; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } mutex_lock(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); + list_add_tail(&obj->uobject.list, &file->ucontext->cq_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); +err_copy: + idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); + +err_free: ib_destroy_cq(cq); -err: +err_file: if (ev_file) - ib_uverbs_release_ucq(file, ev_file, uobj); - kfree(uobj); + ib_uverbs_release_ucq(file, ev_file, obj); + +err: + put_uobj_write(&obj->uobject); return ret; } @@ -683,11 +859,9 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - mutex_lock(&ib_uverbs_idr_mutex); - - cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); - if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq) - goto out; + cq = idr_read_cq(cmd.cq_handle, file->ucontext); + if (!cq) + return -EINVAL; ret = cq->device->resize_cq(cq, cmd.cqe, &udata); if (ret) @@ -701,7 +875,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, ret = -EFAULT; out: - mutex_unlock(&ib_uverbs_idr_mutex); + put_cq_read(cq); return ret ? ret : in_len; } @@ -712,6 +886,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, { struct ib_uverbs_poll_cq cmd; struct ib_uverbs_poll_cq_resp *resp; + struct ib_uobject *uobj; struct ib_cq *cq; struct ib_wc *wc; int ret = 0; @@ -732,15 +907,17 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, goto out_wc; } - mutex_lock(&ib_uverbs_idr_mutex); - cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); - if (!cq || cq->uobject->context != file->ucontext) { + uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); + if (!uobj) { ret = -EINVAL; goto out; } + cq = uobj->object; resp->count = ib_poll_cq(cq, cmd.ne, wc); + put_uobj_read(uobj); + for (i = 0; i < resp->count; i++) { resp->wc[i].wr_id = wc[i].wr_id; resp->wc[i].status = wc[i].status; @@ -762,7 +939,6 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, ret = -EFAULT; out: - mutex_unlock(&ib_uverbs_idr_mutex); kfree(resp); out_wc: @@ -775,22 +951,23 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, int out_len) { struct ib_uverbs_req_notify_cq cmd; + struct ib_uobject *uobj; struct ib_cq *cq; - int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); - if (cq && cq->uobject->context == file->ucontext) { - ib_req_notify_cq(cq, cmd.solicited_only ? - IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); - ret = in_len; - } - mutex_unlock(&ib_uverbs_idr_mutex); + uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); + if (!uobj) + return -EINVAL; + cq = uobj->object; - return ret; + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); + + put_uobj_read(uobj); + + return in_len; } ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, @@ -799,52 +976,50 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, { struct ib_uverbs_destroy_cq cmd; struct ib_uverbs_destroy_cq_resp resp; + struct ib_uobject *uobj; struct ib_cq *cq; - struct ib_ucq_object *uobj; + struct ib_ucq_object *obj; struct ib_uverbs_event_file *ev_file; - u64 user_handle; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - memset(&resp, 0, sizeof resp); - - mutex_lock(&ib_uverbs_idr_mutex); + uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); + if (!uobj) + return -EINVAL; + cq = uobj->object; + ev_file = cq->cq_context; + obj = container_of(cq->uobject, struct ib_ucq_object, uobject); - cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); - if (!cq || cq->uobject->context != file->ucontext) - goto out; + ret = ib_destroy_cq(cq); + if (!ret) + uobj->live = 0; - user_handle = cq->uobject->user_handle; - uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); - ev_file = cq->cq_context; + put_uobj_write(uobj); - ret = ib_destroy_cq(cq); if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); + idr_remove_uobj(&ib_uverbs_cq_idr, uobj); mutex_lock(&file->mutex); - list_del(&uobj->uobject.list); + list_del(&uobj->list); mutex_unlock(&file->mutex); - ib_uverbs_release_ucq(file, ev_file, uobj); + ib_uverbs_release_ucq(file, ev_file, obj); - resp.comp_events_reported = uobj->comp_events_reported; - resp.async_events_reported = uobj->async_events_reported; + memset(&resp, 0, sizeof resp); + resp.comp_events_reported = obj->comp_events_reported; + resp.async_events_reported = obj->async_events_reported; - kfree(uobj); + put_uobj(uobj); if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) - ret = -EFAULT; - -out: - mutex_unlock(&ib_uverbs_idr_mutex); + return -EFAULT; - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, @@ -854,7 +1029,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, struct ib_uverbs_create_qp cmd; struct ib_uverbs_create_qp_resp resp; struct ib_udata udata; - struct ib_uqp_object *uobj; + struct ib_uqp_object *obj; struct ib_pd *pd; struct ib_cq *scq, *rcq; struct ib_srq *srq; @@ -872,23 +1047,21 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); - if (!uobj) + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) return -ENOMEM; - mutex_lock(&ib_uverbs_idr_mutex); + init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext); + down_write(&obj->uevent.uobject.mutex); - pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); - scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); - rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle); - srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL; + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + scq = idr_read_cq(cmd.send_cq_handle, file->ucontext); + rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext); + srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL; - if (!pd || pd->uobject->context != file->ucontext || - !scq || scq->uobject->context != file->ucontext || - !rcq || rcq->uobject->context != file->ucontext || - (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) { + if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) { ret = -EINVAL; - goto err_up; + goto err_put; } attr.event_handler = ib_uverbs_qp_event_handler; @@ -905,16 +1078,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, attr.cap.max_recv_sge = cmd.max_recv_sge; attr.cap.max_inline_data = cmd.max_inline_data; - uobj->uevent.uobject.user_handle = cmd.user_handle; - uobj->uevent.uobject.context = file->ucontext; - uobj->uevent.events_reported = 0; - INIT_LIST_HEAD(&uobj->uevent.event_list); - INIT_LIST_HEAD(&uobj->mcast_list); + obj->uevent.events_reported = 0; + INIT_LIST_HEAD(&obj->uevent.event_list); + INIT_LIST_HEAD(&obj->mcast_list); qp = pd->device->create_qp(pd, &attr, &udata); if (IS_ERR(qp)) { ret = PTR_ERR(qp); - goto err_up; + goto err_put; } qp->device = pd->device; @@ -922,7 +1093,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, qp->send_cq = attr.send_cq; qp->recv_cq = attr.recv_cq; qp->srq = attr.srq; - qp->uobject = &uobj->uevent.uobject; + qp->uobject = &obj->uevent.uobject; qp->event_handler = attr.event_handler; qp->qp_context = attr.qp_context; qp->qp_type = attr.qp_type; @@ -932,14 +1103,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, if (attr.srq) atomic_inc(&attr.srq->usecnt); - memset(&resp, 0, sizeof resp); - resp.qpn = qp->qp_num; - - ret = idr_add_uobj(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject); + obj->uevent.uobject.object = qp; + ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); if (ret) goto err_destroy; - resp.qp_handle = uobj->uevent.uobject.id; + memset(&resp, 0, sizeof resp); + resp.qpn = qp->qp_num; + resp.qp_handle = obj->uevent.uobject.id; resp.max_recv_sge = attr.cap.max_recv_sge; resp.max_send_sge = attr.cap.max_send_sge; resp.max_recv_wr = attr.cap.max_recv_wr; @@ -949,27 +1120,42 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } + put_pd_read(pd); + put_cq_read(scq); + put_cq_read(rcq); + if (srq) + put_srq_read(srq); + mutex_lock(&file->mutex); - list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list); + list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + obj->uevent.uobject.live = 1; + + up_write(&obj->uevent.uobject.mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id); +err_copy: + idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); err_destroy: ib_destroy_qp(qp); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); - - kfree(uobj); +err_put: + if (pd) + put_pd_read(pd); + if (scq) + put_cq_read(scq); + if (rcq) + put_cq_read(rcq); + if (srq) + put_srq_read(srq); + + put_uobj_write(&obj->uevent.uobject); return ret; } @@ -994,15 +1180,15 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, goto out; } - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (qp && qp->uobject->context == file->ucontext) - ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); - else + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) { ret = -EINVAL; + goto out; + } + + ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); - mutex_unlock(&ib_uverbs_idr_mutex); + put_qp_read(qp); if (ret) goto out; @@ -1089,10 +1275,8 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, if (!attr) return -ENOMEM; - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) { + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) { ret = -EINVAL; goto out; } @@ -1144,13 +1328,15 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; ret = ib_modify_qp(qp, attr, cmd.attr_mask); + + put_qp_read(qp); + if (ret) goto out; ret = in_len; out: - mutex_unlock(&ib_uverbs_idr_mutex); kfree(attr); return ret; @@ -1162,8 +1348,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, { struct ib_uverbs_destroy_qp cmd; struct ib_uverbs_destroy_qp_resp resp; + struct ib_uobject *uobj; struct ib_qp *qp; - struct ib_uqp_object *uobj; + struct ib_uqp_object *obj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1171,43 +1358,43 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, memset(&resp, 0, sizeof resp); - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) - goto out; - - uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext); + if (!uobj) + return -EINVAL; + qp = uobj->object; + obj = container_of(uobj, struct ib_uqp_object, uevent.uobject); - if (!list_empty(&uobj->mcast_list)) { - ret = -EBUSY; - goto out; + if (!list_empty(&obj->mcast_list)) { + put_uobj_write(uobj); + return -EBUSY; } ret = ib_destroy_qp(qp); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); + idr_remove_uobj(&ib_uverbs_qp_idr, uobj); mutex_lock(&file->mutex); - list_del(&uobj->uevent.uobject.list); + list_del(&uobj->list); mutex_unlock(&file->mutex); - ib_uverbs_release_uevent(file, &uobj->uevent); + ib_uverbs_release_uevent(file, &obj->uevent); - resp.events_reported = uobj->uevent.events_reported; + resp.events_reported = obj->uevent.events_reported; - kfree(uobj); + put_uobj(uobj); if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) - ret = -EFAULT; - -out: - mutex_unlock(&ib_uverbs_idr_mutex); + return -EFAULT; - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, @@ -1220,6 +1407,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; struct ib_qp *qp; int i, sg_ind; + int is_ud; ssize_t ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1236,12 +1424,11 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, if (!user_wr) return -ENOMEM; - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) goto out; + is_ud = qp->qp_type == IB_QPT_UD; sg_ind = 0; last = NULL; for (i = 0; i < cmd.wr_count; ++i) { @@ -1249,12 +1436,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, buf + sizeof cmd + i * cmd.wqe_size, cmd.wqe_size)) { ret = -EFAULT; - goto out; + goto out_put; } if (user_wr->num_sge + sg_ind > cmd.sge_count) { ret = -EINVAL; - goto out; + goto out_put; } next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + @@ -1262,7 +1449,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, GFP_KERNEL); if (!next) { ret = -ENOMEM; - goto out; + goto out_put; } if (!last) @@ -1278,12 +1465,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, next->send_flags = user_wr->send_flags; next->imm_data = (__be32 __force) user_wr->imm_data; - if (qp->qp_type == IB_QPT_UD) { - next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, - user_wr->wr.ud.ah); + if (is_ud) { + next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, + file->ucontext); if (!next->wr.ud.ah) { ret = -EINVAL; - goto out; + goto out_put; } next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; @@ -1320,7 +1507,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, sg_ind * sizeof (struct ib_sge), next->num_sge * sizeof (struct ib_sge))) { ret = -EFAULT; - goto out; + goto out_put; } sg_ind += next->num_sge; } else @@ -1340,10 +1527,13 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, &resp, sizeof resp)) ret = -EFAULT; -out: - mutex_unlock(&ib_uverbs_idr_mutex); +out_put: + put_qp_read(qp); +out: while (wr) { + if (is_ud && wr->wr.ud.ah) + put_ah_read(wr->wr.ud.ah); next = wr->next; kfree(wr); wr = next; @@ -1458,14 +1648,15 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, if (IS_ERR(wr)) return PTR_ERR(wr); - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) goto out; resp.bad_wr = 0; ret = qp->device->post_recv(qp, wr, &bad_wr); + + put_qp_read(qp); + if (ret) for (next = wr; next; next = next->next) { ++resp.bad_wr; @@ -1479,8 +1670,6 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, ret = -EFAULT; out: - mutex_unlock(&ib_uverbs_idr_mutex); - while (wr) { next = wr->next; kfree(wr); @@ -1509,14 +1698,15 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, if (IS_ERR(wr)) return PTR_ERR(wr); - mutex_lock(&ib_uverbs_idr_mutex); - - srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); - if (!srq || srq->uobject->context != file->ucontext) + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) goto out; resp.bad_wr = 0; ret = srq->device->post_srq_recv(srq, wr, &bad_wr); + + put_srq_read(srq); + if (ret) for (next = wr; next; next = next->next) { ++resp.bad_wr; @@ -1530,8 +1720,6 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, ret = -EFAULT; out: - mutex_unlock(&ib_uverbs_idr_mutex); - while (wr) { next = wr->next; kfree(wr); @@ -1563,17 +1751,15 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, if (!uobj) return -ENOMEM; - mutex_lock(&ib_uverbs_idr_mutex); + init_uobj(uobj, cmd.user_handle, file->ucontext); + down_write(&uobj->mutex); - pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); - if (!pd || pd->uobject->context != file->ucontext) { + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { ret = -EINVAL; - goto err_up; + goto err; } - uobj->user_handle = cmd.user_handle; - uobj->context = file->ucontext; - attr.dlid = cmd.attr.dlid; attr.sl = cmd.attr.sl; attr.src_path_bits = cmd.attr.src_path_bits; @@ -1589,12 +1775,13 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, ah = ib_create_ah(pd, &attr); if (IS_ERR(ah)) { ret = PTR_ERR(ah); - goto err_up; + goto err; } - ah->uobject = uobj; + ah->uobject = uobj; + uobj->object = ah; - ret = idr_add_uobj(&ib_uverbs_ah_idr, ah, uobj); + ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj); if (ret) goto err_destroy; @@ -1603,27 +1790,29 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } + put_pd_read(pd); + mutex_lock(&file->mutex); list_add_tail(&uobj->list, &file->ucontext->ah_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + uobj->live = 1; + + up_write(&uobj->mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_ah_idr, uobj->id); +err_copy: + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); err_destroy: ib_destroy_ah(ah); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); - - kfree(uobj); +err: + put_uobj_write(uobj); return ret; } @@ -1633,35 +1822,34 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, struct ib_uverbs_destroy_ah cmd; struct ib_ah *ah; struct ib_uobject *uobj; - int ret = -EINVAL; + int ret; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); + uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext); + if (!uobj) + return -EINVAL; + ah = uobj->object; - ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle); - if (!ah || ah->uobject->context != file->ucontext) - goto out; + ret = ib_destroy_ah(ah); + if (!ret) + uobj->live = 0; - uobj = ah->uobject; + put_uobj_write(uobj); - ret = ib_destroy_ah(ah); if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle); + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); mutex_lock(&file->mutex); list_del(&uobj->list); mutex_unlock(&file->mutex); - kfree(uobj); + put_uobj(uobj); -out: - mutex_unlock(&ib_uverbs_idr_mutex); - - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, @@ -1670,47 +1858,43 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, { struct ib_uverbs_attach_mcast cmd; struct ib_qp *qp; - struct ib_uqp_object *uobj; + struct ib_uqp_object *obj; struct ib_uverbs_mcast_entry *mcast; - int ret = -EINVAL; + int ret; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) - goto out; + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + return -EINVAL; - uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); - list_for_each_entry(mcast, &uobj->mcast_list, list) + list_for_each_entry(mcast, &obj->mcast_list, list) if (cmd.mlid == mcast->lid && !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { ret = 0; - goto out; + goto out_put; } mcast = kmalloc(sizeof *mcast, GFP_KERNEL); if (!mcast) { ret = -ENOMEM; - goto out; + goto out_put; } mcast->lid = cmd.mlid; memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); - if (!ret) { - uobj = container_of(qp->uobject, struct ib_uqp_object, - uevent.uobject); - list_add_tail(&mcast->list, &uobj->mcast_list); - } else + if (!ret) + list_add_tail(&mcast->list, &obj->mcast_list); + else kfree(mcast); -out: - mutex_unlock(&ib_uverbs_idr_mutex); +out_put: + put_qp_read(qp); return ret ? ret : in_len; } @@ -1720,7 +1904,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, int out_len) { struct ib_uverbs_detach_mcast cmd; - struct ib_uqp_object *uobj; + struct ib_uqp_object *obj; struct ib_qp *qp; struct ib_uverbs_mcast_entry *mcast; int ret = -EINVAL; @@ -1728,19 +1912,17 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - - qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (!qp || qp->uobject->context != file->ucontext) - goto out; + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + return -EINVAL; ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); if (ret) - goto out; + goto out_put; - uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); - list_for_each_entry(mcast, &uobj->mcast_list, list) + list_for_each_entry(mcast, &obj->mcast_list, list) if (cmd.mlid == mcast->lid && !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { list_del(&mcast->list); @@ -1748,8 +1930,8 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, break; } -out: - mutex_unlock(&ib_uverbs_idr_mutex); +out_put: + put_qp_read(qp); return ret ? ret : in_len; } @@ -1761,7 +1943,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, struct ib_uverbs_create_srq cmd; struct ib_uverbs_create_srq_resp resp; struct ib_udata udata; - struct ib_uevent_object *uobj; + struct ib_uevent_object *obj; struct ib_pd *pd; struct ib_srq *srq; struct ib_srq_init_attr attr; @@ -1777,17 +1959,17 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); - if (!uobj) + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) return -ENOMEM; - mutex_lock(&ib_uverbs_idr_mutex); - - pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + init_uobj(&obj->uobject, 0, file->ucontext); + down_write(&obj->uobject.mutex); - if (!pd || pd->uobject->context != file->ucontext) { + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { ret = -EINVAL; - goto err_up; + goto err; } attr.event_handler = ib_uverbs_srq_event_handler; @@ -1796,59 +1978,59 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, attr.attr.max_sge = cmd.max_sge; attr.attr.srq_limit = cmd.srq_limit; - uobj->uobject.user_handle = cmd.user_handle; - uobj->uobject.context = file->ucontext; - uobj->events_reported = 0; - INIT_LIST_HEAD(&uobj->event_list); + obj->events_reported = 0; + INIT_LIST_HEAD(&obj->event_list); srq = pd->device->create_srq(pd, &attr, &udata); if (IS_ERR(srq)) { ret = PTR_ERR(srq); - goto err_up; + goto err; } srq->device = pd->device; srq->pd = pd; - srq->uobject = &uobj->uobject; + srq->uobject = &obj->uobject; srq->event_handler = attr.event_handler; srq->srq_context = attr.srq_context; atomic_inc(&pd->usecnt); atomic_set(&srq->usecnt, 0); - memset(&resp, 0, sizeof resp); - - ret = idr_add_uobj(&ib_uverbs_srq_idr, srq, &uobj->uobject); + obj->uobject.object = srq; + ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); if (ret) goto err_destroy; - resp.srq_handle = uobj->uobject.id; + memset(&resp, 0, sizeof resp); + resp.srq_handle = obj->uobject.id; resp.max_wr = attr.attr.max_wr; resp.max_sge = attr.attr.max_sge; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_idr; + goto err_copy; } + put_pd_read(pd); + mutex_lock(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); + list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); mutex_unlock(&file->mutex); - mutex_unlock(&ib_uverbs_idr_mutex); + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); return in_len; -err_idr: - idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id); +err_copy: + idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); err_destroy: ib_destroy_srq(srq); -err_up: - mutex_unlock(&ib_uverbs_idr_mutex); - - kfree(uobj); +err: + put_uobj_write(&obj->uobject); return ret; } @@ -1864,21 +2046,16 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - - srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); - if (!srq || srq->uobject->context != file->ucontext) { - ret = -EINVAL; - goto out; - } + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) + return -EINVAL; attr.max_wr = cmd.max_wr; attr.srq_limit = cmd.srq_limit; ret = ib_modify_srq(srq, &attr, cmd.attr_mask); -out: - mutex_unlock(&ib_uverbs_idr_mutex); + put_srq_read(srq); return ret ? ret : in_len; } @@ -1899,18 +2076,16 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) + return -EINVAL; - srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); - if (srq && srq->uobject->context == file->ucontext) - ret = ib_query_srq(srq, &attr); - else - ret = -EINVAL; + ret = ib_query_srq(srq, &attr); - mutex_unlock(&ib_uverbs_idr_mutex); + put_srq_read(srq); if (ret) - goto out; + return ret; memset(&resp, 0, sizeof resp); @@ -1920,10 +2095,9 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) - ret = -EFAULT; + return -EFAULT; -out: - return ret ? ret : in_len; + return in_len; } ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, @@ -1932,45 +2106,45 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, { struct ib_uverbs_destroy_srq cmd; struct ib_uverbs_destroy_srq_resp resp; + struct ib_uobject *uobj; struct ib_srq *srq; - struct ib_uevent_object *uobj; + struct ib_uevent_object *obj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - mutex_lock(&ib_uverbs_idr_mutex); - - memset(&resp, 0, sizeof resp); + uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext); + if (!uobj) + return -EINVAL; + srq = uobj->object; + obj = container_of(uobj, struct ib_uevent_object, uobject); - srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); - if (!srq || srq->uobject->context != file->ucontext) - goto out; + ret = ib_destroy_srq(srq); + if (!ret) + uobj->live = 0; - uobj = container_of(srq->uobject, struct ib_uevent_object, uobject); + put_uobj_write(uobj); - ret = ib_destroy_srq(srq); if (ret) - goto out; + return ret; - idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); + idr_remove_uobj(&ib_uverbs_srq_idr, uobj); mutex_lock(&file->mutex); - list_del(&uobj->uobject.list); + list_del(&uobj->list); mutex_unlock(&file->mutex); - ib_uverbs_release_uevent(file, uobj); + ib_uverbs_release_uevent(file, obj); - resp.events_reported = uobj->events_reported; + memset(&resp, 0, sizeof resp); + resp.events_reported = obj->events_reported; - kfree(uobj); + put_uobj(uobj); if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) ret = -EFAULT; -out: - mutex_unlock(&ib_uverbs_idr_mutex); - return ret ? ret : in_len; } diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index ff092a0a94da..5ec2d49e9bb6 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -66,7 +66,7 @@ enum { static struct class *uverbs_class; -DEFINE_MUTEX(ib_uverbs_idr_mutex); +DEFINE_SPINLOCK(ib_uverbs_idr_lock); DEFINE_IDR(ib_uverbs_pd_idr); DEFINE_IDR(ib_uverbs_mr_idr); DEFINE_IDR(ib_uverbs_mw_idr); @@ -183,21 +183,21 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, if (!context) return 0; - mutex_lock(&ib_uverbs_idr_mutex); - list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { - struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); - idr_remove(&ib_uverbs_ah_idr, uobj->id); + struct ib_ah *ah = uobj->object; + + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); ib_destroy_ah(ah); list_del(&uobj->list); kfree(uobj); } list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { - struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); + struct ib_qp *qp = uobj->object; struct ib_uqp_object *uqp = container_of(uobj, struct ib_uqp_object, uevent.uobject); - idr_remove(&ib_uverbs_qp_idr, uobj->id); + + idr_remove_uobj(&ib_uverbs_qp_idr, uobj); ib_uverbs_detach_umcast(qp, uqp); ib_destroy_qp(qp); list_del(&uobj->list); @@ -206,11 +206,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { - struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); + struct ib_cq *cq = uobj->object; struct ib_uverbs_event_file *ev_file = cq->cq_context; struct ib_ucq_object *ucq = container_of(uobj, struct ib_ucq_object, uobject); - idr_remove(&ib_uverbs_cq_idr, uobj->id); + + idr_remove_uobj(&ib_uverbs_cq_idr, uobj); ib_destroy_cq(cq); list_del(&uobj->list); ib_uverbs_release_ucq(file, ev_file, ucq); @@ -218,10 +219,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, } list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { - struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); + struct ib_srq *srq = uobj->object; struct ib_uevent_object *uevent = container_of(uobj, struct ib_uevent_object, uobject); - idr_remove(&ib_uverbs_srq_idr, uobj->id); + + idr_remove_uobj(&ib_uverbs_srq_idr, uobj); ib_destroy_srq(srq); list_del(&uobj->list); ib_uverbs_release_uevent(file, uevent); @@ -231,11 +233,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, /* XXX Free MWs */ list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { - struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); + struct ib_mr *mr = uobj->object; struct ib_device *mrdev = mr->device; struct ib_umem_object *memobj; - idr_remove(&ib_uverbs_mr_idr, uobj->id); + idr_remove_uobj(&ib_uverbs_mr_idr, uobj); ib_dereg_mr(mr); memobj = container_of(uobj, struct ib_umem_object, uobject); @@ -246,15 +248,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, } list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { - struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id); - idr_remove(&ib_uverbs_pd_idr, uobj->id); + struct ib_pd *pd = uobj->object; + + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); ib_dealloc_pd(pd); list_del(&uobj->list); kfree(uobj); } - mutex_unlock(&ib_uverbs_idr_mutex); - return context->device->dealloc_ucontext(context); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 7ced208edacf..ee1f3a355666 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -697,8 +697,12 @@ struct ib_ucontext { struct ib_uobject { u64 user_handle; /* handle given to us by userspace */ struct ib_ucontext *context; /* associated user context */ + void *object; /* containing object */ struct list_head list; /* link to context's list */ u32 id; /* index into kernel idr */ + struct kref ref; + struct rw_semaphore mutex; /* protects .live */ + int live; }; struct ib_umem { -- cgit v1.2.3 From c13c8260da3155f2cefb63b0d1b7dcdcb405c644 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 17:18:44 -0700 Subject: [I/OAT]: DMA memcpy subsystem Provides an API for offloading memory copies to DMA devices Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/dma/Kconfig | 13 ++ drivers/dma/Makefile | 1 + drivers/dma/dmaengine.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dmaengine.h | 337 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 762 insertions(+) create mode 100644 drivers/dma/Kconfig create mode 100644 drivers/dma/Makefile create mode 100644 drivers/dma/dmaengine.c create mode 100644 include/linux/dmaengine.h (limited to 'include') diff --git a/drivers/Kconfig b/drivers/Kconfig index aeb5ab2391e4..8b11cebe65df 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -72,4 +72,6 @@ source "drivers/edac/Kconfig" source "drivers/rtc/Kconfig" +source "drivers/dma/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 447d8e68887a..3c5170310bd0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -74,3 +74,4 @@ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ +obj-$(CONFIG_DMA_ENGINE) += dma/ diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig new file mode 100644 index 000000000000..f9ac4bcf8652 --- /dev/null +++ b/drivers/dma/Kconfig @@ -0,0 +1,13 @@ +# +# DMA engine configuration +# + +menu "DMA Engine support" + +config DMA_ENGINE + bool "Support for DMA engines" + ---help--- + DMA engines offload copy operations from the CPU to dedicated + hardware, allowing the copies to happen asynchronously. + +endmenu diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile new file mode 100644 index 000000000000..10b739138c93 --- /dev/null +++ b/drivers/dma/Makefile @@ -0,0 +1 @@ +obj-y += dmaengine.o diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c new file mode 100644 index 000000000000..473c47b6f094 --- /dev/null +++ b/drivers/dma/dmaengine.c @@ -0,0 +1,408 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ + +/* + * This code implements the DMA subsystem. It provides a HW-neutral interface + * for other kernel code to use asynchronous memory copy capabilities, + * if present, and allows different HW DMA drivers to register as providing + * this capability. + * + * Due to the fact we are accelerating what is already a relatively fast + * operation, the code goes to great lengths to avoid additional overhead, + * such as locking. + * + * LOCKING: + * + * The subsystem keeps two global lists, dma_device_list and dma_client_list. + * Both of these are protected by a mutex, dma_list_mutex. + * + * Each device has a channels list, which runs unlocked but is never modified + * once the device is registered, it's just setup by the driver. + * + * Each client has a channels list, it's only modified under the client->lock + * and in an RCU callback, so it's safe to read under rcu_read_lock(). + * + * Each device has a kref, which is initialized to 1 when the device is + * registered. A kref_put is done for each class_device registered. When the + * class_device is released, the coresponding kref_put is done in the release + * method. Every time one of the device's channels is allocated to a client, + * a kref_get occurs. When the channel is freed, the coresponding kref_put + * happens. The device's release function does a completion, so + * unregister_device does a remove event, class_device_unregister, a kref_put + * for the first reference, then waits on the completion for all other + * references to finish. + * + * Each channel has an open-coded implementation of Rusty Russell's "bigref," + * with a kref and a per_cpu local_t. A single reference is set when on an + * ADDED event, and removed with a REMOVE event. Net DMA client takes an + * extra reference per outstanding transaction. The relase function does a + * kref_put on the device. -ChrisL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(dma_list_mutex); +static LIST_HEAD(dma_device_list); +static LIST_HEAD(dma_client_list); + +/* --- sysfs implementation --- */ + +static ssize_t show_memcpy_count(struct class_device *cd, char *buf) +{ + struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + unsigned long count = 0; + int i; + + for_each_cpu(i) + count += per_cpu_ptr(chan->local, i)->memcpy_count; + + return sprintf(buf, "%lu\n", count); +} + +static ssize_t show_bytes_transferred(struct class_device *cd, char *buf) +{ + struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + unsigned long count = 0; + int i; + + for_each_cpu(i) + count += per_cpu_ptr(chan->local, i)->bytes_transferred; + + return sprintf(buf, "%lu\n", count); +} + +static ssize_t show_in_use(struct class_device *cd, char *buf) +{ + struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + + return sprintf(buf, "%d\n", (chan->client ? 1 : 0)); +} + +static struct class_device_attribute dma_class_attrs[] = { + __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL), + __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL), + __ATTR(in_use, S_IRUGO, show_in_use, NULL), + __ATTR_NULL +}; + +static void dma_async_device_cleanup(struct kref *kref); + +static void dma_class_dev_release(struct class_device *cd) +{ + struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + kref_put(&chan->device->refcount, dma_async_device_cleanup); +} + +static struct class dma_devclass = { + .name = "dma", + .class_dev_attrs = dma_class_attrs, + .release = dma_class_dev_release, +}; + +/* --- client and device registration --- */ + +/** + * dma_client_chan_alloc - try to allocate a channel to a client + * @client: &dma_client + * + * Called with dma_list_mutex held. + */ +static struct dma_chan *dma_client_chan_alloc(struct dma_client *client) +{ + struct dma_device *device; + struct dma_chan *chan; + unsigned long flags; + int desc; /* allocated descriptor count */ + + /* Find a channel, any DMA engine will do */ + list_for_each_entry(device, &dma_device_list, global_node) { + list_for_each_entry(chan, &device->channels, device_node) { + if (chan->client) + continue; + + desc = chan->device->device_alloc_chan_resources(chan); + if (desc >= 0) { + kref_get(&device->refcount); + kref_init(&chan->refcount); + chan->slow_ref = 0; + INIT_RCU_HEAD(&chan->rcu); + chan->client = client; + spin_lock_irqsave(&client->lock, flags); + list_add_tail_rcu(&chan->client_node, + &client->channels); + spin_unlock_irqrestore(&client->lock, flags); + return chan; + } + } + } + + return NULL; +} + +/** + * dma_client_chan_free - release a DMA channel + * @chan: &dma_chan + */ +void dma_chan_cleanup(struct kref *kref) +{ + struct dma_chan *chan = container_of(kref, struct dma_chan, refcount); + chan->device->device_free_chan_resources(chan); + chan->client = NULL; + kref_put(&chan->device->refcount, dma_async_device_cleanup); +} + +static void dma_chan_free_rcu(struct rcu_head *rcu) +{ + struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu); + int bias = 0x7FFFFFFF; + int i; + for_each_cpu(i) + bias -= local_read(&per_cpu_ptr(chan->local, i)->refcount); + atomic_sub(bias, &chan->refcount.refcount); + kref_put(&chan->refcount, dma_chan_cleanup); +} + +static void dma_client_chan_free(struct dma_chan *chan) +{ + atomic_add(0x7FFFFFFF, &chan->refcount.refcount); + chan->slow_ref = 1; + call_rcu(&chan->rcu, dma_chan_free_rcu); +} + +/** + * dma_chans_rebalance - reallocate channels to clients + * + * When the number of DMA channel in the system changes, + * channels need to be rebalanced among clients + */ +static void dma_chans_rebalance(void) +{ + struct dma_client *client; + struct dma_chan *chan; + unsigned long flags; + + mutex_lock(&dma_list_mutex); + + list_for_each_entry(client, &dma_client_list, global_node) { + while (client->chans_desired > client->chan_count) { + chan = dma_client_chan_alloc(client); + if (!chan) + break; + client->chan_count++; + client->event_callback(client, + chan, + DMA_RESOURCE_ADDED); + } + while (client->chans_desired < client->chan_count) { + spin_lock_irqsave(&client->lock, flags); + chan = list_entry(client->channels.next, + struct dma_chan, + client_node); + list_del_rcu(&chan->client_node); + spin_unlock_irqrestore(&client->lock, flags); + client->chan_count--; + client->event_callback(client, + chan, + DMA_RESOURCE_REMOVED); + dma_client_chan_free(chan); + } + } + + mutex_unlock(&dma_list_mutex); +} + +/** + * dma_async_client_register - allocate and register a &dma_client + * @event_callback: callback for notification of channel addition/removal + */ +struct dma_client *dma_async_client_register(dma_event_callback event_callback) +{ + struct dma_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return NULL; + + INIT_LIST_HEAD(&client->channels); + spin_lock_init(&client->lock); + client->chans_desired = 0; + client->chan_count = 0; + client->event_callback = event_callback; + + mutex_lock(&dma_list_mutex); + list_add_tail(&client->global_node, &dma_client_list); + mutex_unlock(&dma_list_mutex); + + return client; +} + +/** + * dma_async_client_unregister - unregister a client and free the &dma_client + * @client: + * + * Force frees any allocated DMA channels, frees the &dma_client memory + */ +void dma_async_client_unregister(struct dma_client *client) +{ + struct dma_chan *chan; + + if (!client) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(chan, &client->channels, client_node) + dma_client_chan_free(chan); + rcu_read_unlock(); + + mutex_lock(&dma_list_mutex); + list_del(&client->global_node); + mutex_unlock(&dma_list_mutex); + + kfree(client); + dma_chans_rebalance(); +} + +/** + * dma_async_client_chan_request - request DMA channels + * @client: &dma_client + * @number: count of DMA channels requested + * + * Clients call dma_async_client_chan_request() to specify how many + * DMA channels they need, 0 to free all currently allocated. + * The resulting allocations/frees are indicated to the client via the + * event callback. + */ +void dma_async_client_chan_request(struct dma_client *client, + unsigned int number) +{ + client->chans_desired = number; + dma_chans_rebalance(); +} + +/** + * dma_async_device_register - + * @device: &dma_device + */ +int dma_async_device_register(struct dma_device *device) +{ + static int id; + int chancnt = 0; + struct dma_chan* chan; + + if (!device) + return -ENODEV; + + init_completion(&device->done); + kref_init(&device->refcount); + device->dev_id = id++; + + /* represent channels in sysfs. Probably want devs too */ + list_for_each_entry(chan, &device->channels, device_node) { + chan->local = alloc_percpu(typeof(*chan->local)); + if (chan->local == NULL) + continue; + + chan->chan_id = chancnt++; + chan->class_dev.class = &dma_devclass; + chan->class_dev.dev = NULL; + snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d", + device->dev_id, chan->chan_id); + + kref_get(&device->refcount); + class_device_register(&chan->class_dev); + } + + mutex_lock(&dma_list_mutex); + list_add_tail(&device->global_node, &dma_device_list); + mutex_unlock(&dma_list_mutex); + + dma_chans_rebalance(); + + return 0; +} + +/** + * dma_async_device_unregister - + * @device: &dma_device + */ +static void dma_async_device_cleanup(struct kref *kref) +{ + struct dma_device *device; + + device = container_of(kref, struct dma_device, refcount); + complete(&device->done); +} + +void dma_async_device_unregister(struct dma_device* device) +{ + struct dma_chan *chan; + unsigned long flags; + + mutex_lock(&dma_list_mutex); + list_del(&device->global_node); + mutex_unlock(&dma_list_mutex); + + list_for_each_entry(chan, &device->channels, device_node) { + if (chan->client) { + spin_lock_irqsave(&chan->client->lock, flags); + list_del(&chan->client_node); + chan->client->chan_count--; + spin_unlock_irqrestore(&chan->client->lock, flags); + chan->client->event_callback(chan->client, + chan, + DMA_RESOURCE_REMOVED); + dma_client_chan_free(chan); + } + class_device_unregister(&chan->class_dev); + } + dma_chans_rebalance(); + + kref_put(&device->refcount, dma_async_device_cleanup); + wait_for_completion(&device->done); +} + +static int __init dma_bus_init(void) +{ + mutex_init(&dma_list_mutex); + return class_register(&dma_devclass); +} + +subsys_initcall(dma_bus_init); + +EXPORT_SYMBOL(dma_async_client_register); +EXPORT_SYMBOL(dma_async_client_unregister); +EXPORT_SYMBOL(dma_async_client_chan_request); +EXPORT_SYMBOL(dma_async_memcpy_buf_to_buf); +EXPORT_SYMBOL(dma_async_memcpy_buf_to_pg); +EXPORT_SYMBOL(dma_async_memcpy_pg_to_pg); +EXPORT_SYMBOL(dma_async_memcpy_complete); +EXPORT_SYMBOL(dma_async_memcpy_issue_pending); +EXPORT_SYMBOL(dma_async_device_register); +EXPORT_SYMBOL(dma_async_device_unregister); +EXPORT_SYMBOL(dma_chan_cleanup); diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h new file mode 100644 index 000000000000..30781546ac99 --- /dev/null +++ b/include/linux/dmaengine.h @@ -0,0 +1,337 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ +#ifndef DMAENGINE_H +#define DMAENGINE_H +#include +#ifdef CONFIG_DMA_ENGINE + +#include +#include +#include +#include +#include + +/** + * enum dma_event - resource PNP/power managment events + * @DMA_RESOURCE_SUSPEND: DMA device going into low power state + * @DMA_RESOURCE_RESUME: DMA device returning to full power + * @DMA_RESOURCE_ADDED: DMA device added to the system + * @DMA_RESOURCE_REMOVED: DMA device removed from the system + */ +enum dma_event { + DMA_RESOURCE_SUSPEND, + DMA_RESOURCE_RESUME, + DMA_RESOURCE_ADDED, + DMA_RESOURCE_REMOVED, +}; + +/** + * typedef dma_cookie_t + * + * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code + */ +typedef s32 dma_cookie_t; + +#define dma_submit_error(cookie) ((cookie) < 0 ? 1 : 0) + +/** + * enum dma_status - DMA transaction status + * @DMA_SUCCESS: transaction completed successfully + * @DMA_IN_PROGRESS: transaction not yet processed + * @DMA_ERROR: transaction failed + */ +enum dma_status { + DMA_SUCCESS, + DMA_IN_PROGRESS, + DMA_ERROR, +}; + +/** + * struct dma_chan_percpu - the per-CPU part of struct dma_chan + * @refcount: local_t used for open-coded "bigref" counting + * @memcpy_count: transaction counter + * @bytes_transferred: byte counter + */ + +struct dma_chan_percpu { + local_t refcount; + /* stats */ + unsigned long memcpy_count; + unsigned long bytes_transferred; +}; + +/** + * struct dma_chan - devices supply DMA channels, clients use them + * @client: ptr to the client user of this chan, will be NULL when unused + * @device: ptr to the dma device who supplies this channel, always !NULL + * @cookie: last cookie value returned to client + * @chan_id: + * @class_dev: + * @refcount: kref, used in "bigref" slow-mode + * @slow_ref: + * @rcu: + * @client_node: used to add this to the client chan list + * @device_node: used to add this to the device chan list + * @local: per-cpu pointer to a struct dma_chan_percpu + */ +struct dma_chan { + struct dma_client *client; + struct dma_device *device; + dma_cookie_t cookie; + + /* sysfs */ + int chan_id; + struct class_device class_dev; + + struct kref refcount; + int slow_ref; + struct rcu_head rcu; + + struct list_head client_node; + struct list_head device_node; + struct dma_chan_percpu *local; +}; + +void dma_chan_cleanup(struct kref *kref); + +static inline void dma_chan_get(struct dma_chan *chan) +{ + if (unlikely(chan->slow_ref)) + kref_get(&chan->refcount); + else { + local_inc(&(per_cpu_ptr(chan->local, get_cpu())->refcount)); + put_cpu(); + } +} + +static inline void dma_chan_put(struct dma_chan *chan) +{ + if (unlikely(chan->slow_ref)) + kref_put(&chan->refcount, dma_chan_cleanup); + else { + local_dec(&(per_cpu_ptr(chan->local, get_cpu())->refcount)); + put_cpu(); + } +} + +/* + * typedef dma_event_callback - function pointer to a DMA event callback + */ +typedef void (*dma_event_callback) (struct dma_client *client, + struct dma_chan *chan, enum dma_event event); + +/** + * struct dma_client - info on the entity making use of DMA services + * @event_callback: func ptr to call when something happens + * @chan_count: number of chans allocated + * @chans_desired: number of chans requested. Can be +/- chan_count + * @lock: protects access to the channels list + * @channels: the list of DMA channels allocated + * @global_node: list_head for global dma_client_list + */ +struct dma_client { + dma_event_callback event_callback; + unsigned int chan_count; + unsigned int chans_desired; + + spinlock_t lock; + struct list_head channels; + struct list_head global_node; +}; + +/** + * struct dma_device - info on the entity supplying DMA services + * @chancnt: how many DMA channels are supported + * @channels: the list of struct dma_chan + * @global_node: list_head for global dma_device_list + * @refcount: + * @done: + * @dev_id: + * Other func ptrs: used to make use of this device's capabilities + */ +struct dma_device { + + unsigned int chancnt; + struct list_head channels; + struct list_head global_node; + + struct kref refcount; + struct completion done; + + int dev_id; + + int (*device_alloc_chan_resources)(struct dma_chan *chan); + void (*device_free_chan_resources)(struct dma_chan *chan); + dma_cookie_t (*device_memcpy_buf_to_buf)(struct dma_chan *chan, + void *dest, void *src, size_t len); + dma_cookie_t (*device_memcpy_buf_to_pg)(struct dma_chan *chan, + struct page *page, unsigned int offset, void *kdata, + size_t len); + dma_cookie_t (*device_memcpy_pg_to_pg)(struct dma_chan *chan, + struct page *dest_pg, unsigned int dest_off, + struct page *src_pg, unsigned int src_off, size_t len); + enum dma_status (*device_memcpy_complete)(struct dma_chan *chan, + dma_cookie_t cookie, dma_cookie_t *last, + dma_cookie_t *used); + void (*device_memcpy_issue_pending)(struct dma_chan *chan); +}; + +/* --- public DMA engine API --- */ + +struct dma_client *dma_async_client_register(dma_event_callback event_callback); +void dma_async_client_unregister(struct dma_client *client); +void dma_async_client_chan_request(struct dma_client *client, + unsigned int number); + +/** + * dma_async_memcpy_buf_to_buf - offloaded copy between virtual addresses + * @chan: DMA channel to offload copy to + * @dest: destination address (virtual) + * @src: source address (virtual) + * @len: length + * + * Both @dest and @src must be mappable to a bus address according to the + * DMA mapping API rules for streaming mappings. + * Both @dest and @src must stay memory resident (kernel memory or locked + * user space pages) + */ +static inline dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan, + void *dest, void *src, size_t len) +{ + int cpu = get_cpu(); + per_cpu_ptr(chan->local, cpu)->bytes_transferred += len; + per_cpu_ptr(chan->local, cpu)->memcpy_count++; + put_cpu(); + + return chan->device->device_memcpy_buf_to_buf(chan, dest, src, len); +} + +/** + * dma_async_memcpy_buf_to_pg - offloaded copy + * @chan: DMA channel to offload copy to + * @page: destination page + * @offset: offset in page to copy to + * @kdata: source address (virtual) + * @len: length + * + * Both @page/@offset and @kdata must be mappable to a bus address according + * to the DMA mapping API rules for streaming mappings. + * Both @page/@offset and @kdata must stay memory resident (kernel memory or + * locked user space pages) + */ +static inline dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan, + struct page *page, unsigned int offset, void *kdata, size_t len) +{ + int cpu = get_cpu(); + per_cpu_ptr(chan->local, cpu)->bytes_transferred += len; + per_cpu_ptr(chan->local, cpu)->memcpy_count++; + put_cpu(); + + return chan->device->device_memcpy_buf_to_pg(chan, page, offset, + kdata, len); +} + +/** + * dma_async_memcpy_buf_to_pg - offloaded copy + * @chan: DMA channel to offload copy to + * @dest_page: destination page + * @dest_off: offset in page to copy to + * @src_page: source page + * @src_off: offset in page to copy from + * @len: length + * + * Both @dest_page/@dest_off and @src_page/@src_off must be mappable to a bus + * address according to the DMA mapping API rules for streaming mappings. + * Both @dest_page/@dest_off and @src_page/@src_off must stay memory resident + * (kernel memory or locked user space pages) + */ +static inline dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan, + struct page *dest_pg, unsigned int dest_off, struct page *src_pg, + unsigned int src_off, size_t len) +{ + int cpu = get_cpu(); + per_cpu_ptr(chan->local, cpu)->bytes_transferred += len; + per_cpu_ptr(chan->local, cpu)->memcpy_count++; + put_cpu(); + + return chan->device->device_memcpy_pg_to_pg(chan, dest_pg, dest_off, + src_pg, src_off, len); +} + +/** + * dma_async_memcpy_issue_pending - flush pending copies to HW + * @chan: + * + * This allows drivers to push copies to HW in batches, + * reducing MMIO writes where possible. + */ +static inline void dma_async_memcpy_issue_pending(struct dma_chan *chan) +{ + return chan->device->device_memcpy_issue_pending(chan); +} + +/** + * dma_async_memcpy_complete - poll for transaction completion + * @chan: DMA channel + * @cookie: transaction identifier to check status of + * @last: returns last completed cookie, can be NULL + * @used: returns last issued cookie, can be NULL + * + * If @last and @used are passed in, upon return they reflect the driver + * internal state and can be used with dma_async_is_complete() to check + * the status of multiple cookies without re-checking hardware state. + */ +static inline enum dma_status dma_async_memcpy_complete(struct dma_chan *chan, + dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used) +{ + return chan->device->device_memcpy_complete(chan, cookie, last, used); +} + +/** + * dma_async_is_complete - test a cookie against chan state + * @cookie: transaction identifier to test status of + * @last_complete: last know completed transaction + * @last_used: last cookie value handed out + * + * dma_async_is_complete() is used in dma_async_memcpy_complete() + * the test logic is seperated for lightweight testing of multiple cookies + */ +static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie, + dma_cookie_t last_complete, dma_cookie_t last_used) +{ + if (last_complete <= last_used) { + if ((cookie <= last_complete) || (cookie > last_used)) + return DMA_SUCCESS; + } else { + if ((cookie <= last_complete) && (cookie > last_used)) + return DMA_SUCCESS; + } + return DMA_IN_PROGRESS; +} + + +/* --- DMA device --- */ + +int dma_async_device_register(struct dma_device *device); +void dma_async_device_unregister(struct dma_device *device); + +#endif /* CONFIG_DMA_ENGINE */ +#endif /* DMAENGINE_H */ -- cgit v1.2.3 From 57c651f74cd8383df10a648e677902849de1bc0b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 23 May 2006 17:39:49 -0700 Subject: [I/OAT]: Move PCI_DEVICE_ID_INTEL_IOAT to linux/pci_ids.h Signed-off-by: David S. Miller --- drivers/dma/ioatdma.h | 3 +-- include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h index 312353d12af2..a5d3b3644160 100644 --- a/drivers/dma/ioatdma.h +++ b/drivers/dma/ioatdma.h @@ -26,8 +26,7 @@ #include #include #include - -#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 +#include #define IOAT_LOW_COMPLETION_MASK 0xffffffc0 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 590dc6dca315..819c8e1324d1 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2043,6 +2043,7 @@ #define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 +#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 #define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 #define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 -- cgit v1.2.3 From db21733488f84a596faaad0d05430b3f51804692 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Sat, 17 Jun 2006 21:24:58 -0700 Subject: [I/OAT]: Setup the networking subsystem as a DMA client Attempts to allocate per-CPU DMA channels Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- drivers/dma/Kconfig | 12 ++++++ include/linux/netdevice.h | 4 ++ include/net/netdma.h | 38 +++++++++++++++++ net/core/dev.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 include/net/netdma.h (limited to 'include') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 0f15e769c6bc..30d021d1a07c 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -10,6 +10,18 @@ config DMA_ENGINE DMA engines offload copy operations from the CPU to dedicated hardware, allowing the copies to happen asynchronously. +comment "DMA Clients" + +config NET_DMA + bool "Network: TCP receive copy offload" + depends on DMA_ENGINE && NET + default y + ---help--- + This enables the use of DMA engines in the network stack to + offload receive copy-to-user operations, freeing CPU cycles. + Since this is the main user of the DMA engine, it should be enabled; + say Y here. + comment "DMA Devices" config INTEL_IOATDMA diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f4169bbb60eb..b5760c67af9c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -37,6 +37,7 @@ #include #include #include +#include struct divert_blk; struct vlan_group; @@ -593,6 +594,9 @@ struct softnet_data struct sk_buff *completion_queue; struct net_device backlog_dev; /* Sorry. 8) */ +#ifdef CONFIG_NET_DMA + struct dma_chan *net_dma; +#endif }; DECLARE_PER_CPU(struct softnet_data,softnet_data); diff --git a/include/net/netdma.h b/include/net/netdma.h new file mode 100644 index 000000000000..cbfe89d7e5d0 --- /dev/null +++ b/include/net/netdma.h @@ -0,0 +1,38 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ +#ifndef NETDMA_H +#define NETDMA_H +#include +#ifdef CONFIG_NET_DMA +#include + +static inline struct dma_chan *get_softnet_dma(void) +{ + struct dma_chan *chan; + rcu_read_lock(); + chan = rcu_dereference(__get_cpu_var(softnet_data.net_dma)); + if (chan) + dma_chan_get(chan); + rcu_read_unlock(); + return chan; +} +#endif /* CONFIG_NET_DMA */ +#endif /* NETDMA_H */ diff --git a/net/core/dev.c b/net/core/dev.c index 4fba549caf29..6bfa78c66c25 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -115,6 +115,7 @@ #include #include #include +#include /* * The list of packet types we will receive (as opposed to discard) @@ -148,6 +149,12 @@ static DEFINE_SPINLOCK(ptype_lock); static struct list_head ptype_base[16]; /* 16 way hashed list */ static struct list_head ptype_all; /* Taps */ +#ifdef CONFIG_NET_DMA +static struct dma_client *net_dma_client; +static unsigned int net_dma_count; +static spinlock_t net_dma_event_lock; +#endif + /* * The @dev_base list is protected by @dev_base_lock and the rtnl * semaphore. @@ -1846,6 +1853,19 @@ static void net_rx_action(struct softirq_action *h) } } out: +#ifdef CONFIG_NET_DMA + /* + * There may not be any more sk_buffs coming right now, so push + * any pending DMA copies to hardware + */ + if (net_dma_client) { + struct dma_chan *chan; + rcu_read_lock(); + list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node) + dma_async_memcpy_issue_pending(chan); + rcu_read_unlock(); + } +#endif local_irq_enable(); return; @@ -3300,6 +3320,88 @@ static int dev_cpu_callback(struct notifier_block *nfb, } #endif /* CONFIG_HOTPLUG_CPU */ +#ifdef CONFIG_NET_DMA +/** + * net_dma_rebalance - + * This is called when the number of channels allocated to the net_dma_client + * changes. The net_dma_client tries to have one DMA channel per CPU. + */ +static void net_dma_rebalance(void) +{ + unsigned int cpu, i, n; + struct dma_chan *chan; + + lock_cpu_hotplug(); + + if (net_dma_count == 0) { + for_each_online_cpu(cpu) + rcu_assign_pointer(per_cpu(softnet_data.net_dma, cpu), NULL); + unlock_cpu_hotplug(); + return; + } + + i = 0; + cpu = first_cpu(cpu_online_map); + + rcu_read_lock(); + list_for_each_entry(chan, &net_dma_client->channels, client_node) { + n = ((num_online_cpus() / net_dma_count) + + (i < (num_online_cpus() % net_dma_count) ? 1 : 0)); + + while(n) { + per_cpu(softnet_data.net_dma, cpu) = chan; + cpu = next_cpu(cpu, cpu_online_map); + n--; + } + i++; + } + rcu_read_unlock(); + + unlock_cpu_hotplug(); +} + +/** + * netdev_dma_event - event callback for the net_dma_client + * @client: should always be net_dma_client + * @chan: + * @event: + */ +static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan, + enum dma_event event) +{ + spin_lock(&net_dma_event_lock); + switch (event) { + case DMA_RESOURCE_ADDED: + net_dma_count++; + net_dma_rebalance(); + break; + case DMA_RESOURCE_REMOVED: + net_dma_count--; + net_dma_rebalance(); + break; + default: + break; + } + spin_unlock(&net_dma_event_lock); +} + +/** + * netdev_dma_regiser - register the networking subsystem as a DMA client + */ +static int __init netdev_dma_register(void) +{ + spin_lock_init(&net_dma_event_lock); + net_dma_client = dma_async_client_register(netdev_dma_event); + if (net_dma_client == NULL) + return -ENOMEM; + + dma_async_client_chan_request(net_dma_client, num_online_cpus()); + return 0; +} + +#else +static int __init netdev_dma_register(void) { return -ENODEV; } +#endif /* CONFIG_NET_DMA */ /* * Initialize the DEV module. At boot time this walks the device list and @@ -3353,6 +3455,8 @@ static int __init net_dev_init(void) atomic_set(&queue->backlog_dev.refcnt, 1); } + netdev_dma_register(); + dev_boot_phase = 0; open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); -- cgit v1.2.3 From de5506e155276d385712c2aa1c2d9a27cd4ed947 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 17:50:37 -0700 Subject: [I/OAT]: Utility functions for offloading sk_buff to iovec copies Provides for pinning user space pages in memory, copying to iovecs, and copying from sk_buffs including fragmented and chained sk_buffs. Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- drivers/dma/Makefile | 3 +- drivers/dma/iovlock.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dmaengine.h | 22 ++++ include/net/netdma.h | 6 + net/core/Makefile | 1 + net/core/user_dma.c | 127 +++++++++++++++++++ 6 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 drivers/dma/iovlock.c create mode 100644 net/core/user_dma.c (limited to 'include') diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index c8a5f5677313..bdcfdbdb1aec 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,2 +1,3 @@ -obj-y += dmaengine.o +obj-$(CONFIG_DMA_ENGINE) += dmaengine.o +obj-$(CONFIG_NET_DMA) += iovlock.o obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c new file mode 100644 index 000000000000..5ed327e453a2 --- /dev/null +++ b/drivers/dma/iovlock.c @@ -0,0 +1,301 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * Portions based on net/core/datagram.c and copyrighted by their authors. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ + +/* + * This code allows the net stack to make use of a DMA engine for + * skb to iovec copies. + */ + +#include +#include +#include /* for memcpy_toiovec */ +#include +#include + +int num_pages_spanned(struct iovec *iov) +{ + return + ((PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) - + ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT); +} + +/* + * Pin down all the iovec pages needed for len bytes. + * Return a struct dma_pinned_list to keep track of pages pinned down. + * + * We are allocating a single chunk of memory, and then carving it up into + * 3 sections, the latter 2 whose size depends on the number of iovecs and the + * total number of pages, respectively. + */ +struct dma_pinned_list *dma_pin_iovec_pages(struct iovec *iov, size_t len) +{ + struct dma_pinned_list *local_list; + struct page **pages; + int i; + int ret; + int nr_iovecs = 0; + int iovec_len_used = 0; + int iovec_pages_used = 0; + long err; + + /* don't pin down non-user-based iovecs */ + if (segment_eq(get_fs(), KERNEL_DS)) + return NULL; + + /* determine how many iovecs/pages there are, up front */ + do { + iovec_len_used += iov[nr_iovecs].iov_len; + iovec_pages_used += num_pages_spanned(&iov[nr_iovecs]); + nr_iovecs++; + } while (iovec_len_used < len); + + /* single kmalloc for pinned list, page_list[], and the page arrays */ + local_list = kmalloc(sizeof(*local_list) + + (nr_iovecs * sizeof (struct dma_page_list)) + + (iovec_pages_used * sizeof (struct page*)), GFP_KERNEL); + if (!local_list) { + err = -ENOMEM; + goto out; + } + + /* list of pages starts right after the page list array */ + pages = (struct page **) &local_list->page_list[nr_iovecs]; + + for (i = 0; i < nr_iovecs; i++) { + struct dma_page_list *page_list = &local_list->page_list[i]; + + len -= iov[i].iov_len; + + if (!access_ok(VERIFY_WRITE, iov[i].iov_base, iov[i].iov_len)) { + err = -EFAULT; + goto unpin; + } + + page_list->nr_pages = num_pages_spanned(&iov[i]); + page_list->base_address = iov[i].iov_base; + + page_list->pages = pages; + pages += page_list->nr_pages; + + /* pin pages down */ + down_read(¤t->mm->mmap_sem); + ret = get_user_pages( + current, + current->mm, + (unsigned long) iov[i].iov_base, + page_list->nr_pages, + 1, /* write */ + 0, /* force */ + page_list->pages, + NULL); + up_read(¤t->mm->mmap_sem); + + if (ret != page_list->nr_pages) { + err = -ENOMEM; + goto unpin; + } + + local_list->nr_iovecs = i + 1; + } + + return local_list; + +unpin: + dma_unpin_iovec_pages(local_list); +out: + return ERR_PTR(err); +} + +void dma_unpin_iovec_pages(struct dma_pinned_list *pinned_list) +{ + int i, j; + + if (!pinned_list) + return; + + for (i = 0; i < pinned_list->nr_iovecs; i++) { + struct dma_page_list *page_list = &pinned_list->page_list[i]; + for (j = 0; j < page_list->nr_pages; j++) { + set_page_dirty_lock(page_list->pages[j]); + page_cache_release(page_list->pages[j]); + } + } + + kfree(pinned_list); +} + +static dma_cookie_t dma_memcpy_to_kernel_iovec(struct dma_chan *chan, struct + iovec *iov, unsigned char *kdata, size_t len) +{ + dma_cookie_t dma_cookie = 0; + + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, iov->iov_len, len); + dma_cookie = dma_async_memcpy_buf_to_buf( + chan, + iov->iov_base, + kdata, + copy); + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; + } + iov++; + } + + return dma_cookie; +} + +/* + * We have already pinned down the pages we will be using in the iovecs. + * Each entry in iov array has corresponding entry in pinned_list->page_list. + * Using array indexing to keep iov[] and page_list[] in sync. + * Initial elements in iov array's iov->iov_len will be 0 if already copied into + * by another call. + * iov array length remaining guaranteed to be bigger than len. + */ +dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov, + struct dma_pinned_list *pinned_list, unsigned char *kdata, size_t len) +{ + int iov_byte_offset; + int copy; + dma_cookie_t dma_cookie = 0; + int iovec_idx; + int page_idx; + + if (!chan) + return memcpy_toiovec(iov, kdata, len); + + /* -> kernel copies (e.g. smbfs) */ + if (!pinned_list) + return dma_memcpy_to_kernel_iovec(chan, iov, kdata, len); + + iovec_idx = 0; + while (iovec_idx < pinned_list->nr_iovecs) { + struct dma_page_list *page_list; + + /* skip already used-up iovecs */ + while (!iov[iovec_idx].iov_len) + iovec_idx++; + + page_list = &pinned_list->page_list[iovec_idx]; + + iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK); + page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK) + - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT; + + /* break up copies to not cross page boundary */ + while (iov[iovec_idx].iov_len) { + copy = min_t(int, PAGE_SIZE - iov_byte_offset, len); + copy = min_t(int, copy, iov[iovec_idx].iov_len); + + dma_cookie = dma_async_memcpy_buf_to_pg(chan, + page_list->pages[page_idx], + iov_byte_offset, + kdata, + copy); + + len -= copy; + iov[iovec_idx].iov_len -= copy; + iov[iovec_idx].iov_base += copy; + + if (!len) + return dma_cookie; + + kdata += copy; + iov_byte_offset = 0; + page_idx++; + } + iovec_idx++; + } + + /* really bad if we ever run out of iovecs */ + BUG(); + return -EFAULT; +} + +dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov, + struct dma_pinned_list *pinned_list, struct page *page, + unsigned int offset, size_t len) +{ + int iov_byte_offset; + int copy; + dma_cookie_t dma_cookie = 0; + int iovec_idx; + int page_idx; + int err; + + /* this needs as-yet-unimplemented buf-to-buff, so punt. */ + /* TODO: use dma for this */ + if (!chan || !pinned_list) { + u8 *vaddr = kmap(page); + err = memcpy_toiovec(iov, vaddr + offset, len); + kunmap(page); + return err; + } + + iovec_idx = 0; + while (iovec_idx < pinned_list->nr_iovecs) { + struct dma_page_list *page_list; + + /* skip already used-up iovecs */ + while (!iov[iovec_idx].iov_len) + iovec_idx++; + + page_list = &pinned_list->page_list[iovec_idx]; + + iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK); + page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK) + - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT; + + /* break up copies to not cross page boundary */ + while (iov[iovec_idx].iov_len) { + copy = min_t(int, PAGE_SIZE - iov_byte_offset, len); + copy = min_t(int, copy, iov[iovec_idx].iov_len); + + dma_cookie = dma_async_memcpy_pg_to_pg(chan, + page_list->pages[page_idx], + iov_byte_offset, + page, + offset, + copy); + + len -= copy; + iov[iovec_idx].iov_len -= copy; + iov[iovec_idx].iov_base += copy; + + if (!len) + return dma_cookie; + + offset += copy; + iov_byte_offset = 0; + page_idx++; + } + iovec_idx++; + } + + /* really bad if we ever run out of iovecs */ + BUG(); + return -EFAULT; +} diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 30781546ac99..78b236ca04f8 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -333,5 +333,27 @@ static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie, int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device); +/* --- Helper iov-locking functions --- */ + +struct dma_page_list { + char *base_address; + int nr_pages; + struct page **pages; +}; + +struct dma_pinned_list { + int nr_iovecs; + struct dma_page_list page_list[0]; +}; + +struct dma_pinned_list *dma_pin_iovec_pages(struct iovec *iov, size_t len); +void dma_unpin_iovec_pages(struct dma_pinned_list* pinned_list); + +dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov, + struct dma_pinned_list *pinned_list, unsigned char *kdata, size_t len); +dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov, + struct dma_pinned_list *pinned_list, struct page *page, + unsigned int offset, size_t len); + #endif /* CONFIG_DMA_ENGINE */ #endif /* DMAENGINE_H */ diff --git a/include/net/netdma.h b/include/net/netdma.h index cbfe89d7e5d0..19760eb131aa 100644 --- a/include/net/netdma.h +++ b/include/net/netdma.h @@ -23,6 +23,7 @@ #include #ifdef CONFIG_NET_DMA #include +#include static inline struct dma_chan *get_softnet_dma(void) { @@ -34,5 +35,10 @@ static inline struct dma_chan *get_softnet_dma(void) rcu_read_unlock(); return chan; } + +int dma_skb_copy_datagram_iovec(struct dma_chan* chan, + const struct sk_buff *skb, int offset, struct iovec *to, + size_t len, struct dma_pinned_list *pinned_list); + #endif /* CONFIG_NET_DMA */ #endif /* NETDMA_H */ diff --git a/net/core/Makefile b/net/core/Makefile index 79fe12cced27..e9bd2467d5a9 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_WIRELESS_EXT) += wireless.o obj-$(CONFIG_NETPOLL) += netpoll.o +obj-$(CONFIG_NET_DMA) += user_dma.o diff --git a/net/core/user_dma.c b/net/core/user_dma.c new file mode 100644 index 000000000000..9eee91bcbf3f --- /dev/null +++ b/net/core/user_dma.c @@ -0,0 +1,127 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * Portions based on net/core/datagram.c and copyrighted by their authors. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ + +/* + * This code allows the net stack to make use of a DMA engine for + * skb to iovec copies. + */ + +#include +#include +#include /* for BUG_TRAP */ +#include + +/** + * dma_skb_copy_datagram_iovec - Copy a datagram to an iovec. + * @skb - buffer to copy + * @offset - offset in the buffer to start copying from + * @iovec - io vector to copy to + * @len - amount of data to copy from buffer to iovec + * @pinned_list - locked iovec buffer data + * + * Note: the iovec is modified during the copy. + */ +int dma_skb_copy_datagram_iovec(struct dma_chan *chan, + struct sk_buff *skb, int offset, struct iovec *to, + size_t len, struct dma_pinned_list *pinned_list) +{ + int start = skb_headlen(skb); + int i, copy = start - offset; + dma_cookie_t cookie = 0; + + /* Copy header. */ + if (copy > 0) { + if (copy > len) + copy = len; + cookie = dma_memcpy_to_iovec(chan, to, pinned_list, + skb->data + offset, copy); + if (cookie < 0) + goto fault; + len -= copy; + if (len == 0) + goto end; + offset += copy; + } + + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset + len); + + end = start + skb_shinfo(skb)->frags[i].size; + copy = end - offset; + if ((copy = end - offset) > 0) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + + cookie = dma_memcpy_pg_to_iovec(chan, to, pinned_list, page, + frag->page_offset + offset - start, copy); + if (cookie < 0) + goto fault; + len -= copy; + if (len == 0) + goto end; + offset += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + for (; list; list = list->next) { + int end; + + BUG_TRAP(start <= offset + len); + + end = start + list->len; + copy = end - offset; + if (copy > 0) { + if (copy > len) + copy = len; + cookie = dma_skb_copy_datagram_iovec(chan, list, + offset - start, to, copy, + pinned_list); + if (cookie < 0) + goto fault; + len -= copy; + if (len == 0) + goto end; + offset += copy; + } + start = end; + } + } + +end: + if (!len) { + skb->dma_cookie = cookie; + return cookie; + } + +fault: + return -EFAULT; +} -- cgit v1.2.3 From 97fc2f0848c928c63c2ae619deee61a0b1107b69 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 17:55:33 -0700 Subject: [I/OAT]: Structure changes for TCP recv offload to I/OAT Adds an async_wait_queue and some additional fields to tcp_sock, and a dma_cookie_t to sk_buff. Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++++ include/linux/tcp.h | 8 ++++++++ include/net/sock.h | 2 ++ include/net/tcp.h | 7 +++++++ net/core/sock.c | 6 ++++++ 5 files changed, 27 insertions(+) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f8f234708b98..23bad3bf3c9d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -29,6 +29,7 @@ #include #include #include +#include #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ @@ -285,6 +286,9 @@ struct sk_buff { __u16 tc_verd; /* traffic control verdict */ #endif #endif +#ifdef CONFIG_NET_DMA + dma_cookie_t dma_cookie; +#endif /* These elements must be at the end, see alloc_skb() for details. */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 542d39596bd8..c90daa5da6c3 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -18,6 +18,7 @@ #define _LINUX_TCP_H #include +#include #include struct tcphdr { @@ -233,6 +234,13 @@ struct tcp_sock { struct iovec *iov; int memory; int len; +#ifdef CONFIG_NET_DMA + /* members for async copy */ + struct dma_chan *dma_chan; + int wakeup; + struct dma_pinned_list *pinned_list; + dma_cookie_t dma_cookie; +#endif } ucopy; __u32 snd_wl1; /* Sequence for window update */ diff --git a/include/net/sock.h b/include/net/sock.h index c9fad6fb629b..90c65cb091a8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -132,6 +132,7 @@ struct sock_common { * @sk_receive_queue: incoming packets * @sk_wmem_alloc: transmit queue bytes committed * @sk_write_queue: Packet sending queue + * @sk_async_wait_queue: DMA copied packets * @sk_omem_alloc: "o" is "option" or "other" * @sk_wmem_queued: persistent queue size * @sk_forward_alloc: space allocated forward @@ -205,6 +206,7 @@ struct sock { atomic_t sk_omem_alloc; struct sk_buff_head sk_receive_queue; struct sk_buff_head sk_write_queue; + struct sk_buff_head sk_async_wait_queue; int sk_wmem_queued; int sk_forward_alloc; gfp_t sk_allocation; diff --git a/include/net/tcp.h b/include/net/tcp.h index 3c989db8a7aa..d0c2c2fa7587 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -817,6 +818,12 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp) tp->ucopy.len = 0; tp->ucopy.memory = 0; skb_queue_head_init(&tp->ucopy.prequeue); +#ifdef CONFIG_NET_DMA + tp->ucopy.dma_chan = NULL; + tp->ucopy.wakeup = 0; + tp->ucopy.pinned_list = NULL; + tp->ucopy.dma_cookie = 0; +#endif } /* Packet is added to VJ-style prequeue for processing in process diff --git a/net/core/sock.c b/net/core/sock.c index ed2afdb9ea2d..5d820c376653 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -832,6 +832,9 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) atomic_set(&newsk->sk_omem_alloc, 0); skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); +#ifdef CONFIG_NET_DMA + skb_queue_head_init(&newsk->sk_async_wait_queue); +#endif rwlock_init(&newsk->sk_dst_lock); rwlock_init(&newsk->sk_callback_lock); @@ -1383,6 +1386,9 @@ void sock_init_data(struct socket *sock, struct sock *sk) skb_queue_head_init(&sk->sk_receive_queue); skb_queue_head_init(&sk->sk_write_queue); skb_queue_head_init(&sk->sk_error_queue); +#ifdef CONFIG_NET_DMA + skb_queue_head_init(&sk->sk_async_wait_queue); +#endif sk->sk_send_head = NULL; -- cgit v1.2.3 From 0e4b4992b8007c6b62ec143cbbb292f98813ca11 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 18:00:16 -0700 Subject: [I/OAT]: Rename cleanup_rbuf to tcp_cleanup_rbuf and make non-static Needed to be able to call tcp_cleanup_rbuf in tcp_input.c for I/OAT Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- include/net/tcp.h | 2 ++ net/ipv4/tcp.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index d0c2c2fa7587..578cccf275d3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -294,6 +294,8 @@ extern int tcp_rcv_established(struct sock *sk, extern void tcp_rcv_space_adjust(struct sock *sk); +extern void tcp_cleanup_rbuf(struct sock *sk, int copied); + extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e2b7b8055037..1c0cfd7a8bbb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -937,7 +937,7 @@ static int tcp_recv_urg(struct sock *sk, long timeo, * calculation of whether or not we must ACK for the sake of * a window update. */ -static void cleanup_rbuf(struct sock *sk, int copied) +void tcp_cleanup_rbuf(struct sock *sk, int copied) { struct tcp_sock *tp = tcp_sk(sk); int time_to_ack = 0; @@ -1086,7 +1086,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, /* Clean up data we have read: This will do ACK frames. */ if (copied) - cleanup_rbuf(sk, copied); + tcp_cleanup_rbuf(sk, copied); return copied; } @@ -1220,7 +1220,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } } - cleanup_rbuf(sk, copied); + tcp_cleanup_rbuf(sk, copied); if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) { /* Install new reader */ @@ -1391,7 +1391,7 @@ skip_copy: */ /* Clean up data we have read: This will do ACK frames. */ - cleanup_rbuf(sk, copied); + tcp_cleanup_rbuf(sk, copied); TCP_CHECK_TIMER(sk); release_sock(sk); @@ -1858,7 +1858,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && inet_csk_ack_scheduled(sk)) { icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; - cleanup_rbuf(sk, 1); + tcp_cleanup_rbuf(sk, 1); if (!(val & 1)) icsk->icsk_ack.pingpong = 1; } -- cgit v1.2.3 From 624d1164730d58a494cc5aa4afa37d02c41e83a7 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 18:01:28 -0700 Subject: [I/OAT]: Make sk_eat_skb I/OAT aware. Add an extra argument to sk_eat_skb, and make it move early copied packets to the async_wait_queue instead of freeing them. Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- include/net/sock.h | 13 ++++++++++++- net/dccp/proto.c | 4 ++-- net/ipv4/tcp.c | 8 ++++---- net/llc/af_llc.c | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 90c65cb091a8..75b0e97ed93d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1273,11 +1273,22 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) * This routine must be called with interrupts disabled or with the socket * locked so that the sk_buff queue operation is ok. */ -static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb) +#ifdef CONFIG_NET_DMA +static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_early) +{ + __skb_unlink(skb, &sk->sk_receive_queue); + if (!copied_early) + __kfree_skb(skb); + else + __skb_queue_tail(&sk->sk_async_wait_queue, skb); +} +#else +static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_early) { __skb_unlink(skb, &sk->sk_receive_queue); __kfree_skb(skb); } +#endif extern void sock_enable_timestamp(struct sock *sk); extern int sock_get_timestamp(struct sock *, struct timeval __user *); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 2e0ee8355c41..5317fd3e6691 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -719,7 +719,7 @@ int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } dccp_pr_debug("packet_type=%s\n", dccp_packet_name(dh->dccph_type)); - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); verify_sock_status: if (sock_flag(sk, SOCK_DONE)) { len = 0; @@ -773,7 +773,7 @@ verify_sock_status: } found_fin_ok: if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); break; } while (1); out: diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1c0cfd7a8bbb..4e067d25a63c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1072,11 +1072,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, break; } if (skb->h.th->fin) { - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); ++seq; break; } - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); if (!desc->count) break; } @@ -1356,14 +1356,14 @@ skip_copy: if (skb->h.th->fin) goto found_fin_ok; if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); continue; found_fin_ok: /* Process the FIN. */ ++*seq; if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); break; } while (len > 0); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 5a04db745c8d..7465170a36ca 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -789,7 +789,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, continue; if (!(flags & MSG_PEEK)) { - sk_eat_skb(sk, skb); + sk_eat_skb(sk, skb, 0); *seq = 0; } } while (len > 0); -- cgit v1.2.3 From 9593782585e0cf70babe787a8463d492a68b1744 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 May 2006 18:02:55 -0700 Subject: [I/OAT]: Add a sysctl for tuning the I/OAT offloaded I/O threshold Any socket recv of less than this ammount will not be offloaded Signed-off-by: Chris Leech Signed-off-by: David S. Miller --- include/linux/sysctl.h | 1 + include/net/tcp.h | 1 + net/core/user_dma.c | 4 ++++ net/ipv4/sysctl_net_ipv4.c | 10 ++++++++++ 4 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 76eaeff76f82..cd9e7c0825ad 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -403,6 +403,7 @@ enum NET_TCP_MTU_PROBING=113, NET_TCP_BASE_MSS=114, NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115, + NET_TCP_DMA_COPYBREAK=116, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index 578cccf275d3..f1f472746e6c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -219,6 +219,7 @@ extern int sysctl_tcp_adv_win_scale; extern int sysctl_tcp_tw_reuse; extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; +extern int sysctl_tcp_dma_copybreak; extern int sysctl_tcp_nometrics_save; extern int sysctl_tcp_moderate_rcvbuf; extern int sysctl_tcp_tso_win_divisor; diff --git a/net/core/user_dma.c b/net/core/user_dma.c index 9eee91bcbf3f..b7c98dbcdb81 100644 --- a/net/core/user_dma.c +++ b/net/core/user_dma.c @@ -30,6 +30,10 @@ #include /* for BUG_TRAP */ #include +#define NET_DMA_DEFAULT_COPYBREAK 4096 + +int sysctl_tcp_dma_copybreak = NET_DMA_DEFAULT_COPYBREAK; + /** * dma_skb_copy_datagram_iovec - Copy a datagram to an iovec. * @skb - buffer to copy diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 6b6c3adfcf00..6a6aa537b7aa 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -688,6 +688,16 @@ ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, +#ifdef CONFIG_NET_DMA + { + .ctl_name = NET_TCP_DMA_COPYBREAK, + .procname = "tcp_dma_copybreak", + .data = &sysctl_tcp_dma_copybreak, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, +#endif { .ctl_name = 0 } }; -- cgit v1.2.3 From aecbd4e45c2e469e0452ffb2c0b0d881e2815bb8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 25 May 2006 15:08:30 -0700 Subject: [LLC]: use more efficient ether address routines Use more cache efficient Ethernet address manipulation functions in etherdevice.h. Signed-off-by: Stephen Hemminger --- include/net/llc_if.h | 13 ++++++------- net/llc/llc_if.c | 2 -- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/net/llc_if.h b/include/net/llc_if.h index 090eaa0d71f9..a05d04ac4513 100644 --- a/include/net/llc_if.h +++ b/include/net/llc_if.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #define LLC_DATAUNIT_PRIM 1 @@ -61,8 +62,6 @@ #define LLC_STATUS_CONFLICT 7 /* disconnect conn */ #define LLC_STATUS_RESET_DONE 8 /* */ -extern u8 llc_mac_null_var[IFHWADDRLEN]; - /** * llc_mac_null - determines if a address is a null mac address * @mac: Mac address to test if null. @@ -70,12 +69,12 @@ extern u8 llc_mac_null_var[IFHWADDRLEN]; * Determines if a given address is a null mac address. Returns 0 if the * address is not a null mac, 1 if the address is a null mac. */ -static __inline__ int llc_mac_null(u8 *mac) +static inline int llc_mac_null(const u8 *mac) { - return !memcmp(mac, llc_mac_null_var, IFHWADDRLEN); + return is_zero_ether_addr(mac); } -static __inline__ int llc_addrany(struct llc_addr *addr) +static inline int llc_addrany(const struct llc_addr *addr) { return llc_mac_null(addr->mac) && !addr->lsap; } @@ -89,9 +88,9 @@ static __inline__ int llc_addrany(struct llc_addr *addr) * is not a complete match up to len, 1 if a complete match up to len is * found. */ -static __inline__ int llc_mac_match(u8 *mac1, u8 *mac2) +static inline int llc_mac_match(const u8 *mac1, const u8 *mac2) { - return !memcmp(mac1, mac2, IFHWADDRLEN); + return !compare_ether_addr(mac1, mac2); } extern int llc_establish_connection(struct sock *sk, u8 *lmac, diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c index ba90f7f0801a..5ae47be7dde0 100644 --- a/net/llc/llc_if.c +++ b/net/llc/llc_if.c @@ -26,8 +26,6 @@ #include #include -u8 llc_mac_null_var[IFHWADDRLEN]; - /** * llc_build_and_send_pkt - Connection data sending for upper layers. * @sk: connection -- cgit v1.2.3 From bc0e646796928918e45b6465e02616f2fe65c3c1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 25 May 2006 15:10:37 -0700 Subject: [LLC]: add multicast support for datagrams Allow mulitcast reception of datagrams (similar to UDP). All sockets bound to the same SAP receive a clone. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/llc_if.h | 4 ++++ net/llc/llc_sap.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/llc_if.h b/include/net/llc_if.h index a05d04ac4513..c608812a8e89 100644 --- a/include/net/llc_if.h +++ b/include/net/llc_if.h @@ -79,6 +79,10 @@ static inline int llc_addrany(const struct llc_addr *addr) return llc_mac_null(addr->mac) && !addr->lsap; } +static inline int llc_mac_multicast(const u8 *mac) +{ + return is_multicast_ether_addr(mac); +} /** * llc_mac_match - determines if two mac addresses are the same * @mac1: First mac address to compare. diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 4029ceee9b91..20c4eb5c1ac6 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -282,7 +282,7 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb) * mac, and local sap. Returns pointer for socket found, %NULL otherwise. */ static struct sock *llc_lookup_dgram(struct llc_sap *sap, - struct llc_addr *laddr) + const struct llc_addr *laddr) { struct sock *rc; struct hlist_node *node; @@ -304,19 +304,62 @@ found: return rc; } +/** + * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. + * @sap: SAP + * @laddr: address of local LLC (MAC + SAP) + * + * Search socket list of the SAP and finds connections with same sap. + * Deliver clone to each. + */ +static void llc_sap_mcast(struct llc_sap *sap, + const struct llc_addr *laddr, + struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + read_lock_bh(&sap->sk_list.lock); + sk_for_each(sk, node, &sap->sk_list.list) { + struct llc_sock *llc = llc_sk(sk); + struct sk_buff *skb1; + + if (sk->sk_type != SOCK_DGRAM) + continue; + + if (llc->laddr.lsap != laddr->lsap) + continue; + + skb1 = skb_clone(skb, GFP_ATOMIC); + if (!skb1) + break; + + sock_hold(sk); + skb_set_owner_r(skb1, sk); + llc_sap_rcv(sap, skb1); + sock_put(sk); + } + read_unlock_bh(&sap->sk_list.lock); +} + + void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb) { struct llc_addr laddr; - struct sock *sk; llc_pdu_decode_da(skb, laddr.mac); llc_pdu_decode_dsap(skb, &laddr.lsap); - sk = llc_lookup_dgram(sap, &laddr); - if (sk) { - skb_set_owner_r(skb, sk); - llc_sap_rcv(sap, skb); - sock_put(sk); - } else + if (llc_mac_multicast(laddr.mac)) { + llc_sap_mcast(sap, &laddr, skb); kfree_skb(skb); + } else { + struct sock *sk = llc_lookup_dgram(sap, &laddr); + if (sk) { + skb_set_owner_r(skb, sk); + llc_sap_rcv(sap, skb); + sock_put(sk); + } else + kfree_skb(skb); + } } -- cgit v1.2.3 From 30b6c28d2aca4669f2e609ad5d77ea2a6cf0dd3a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 26 May 2006 17:44:45 -0700 Subject: [TG3]: Add 5786 PCI ID Add PCI ID for BCM5786 which is a variant of 5787. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 ++ include/linux/pci_ids.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 862c226dbbe2..cb0ebf83c843 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -229,6 +229,8 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 819c8e1324d1..cf45e8bb69a8 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1887,6 +1887,7 @@ #define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 +#define PCI_DEVICE_ID_TIGON3_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c #define PCI_DEVICE_ID_TIGON3_5789 0x169d -- cgit v1.2.3 From 546be2405be119ef55467aace45f337a16e5d424 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 27 May 2006 23:03:58 -0700 Subject: [IPSEC] xfrm: Undo afinfo lock proliferation The number of locks used to manage afinfo structures can easily be reduced down to one each for policy and state respectively. This is based on the observation that the write locks are only held by module insertion/removal which are very rare events so there is no need to further differentiate between the insertion of modules like ipv6 versus esp6. The removal of the read locks in xfrm4_policy.c/xfrm6_policy.c might look suspicious at first. However, after you realise that nobody ever takes the corresponding write lock you'll feel better :) As far as I can gather it's an attempt to guard against the removal of the corresponding modules. Since neither module can be unloaded at all we can leave it to whoever fixes up IPv6 unloading :) Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 9 +------- net/ipv4/xfrm4_policy.c | 6 ----- net/ipv4/xfrm4_state.c | 1 - net/ipv6/xfrm6_policy.c | 6 ----- net/ipv6/xfrm6_state.c | 1 - net/xfrm/xfrm_policy.c | 58 +++++++++++++++++++++++++++++-------------------- net/xfrm/xfrm_state.c | 9 +++----- 7 files changed, 38 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index afa508d92c93..ed7c9747059d 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -204,8 +204,7 @@ struct xfrm_type; struct xfrm_dst; struct xfrm_policy_afinfo { unsigned short family; - rwlock_t lock; - struct xfrm_type_map *type_map; + struct xfrm_type *type_map[256]; struct dst_ops *dst_ops; void (*garbage_collect)(void); int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); @@ -232,7 +231,6 @@ extern int __xfrm_state_delete(struct xfrm_state *x); struct xfrm_state_afinfo { unsigned short family; - rwlock_t lock; struct list_head *state_bydst; struct list_head *state_byspi; int (*init_flags)(struct xfrm_state *x); @@ -264,11 +262,6 @@ struct xfrm_type u32 (*get_max_size)(struct xfrm_state *, int size); }; -struct xfrm_type_map { - rwlock_t lock; - struct xfrm_type *map[256]; -}; - extern int xfrm_register_type(struct xfrm_type *type, unsigned short family); extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family); extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 8604c747bca5..c0465284dfac 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -17,8 +17,6 @@ static struct dst_ops xfrm4_dst_ops; static struct xfrm_policy_afinfo xfrm4_policy_afinfo; -static struct xfrm_type_map xfrm4_type_map = { .lock = RW_LOCK_UNLOCKED }; - static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) { return __ip_route_output_key((struct rtable**)dst, fl); @@ -237,9 +235,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) static inline int xfrm4_garbage_collect(void) { - read_lock(&xfrm4_policy_afinfo.lock); xfrm4_policy_afinfo.garbage_collect(); - read_unlock(&xfrm4_policy_afinfo.lock); return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2); } @@ -299,8 +295,6 @@ static struct dst_ops xfrm4_dst_ops = { static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { .family = AF_INET, - .lock = RW_LOCK_UNLOCKED, - .type_map = &xfrm4_type_map, .dst_ops = &xfrm4_dst_ops, .dst_lookup = xfrm4_dst_lookup, .find_bundle = __xfrm4_find_bundle, diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index dbabf81a9b7b..81e1751c966e 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -131,7 +131,6 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, static struct xfrm_state_afinfo xfrm4_state_afinfo = { .family = AF_INET, - .lock = RW_LOCK_UNLOCKED, .init_flags = xfrm4_init_flags, .init_tempsel = __xfrm4_init_tempsel, .state_lookup = __xfrm4_state_lookup, diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 88c840f1beb6..ee715f2691e9 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -23,8 +23,6 @@ static struct dst_ops xfrm6_dst_ops; static struct xfrm_policy_afinfo xfrm6_policy_afinfo; -static struct xfrm_type_map xfrm6_type_map = { .lock = RW_LOCK_UNLOCKED }; - static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) { int err = 0; @@ -249,9 +247,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) static inline int xfrm6_garbage_collect(void) { - read_lock(&xfrm6_policy_afinfo.lock); xfrm6_policy_afinfo.garbage_collect(); - read_unlock(&xfrm6_policy_afinfo.lock); return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); } @@ -311,8 +307,6 @@ static struct dst_ops xfrm6_dst_ops = { static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { .family = AF_INET6, - .lock = RW_LOCK_UNLOCKED, - .type_map = &xfrm6_type_map, .dst_ops = &xfrm6_dst_ops, .dst_lookup = xfrm6_dst_lookup, .find_bundle = __xfrm6_find_bundle, diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index a5723024d3b3..b33296b3f6de 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -135,7 +135,6 @@ __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, static struct xfrm_state_afinfo xfrm6_state_afinfo = { .family = AF_INET6, - .lock = RW_LOCK_UNLOCKED, .init_tempsel = __xfrm6_init_tempsel, .state_lookup = __xfrm6_state_lookup, .find_acq = __xfrm6_find_acq, diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b469c8b54613..44b64a593c01 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -46,45 +46,43 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock); static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); +static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family); +static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo); int xfrm_register_type(struct xfrm_type *type, unsigned short family) { - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - struct xfrm_type_map *typemap; + struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family); + struct xfrm_type **typemap; int err = 0; if (unlikely(afinfo == NULL)) return -EAFNOSUPPORT; typemap = afinfo->type_map; - write_lock_bh(&typemap->lock); - if (likely(typemap->map[type->proto] == NULL)) - typemap->map[type->proto] = type; + if (likely(typemap[type->proto] == NULL)) + typemap[type->proto] = type; else err = -EEXIST; - write_unlock_bh(&typemap->lock); - xfrm_policy_put_afinfo(afinfo); + xfrm_policy_unlock_afinfo(afinfo); return err; } EXPORT_SYMBOL(xfrm_register_type); int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) { - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - struct xfrm_type_map *typemap; + struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family); + struct xfrm_type **typemap; int err = 0; if (unlikely(afinfo == NULL)) return -EAFNOSUPPORT; typemap = afinfo->type_map; - write_lock_bh(&typemap->lock); - if (unlikely(typemap->map[type->proto] != type)) + if (unlikely(typemap[type->proto] != type)) err = -ENOENT; else - typemap->map[type->proto] = NULL; - write_unlock_bh(&typemap->lock); - xfrm_policy_put_afinfo(afinfo); + typemap[type->proto] = NULL; + xfrm_policy_unlock_afinfo(afinfo); return err; } EXPORT_SYMBOL(xfrm_unregister_type); @@ -92,7 +90,7 @@ EXPORT_SYMBOL(xfrm_unregister_type); struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) { struct xfrm_policy_afinfo *afinfo; - struct xfrm_type_map *typemap; + struct xfrm_type **typemap; struct xfrm_type *type; int modload_attempted = 0; @@ -102,11 +100,9 @@ retry: return NULL; typemap = afinfo->type_map; - read_lock(&typemap->lock); - type = typemap->map[proto]; + type = typemap[proto]; if (unlikely(type && !try_module_get(type->owner))) type = NULL; - read_unlock(&typemap->lock); if (!type && !modload_attempted) { xfrm_policy_put_afinfo(afinfo); request_module("xfrm-type-%d-%d", @@ -1306,17 +1302,31 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) return NULL; read_lock(&xfrm_policy_afinfo_lock); afinfo = xfrm_policy_afinfo[family]; - if (likely(afinfo != NULL)) - read_lock(&afinfo->lock); - read_unlock(&xfrm_policy_afinfo_lock); + if (unlikely(!afinfo)) + read_unlock(&xfrm_policy_afinfo_lock); return afinfo; } static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) { - if (unlikely(afinfo == NULL)) - return; - read_unlock(&afinfo->lock); + read_unlock(&xfrm_policy_afinfo_lock); +} + +static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family) +{ + struct xfrm_policy_afinfo *afinfo; + if (unlikely(family >= NPROTO)) + return NULL; + write_lock_bh(&xfrm_policy_afinfo_lock); + afinfo = xfrm_policy_afinfo[family]; + if (unlikely(!afinfo)) + write_unlock_bh(&xfrm_policy_afinfo_lock); + return afinfo; +} + +static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo) +{ + write_unlock_bh(&xfrm_policy_afinfo_lock); } static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 93a2f36ad3db..ee62c239a7e3 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1103,17 +1103,14 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) return NULL; read_lock(&xfrm_state_afinfo_lock); afinfo = xfrm_state_afinfo[family]; - if (likely(afinfo != NULL)) - read_lock(&afinfo->lock); - read_unlock(&xfrm_state_afinfo_lock); + if (unlikely(!afinfo)) + read_unlock(&xfrm_state_afinfo_lock); return afinfo; } static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) { - if (unlikely(afinfo == NULL)) - return; - read_unlock(&afinfo->lock); + read_unlock(&xfrm_state_afinfo_lock); } /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ -- cgit v1.2.3 From b59f45d0b2878ab76f8053b0973654e6621828ee Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 27 May 2006 23:05:54 -0700 Subject: [IPSEC] xfrm: Abstract out encapsulation modes This patch adds the structure xfrm_mode. It is meant to represent the operations carried out by transport/tunnel modes. By doing this we allow additional encapsulation modes to be added without clogging up the xfrm_input/xfrm_output paths. Candidate modes include 4-to-6 tunnel mode, 6-to-4 tunnel mode, and BEET modes. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/xfrm.h | 4 ++ include/net/xfrm.h | 17 ++++++ net/ipv4/Kconfig | 18 ++++++ net/ipv4/Makefile | 2 + net/ipv4/xfrm4_input.c | 28 +-------- net/ipv4/xfrm4_mode_transport.c | 69 ++++++++++++++++++++++ net/ipv4/xfrm4_mode_tunnel.c | 125 ++++++++++++++++++++++++++++++++++++++++ net/ipv4/xfrm4_output.c | 61 +------------------- net/ipv6/Kconfig | 20 +++++++ net/ipv6/Makefile | 2 + net/ipv6/ip6_output.c | 2 + net/ipv6/xfrm6_input.c | 29 +--------- net/ipv6/xfrm6_mode_transport.c | 73 +++++++++++++++++++++++ net/ipv6/xfrm6_mode_tunnel.c | 121 ++++++++++++++++++++++++++++++++++++++ net/ipv6/xfrm6_output.c | 63 +------------------- net/xfrm/xfrm_policy.c | 83 ++++++++++++++++++++++++++ net/xfrm/xfrm_state.c | 6 ++ 17 files changed, 553 insertions(+), 170 deletions(-) create mode 100644 net/ipv4/xfrm4_mode_transport.c create mode 100644 net/ipv4/xfrm4_mode_tunnel.c create mode 100644 net/ipv6/xfrm6_mode_transport.c create mode 100644 net/ipv6/xfrm6_mode_tunnel.c (limited to 'include') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 6b42cc474c01..46a15c7a1a13 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -118,6 +118,10 @@ enum XFRM_SHARE_UNIQUE /* Use once */ }; +#define XFRM_MODE_TRANSPORT 0 +#define XFRM_MODE_TUNNEL 1 +#define XFRM_MODE_MAX 2 + /* Netlink configuration messages. */ enum { XFRM_MSG_BASE = 0x10, diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ed7c9747059d..ed5bb34f817f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -20,6 +20,8 @@ #include #define XFRM_ALIGN8(len) (((len) + 7) & ~7) +#define MODULE_ALIAS_XFRM_MODE(family, encap) \ + MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) extern struct sock *xfrm_nl; extern u32 sysctl_xfrm_aevent_etime; @@ -164,6 +166,7 @@ struct xfrm_state /* Reference to data common to all the instances of this * transformer. */ struct xfrm_type *type; + struct xfrm_mode *mode; /* Security context */ struct xfrm_sec_ctx *security; @@ -205,6 +208,7 @@ struct xfrm_dst; struct xfrm_policy_afinfo { unsigned short family; struct xfrm_type *type_map[256]; + struct xfrm_mode *mode_map[XFRM_MODE_MAX]; struct dst_ops *dst_ops; void (*garbage_collect)(void); int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); @@ -267,6 +271,19 @@ extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family); extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family); extern void xfrm_put_type(struct xfrm_type *type); +struct xfrm_mode { + int (*input)(struct xfrm_state *x, struct sk_buff *skb); + int (*output)(struct sk_buff *skb); + + struct module *owner; + unsigned int encap; +}; + +extern int xfrm_register_mode(struct xfrm_mode *mode, int family); +extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family); +extern struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family); +extern void xfrm_put_mode(struct xfrm_mode *mode); + struct xfrm_tmpl { /* id in template is interpreted as: diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index e40f75322377..35eb70b1448d 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -414,6 +414,24 @@ config INET_TUNNEL tristate default n +config INET_XFRM_MODE_TRANSPORT + tristate "IP: IPsec transport mode" + default y + select XFRM + ---help--- + Support for IPsec transport mode. + + If unsure, say Y. + +config INET_XFRM_MODE_TUNNEL + tristate "IP: IPsec tunnel mode" + default y + select XFRM + ---help--- + Support for IPsec tunnel mode. + + If unsure, say Y. + config INET_DIAG tristate "INET: socket monitoring interface" default y diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 9ef50a0b9d2c..4cc94482eacc 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o obj-$(CONFIG_INET_TUNNEL) += tunnel4.o +obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o +obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 3e174c83bfe7..817ed84511a6 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -24,15 +23,6 @@ int xfrm4_rcv(struct sk_buff *skb) EXPORT_SYMBOL(xfrm4_rcv); -static inline void ipip_ecn_decapsulate(struct sk_buff *skb) -{ - struct iphdr *outer_iph = skb->nh.iph; - struct iphdr *inner_iph = skb->h.ipiph; - - if (INET_ECN_is_ce(outer_iph->tos)) - IP_ECN_set_ce(inner_iph); -} - static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) { switch (nexthdr) { @@ -113,24 +103,10 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) xfrm_vec[xfrm_nr++] = x; - iph = skb->nh.iph; + if (x->mode->input(x, skb)) + goto drop; if (x->props.mode) { - if (iph->protocol != IPPROTO_IPIP) - goto drop; - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto drop; - if (skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto drop; - if (x->props.flags & XFRM_STATE_DECAP_DSCP) - ipv4_copy_dscp(iph, skb->h.ipiph); - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip_ecn_decapsulate(skb); - skb->mac.raw = memmove(skb->data - skb->mac_len, - skb->mac.raw, skb->mac_len); - skb->nh.raw = skb->data; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); decaps = 1; break; } diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c new file mode 100644 index 000000000000..e46d9a4ccc55 --- /dev/null +++ b/net/ipv4/xfrm4_mode_transport.c @@ -0,0 +1,69 @@ +/* + * xfrm4_mode_transport.c - Transport mode encapsulation for IPv4. + * + * Copyright (c) 2004-2006 Herbert Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Add encapsulation header. + * + * The IP header will be moved forward to make space for the encapsulation + * header. + * + * On exit, skb->h will be set to the start of the payload to be processed + * by x->type->output and skb->nh will be set to the top IP header. + */ +static int xfrm4_transport_output(struct sk_buff *skb) +{ + struct xfrm_state *x; + struct iphdr *iph; + int ihl; + + iph = skb->nh.iph; + skb->h.ipiph = iph; + + ihl = iph->ihl * 4; + skb->h.raw += ihl; + + x = skb->dst->xfrm; + skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl); + return 0; +} + +static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) +{ + return 0; +} + +static struct xfrm_mode xfrm4_transport_mode = { + .input = xfrm4_transport_input, + .output = xfrm4_transport_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_TRANSPORT, +}; + +static int __init xfrm4_transport_init(void) +{ + return xfrm_register_mode(&xfrm4_transport_mode, AF_INET); +} + +static void __exit xfrm4_transport_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm4_transport_mode, AF_INET); + BUG_ON(err); +} + +module_init(xfrm4_transport_init); +module_exit(xfrm4_transport_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TRANSPORT); diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c new file mode 100644 index 000000000000..f8d880beb12f --- /dev/null +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -0,0 +1,125 @@ +/* + * xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4. + * + * Copyright (c) 2004-2006 Herbert Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void ipip_ecn_decapsulate(struct sk_buff *skb) +{ + struct iphdr *outer_iph = skb->nh.iph; + struct iphdr *inner_iph = skb->h.ipiph; + + if (INET_ECN_is_ce(outer_iph->tos)) + IP_ECN_set_ce(inner_iph); +} + +/* Add encapsulation header. + * + * The top IP header will be constructed per RFC 2401. The following fields + * in it shall be filled in by x->type->output: + * tot_len + * check + * + * On exit, skb->h will be set to the start of the payload to be processed + * by x->type->output and skb->nh will be set to the top IP header. + */ +static int xfrm4_tunnel_output(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + int flags; + + iph = skb->nh.iph; + skb->h.ipiph = iph; + + skb->nh.raw = skb_push(skb, x->props.header_len); + top_iph = skb->nh.iph; + + top_iph->ihl = 5; + top_iph->version = 4; + + /* DS disclosed */ + top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); + + flags = x->props.flags; + if (flags & XFRM_STATE_NOECN) + IP_ECN_clear(top_iph); + + top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? + 0 : (iph->frag_off & htons(IP_DF)); + if (!top_iph->frag_off) + __ip_select_ident(top_iph, dst->child, 0); + + top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); + + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + top_iph->protocol = IPPROTO_IPIP; + + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + return 0; +} + +static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + int err = -EINVAL; + + if (iph->protocol != IPPROTO_IPIP) + goto out; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + + if (skb_cloned(skb) && + (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + goto out; + + if (x->props.flags & XFRM_STATE_DECAP_DSCP) + ipv4_copy_dscp(iph, skb->h.ipiph); + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip_ecn_decapsulate(skb); + skb->mac.raw = memmove(skb->data - skb->mac_len, + skb->mac.raw, skb->mac_len); + skb->nh.raw = skb->data; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + err = 0; + +out: + return err; +} + +static struct xfrm_mode xfrm4_tunnel_mode = { + .input = xfrm4_tunnel_input, + .output = xfrm4_tunnel_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_TUNNEL, +}; + +static int __init xfrm4_tunnel_init(void) +{ + return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET); +} + +static void __exit xfrm4_tunnel_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET); + BUG_ON(err); +} + +module_init(xfrm4_tunnel_init); +module_exit(xfrm4_tunnel_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL); diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 4ef8efaf6a67..ac9d91d4bb05 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -12,67 +12,10 @@ #include #include #include -#include #include #include #include -/* Add encapsulation header. - * - * In transport mode, the IP header will be moved forward to make space - * for the encapsulation header. - * - * In tunnel mode, the top IP header will be constructed per RFC 2401. - * The following fields in it shall be filled in by x->type->output: - * tot_len - * check - * - * On exit, skb->h will be set to the start of the payload to be processed - * by x->type->output and skb->nh will be set to the top IP header. - */ -static void xfrm4_encap(struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - int flags; - - iph = skb->nh.iph; - skb->h.ipiph = iph; - - skb->nh.raw = skb_push(skb, x->props.header_len); - top_iph = skb->nh.iph; - - if (!x->props.mode) { - skb->h.raw += iph->ihl*4; - memmove(top_iph, iph, iph->ihl*4); - return; - } - - top_iph->ihl = 5; - top_iph->version = 4; - - /* DS disclosed */ - top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); - - flags = x->props.flags; - if (flags & XFRM_STATE_NOECN) - IP_ECN_clear(top_iph); - - top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? - 0 : (iph->frag_off & htons(IP_DF)); - if (!top_iph->frag_off) - __ip_select_ident(top_iph, dst->child, 0); - - top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); - - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - top_iph->protocol = IPPROTO_IPIP; - - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); -} - static int xfrm4_tunnel_check_size(struct sk_buff *skb) { int mtu, ret = 0; @@ -121,7 +64,9 @@ static int xfrm4_output_one(struct sk_buff *skb) if (err) goto error; - xfrm4_encap(skb); + err = x->mode->output(skb); + if (err) + goto error; err = x->type->output(x, skb); if (err) diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index f8a107ab5592..e923d4dea418 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -106,6 +106,26 @@ config INET6_TUNNEL tristate default n +config INET6_XFRM_MODE_TRANSPORT + tristate "IPv6: IPsec transport mode" + depends on IPV6 + default IPV6 + select XFRM + ---help--- + Support for IPsec transport mode. + + If unsure, say Y. + +config INET6_XFRM_MODE_TUNNEL + tristate "IPv6: IPsec tunnel mode" + depends on IPV6 + default IPV6 + select XFRM + ---help--- + Support for IPsec tunnel mode. + + If unsure, say Y. + config IPV6_TUNNEL tristate "IPv6: IPv6-in-IPv6 tunnel" select INET6_TUNNEL diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index a760b0988fbb..386e0a626948 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -20,6 +20,8 @@ obj-$(CONFIG_INET6_ESP) += esp6.o obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o +obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o +obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e46048974f37..416f6e428a0a 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -488,6 +489,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } +EXPORT_SYMBOL_GPL(ip6_find_1stfragopt); static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 00cfdee18dca..0405d74ff910 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -13,21 +13,9 @@ #include #include #include -#include -#include -#include #include #include -static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) -{ - struct ipv6hdr *outer_iph = skb->nh.ipv6h; - struct ipv6hdr *inner_iph = skb->h.ipv6h; - - if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) - IP6_ECN_set_ce(inner_iph); -} - int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) { int err; @@ -81,21 +69,10 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) xfrm_vec[xfrm_nr++] = x; + if (x->mode->input(x, skb)) + goto drop; + if (x->props.mode) { /* XXX */ - if (nexthdr != IPPROTO_IPV6) - goto drop; - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto drop; - if (skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto drop; - if (x->props.flags & XFRM_STATE_DECAP_DSCP) - ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip6_ecn_decapsulate(skb); - skb->mac.raw = memmove(skb->data - skb->mac_len, - skb->mac.raw, skb->mac_len); - skb->nh.raw = skb->data; decaps = 1; break; } diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c new file mode 100644 index 000000000000..5efbbae08ef0 --- /dev/null +++ b/net/ipv6/xfrm6_mode_transport.c @@ -0,0 +1,73 @@ +/* + * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6. + * + * Copyright (C) 2002 USAGI/WIDE Project + * Copyright (c) 2004-2006 Herbert Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Add encapsulation header. + * + * The IP header and mutable extension headers will be moved forward to make + * space for the encapsulation header. + * + * On exit, skb->h will be set to the start of the encapsulation header to be + * filled in by x->type->output and skb->nh will be set to the nextheader field + * of the extension header directly preceding the encapsulation header, or in + * its absence, that of the top IP header. The value of skb->data will always + * point to the top IP header. + */ +static int xfrm6_transport_output(struct sk_buff *skb) +{ + struct xfrm_state *x = skb->dst->xfrm; + struct ipv6hdr *iph; + u8 *prevhdr; + int hdr_len; + + skb_push(skb, x->props.header_len); + iph = skb->nh.ipv6h; + + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); + skb->nh.raw = prevhdr - x->props.header_len; + skb->h.raw = skb->data + hdr_len; + memmove(skb->data, iph, hdr_len); + return 0; +} + +static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) +{ + return 0; +} + +static struct xfrm_mode xfrm6_transport_mode = { + .input = xfrm6_transport_input, + .output = xfrm6_transport_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_TRANSPORT, +}; + +static int __init xfrm6_transport_init(void) +{ + return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6); +} + +static void __exit xfrm6_transport_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6); + BUG_ON(err); +} + +module_init(xfrm6_transport_init); +module_exit(xfrm6_transport_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT); diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c new file mode 100644 index 000000000000..8af79be2edca --- /dev/null +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -0,0 +1,121 @@ +/* + * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6. + * + * Copyright (C) 2002 USAGI/WIDE Project + * Copyright (c) 2004-2006 Herbert Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) +{ + struct ipv6hdr *outer_iph = skb->nh.ipv6h; + struct ipv6hdr *inner_iph = skb->h.ipv6h; + + if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) + IP6_ECN_set_ce(inner_iph); +} + +/* Add encapsulation header. + * + * The top IP header will be constructed per RFC 2401. The following fields + * in it shall be filled in by x->type->output: + * payload_len + * + * On exit, skb->h will be set to the start of the encapsulation header to be + * filled in by x->type->output and skb->nh will be set to the nextheader field + * of the extension header directly preceding the encapsulation header, or in + * its absence, that of the top IP header. The value of skb->data will always + * point to the top IP header. + */ +static int xfrm6_tunnel_output(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct ipv6hdr *iph, *top_iph; + int dsfield; + + skb_push(skb, x->props.header_len); + iph = skb->nh.ipv6h; + + skb->nh.raw = skb->data; + top_iph = skb->nh.ipv6h; + skb->nh.raw = &top_iph->nexthdr; + skb->h.ipv6h = top_iph + 1; + + top_iph->version = 6; + top_iph->priority = iph->priority; + top_iph->flow_lbl[0] = iph->flow_lbl[0]; + top_iph->flow_lbl[1] = iph->flow_lbl[1]; + top_iph->flow_lbl[2] = iph->flow_lbl[2]; + dsfield = ipv6_get_dsfield(top_iph); + dsfield = INET_ECN_encapsulate(dsfield, dsfield); + if (x->props.flags & XFRM_STATE_NOECN) + dsfield &= ~INET_ECN_MASK; + ipv6_change_dsfield(top_iph, 0, dsfield); + top_iph->nexthdr = IPPROTO_IPV6; + top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); + ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); + ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); + return 0; +} + +static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) +{ + int err = -EINVAL; + + if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6) + goto out; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto out; + + if (skb_cloned(skb) && + (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + goto out; + + if (x->props.flags & XFRM_STATE_DECAP_DSCP) + ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip6_ecn_decapsulate(skb); + skb->mac.raw = memmove(skb->data - skb->mac_len, + skb->mac.raw, skb->mac_len); + skb->nh.raw = skb->data; + err = 0; + +out: + return err; +} + +static struct xfrm_mode xfrm6_tunnel_mode = { + .input = xfrm6_tunnel_input, + .output = xfrm6_tunnel_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_TUNNEL, +}; + +static int __init xfrm6_tunnel_init(void) +{ + return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6); +} + +static void __exit xfrm6_tunnel_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6); + BUG_ON(err); +} + +module_init(xfrm6_tunnel_init); +module_exit(xfrm6_tunnel_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 80242172a5df..16e84254a252 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -14,68 +14,9 @@ #include #include #include -#include -#include #include #include -/* Add encapsulation header. - * - * In transport mode, the IP header and mutable extension headers will be moved - * forward to make space for the encapsulation header. - * - * In tunnel mode, the top IP header will be constructed per RFC 2401. - * The following fields in it shall be filled in by x->type->output: - * payload_len - * - * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and skb->nh will be set to the nextheader field - * of the extension header directly preceding the encapsulation header, or in - * its absence, that of the top IP header. The value of skb->data will always - * point to the top IP header. - */ -static void xfrm6_encap(struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct ipv6hdr *iph, *top_iph; - int dsfield; - - skb_push(skb, x->props.header_len); - iph = skb->nh.ipv6h; - - if (!x->props.mode) { - u8 *prevhdr; - int hdr_len; - - hdr_len = ip6_find_1stfragopt(skb, &prevhdr); - skb->nh.raw = prevhdr - x->props.header_len; - skb->h.raw = skb->data + hdr_len; - memmove(skb->data, iph, hdr_len); - return; - } - - skb->nh.raw = skb->data; - top_iph = skb->nh.ipv6h; - skb->nh.raw = &top_iph->nexthdr; - skb->h.ipv6h = top_iph + 1; - - top_iph->version = 6; - top_iph->priority = iph->priority; - top_iph->flow_lbl[0] = iph->flow_lbl[0]; - top_iph->flow_lbl[1] = iph->flow_lbl[1]; - top_iph->flow_lbl[2] = iph->flow_lbl[2]; - dsfield = ipv6_get_dsfield(top_iph); - dsfield = INET_ECN_encapsulate(dsfield, dsfield); - if (x->props.flags & XFRM_STATE_NOECN) - dsfield &= ~INET_ECN_MASK; - ipv6_change_dsfield(top_iph, 0, dsfield); - top_iph->nexthdr = IPPROTO_IPV6; - top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); - ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); - ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); -} - static int xfrm6_tunnel_check_size(struct sk_buff *skb) { int mtu, ret = 0; @@ -118,7 +59,9 @@ static int xfrm6_output_one(struct sk_buff *skb) if (err) goto error; - xfrm6_encap(skb); + err = x->mode->output(skb); + if (err) + goto error; err = x->type->output(x, skb); if (err) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 44b64a593c01..b8936926c24b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -138,6 +138,89 @@ void xfrm_put_type(struct xfrm_type *type) module_put(type->owner); } +int xfrm_register_mode(struct xfrm_mode *mode, int family) +{ + struct xfrm_policy_afinfo *afinfo; + struct xfrm_mode **modemap; + int err; + + if (unlikely(mode->encap >= XFRM_MODE_MAX)) + return -EINVAL; + + afinfo = xfrm_policy_lock_afinfo(family); + if (unlikely(afinfo == NULL)) + return -EAFNOSUPPORT; + + err = -EEXIST; + modemap = afinfo->mode_map; + if (likely(modemap[mode->encap] == NULL)) { + modemap[mode->encap] = mode; + err = 0; + } + + xfrm_policy_unlock_afinfo(afinfo); + return err; +} +EXPORT_SYMBOL(xfrm_register_mode); + +int xfrm_unregister_mode(struct xfrm_mode *mode, int family) +{ + struct xfrm_policy_afinfo *afinfo; + struct xfrm_mode **modemap; + int err; + + if (unlikely(mode->encap >= XFRM_MODE_MAX)) + return -EINVAL; + + afinfo = xfrm_policy_lock_afinfo(family); + if (unlikely(afinfo == NULL)) + return -EAFNOSUPPORT; + + err = -ENOENT; + modemap = afinfo->mode_map; + if (likely(modemap[mode->encap] == mode)) { + modemap[mode->encap] = NULL; + err = 0; + } + + xfrm_policy_unlock_afinfo(afinfo); + return err; +} +EXPORT_SYMBOL(xfrm_unregister_mode); + +struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) +{ + struct xfrm_policy_afinfo *afinfo; + struct xfrm_mode *mode; + int modload_attempted = 0; + + if (unlikely(encap >= XFRM_MODE_MAX)) + return NULL; + +retry: + afinfo = xfrm_policy_get_afinfo(family); + if (unlikely(afinfo == NULL)) + return NULL; + + mode = afinfo->mode_map[encap]; + if (unlikely(mode && !try_module_get(mode->owner))) + mode = NULL; + if (!mode && !modload_attempted) { + xfrm_policy_put_afinfo(afinfo); + request_module("xfrm-mode-%d-%d", family, encap); + modload_attempted = 1; + goto retry; + } + + xfrm_policy_put_afinfo(afinfo); + return mode; +} + +void xfrm_put_mode(struct xfrm_mode *mode) +{ + module_put(mode->owner); +} + static inline unsigned long make_jiffies(long secs) { if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index ee62c239a7e3..17b29ec3c417 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -77,6 +77,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) kfree(x->ealg); kfree(x->calg); kfree(x->encap); + if (x->mode) + xfrm_put_mode(x->mode); if (x->type) { x->type->destructor(x); xfrm_put_type(x->type); @@ -1193,6 +1195,10 @@ int xfrm_init_state(struct xfrm_state *x) if (err) goto error; + x->mode = xfrm_get_mode(x->props.mode, family); + if (x->mode == NULL) + goto error; + x->km.state = XFRM_STATE_VALID; error: -- cgit v1.2.3 From 73654d61e556483ad324b90989eae26b22df6ef6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 27 May 2006 23:06:33 -0700 Subject: [IPSEC] xfrm: Use IPPROTO_MAX instead of 256 The size of the type_map array (256) comes from the number of IP protocols, i.e., IPPROTO_MAX. This patch is based on a suggestion from Ingo Oeser. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ed5bb34f817f..9c5ee9f20b65 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -207,7 +207,7 @@ struct xfrm_type; struct xfrm_dst; struct xfrm_policy_afinfo { unsigned short family; - struct xfrm_type *type_map[256]; + struct xfrm_type *type_map[IPPROTO_MAX]; struct xfrm_mode *mode_map[XFRM_MODE_MAX]; struct dst_ops *dst_ops; void (*garbage_collect)(void); -- cgit v1.2.3 From 62b7743483b402f8fb73545d5d487ca714e82766 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 29 May 2006 18:20:32 -0700 Subject: [NETFILTER]: x_tables: add quota match Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/xt_quota.h | 16 +++++++ net/netfilter/Kconfig | 10 ++++ net/netfilter/Makefile | 1 + net/netfilter/xt_quota.c | 96 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 include/linux/netfilter/xt_quota.h create mode 100644 net/netfilter/xt_quota.c (limited to 'include') diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h new file mode 100644 index 000000000000..acd7fd77bbee --- /dev/null +++ b/include/linux/netfilter/xt_quota.h @@ -0,0 +1,16 @@ +#ifndef _XT_QUOTA_H +#define _XT_QUOTA_H + +enum xt_quota_flags { + XT_QUOTA_INVERT = 0x1, +}; +#define XT_QUOTA_MASK 0x1 + +struct xt_quota_info { + u_int32_t flags; + u_int32_t pad; + aligned_u64 quota; + struct xt_quota_info *master; +}; + +#endif /* _XT_QUOTA_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index e2893effdfaa..5543c7b74535 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -329,6 +329,16 @@ config NETFILTER_XT_MATCH_PKTTYPE To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_QUOTA + tristate '"quota" match support' + depends on NETFILTER_XTABLES + help + This option adds a `quota' match, which allows to match on a + byte counter. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + config NETFILTER_XT_MATCH_REALM tristate '"realm" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 95b7e416512d..4b6a6ea07373 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o +obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c new file mode 100644 index 000000000000..4cdba7469dc4 --- /dev/null +++ b/net/netfilter/xt_quota.c @@ -0,0 +1,96 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston + */ +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sam Johnston "); + +static DEFINE_SPINLOCK(quota_lock); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + const struct xt_match *match, const void *matchinfo, + int offset, unsigned int protoff, int *hotdrop) +{ + struct xt_quota_info *q = ((struct xt_quota_info *)matchinfo)->master; + int ret = q->flags & XT_QUOTA_INVERT ? 1 : 0; + + spin_lock_bh("a_lock); + if (q->quota >= skb->len) { + q->quota -= skb->len; + ret ^= 1; + } else { + /* we do not allow even small packets from now on */ + q->quota = 0; + } + spin_unlock_bh("a_lock); + + return ret; +} + +static int +checkentry(const char *tablename, const void *entry, + const struct xt_match *match, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + struct xt_quota_info *q = (struct xt_quota_info *)matchinfo; + + if (q->flags & ~XT_QUOTA_MASK) + return 0; + /* For SMP, we only want to use one set of counters. */ + q->master = q; + return 1; +} + +static struct xt_match quota_match = { + .name = "quota", + .family = AF_INET, + .match = match, + .matchsize = sizeof(struct xt_quota_info), + .checkentry = checkentry, + .me = THIS_MODULE +}; + +static struct xt_match quota_match6 = { + .name = "quota", + .family = AF_INET6, + .match = match, + .matchsize = sizeof(struct xt_quota_info), + .checkentry = checkentry, + .me = THIS_MODULE +}; + +static int __init xt_quota_init(void) +{ + int ret; + + ret = xt_register_match("a_match); + if (ret) + goto err1; + ret = xt_register_match("a_match6); + if (ret) + goto err2; + return ret; + +err2: + xt_unregister_match("a_match); +err1: + return ret; +} + +static void __exit xt_quota_fini(void) +{ + xt_unregister_match("a_match6); + xt_unregister_match("a_match); +} + +module_init(xt_quota_init); +module_exit(xt_quota_fini); -- cgit v1.2.3 From f3389805e53a13bd969ee1c8fc5a4137b7c6c167 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 29 May 2006 18:21:00 -0700 Subject: [NETFILTER]: x_tables: add statistic match Add statistic match which is a combination of the nth and random matches. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/xt_statistic.h | 32 ++++++++++ net/netfilter/Kconfig | 6 ++ net/netfilter/Makefile | 1 + net/netfilter/xt_statistic.c | 112 +++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 include/linux/netfilter/xt_statistic.h create mode 100644 net/netfilter/xt_statistic.c (limited to 'include') diff --git a/include/linux/netfilter/xt_statistic.h b/include/linux/netfilter/xt_statistic.h new file mode 100644 index 000000000000..c344e9916e23 --- /dev/null +++ b/include/linux/netfilter/xt_statistic.h @@ -0,0 +1,32 @@ +#ifndef _XT_STATISTIC_H +#define _XT_STATISTIC_H + +enum xt_statistic_mode { + XT_STATISTIC_MODE_RANDOM, + XT_STATISTIC_MODE_NTH, + __XT_STATISTIC_MODE_MAX +}; +#define XT_STATISTIC_MODE_MAX (__XT_STATISTIC_MODE_MAX - 1) + +enum xt_statistic_flags { + XT_STATISTIC_INVERT = 0x1, +}; +#define XT_STATISTIC_MASK 0x1 + +struct xt_statistic_info { + u_int16_t mode; + u_int16_t flags; + union { + struct { + u_int32_t probability; + } random; + struct { + u_int32_t every; + u_int32_t packet; + u_int32_t count; + } nth; + } u; + struct xt_statistic_info *master __attribute__((aligned(8))); +}; + +#endif /* _XT_STATISTIC_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 5543c7b74535..85a7e1770252 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -375,6 +375,12 @@ config NETFILTER_XT_MATCH_STATE To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_STATISTIC + tristate '"statistic" match support' + depends on NETFILTER_XTABLES + help + statistic module + config NETFILTER_XT_MATCH_STRING tristate '"string" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 4b6a6ea07373..df1da25f40df 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o +obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c new file mode 100644 index 000000000000..de1037f58596 --- /dev/null +++ b/net/netfilter/xt_statistic.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006 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. + * + * Based on ipt_random and ipt_nth by Fabrice MARIE . + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("xtables statistical match module"); +MODULE_ALIAS("ipt_statistic"); +MODULE_ALIAS("ip6t_statistic"); + +static DEFINE_SPINLOCK(nth_lock); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + const struct xt_match *match, const void *matchinfo, + int offset, unsigned int protoff, int *hotdrop) +{ + struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo; + int ret = info->flags & XT_STATISTIC_INVERT ? 1 : 0; + + switch (info->mode) { + case XT_STATISTIC_MODE_RANDOM: + if ((net_random() & 0x7FFFFFFF) < info->u.random.probability) + ret ^= 1; + break; + case XT_STATISTIC_MODE_NTH: + info = info->master; + spin_lock_bh(&nth_lock); + if (info->u.nth.count++ == info->u.nth.every) { + info->u.nth.count = 0; + ret ^= 1; + } + spin_unlock_bh(&nth_lock); + break; + } + + return ret; +} + +static int +checkentry(const char *tablename, const void *entry, + const struct xt_match *match, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo; + + if (info->mode > XT_STATISTIC_MODE_MAX || + info->flags & ~XT_STATISTIC_MASK) + return 0; + info->master = info; + return 1; +} + +static struct xt_match statistic_match = { + .name = "statistic", + .match = match, + .matchsize = sizeof(struct xt_statistic_info), + .checkentry = checkentry, + .family = AF_INET, + .me = THIS_MODULE, +}; + +static struct xt_match statistic_match6 = { + .name = "statistic", + .match = match, + .matchsize = sizeof(struct xt_statistic_info), + .checkentry = checkentry, + .family = AF_INET6, + .me = THIS_MODULE, +}; + +static int __init xt_statistic_init(void) +{ + int ret; + + ret = xt_register_match(&statistic_match); + if (ret) + goto err1; + + ret = xt_register_match(&statistic_match6); + if (ret) + goto err2; + return ret; +err2: + xt_unregister_match(&statistic_match); +err1: + return ret; +} + +static void __exit xt_statistic_fini(void) +{ + xt_unregister_match(&statistic_match6); + xt_unregister_match(&statistic_match); +} + +module_init(xt_statistic_init); +module_exit(xt_statistic_fini); -- cgit v1.2.3 From 39a27a35c5c1b5be499a0576a35c45a011788bf8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 29 May 2006 18:23:54 -0700 Subject: [NETFILTER]: conntrack: add sysctl to disable checksumming Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 1 + include/linux/sysctl.h | 2 ++ include/net/netfilter/nf_conntrack.h | 1 + net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 2 +- net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 2 +- net/ipv4/netfilter/ip_conntrack_proto_udp.c | 2 +- net/ipv4/netfilter/ip_conntrack_standalone.c | 11 +++++++++++ net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 2 +- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 +- net/netfilter/nf_conntrack_proto_tcp.c | 5 +++-- net/netfilter/nf_conntrack_proto_udp.c | 3 ++- net/netfilter/nf_conntrack_standalone.c | 11 +++++++++++ 12 files changed, 36 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index d54d7b278e96..5473c01f69ea 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -293,6 +293,7 @@ static inline int is_dying(struct ip_conntrack *ct) } extern unsigned int ip_conntrack_htable_size; +extern int ip_conntrack_checksum; #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index cd9e7c0825ad..98338ed2c0b6 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -313,6 +313,7 @@ enum NET_NF_CONNTRACK_FRAG6_TIMEOUT=29, NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30, NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31, + NET_NF_CONNTRACK_CHECKSUM=32, }; /* /proc/sys/net/ipv4 */ @@ -492,6 +493,7 @@ enum NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25, NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26, NET_IPV4_NF_CONNTRACK_COUNT=27, + NET_IPV4_NF_CONNTRACK_CHECKSUM=28, }; /* /proc/sys/net/ipv6 */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 916013ca4a5c..dbe7a114d0c5 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -285,6 +285,7 @@ static inline int nf_ct_is_dying(struct nf_conn *ct) } extern unsigned int nf_conntrack_htable_size; +extern int nf_conntrack_checksum; #define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++) diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index d8b14a9010a6..23f1c504586d 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -224,7 +224,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, } /* See ip_conntrack_proto_tcp.c */ - if (hooknum == NF_IP_PRE_ROUTING && + if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && nf_ip_checksum(skb, hooknum, skb->nh.iph->ihl * 4, 0)) { if (LOG_INVALID(IPPROTO_ICMP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 062b252b58ad..c5c2ce5cdeb8 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -870,7 +870,7 @@ static int tcp_error(struct sk_buff *skb, * and moreover root might send raw packets. */ /* FIXME: Source route IP option packets --RR */ - if (hooknum == NF_IP_PRE_ROUTING && + if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_TCP)) { if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 70899868783b..9b2c16b4d2ff 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -120,7 +120,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, * because the semantic of CHECKSUM_HW is different there * and moreover root might send raw packets. * FIXME: Source route IP option packets --RR */ - if (hooknum == NF_IP_PRE_ROUTING && + if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) { if (LOG_INVALID(IPPROTO_UDP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index f0cc7feb0da3..6cb9b989d14c 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -564,6 +564,8 @@ extern unsigned int ip_ct_generic_timeout; static int log_invalid_proto_min = 0; static int log_invalid_proto_max = 255; +int ip_conntrack_checksum = 1; + static struct ctl_table_header *ip_ct_sysctl_header; static ctl_table ip_ct_sysctl_table[] = { @@ -591,6 +593,14 @@ static ctl_table ip_ct_sysctl_table[] = { .mode = 0444, .proc_handler = &proc_dointvec, }, + { + .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM, + .procname = "ip_conntrack_checksum", + .data = &ip_conntrack_checksum, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, .procname = "ip_conntrack_tcp_timeout_syn_sent", @@ -946,6 +956,7 @@ EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname); EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get); EXPORT_SYMBOL_GPL(ip_conntrack_proto_put); EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find); +EXPORT_SYMBOL_GPL(ip_conntrack_checksum); #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 4b0d361cc6e6..663a73ee3f2f 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -235,7 +235,7 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff, } /* See ip_conntrack_proto_tcp.c */ - if (hooknum == NF_IP_PRE_ROUTING && + if (nf_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && nf_ip_checksum(skb, hooknum, dataoff, 0)) { if (LOG_INVALID(IPPROTO_ICMP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 86c6703265d0..ef18a7b7014b 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -233,7 +233,7 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, return -NF_ACCEPT; } - if (hooknum == NF_IP6_PRE_ROUTING && + if (nf_conntrack_checksum && hooknum == NF_IP6_PRE_ROUTING && nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, "nf_ct_icmpv6: ICMPv6 checksum failed\n"); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 69899f27d26a..12fb7c0a1509 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -828,8 +828,9 @@ static int tcp_error(struct sk_buff *skb, * and moreover root might send raw packets. */ /* FIXME: Source route IP option packets --RR */ - if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || - (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) && + if (nf_conntrack_checksum && + ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || + (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) && nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) { if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index d93edbfde9e3..ae07ebe3ab37 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -134,7 +134,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff, * because the semantic of CHECKSUM_HW is different there * and moreover root might send raw packets. * FIXME: Source route IP option packets --RR */ - if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || + if (nf_conntrack_checksum && + ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) && nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { if (LOG_INVALID(IPPROTO_UDP)) diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 408960c6a544..e01d20d8e287 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -455,6 +455,8 @@ extern unsigned int nf_ct_generic_timeout; static int log_invalid_proto_min = 0; static int log_invalid_proto_max = 255; +int nf_conntrack_checksum = 1; + static struct ctl_table_header *nf_ct_sysctl_header; static ctl_table nf_ct_sysctl_table[] = { @@ -482,6 +484,14 @@ static ctl_table nf_ct_sysctl_table[] = { .mode = 0444, .proc_handler = &proc_dointvec, }, + { + .ctl_name = NET_NF_CONNTRACK_CHECKSUM, + .procname = "nf_conntrack_checksum", + .data = &nf_conntrack_checksum, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, .procname = "nf_conntrack_tcp_timeout_syn_sent", @@ -851,6 +861,7 @@ EXPORT_SYMBOL(nf_ct_proto_put); EXPORT_SYMBOL(nf_ct_l3proto_find_get); EXPORT_SYMBOL(nf_ct_l3proto_put); EXPORT_SYMBOL(nf_ct_l3protos); +EXPORT_SYMBOL_GPL(nf_conntrack_checksum); EXPORT_SYMBOL(nf_conntrack_expect_alloc); EXPORT_SYMBOL(nf_conntrack_expect_put); EXPORT_SYMBOL(nf_conntrack_expect_related); -- cgit v1.2.3 From 997ae831ade74bdaed4172b1c02060b9efd6e206 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 29 May 2006 18:24:20 -0700 Subject: [NETFILTER]: conntrack: add fixed timeout flag in connection tracking Add a flag in a connection status to have a non updated timeout. This permits to have connection that automatically die at a given time. Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_common.h | 4 ++++ net/ipv4/netfilter/ip_conntrack_core.c | 6 ++++++ net/netfilter/nf_conntrack_core.c | 6 ++++++ 3 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 3ff88c878308..d2e4bd7a7a14 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -69,6 +69,10 @@ enum ip_conntrack_status { /* Connection is dying (removed from lists), can not be unset. */ IPS_DYING_BIT = 9, IPS_DYING = (1 << IPS_DYING_BIT), + + /* Connection has fixed timeout. */ + IPS_FIXED_TIMEOUT_BIT = 10, + IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), }; /* Connection tracking event bits */ diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index a297da7bbef5..4fe9e69378df 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -1130,6 +1130,12 @@ void __ip_ct_refresh_acct(struct ip_conntrack *ct, write_lock_bh(&ip_conntrack_lock); + /* Only update if this is not a fixed timeout */ + if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + write_unlock_bh(&ip_conntrack_lock); + return; + } + /* If not in hash table, timer will not be active yet */ if (!is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f9b83f91371a..bc2bd4c3859e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1396,6 +1396,12 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, write_lock_bh(&nf_conntrack_lock); + /* Only update if this is not a fixed timeout */ + if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { + write_unlock_bh(&nf_conntrack_lock); + return; + } + /* If not in hash table, timer will not be active yet */ if (!nf_ct_is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; -- cgit v1.2.3 From 3726add76643c715d437aceda320d319153b6113 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 29 May 2006 18:24:39 -0700 Subject: [NETFILTER]: ctnetlink: fix NAT configuration The current configuration only allows to configure one manip and overloads conntrack status flags with netlink semantic. Signed-off-by: Patrick Mchardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink_conntrack.h | 4 +- net/ipv4/netfilter/ip_conntrack_netlink.c | 53 +++++++++++---------------- net/netfilter/nf_conntrack_netlink.c | 53 +++++++++++---------------- 3 files changed, 47 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 668ec946c8e2..b5883ccee295 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -27,13 +27,15 @@ enum ctattr_type { CTA_STATUS, CTA_PROTOINFO, CTA_HELP, - CTA_NAT, + CTA_NAT_SRC, +#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */ CTA_TIMEOUT, CTA_MARK, CTA_COUNTERS_ORIG, CTA_COUNTERS_REPLY, CTA_USE, CTA_ID, + CTA_NAT_DST, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 01bd7cab9367..af152e3623dc 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -629,7 +629,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { }; static inline int -ctnetlink_parse_nat(struct nfattr *cda[], +ctnetlink_parse_nat(struct nfattr *nat, const struct ip_conntrack *ct, struct ip_nat_range *range) { struct nfattr *tb[CTA_NAT_MAX]; @@ -639,7 +639,7 @@ ctnetlink_parse_nat(struct nfattr *cda[], memset(range, 0, sizeof(*range)); - nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]); + nfattr_parse_nested(tb, CTA_NAT_MAX, nat); if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; @@ -854,39 +854,30 @@ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) /* ASSURED bit can only be set */ return -EINVAL; - if (cda[CTA_NAT-1]) { + if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { #ifndef CONFIG_IP_NF_NAT_NEEDED return -EINVAL; #else - unsigned int hooknum; struct ip_nat_range range; - if (ctnetlink_parse_nat(cda, ct, &range) < 0) - return -EINVAL; - - DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", - NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), - htons(range.min.all), htons(range.max.all)); - - /* This is tricky but it works. ip_nat_setup_info needs the - * hook number as parameter, so let's do the correct - * conversion and run away */ - if (status & IPS_SRC_NAT_DONE) - hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ - else if (status & IPS_DST_NAT_DONE) - hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ - else - return -EINVAL; /* Missing NAT flags */ - - DEBUGP("NAT status: %lu\n", - status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); - - if (ip_nat_initialized(ct, HOOK2MANIP(hooknum))) - return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); - - DEBUGP("NAT status after setup_info: %lu\n", - ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); + if (cda[CTA_NAT_DST-1]) { + if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, + &range) < 0) + return -EINVAL; + if (ip_nat_initialized(ct, + HOOK2MANIP(NF_IP_PRE_ROUTING))) + return -EEXIST; + ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); + } + if (cda[CTA_NAT_SRC-1]) { + if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, + &range) < 0) + return -EINVAL; + if (ip_nat_initialized(ct, + HOOK2MANIP(NF_IP_POST_ROUTING))) + return -EEXIST; + ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + } #endif } @@ -1106,7 +1097,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, /* implicit 'else' */ /* we only allow nat config for new conntracks */ - if (cda[CTA_NAT-1]) { + if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { err = -EINVAL; goto out_unlock; } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index bd10eb944b65..8f27fe9446f2 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -641,7 +641,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { }; static inline int -ctnetlink_parse_nat(struct nfattr *cda[], +ctnetlink_parse_nat(struct nfattr *nat, const struct nf_conn *ct, struct ip_nat_range *range) { struct nfattr *tb[CTA_NAT_MAX]; @@ -651,7 +651,7 @@ ctnetlink_parse_nat(struct nfattr *cda[], memset(range, 0, sizeof(*range)); - nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]); + nfattr_parse_nested(tb, CTA_NAT_MAX, nat); if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; @@ -866,39 +866,30 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) /* ASSURED bit can only be set */ return -EINVAL; - if (cda[CTA_NAT-1]) { + if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { #ifndef CONFIG_IP_NF_NAT_NEEDED return -EINVAL; #else - unsigned int hooknum; struct ip_nat_range range; - if (ctnetlink_parse_nat(cda, ct, &range) < 0) - return -EINVAL; - - DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", - NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), - htons(range.min.all), htons(range.max.all)); - - /* This is tricky but it works. ip_nat_setup_info needs the - * hook number as parameter, so let's do the correct - * conversion and run away */ - if (status & IPS_SRC_NAT_DONE) - hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ - else if (status & IPS_DST_NAT_DONE) - hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ - else - return -EINVAL; /* Missing NAT flags */ - - DEBUGP("NAT status: %lu\n", - status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); - - if (ip_nat_initialized(ct, HOOK2MANIP(hooknum))) - return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); - - DEBUGP("NAT status after setup_info: %lu\n", - ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); + if (cda[CTA_NAT_DST-1]) { + if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, + &range) < 0) + return -EINVAL; + if (ip_nat_initialized(ct, + HOOK2MANIP(NF_IP_PRE_ROUTING))) + return -EEXIST; + ip_nat_setup_info(ct, &range, hooknum); + } + if (cda[CTA_NAT_SRC-1]) { + if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, + &range) < 0) + return -EINVAL; + if (ip_nat_initialized(ct, + HOOK2MANIP(NF_IP_POST_ROUTING))) + return -EEXIST; + ip_nat_setup_info(ct, &range, hooknum); + } #endif } @@ -1122,7 +1113,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, /* implicit 'else' */ /* we only allow nat config for new conntracks */ - if (cda[CTA_NAT-1]) { + if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { err = -EINVAL; goto out_unlock; } -- cgit v1.2.3 From c0d4cfd96dd0cc0dbf49435898808b5553af4822 Mon Sep 17 00:00:00 2001 From: Jing Min Zhao Date: Mon, 29 May 2006 18:26:27 -0700 Subject: [NETFILTER]: H.323 helper: Add support for Call Forwarding Signed-off-by: Jing Min Zhao Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 1 + include/linux/netfilter_ipv4/ip_conntrack_h323.h | 7 ++ .../ip_conntrack_helper_h323_types.h | 3 +- net/ipv4/netfilter/Kconfig | 8 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 112 +++++++++++++++++++++ .../netfilter/ip_conntrack_helper_h323_types.c | 6 +- net/ipv4/netfilter/ip_nat_helper_h323.c | 77 ++++++++++++++ 7 files changed, 206 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 5473c01f69ea..17d7ef938a09 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -154,6 +154,7 @@ struct ip_conntrack_expect unsigned int flags; #ifdef CONFIG_IP_NF_NAT_NEEDED + u_int32_t saved_ip; /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ union ip_conntrack_manip_proto saved_proto; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index eace86bd2adb..3cbff7379002 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -71,6 +71,13 @@ extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, unsigned char **data, int dataoff, TransportAddress * addr, u_int16_t port, struct ip_conntrack_expect * exp); +extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb, + struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress * addr, + u_int16_t port, + struct ip_conntrack_expect * exp); extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress * addr, diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h index cc98f7aa5abe..3d4a773799fc 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h @@ -1,4 +1,4 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006 +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 * * Copyright (c) 2006 Jing Min Zhao * @@ -412,6 +412,7 @@ typedef struct Facility_UUIE { /* SEQUENCE */ eFacility_UUIE_destinationInfo = (1 << 14), eFacility_UUIE_h245SecurityMode = (1 << 13), } options; + TransportAddress alternativeAddress; FacilityReason reason; TransportAddress h245Address; Facility_UUIE_fastStart fastStart; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 1540e227890f..f86aeda3a5a0 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -183,10 +183,10 @@ config IP_NF_H323 With this module you can support H.323 on a connection tracking/NAT firewall. - This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP - and T.120 based data and applications including audio, video, FAX, - chat, whiteboard, file transfer, etc. For more information, please - see http://nath323.sourceforge.net/. + This module supports RAS, Fast Start, H.245 Tunnelling, Call + Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat, + whiteboard, file transfer, etc. For more information, please + visit http://nath323.sourceforge.net/. If you want to compile it as a module, say 'M' here and read Documentation/modules.txt. If unsure, say 'N'. diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 518f581d39ec..3052468a6ab1 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #if 0 #define DEBUGP printk @@ -38,6 +40,13 @@ static int gkrouted_only = 1; module_param(gkrouted_only, int, 0600); MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); +static char *internal_net = NULL; +static u_int32_t internal_net_addr = 0; +static u_int32_t internal_net_mask = 0; +module_param(internal_net, charp, 0600); +MODULE_PARM_DESC(internal_net, "specify your internal network using format " + "address/mask. this is used by call forwarding support"); + /* Hooks for NAT */ int (*set_h245_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, @@ -77,6 +86,12 @@ int (*nat_h245_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, TransportAddress * addr, u_int16_t port, struct ip_conntrack_expect * exp); +int (*nat_callforwarding_hook) (struct sk_buff ** pskb, + struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress * addr, u_int16_t port, + struct ip_conntrack_expect * exp); int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, @@ -683,6 +698,76 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, return ret; } +/* Forwarding declaration */ +void ip_conntrack_q931_expect(struct ip_conntrack *new, + struct ip_conntrack_expect *this); + +/****************************************************************************/ +static int expect_callforwarding(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress * addr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + u_int32_t ip; + u_int16_t port; + struct ip_conntrack_expect *exp = NULL; + + /* Read alternativeAddress */ + if (!get_h225_addr(*data, addr, &ip, &port) || port == 0) + return 0; + + /* If the calling party is on the same side of the forward-to party, + * we don't need to track the second call */ + if (internal_net && + ((ip & internal_net_mask) == internal_net_addr) == + ((ct->tuplehash[!dir].tuple.src.ip & internal_net_mask) == + internal_net_addr)) { + DEBUGP("ip_ct_q931: Call Forwarding not tracked\n"); + return 0; + } + + /* Create expect for the second call leg */ + if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) + return -1; + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.ip = ip; + exp->tuple.dst.u.tcp.port = htons(port); + exp->tuple.dst.protonum = IPPROTO_TCP; + exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.u.tcp.port = 0; + exp->mask.dst.ip = 0xFFFFFFFF; + exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.protonum = 0xFF; + exp->flags = 0; + + if (ct->tuplehash[dir].tuple.src.ip != + ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) { + /* Need NAT */ + ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff, + addr, port, exp); + } else { /* Conntrack only */ + exp->expectfn = ip_conntrack_q931_expect; + + if (ip_conntrack_expect_related(exp) == 0) { + DEBUGP("ip_ct_q931: expect Call Forwarding " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), + ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), + ntohs(exp->tuple.dst.u.tcp.port)); + } else + ret = -1; + } + + ip_conntrack_expect_put(exp); + + return ret; +} + /****************************************************************************/ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, @@ -878,6 +963,15 @@ static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct, DEBUGP("ip_ct_q931: Facility\n"); + if (facility->reason.choice == eFacilityReason_callForwarded) { + if (facility->options & eFacility_UUIE_alternativeAddress) + return expect_callforwarding(pskb, ct, ctinfo, data, + dataoff, + &facility-> + alternativeAddress); + return 0; + } + if (facility->options & eFacility_UUIE_h245Address) { ret = expect_h245(pskb, ct, ctinfo, data, dataoff, &facility->h245Address); @@ -1668,6 +1762,7 @@ static void fini(void) static int __init init(void) { int ret; + char *p; h323_buffer = kmalloc(65536, GFP_KERNEL); if (!h323_buffer) @@ -1678,6 +1773,22 @@ static int __init init(void) return ret; } + if (internal_net) { + if ((p = strchr(internal_net, '/'))) + *p++ = 0; + if (isdigit(internal_net[0])) { + internal_net_addr = in_aton(internal_net); + if (p && isdigit(p[0])) + internal_net_mask = in_aton(p); + else + internal_net_mask = 0xffffffff; + internal_net_addr &= internal_net_mask; + } + DEBUGP("ip_ct_h323: internal_net = %u.%u.%u.%u/%u.%u.%u.%u\n", + NIPQUAD(internal_net_addr), + NIPQUAD(internal_net_mask)); + } + DEBUGP("ip_ct_h323: init success\n"); return 0; } @@ -1696,6 +1807,7 @@ EXPORT_SYMBOL_GPL(set_ras_addr_hook); EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook); EXPORT_SYMBOL_GPL(nat_t120_hook); EXPORT_SYMBOL_GPL(nat_h245_hook); +EXPORT_SYMBOL_GPL(nat_callforwarding_hook); EXPORT_SYMBOL_GPL(nat_q931_hook); MODULE_AUTHOR("Jing Min Zhao "); diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c index 022c47b9f6c9..4b359618bedd 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c @@ -1,4 +1,4 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006 +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 * * Copyright (c) 2006 Jing Min Zhao * @@ -1069,8 +1069,8 @@ static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ static field_t _Facility_UUIE[] = { /* SEQUENCE */ {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("alternativeAddress") CHOICE, 3, 7, 7, SKIP | EXT | OPT, 0, - _TransportAddress}, + {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, _Facility_UUIE_alternativeAliasAddress}, {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c index d45663d137a7..419b878fb467 100644 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c @@ -486,6 +486,80 @@ static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct, return 0; } +/****************************************************************************/ +static void ip_nat_callforwarding_expect(struct ip_conntrack *new, + struct ip_conntrack_expect *this) +{ + struct ip_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip; + + /* hook doesn't matter, but it has to do source manip */ + ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* 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 = this->saved_proto; + range.min_ip = range.max_ip = this->saved_ip; + + /* hook doesn't matter, but it has to do destination manip */ + ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); + + ip_conntrack_q931_expect(new, this); +} + +/****************************************************************************/ +static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress * addr, u_int16_t port, + struct ip_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port; + + /* Set expectations for NAT */ + exp->saved_ip = exp->tuple.dst.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_callforwarding_expect; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (nated_port = port; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (ip_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("ip_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (!set_h225_addr(pskb, data, dataoff, addr, + ct->tuplehash[!dir].tuple.dst.ip, + nated_port) == 0) { + ip_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("ip_nat_q931: expect Call Forwarding " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + /****************************************************************************/ static int __init init(void) { @@ -496,6 +570,7 @@ static int __init init(void) BUG_ON(nat_rtp_rtcp_hook != NULL); BUG_ON(nat_t120_hook != NULL); BUG_ON(nat_h245_hook != NULL); + BUG_ON(nat_callforwarding_hook != NULL); BUG_ON(nat_q931_hook != NULL); set_h245_addr_hook = set_h245_addr; @@ -505,6 +580,7 @@ static int __init init(void) nat_rtp_rtcp_hook = nat_rtp_rtcp; nat_t120_hook = nat_t120; nat_h245_hook = nat_h245; + nat_callforwarding_hook = nat_callforwarding; nat_q931_hook = nat_q931; DEBUGP("ip_nat_h323: init success\n"); @@ -521,6 +597,7 @@ static void __exit fini(void) nat_rtp_rtcp_hook = NULL; nat_t120_hook = NULL; nat_h245_hook = NULL; + nat_callforwarding_hook = NULL; nat_q931_hook = NULL; synchronize_net(); } -- cgit v1.2.3 From ae5b7d8ba2c28d7d9835856fe0ca5f6ec95ea768 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 29 May 2006 18:27:09 -0700 Subject: [NETFILTER]: Add SIP connection tracking helper Add SIP connection tracking helper. Originally written by Christian Hentschel , some cleanup, minor fixes and bidirectional SIP support added by myself. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 44 +++ net/ipv4/netfilter/Kconfig | 18 + net/ipv4/netfilter/Makefile | 2 + net/ipv4/netfilter/ip_conntrack_sip.c | 471 ++++++++++++++++++++++++ net/ipv4/netfilter/ip_nat_sip.c | 249 +++++++++++++ 5 files changed, 784 insertions(+) create mode 100644 include/linux/netfilter_ipv4/ip_conntrack_sip.h create mode 100644 net/ipv4/netfilter/ip_conntrack_sip.c create mode 100644 net/ipv4/netfilter/ip_nat_sip.c (limited to 'include') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h new file mode 100644 index 000000000000..913dad66c0fb --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -0,0 +1,44 @@ +#ifndef __IP_CONNTRACK_SIP_H__ +#define __IP_CONNTRACK_SIP_H__ +#ifdef __KERNEL__ + +#define SIP_PORT 5060 +#define SIP_TIMEOUT 3600 + +#define POS_VIA 0 +#define POS_CONTACT 1 +#define POS_CONTENT 2 +#define POS_MEDIA 3 +#define POS_OWNER 4 +#define POS_CONNECTION 5 +#define POS_REQ_HEADER 6 +#define POS_SDP_HEADER 7 + +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 (*match_len)(const char *, const char *, int *); +}; + +extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr); +extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *exp, + const char *dptr); + +extern int ct_sip_get_info(const char *dptr, size_t dlen, + unsigned int *matchoff, + unsigned int *matchlen, + struct sip_header_nfo *hnfo); +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); +#endif /* __KERNEL__ */ +#endif /* __IP_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index f86aeda3a5a0..ff4b118f14a9 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -191,6 +191,18 @@ config IP_NF_H323 If you want to compile it as a module, say 'M' here and read Documentation/modules.txt. If unsure, say 'N'. +config IP_NF_SIP + tristate "SIP protocol support (EXPERIMENTAL)" + depends on IP_NF_CONNTRACK && EXPERIMENTAL + help + SIP is an application-layer control protocol that can establish, + modify, and terminate multimedia sessions (conferences) such as + Internet telephony calls. With the ip_conntrack_sip and + the ip_nat_sip modules you can support the protocol on a connection + tracking/NATing firewall. + + To compile it as a module, choose M here. If unsure, say Y. + config IP_NF_QUEUE tristate "IP Userspace queueing via NETLINK (OBSOLETE)" help @@ -503,6 +515,12 @@ config IP_NF_NAT_H323 default IP_NF_NAT if IP_NF_H323=y default m if IP_NF_H323=m +config IP_NF_NAT_SIP + tristate + depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n + default IP_NF_NAT if IP_NF_SIP=y + default m if IP_NF_SIP=m + # mangle + specific targets config IP_NF_MANGLE tristate "Packet mangling" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 461cb1eb5de7..3ded4a3af59c 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o +obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o # NAT helpers @@ -40,6 +41,7 @@ obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o +obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c new file mode 100644 index 000000000000..fc87ce0da40d --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -0,0 +1,471 @@ +/* SIP extension for IP connection tracking. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_conntrack_ftp.c and other modules. + * + * 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 + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP connection tracking helper"); + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "port numbers of sip servers"); + +static unsigned int sip_timeout = SIP_TIMEOUT; +module_param(sip_timeout, uint, 0600); +MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); + +unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr); +EXPORT_SYMBOL_GPL(ip_nat_sip_hook); + +unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *exp, + const char *dptr); +EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); + +int ct_sip_get_info(const char *dptr, size_t dlen, + unsigned int *matchoff, + unsigned int *matchlen, + struct sip_header_nfo *hnfo); +EXPORT_SYMBOL_GPL(ct_sip_get_info); + + +static int digits_len(const char *dptr, const char *limit, int *shift); +static int epaddr_len(const char *dptr, const char *limit, int *shift); +static int skp_digits_len(const char *dptr, const char *limit, int *shift); +static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); + +struct sip_header_nfo ct_sip_hdrs[] = { + { /* 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, + }, + { /* 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 + }, + { /* 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 + }, + { /* SDP media info */ + .lname = "\nm=", + .lnlen = sizeof("\nm=") - 1, + .sname = "\rm=", + .snlen = sizeof("\rm=") - 1, + .ln_str = "audio ", + .ln_strlen = sizeof("audio ") - 1, + .match_len = digits_len + }, + { /* SDP owner address*/ + .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 + }, + { /* SDP connection info */ + .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 + }, + { /* Requests headers */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .sname = "sip:", + .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len + }, + { /* SDP version header */ + .lname = "\nv=", + .lnlen = sizeof("\nv=") - 1, + .sname = "\rv=", + .snlen = sizeof("\rv=") - 1, + .ln_str = "=", + .ln_strlen = sizeof("=") - 1, + .match_len = digits_len + } +}; +EXPORT_SYMBOL_GPL(ct_sip_hdrs); + +/* get line lenght 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) +{ + const char *limit = haystack + (haystack_len - needle_len); + + while (haystack <= limit) { + if (memcmp(haystack, needle, needle_len) == 0) + return haystack; + haystack++; + } + return NULL; +} +EXPORT_SYMBOL_GPL(ct_sip_search); + +static int digits_len(const char *dptr, const char *limit, int *shift) +{ + int len = 0; + while (dptr <= limit && isdigit(*dptr)) { + dptr++; + len++; + } + return len; +} + +/* get digits lenght, skiping blank spaces. */ +static int skp_digits_len(const char *dptr, const char *limit, int *shift) +{ + for (; dptr <= limit && *dptr == ' '; dptr++) + (*shift)++; + + return digits_len(dptr, limit, shift); +} + +/* Simple ipaddr parser.. */ +static int parse_ipaddr(const char *cp, const char **endp, + u_int32_t *ipaddr, const char *limit) +{ + unsigned long int val; + int i, digit = 0; + + for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) { + digit = 0; + if (!isdigit(*cp)) + break; + + val = simple_strtoul(cp, (char **)&cp, 10); + if (val > 0xFF) + return -1; + + ((u_int8_t *)ipaddr)[i] = val; + digit = 1; + + if (*cp != '.') + break; + cp++; + } + if (!digit) + return -1; + + if (endp) + *endp = cp; + + return 0; +} + +/* skip ip address. returns it lenght. */ +static int epaddr_len(const char *dptr, const char *limit, int *shift) +{ + const char *aux = dptr; + u_int32_t ip; + + if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) { + DEBUGP("ip: %s parse failed.!\n", dptr); + return 0; + } + + /* Port number */ + if (*dptr == ':') { + dptr++; + dptr += digits_len(dptr, limit, shift); + } + return dptr - aux; +} + +/* get address length, skiping user info. */ +static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) +{ + int s = *shift; + + for (; dptr <= limit && *dptr != '@'; dptr++) + (*shift)++; + + if (*dptr == '@') { + dptr++; + (*shift)++; + } else + *shift = s; + + return epaddr_len(dptr, limit, shift); +} + +/* Returns 0 if not found, -1 error parsing. */ +int ct_sip_get_info(const char *dptr, size_t dlen, + unsigned int *matchoff, + unsigned int *matchlen, + struct sip_header_nfo *hnfo) +{ + const char *limit, *aux, *k = dptr; + int shift = 0; + + limit = dptr + (dlen - hnfo->lnlen); + + while (dptr <= limit) { + if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && + (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { + dptr++; + continue; + } + aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, + ct_sip_lnlen(dptr, limit)); + if (!aux) { + DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, + hnfo->lname); + return -1; + } + aux += hnfo->ln_strlen; + + *matchlen = hnfo->match_len(aux, limit, &shift); + if (!*matchlen) + return -1; + + *matchoff = (aux - k) + shift; + + DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, + *matchlen); + return 1; + } + DEBUGP("%s header not found.\n", hnfo->lname); + return 0; +} + +static int set_expected_rtp(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + u_int32_t ipaddr, u_int16_t port, + const char *dptr) +{ + struct ip_conntrack_expect *exp; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int ret; + + exp = ip_conntrack_expect_alloc(ct); + if (exp == NULL) + return NF_DROP; + + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.src.u.udp.port = 0; + exp->tuple.dst.ip = ipaddr; + exp->tuple.dst.u.udp.port = htons(port); + exp->tuple.dst.protonum = IPPROTO_UDP; + + exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.u.udp.port = 0; + exp->mask.dst.ip = 0xFFFFFFFF; + exp->mask.dst.u.udp.port = 0xFFFF; + exp->mask.dst.protonum = 0xFF; + + exp->expectfn = NULL; + exp->flags = 0; + + if (ip_nat_sdp_hook) + ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr); + else { + if (ip_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + else + ret = NF_ACCEPT; + } + ip_conntrack_expect_put(exp); + + return ret; +} + +static int sip_help(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + unsigned int dataoff, datalen; + const char *dptr; + int ret = NF_ACCEPT; + int matchoff, matchlen; + u_int32_t ipaddr; + u_int16_t port; + + /* No Data ? */ + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + if (dataoff >= (*pskb)->len) { + DEBUGP("skb->len = %u\n", (*pskb)->len); + return NF_ACCEPT; + } + + ip_ct_refresh(ct, *pskb, sip_timeout * HZ); + + if (!skb_is_nonlinear(*pskb)) + dptr = (*pskb)->data + dataoff; + else { + DEBUGP("Copy of skbuff not supported yet.\n"); + goto out; + } + + if (ip_nat_sip_hook) { + if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) { + ret = NF_DROP; + goto out; + } + } + + /* After this point NAT, could have mangled skb, so + we need to recalculate payload lenght. */ + datalen = (*pskb)->len - dataoff; + + if (datalen < (sizeof("SIP/2.0 200") - 1)) + goto out; + + /* RTP info only in some SDP pkts */ + if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && + memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { + goto out; + } + /* Get ip and port address from SDP packet. */ + if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, + &ct_sip_hdrs[POS_CONNECTION]) > 0) { + + /* We'll drop only if there are parse problems. */ + if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, + dptr + datalen) < 0) { + ret = NF_DROP; + goto out; + } + if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, + &ct_sip_hdrs[POS_MEDIA]) > 0) { + + port = simple_strtoul(dptr + matchoff, NULL, 10); + if (port < 1024) { + ret = NF_DROP; + goto out; + } + ret = set_expected_rtp(pskb, ct, ctinfo, + ipaddr, port, dptr); + } + } +out: + return ret; +} + +static struct ip_conntrack_helper sip[MAX_PORTS]; +static char sip_names[MAX_PORTS][10]; + +static void fini(void) +{ + int i; + for (i = 0; i < ports_c; i++) { + DEBUGP("unregistering helper for port %d\n", ports[i]); + ip_conntrack_helper_unregister(&sip[i]); + } +} + +static int __init init(void) +{ + int i, ret; + char *tmpname; + + if (ports_c == 0) + ports[ports_c++] = SIP_PORT; + + for (i = 0; i < ports_c; i++) { + /* Create helper structure */ + memset(&sip[i], 0, sizeof(struct ip_conntrack_helper)); + + sip[i].tuple.dst.protonum = IPPROTO_UDP; + sip[i].tuple.src.u.udp.port = htons(ports[i]); + sip[i].mask.src.u.udp.port = 0xFFFF; + sip[i].mask.dst.protonum = 0xFF; + sip[i].max_expected = 1; + sip[i].timeout = 3 * 60; /* 3 minutes */ + sip[i].me = THIS_MODULE; + sip[i].help = sip_help; + + tmpname = &sip_names[i][0]; + if (ports[i] == SIP_PORT) + sprintf(tmpname, "sip"); + else + sprintf(tmpname, "sip-%d", i); + sip[i].name = tmpname; + + DEBUGP("port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(&sip[i]); + if (ret) { + printk("ERROR registering helper for port %d\n", + ports[i]); + fini(); + return ret; + } + } + return 0; +} + +module_init(init); +module_exit(fini); diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c new file mode 100644 index 000000000000..6ffba63adca2 --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -0,0 +1,249 @@ +/* SIP extension for UDP NAT alteration. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_nat_ftp.c and other modules. + * + * 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 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP NAT helper"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +extern struct sip_header_nfo ct_sip_hdrs[]; + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + struct sip_header_nfo *hnfo) +{ + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) + return 0; + + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; + + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; +} + +static unsigned int ip_nat_sip(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int bufflen, dataoff; + u_int32_t ip; + u_int16_t port; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + ip = ct->tuplehash[!dir].tuple.dst.ip; + port = ct->tuplehash[!dir].tuple.dst.u.udp.port; + bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); + + /* short packet ? */ + if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) + return 0; + + /* Basic rules: requests and responses. */ + if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { + const char *aux; + + if ((ctinfo) < IP_CT_IS_REPLY) { + mangle_sip_packet(pskb, ctinfo, ct, dptr, + (*pskb)->len - dataoff, + buffer, bufflen, + &ct_sip_hdrs[POS_CONTACT]); + return 1; + } + + if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, + (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + return 0; + + /* This search should ignore case, but later.. */ + aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, + (*pskb)->len - dataoff); + if (!aux) + return 0; + + if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), + ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) + return 1; + + return mangle_sip_packet(pskb, ctinfo, ct, dptr, + (*pskb)->len - dataoff, + buffer, bufflen, + &ct_sip_hdrs[POS_CONTACT]); + } + if ((ctinfo) < IP_CT_IS_REPLY) { + if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, + (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + return 0; + + /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ + mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); + return 1; + } + /* This mangle requests headers. */ + return mangle_sip_packet(pskb, ctinfo, ct, dptr, + ct_sip_lnlen(*dptr, + *dptr + (*pskb)->len - dataoff), + buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); +} + +static int mangle_content_len(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char *dptr) +{ + unsigned int dataoff, matchoff, matchlen; + char buffer[sizeof("65536")]; + int bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Get actual SDP lenght */ + if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, &ct_sip_hdrs[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 = (*pskb)->len - dataoff - matchoff + 2; + + /* Now, update SDP lenght */ + if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { + + bufflen = sprintf(buffer, "%u", c_len); + + return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, + buffer, bufflen); + } + } + return 0; +} + +static unsigned int mangle_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + u_int32_t newip, u_int16_t port, + const char *dptr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int dataoff, bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Mangle owner and contact info. */ + bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) + return 0; + + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION])) + return 0; + + /* Mangle media port. */ + bufflen = sprintf(buffer, "%u", port); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) + return 0; + + return mangle_content_len(pskb, ctinfo, ct, dptr); +} + +/* 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 **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *exp, + const char *dptr) +{ + struct ip_conntrack *ct = exp->master; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + u_int32_t newip; + u_int16_t port; + + DEBUGP("ip_nat_sdp():\n"); + + /* Connection will come from reply */ + newip = ct->tuplehash[!dir].tuple.dst.ip; + + exp->tuple.dst.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_follow_master; + + /* 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 (ip_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { + ip_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit fini(void) +{ + ip_nat_sip_hook = NULL; + ip_nat_sdp_hook = NULL; + /* Make sure noone calls it, meanwhile. */ + synchronize_net(); +} + +static int __init init(void) +{ + BUG_ON(ip_nat_sip_hook); + BUG_ON(ip_nat_sdp_hook); + ip_nat_sip_hook = ip_nat_sip; + ip_nat_sdp_hook = ip_nat_sdp; + return 0; +} + +module_init(init); +module_exit(fini); -- cgit v1.2.3 From 72dc5b9225c53310c010b68a70ea97c8c8e24bdf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Jun 2006 17:30:08 -0700 Subject: [TCP]: Minimum congestion window consolidation. Many of the TCP congestion methods all just use ssthresh as the minimum congestion window on decrease. Rather than duplicating the code, just have that be the default if that handle in the ops structure is not set. Minor behaviour change to TCP compound. It probably wants to use this (ssthresh) as lower bound, rather than ssthresh/2 because the latter causes undershoot on loss. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/tcp.h | 4 ++-- net/ipv4/tcp_bic.c | 7 ------- net/ipv4/tcp_compound.c | 1 - net/ipv4/tcp_cong.c | 6 +++--- net/ipv4/tcp_cubic.c | 6 ------ net/ipv4/tcp_htcp.c | 9 --------- net/ipv4/tcp_input.c | 13 +++++++++++-- net/ipv4/tcp_veno.c | 7 ------- net/ipv4/tcp_westwood.c | 18 +++++++----------- 9 files changed, 23 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index f1f472746e6c..de88c5472bfc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -632,7 +632,7 @@ struct tcp_congestion_ops { /* return slow start threshold (required) */ u32 (*ssthresh)(struct sock *sk); /* lower bound for congestion window (optional) */ - u32 (*min_cwnd)(struct sock *sk); + u32 (*min_cwnd)(const struct sock *sk); /* do new cwnd calculation (required) */ void (*cong_avoid)(struct sock *sk, u32 ack, u32 rtt, u32 in_flight, int good_ack); @@ -667,7 +667,7 @@ extern struct tcp_congestion_ops tcp_init_congestion_ops; extern u32 tcp_reno_ssthresh(struct sock *sk); extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight, int flag); -extern u32 tcp_reno_min_cwnd(struct sock *sk); +extern u32 tcp_reno_min_cwnd(const struct sock *sk); extern struct tcp_congestion_ops tcp_reno; static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state) diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index 035f2092d73a..b2d9021ad22b 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -198,12 +198,6 @@ static u32 bictcp_undo_cwnd(struct sock *sk) return max(tp->snd_cwnd, ca->last_max_cwnd); } -static u32 bictcp_min_cwnd(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - return tp->snd_ssthresh; -} - static void bictcp_state(struct sock *sk, u8 new_state) { if (new_state == TCP_CA_Loss) @@ -231,7 +225,6 @@ static struct tcp_congestion_ops bictcp = { .cong_avoid = bictcp_cong_avoid, .set_state = bictcp_state, .undo_cwnd = bictcp_undo_cwnd, - .min_cwnd = bictcp_min_cwnd, .pkts_acked = bictcp_acked, .owner = THIS_MODULE, .name = "bic", diff --git a/net/ipv4/tcp_compound.c b/net/ipv4/tcp_compound.c index ec68cb8081c1..bc54f7e9aea9 100644 --- a/net/ipv4/tcp_compound.c +++ b/net/ipv4/tcp_compound.c @@ -419,7 +419,6 @@ static struct tcp_congestion_ops tcp_compound = { .init = tcp_compound_init, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_compound_cong_avoid, - .min_cwnd = tcp_reno_min_cwnd, .rtt_sample = tcp_compound_rtt_calc, .set_state = tcp_compound_state, .cwnd_event = tcp_compound_cwnd_event, diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 91c2f41c7f58..857eefc52aab 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -38,7 +38,7 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca) int ret = 0; /* all algorithms must implement ssthresh and cong_avoid ops */ - if (!ca->ssthresh || !ca->cong_avoid || !ca->min_cwnd) { + if (!ca->ssthresh || !ca->cong_avoid) { printk(KERN_ERR "TCP %s does not implement required ops\n", ca->name); return -EINVAL; @@ -251,8 +251,8 @@ u32 tcp_reno_ssthresh(struct sock *sk) } EXPORT_SYMBOL_GPL(tcp_reno_ssthresh); -/* Lower bound on congestion window. */ -u32 tcp_reno_min_cwnd(struct sock *sk) +/* Lower bound on congestion window with halving. */ +u32 tcp_reno_min_cwnd(const struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); return tp->snd_ssthresh/2; diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 31a4986dfbf7..78b7a6b9e4de 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -325,11 +325,6 @@ static u32 bictcp_undo_cwnd(struct sock *sk) return max(tcp_sk(sk)->snd_cwnd, ca->last_max_cwnd); } -static u32 bictcp_min_cwnd(struct sock *sk) -{ - return tcp_sk(sk)->snd_ssthresh; -} - static void bictcp_state(struct sock *sk, u8 new_state) { if (new_state == TCP_CA_Loss) @@ -357,7 +352,6 @@ static struct tcp_congestion_ops cubictcp = { .cong_avoid = bictcp_cong_avoid, .set_state = bictcp_state, .undo_cwnd = bictcp_undo_cwnd, - .min_cwnd = bictcp_min_cwnd, .pkts_acked = bictcp_acked, .owner = THIS_MODULE, .name = "cubic", diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 1b2ff53f98ed..3d92c1859267 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -246,14 +246,6 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, } } -/* Lower bound on congestion window. */ -static u32 htcp_min_cwnd(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - return tp->snd_ssthresh; -} - - static void htcp_init(struct sock *sk) { struct htcp *ca = inet_csk_ca(sk); @@ -285,7 +277,6 @@ static void htcp_state(struct sock *sk, u8 new_state) static struct tcp_congestion_ops htcp = { .init = htcp_init, .ssthresh = htcp_recalc_ssthresh, - .min_cwnd = htcp_min_cwnd, .cong_avoid = htcp_cong_avoid, .set_state = htcp_state, .undo_cwnd = htcp_cwnd_undo, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6d167889a4b0..e08245bdda3a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1689,17 +1689,26 @@ static inline void tcp_moderate_cwnd(struct tcp_sock *tp) tp->snd_cwnd_stamp = tcp_time_stamp; } +/* Lower bound on congestion window is slow start threshold + * unless congestion avoidance choice decides to overide it. + */ +static inline u32 tcp_cwnd_min(const struct sock *sk) +{ + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; + + return ca_ops->min_cwnd ? ca_ops->min_cwnd(sk) : tcp_sk(sk)->snd_ssthresh; +} + /* Decrease cwnd each second ack. */ static void tcp_cwnd_down(struct sock *sk) { - const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); int decr = tp->snd_cwnd_cnt + 1; tp->snd_cwnd_cnt = decr&1; decr >>= 1; - if (decr && tp->snd_cwnd > icsk->icsk_ca_ops->min_cwnd(sk)) + if (decr && tp->snd_cwnd > tcp_cwnd_min(sk)) tp->snd_cwnd -= decr; tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1); diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 1091671751c4..11b42a7135c1 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -199,17 +199,10 @@ static u32 tcp_veno_ssthresh(struct sock *sk) return max(tp->snd_cwnd >> 1U, 2U); } -static u32 tcp_veno_min_cwnd(struct sock * sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - return tp->snd_ssthresh; -} - static struct tcp_congestion_ops tcp_veno = { .init = tcp_veno_init, .ssthresh = tcp_veno_ssthresh, .cong_avoid = tcp_veno_cong_avoid, - .min_cwnd = tcp_veno_min_cwnd, .rtt_sample = tcp_veno_rtt_calc, .set_state = tcp_veno_state, .cwnd_event = tcp_veno_cwnd_event, diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index 0c340c3756c2..29eb258b6d82 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c @@ -162,12 +162,6 @@ static inline u32 westwood_acked_count(struct sock *sk) return w->cumul_ack; } -static inline u32 westwood_bw_rttmin(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct westwood *w = inet_csk_ca(sk); - return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2); -} /* * TCP Westwood @@ -175,9 +169,11 @@ static inline u32 westwood_bw_rttmin(const struct sock *sk) * in packets we use mss_cache). Rttmin is guaranteed to be >= 2 * so avoids ever returning 0. */ -static u32 tcp_westwood_cwnd_min(struct sock *sk) +static u32 tcp_westwood_bw_rttmin(const struct sock *sk) { - return westwood_bw_rttmin(sk); + const struct tcp_sock *tp = tcp_sk(sk); + const struct westwood *w = inet_csk_ca(sk); + return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2); } static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) @@ -191,11 +187,11 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) break; case CA_EVENT_COMPLETE_CWR: - tp->snd_cwnd = tp->snd_ssthresh = westwood_bw_rttmin(sk); + tp->snd_cwnd = tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); break; case CA_EVENT_FRTO: - tp->snd_ssthresh = westwood_bw_rttmin(sk); + tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); break; case CA_EVENT_SLOW_ACK: @@ -235,7 +231,7 @@ static struct tcp_congestion_ops tcp_westwood = { .init = tcp_westwood_init, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_reno_cong_avoid, - .min_cwnd = tcp_westwood_cwnd_min, + .min_cwnd = tcp_westwood_bw_rttmin, .cwnd_event = tcp_westwood_event, .get_info = tcp_westwood_info, .pkts_acked = tcp_westwood_pkts_acked, -- cgit v1.2.3 From 338fcf9886df9ad2873772197a73a57818973316 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 5 Jun 2006 21:04:39 -0700 Subject: [IPV4] igmp: Fixup struct ip_mc_list::multiaddr type All users except two expect 32-bit big-endian value. One is of ->multiaddr = ->multiaddr variety. And last one is "%08lX". Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- net/ipv4/igmp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 28f4f3b36950..899c3d4776f3 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -169,7 +169,7 @@ struct ip_sf_list struct ip_mc_list { struct in_device *interface; - unsigned long multiaddr; + __be32 multiaddr; struct ip_sf_list *sources; struct ip_sf_list *tomb; unsigned int sfmode; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d512239a1473..ab680c851aa2 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2361,7 +2361,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v) } seq_printf(seq, - "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n", + "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n", im->multiaddr, im->users, im->tm_running, im->tm_running ? jiffies_to_clock_t(im->timer.expires-jiffies) : 0, -- cgit v1.2.3 From 6d7416535097ed0943bdae8e69c14ba43061cab1 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 5 Jun 2006 21:06:41 -0700 Subject: [IPV4]: Right prototype of __raw_v4_lookup() All users pass 32-bit values as addresses and internally they're compared with 32-bit entities. So, change "laddr" and "raddr" types to __be32. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/net/raw.h | 2 +- net/ipv4/raw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/raw.h b/include/net/raw.h index e67b28a0248c..d83571fe4c69 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -36,7 +36,7 @@ extern rwlock_t raw_v4_lock; extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, - unsigned long raddr, unsigned long laddr, + __be32 raddr, __be32 laddr, int dif); extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index fc2562415555..bd221ec3f81e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -103,7 +103,7 @@ static void raw_v4_unhash(struct sock *sk) } struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, - unsigned long raddr, unsigned long laddr, + __be32 raddr, __be32 laddr, int dif) { struct hlist_node *node; -- cgit v1.2.3 From c8c05a8eec6f1258f6d5cb71a44ee5dc1e989b63 Mon Sep 17 00:00:00 2001 From: Catherine Zhang Date: Thu, 8 Jun 2006 23:39:49 -0700 Subject: [LSM-IPsec]: SELinux Authorize This patch contains a fix for the previous patch that adds security contexts to IPsec policies and security associations. In the previous patch, no authorization (besides the check for write permissions to SAD and SPD) is required to delete IPsec policies and security assocations with security contexts. Thus a user authorized to change SAD and SPD can bypass the IPsec policy authorization by simply deleteing policies with security contexts. To fix this security hole, an additional authorization check is added for removing security policies and security associations with security contexts. Note that if no security context is supplied on add or present on policy to be deleted, the SELinux module allows the change unconditionally. The hook is called on deletion when no context is present, which we may want to change. At present, I left it up to the module. LSM changes: The patch adds two new LSM hooks: xfrm_policy_delete and xfrm_state_delete. The new hooks are necessary to authorize deletion of IPsec policies that have security contexts. The existing hooks xfrm_policy_free and xfrm_state_free lack the context to do the authorization, so I decided to split authorization of deletion and memory management of security data, as is typical in the LSM interface. Use: The new delete hooks are checked when xfrm_policy or xfrm_state are deleted by either the xfrm_user interface (xfrm_get_policy, xfrm_del_sa) or the pfkey interface (pfkey_spddelete, pfkey_delete). SELinux changes: The new policy_delete and state_delete functions are added. Signed-off-by: Catherine Zhang Signed-off-by: Trent Jaeger Acked-by: James Morris Signed-off-by: David S. Miller --- include/linux/security.h | 40 ++++++++++++++++++++++++++++++++++------ net/key/af_key.c | 17 +++++++++++------ net/xfrm/xfrm_user.c | 19 ++++++++++++------- security/dummy.c | 12 ++++++++++++ security/selinux/hooks.c | 2 ++ security/selinux/include/xfrm.h | 2 ++ security/selinux/xfrm.c | 39 +++++++++++++++++++++++++++++++++++---- 7 files changed, 108 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index 1bab48f6aeac..14c9bd050607 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -805,31 +805,37 @@ struct swap_info_struct; * 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->selector.security field. + * 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->selector.security field - * that contains the information from the old->selector.security field. + * Allocate a security structure to the new->security field + * that contains the information from the old->security field. * Return 0 if operation was successful (memory to allocate). * @xfrm_policy_free_security: * @xp contains the xfrm_policy - * Deallocate xp->selector.security. + * Deallocate xp->security. + * @xfrm_policy_delete_security: + * @xp contains the xfrm_policy. + * Authorize deletion of xp->security. * @xfrm_state_alloc_security: * @x contains the xfrm_state being added to the Security Association * Database by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level SA generation program (e.g., setkey or racoon). - * Allocate a security structure to the x->sel.security field. The + * Allocate a security structure to the x->security field. The * security field is initialized to NULL when the xfrm_state is * allocated. * Return 0 if operation was successful (memory to allocate, legal context). * @xfrm_state_free_security: * @x contains the xfrm_state. - * Deallocate x>sel.security. + * Deallocate x->security. + * @xfrm_state_delete_security: + * @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 * checked. @@ -1298,8 +1304,10 @@ struct security_operations { int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, 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_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); 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 sk_sid, u8 dir); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ @@ -2934,11 +2942,21 @@ static inline void security_xfrm_policy_free(struct xfrm_policy *xp) security_ops->xfrm_policy_free_security(xp); } +static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) +{ + return security_ops->xfrm_policy_delete_security(xp); +} + static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { return security_ops->xfrm_state_alloc_security(x, sec_ctx); } +static inline int security_xfrm_state_delete(struct xfrm_state *x) +{ + return security_ops->xfrm_state_delete_security(x); +} + static inline void security_xfrm_state_free(struct xfrm_state *x) { security_ops->xfrm_state_free_security(x); @@ -2963,6 +2981,11 @@ static inline void security_xfrm_policy_free(struct xfrm_policy *xp) { } +static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) +{ + return 0; +} + static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { return 0; @@ -2972,6 +2995,11 @@ static inline void security_xfrm_state_free(struct xfrm_state *x) { } +static inline int security_xfrm_state_delete(struct xfrm_policy *xp) +{ + return 0; +} + static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) { return 0; diff --git a/net/key/af_key.c b/net/key/af_key.c index 859582275cab..d5e2121ea207 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1454,21 +1454,23 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h if (x == NULL) return -ESRCH; + if ((err = security_xfrm_state_delete(x))) + goto out; + if (xfrm_state_kern(x)) { - xfrm_state_put(x); - return -EPERM; + err = -EPERM; + goto out; } err = xfrm_state_delete(x); - if (err < 0) { - xfrm_state_put(x); - return err; - } + if (err < 0) + goto out; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; c.event = XFRM_MSG_DELSA; km_state_notify(x, &c); +out: xfrm_state_put(x); return err; @@ -2274,11 +2276,14 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg err = 0; + if ((err = security_xfrm_policy_delete(xp))) + goto out; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; c.event = XFRM_MSG_DELPOLICY; km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); +out: xfrm_pol_put(xp); return err; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 81d1005830f4..a3733d2db3ba 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -427,23 +427,25 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) if (x == NULL) return -ESRCH; + if (err = security_xfrm_state_delete(x)) + goto out; + if (xfrm_state_kern(x)) { - xfrm_state_put(x); - return -EPERM; + err = -EPERM; + goto out; } err = xfrm_state_delete(x); - if (err < 0) { - xfrm_state_put(x); - return err; - } + if (err < 0) + goto out; c.seq = nlh->nlmsg_seq; c.pid = nlh->nlmsg_pid; c.event = nlh->nlmsg_type; km_state_notify(x, &c); - xfrm_state_put(x); +out: + xfrm_state_put(x); return err; } @@ -1055,6 +1057,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr MSG_DONTWAIT); } } else { + if (err = security_xfrm_policy_delete(xp)) + goto out; c.data.byid = p->index; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; @@ -1064,6 +1068,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr xfrm_pol_put(xp); +out: return err; } diff --git a/security/dummy.c b/security/dummy.c index 8ccccccc12ac..64f6da0f422e 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -810,6 +810,11 @@ static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp) { } +static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) +{ + return 0; +} + static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { return 0; @@ -819,6 +824,11 @@ static void dummy_xfrm_state_free_security(struct xfrm_state *x) { } +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) { return 0; @@ -1024,8 +1034,10 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, xfrm_policy_alloc_security); set_to_dummy_if_null(ops, xfrm_policy_clone_security); set_to_dummy_if_null(ops, xfrm_policy_free_security); + set_to_dummy_if_null(ops, xfrm_policy_delete_security); set_to_dummy_if_null(ops, xfrm_state_alloc_security); set_to_dummy_if_null(ops, xfrm_state_free_security); + set_to_dummy_if_null(ops, xfrm_state_delete_security); set_to_dummy_if_null(ops, xfrm_policy_lookup); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ #ifdef CONFIG_KEYS diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 90b4cdc0c948..cf7b62ca886a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4374,8 +4374,10 @@ static struct security_operations selinux_ops = { .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, .xfrm_policy_clone_security = selinux_xfrm_policy_clone, .xfrm_policy_free_security = selinux_xfrm_policy_free, + .xfrm_policy_delete_security = selinux_xfrm_policy_delete, .xfrm_state_alloc_security = selinux_xfrm_state_alloc, .xfrm_state_free_security = selinux_xfrm_state_free, + .xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_policy_lookup = selinux_xfrm_policy_lookup, #endif }; diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index c10f1fc41502..f0f4e480ff99 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -9,8 +9,10 @@ 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_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); 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 sk_sid, u8 dir); /* diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index abe99d881376..0e24df41099f 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -132,10 +132,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us goto out; /* - * Does the subject have permission to set security or permission to - * do the relabel? - * Must be permitted to relabel from default socket type (process type) - * to specified context + * Does the subject have permission to set security context? */ rc = avc_has_perm(tsec->sid, ctx->ctx_sid, SECCLASS_ASSOCIATION, @@ -200,6 +197,23 @@ void selinux_xfrm_policy_free(struct xfrm_policy *xp) kfree(ctx); } +/* + * LSM hook implementation that authorizes deletion of labeled policies. + */ +int selinux_xfrm_policy_delete(struct xfrm_policy *xp) +{ + struct task_security_struct *tsec = current->security; + struct xfrm_sec_ctx *ctx = xp->security; + int rc = 0; + + if (ctx) + rc = avc_has_perm(tsec->sid, ctx->ctx_sid, + SECCLASS_ASSOCIATION, + ASSOCIATION__SETCONTEXT, NULL); + + return rc; +} + /* * LSM hook implementation that allocs and transfers sec_ctx spec to * xfrm_state. @@ -292,6 +306,23 @@ u32 selinux_socket_getpeer_dgram(struct sk_buff *skb) return SECSID_NULL; } + /* + * LSM hook implementation that authorizes deletion of labeled SAs. + */ +int selinux_xfrm_state_delete(struct xfrm_state *x) +{ + struct task_security_struct *tsec = current->security; + struct xfrm_sec_ctx *ctx = x->security; + int rc = 0; + + if (ctx) + rc = avc_has_perm(tsec->sid, ctx->ctx_sid, + SECCLASS_ASSOCIATION, + ASSOCIATION__SETCONTEXT, NULL); + + return rc; +} + /* * LSM hook that controls access to unlabelled packets. If * a xfrm_state is authorizable (defined by macro) then it was -- cgit v1.2.3 From 6f68dc37759b1d6ff3b4d4a9d097605a09f8f043 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Jun 2006 23:58:52 -0700 Subject: [NET]: Fix warnings after LSM-IPSEC changes. Assignment used as truth value in xfrm_del_sa() and xfrm_get_policy(). Wrong argument type declared for security_xfrm_state_delete() when SELINUX is disabled. Signed-off-by: David S. Miller --- include/linux/security.h | 2 +- net/xfrm/xfrm_user.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index 14c9bd050607..4dfb1b84a9b3 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2995,7 +2995,7 @@ static inline void security_xfrm_state_free(struct xfrm_state *x) { } -static inline int security_xfrm_state_delete(struct xfrm_policy *xp) +static inline int security_xfrm_state_delete(struct xfrm_state *x) { return 0; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index a3733d2db3ba..c21dc26141ea 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -427,7 +427,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) if (x == NULL) return -ESRCH; - if (err = security_xfrm_state_delete(x)) + if ((err = security_xfrm_state_delete(x)) != 0) goto out; if (xfrm_state_kern(x)) { @@ -1057,7 +1057,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr MSG_DONTWAIT); } } else { - if (err = security_xfrm_policy_delete(xp)) + if ((err = security_xfrm_policy_delete(xp)) != 0) goto out; c.data.byid = p->index; c.event = nlh->nlmsg_type; -- cgit v1.2.3 From c749b29fae74ed59c507d84025b3298202b42609 Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 9 Jun 2006 00:28:25 -0700 Subject: [SECMARK]: Add SELinux exports Add and export new functions to the in-kernel SELinux API in support of the new secmark-based packet controls. Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/selinux.h | 32 ++++++++++++++++++++++++++++++++ security/selinux/exports.c | 22 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'include') diff --git a/include/linux/selinux.h b/include/linux/selinux.h index 4047bcde4484..aad4e390d6a5 100644 --- a/include/linux/selinux.h +++ b/include/linux/selinux.h @@ -118,6 +118,27 @@ void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid); */ 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 + * @sid: ID value returned via this. + * + * Returns 0 if successful, with the SID stored in sid. A value + * of zero for sid indicates no SID could be determined (but no error + * occurred). + */ +int selinux_string_to_sid(char *str, u32 *sid); + +/** + * selinux_relabel_packet_permission - check permission to relabel a packet + * @sid: ID value to be applied to network packet (via SECMARK, most likely) + * + * Returns 0 if the current task is allowed to label packets with the + * supplied security ID. Note that it is implicit that the packet is always + * being relabeled from the default unlabled value, and that the access + * control decision is made in the AVC. + */ +int selinux_relabel_packet_permission(u32 sid); #else @@ -172,6 +193,17 @@ 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; + return 0; +} + +static inline int selinux_relabel_packet_permission(u32 sid) +{ + return 0; +} + #endif /* CONFIG_SECURITY_SELINUX */ #endif /* _LINUX_SELINUX_H */ diff --git a/security/selinux/exports.c b/security/selinux/exports.c index ae4c73eb3085..9d7737db5e51 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -72,3 +72,25 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid) *sid = 0; } +int selinux_string_to_sid(char *str, u32 *sid) +{ + if (selinux_enabled) + return security_context_to_sid(str, strlen(str), sid); + else { + *sid = 0; + return 0; + } +} +EXPORT_SYMBOL_GPL(selinux_string_to_sid); + +int selinux_relabel_packet_permission(u32 sid) +{ + if (selinux_enabled) { + struct task_security_struct *tsec = current->security; + + return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET, + PACKET__RELABELTO, NULL); + } + return 0; +} +EXPORT_SYMBOL_GPL(selinux_relabel_packet_permission); -- cgit v1.2.3 From 984bc16cc92ea3c247bf34ad667cfb95331b9d3c Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 9 Jun 2006 00:29:17 -0700 Subject: [SECMARK]: Add secmark support to core networking. Add a secmark field to the skbuff structure, to allow security subsystems to place security markings on network packets. This is similar to the nfmark field, except is intended for implementing security policy, rather than than networking policy. This patch was already acked in principle by Dave Miller. Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/skbuff.h | 22 ++++++++++++++++++++++ net/Kconfig | 7 +++++++ net/core/skbuff.c | 3 ++- net/ipv4/ip_output.c | 1 + net/ipv4/netfilter/ipt_REJECT.c | 1 + net/ipv6/ip6_output.c | 1 + 6 files changed, 34 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 23bad3bf3c9d..fe2c58e5306f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -210,6 +210,7 @@ enum { * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @tc_index: Traffic control index * @tc_verd: traffic control verdict + * @secmark: security marking */ struct sk_buff { @@ -289,6 +290,9 @@ struct sk_buff { #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; #endif +#ifdef CONFIG_NETWORK_SECMARK + __u32 secmark; +#endif /* These elements must be at the end, see alloc_skb() for details. */ @@ -1400,5 +1404,23 @@ static inline void nf_reset(struct sk_buff *skb) static inline void nf_reset(struct sk_buff *skb) {} #endif /* CONFIG_NETFILTER */ +#ifdef CONFIG_NETWORK_SECMARK +static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from) +{ + to->secmark = from->secmark; +} + +static inline void skb_init_secmark(struct sk_buff *skb) +{ + skb->secmark = 0; +} +#else +static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from) +{ } + +static inline void skb_init_secmark(struct sk_buff *skb) +{ } +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/Kconfig b/net/Kconfig index ccadc8e48152..c6cec5aa5486 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -66,6 +66,13 @@ source "net/ipv6/Kconfig" endif # if INET +config NETWORK_SECMARK + bool "Security Marking" + help + This enables security marking of network packets, similar + to nfmark, but designated for security purposes. + If you are unsure how to answer this question, answer N. + menuconfig NETFILTER bool "Network packet filtering (replaces ipchains)" ---help--- diff --git a/net/core/skbuff.c b/net/core/skbuff.c index fb3770f9c094..96cdcbe24ba2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -464,7 +464,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) n->tc_verd = CLR_TC_MUNGED(n->tc_verd); C(input_dev); #endif - + skb_copy_secmark(n, skb); #endif C(truesize); atomic_set(&n->users, 1); @@ -526,6 +526,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif new->tc_index = old->tc_index; #endif + skb_copy_secmark(new, old); atomic_set(&new->users, 1); skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size; skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index cff9c3a72daf..d4bb3fae4e49 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -410,6 +410,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) nf_bridge_get(to->nf_bridge); #endif #endif + skb_copy_secmark(to, from); } /* diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 0bba3c2bb786..431a3ce6f7b7 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -147,6 +147,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); nskb->nfmark = 0; + skb_init_secmark(nskb); tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 416f6e428a0a..d29620f4910e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -459,6 +459,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) nf_bridge_get(to->nf_bridge); #endif #endif + skb_copy_secmark(to, from); } int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) -- cgit v1.2.3 From 5e6874cdb8de94cd3c15d853a8ef9c6f4c305055 Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 9 Jun 2006 00:30:57 -0700 Subject: [SECMARK]: Add xtables SECMARK target Add a SECMARK target to xtables, allowing the admin to apply security marks to packets via both iptables and ip6tables. The target currently handles SELinux security marking, but can be extended for other purposes as needed. Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/netfilter/xt_SECMARK.h | 26 ++++++ net/netfilter/Kconfig | 9 ++ net/netfilter/Makefile | 1 + net/netfilter/xt_SECMARK.c | 156 +++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 include/linux/netfilter/xt_SECMARK.h create mode 100644 net/netfilter/xt_SECMARK.c (limited to 'include') diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h new file mode 100644 index 000000000000..c53fbffa997d --- /dev/null +++ b/include/linux/netfilter/xt_SECMARK.h @@ -0,0 +1,26 @@ +#ifndef _XT_SECMARK_H_target +#define _XT_SECMARK_H_target + +/* + * This is intended for use by various security subsystems (but not + * at the same time). + * + * 'mode' refers to the specific security subsystem which the + * packets are being marked for. + */ +#define SECMARK_MODE_SEL 0x01 /* SELinux */ +#define SECMARK_SELCTX_MAX 256 + +struct xt_secmark_target_selinux_info { + u_int32_t selsid; + char selctx[SECMARK_SELCTX_MAX]; +}; + +struct xt_secmark_target_info { + u_int8_t mode; + union { + struct xt_secmark_target_selinux_info sel; + } u; +}; + +#endif /*_XT_SECMARK_H_target */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 85a7e1770252..10eccdd4d6ea 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -174,6 +174,15 @@ config NETFILTER_XT_TARGET_NOTRACK If you want to compile it as a module, say M here and read . If unsure, say `N'. +config NETFILTER_XT_TARGET_SECMARK + tristate '"SECMARK" target support' + depends on NETFILTER_XTABLES && NETWORK_SECMARK + help + The SECMARK target allows security marking of network + packets, for use with security subsystems. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_COMMENT tristate '"comment" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index df1da25f40df..3645de046890 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o +obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o # matches obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c new file mode 100644 index 000000000000..c2ce9c4011cc --- /dev/null +++ b/net/netfilter/xt_SECMARK.c @@ -0,0 +1,156 @@ +/* + * Module for modifying the secmark field of the skb, for use by + * security subsystems. + * + * Based on the nfmark match by: + * (C) 1999-2001 Marc Boucher + * + * (C) 2006 Red Hat, Inc., James Morris + * + * 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 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Morris "); +MODULE_DESCRIPTION("ip[6]tables SECMARK modification module"); +MODULE_ALIAS("ipt_SECMARK"); +MODULE_ALIAS("ip6t_SECMARK"); + +#define PFX "SECMARK: " + +static u8 mode; + +static unsigned int target(struct sk_buff **pskb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, + const void *targinfo, void *userinfo) +{ + u32 secmark = 0; + const struct xt_secmark_target_info *info = targinfo; + + BUG_ON(info->mode != mode); + + switch (mode) { + case SECMARK_MODE_SEL: + secmark = info->u.sel.selsid; + break; + + default: + BUG(); + } + + if ((*pskb)->secmark != secmark) + (*pskb)->secmark = secmark; + + return XT_CONTINUE; +} + +static int checkentry_selinux(struct xt_secmark_target_info *info) +{ + int err; + struct xt_secmark_target_selinux_info *sel = &info->u.sel; + + err = selinux_string_to_sid(sel->selctx, &sel->selsid); + if (err) { + if (err == -EINVAL) + printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n", + sel->selctx); + return 0; + } + + if (!sel->selsid) { + printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n", + sel->selctx); + return 0; + } + + err = selinux_relabel_packet_permission(sel->selsid); + if (err) { + printk(KERN_INFO PFX "unable to obtain relabeling permission\n"); + return 0; + } + + return 1; +} + +static int checkentry(const char *tablename, const void *entry, + const struct xt_target *target, void *targinfo, + unsigned int targinfosize, unsigned int hook_mask) +{ + struct xt_secmark_target_info *info = targinfo; + + if (mode && mode != info->mode) { + printk(KERN_INFO PFX "mode already set to %hu cannot mix with " + "rules for mode %hu\n", mode, info->mode); + return 0; + } + + switch (info->mode) { + case SECMARK_MODE_SEL: + if (!checkentry_selinux(info)) + return 0; + break; + + default: + printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); + return 0; + } + + if (!mode) + mode = info->mode; + return 1; +} + +static struct xt_target ipt_secmark_reg = { + .name = "SECMARK", + .target = target, + .targetsize = sizeof(struct xt_secmark_target_info), + .table = "mangle", + .checkentry = checkentry, + .me = THIS_MODULE, + .family = AF_INET, + .revision = 0, +}; + +static struct xt_target ip6t_secmark_reg = { + .name = "SECMARK", + .target = target, + .targetsize = sizeof(struct xt_secmark_target_info), + .table = "mangle", + .checkentry = checkentry, + .me = THIS_MODULE, + .family = AF_INET6, + .revision = 0, +}; + +static int __init xt_secmark_init(void) +{ + int err; + + err = xt_register_target(&ipt_secmark_reg); + if (err) + return err; + + err = xt_register_target(&ip6t_secmark_reg); + if (err) + xt_unregister_target(&ipt_secmark_reg); + + return err; +} + +static void __exit xt_secmark_fini(void) +{ + xt_unregister_target(&ip6t_secmark_reg); + xt_unregister_target(&ipt_secmark_reg); +} + +module_init(xt_secmark_init); +module_exit(xt_secmark_fini); -- cgit v1.2.3 From 7c9728c393dceb724d66d696cfabce82151a78e5 Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 9 Jun 2006 00:31:46 -0700 Subject: [SECMARK]: Add secmark support to conntrack Add a secmark field to IP and NF conntracks, so that security markings on packets can be copied to their associated connections, and also copied back to packets as required. This is similar to the network mark field currently used with conntrack, although it is intended for enforcement of security policy rather than network policy. Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 4 ++++ include/net/netfilter/nf_conntrack.h | 4 ++++ include/net/netfilter/nf_conntrack_compat.h | 26 ++++++++++++++++++++++++++ net/ipv4/netfilter/Kconfig | 12 ++++++++++++ net/ipv4/netfilter/ip_conntrack_core.c | 3 +++ net/ipv4/netfilter/ip_conntrack_standalone.c | 5 +++++ net/netfilter/Kconfig | 12 ++++++++++++ net/netfilter/nf_conntrack_core.c | 3 +++ net/netfilter/nf_conntrack_standalone.c | 5 +++++ 9 files changed, 74 insertions(+) (limited to 'include') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 17d7ef938a09..e0e9951eb8c3 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -121,6 +121,10 @@ struct ip_conntrack u_int32_t mark; #endif +#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK + u_int32_t secmark; +#endif + /* Traversed often, so hopefully in different cacheline to top */ /* These are my tuples; original and reply */ struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index dbe7a114d0c5..411117815807 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -114,6 +114,10 @@ struct nf_conn u_int32_t mark; #endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + u_int32_t secmark; +#endif + /* Storage reserved for other modules: */ union nf_conntrack_proto proto; diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h index 3cac19fb3648..f1b1482d7200 100644 --- a/include/net/netfilter/nf_conntrack_compat.h +++ b/include/net/netfilter/nf_conntrack_compat.h @@ -20,6 +20,19 @@ static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, } #endif /* CONFIG_IP_NF_CONNTRACK_MARK */ +#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK +static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb, + u_int32_t *ctinfo) +{ + struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); + + if (ct) + return &ct->secmark; + else + return NULL; +} +#endif /* CONFIG_IP_NF_CONNTRACK_SECMARK */ + #ifdef CONFIG_IP_NF_CT_ACCT static inline struct ip_conntrack_counter * nf_ct_get_counters(const struct sk_buff *skb) @@ -70,6 +83,19 @@ static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, } #endif /* CONFIG_NF_CONNTRACK_MARK */ +#ifdef CONFIG_NF_CONNTRACK_SECMARK +static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb, + u_int32_t *ctinfo) +{ + struct nf_conn *ct = nf_ct_get(skb, ctinfo); + + if (ct) + return &ct->secmark; + else + return NULL; +} +#endif /* CONFIG_NF_CONNTRACK_MARK */ + #ifdef CONFIG_NF_CT_ACCT static inline struct ip_conntrack_counter * nf_ct_get_counters(const struct sk_buff *skb) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index ff4b118f14a9..e1d7f5fbc526 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -55,6 +55,18 @@ config IP_NF_CONNTRACK_MARK of packets, but this mark value is kept in the conntrack session instead of the individual packets. +config IP_NF_CONNTRACK_SECMARK + bool 'Connection tracking security mark support' + depends on IP_NF_CONNTRACK && NETWORK_SECMARK + help + This option enables security markings to be applied to + connections. Typically they are copied to connections from + packets using the CONNSECMARK target and copied back from + connections to packets with the same target, with the packets + being originally labeled via SECMARK. + + If unsure, say 'N'. + config IP_NF_CONNTRACK_EVENTS bool "Connection tracking events (EXPERIMENTAL)" depends on EXPERIMENTAL && IP_NF_CONNTRACK diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 4fe9e69378df..7e4cf9a4d15f 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -723,6 +723,9 @@ init_conntrack(struct ip_conntrack_tuple *tuple, defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) /* this is ugly, but there is no other place where to put it */ conntrack->nat.masq_index = exp->master->nat.masq_index; +#endif +#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK + conntrack->secmark = exp->master->secmark; #endif nf_conntrack_get(&conntrack->master->ct_general); CONNTRACK_STAT_INC(expect_new); diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 6cb9b989d14c..88445aac3f28 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -189,6 +189,11 @@ static int ct_seq_show(struct seq_file *s, void *v) return -ENOSPC; #endif +#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK + if (seq_printf(s, "secmark=%u ", conntrack->secmark)) + return -ENOSPC; +#endif + if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) return -ENOSPC; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 10eccdd4d6ea..023f81e5f96b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -60,6 +60,18 @@ config NF_CONNTRACK_MARK of packets, but this mark value is kept in the conntrack session instead of the individual packets. +config NF_CONNTRACK_SECMARK + bool 'Connection tracking security mark support' + depends on NF_CONNTRACK && NETWORK_SECMARK + help + This option enables security markings to be applied to + connections. Typically they are copied to connections from + packets using the CONNSECMARK target and copied back from + connections to packets with the same target, with the packets + being originally labeled via SECMARK. + + If unsure, say 'N'. + config NF_CONNTRACK_EVENTS bool "Connection tracking events (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index bc2bd4c3859e..cd299f4b7db1 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -989,6 +989,9 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, conntrack->master = exp->master; #ifdef CONFIG_NF_CONNTRACK_MARK conntrack->mark = exp->master->mark; +#endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + conntrack->secmark = exp->master->secmark; #endif nf_conntrack_get(&conntrack->master->ct_general); NF_CT_STAT_INC(expect_new); diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e01d20d8e287..e34c574f0351 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -213,6 +213,11 @@ static int ct_seq_show(struct seq_file *s, void *v) return -ENOSPC; #endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + if (seq_printf(s, "secmark=%u ", conntrack->secmark)) + return -ENOSPC; +#endif + if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) return -ENOSPC; -- cgit v1.2.3 From 100468e9c05c10fb6872751c1af523b996d6afa9 Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 9 Jun 2006 00:32:39 -0700 Subject: [SECMARK]: Add CONNSECMARK xtables target Add a new xtables target, CONNSECMARK, which is used to specify rules for copying security marks from packets to connections, and for copyying security marks back from connections to packets. This is similar to the CONNMARK target, but is more limited in scope in that it only allows copying of security marks to and from packets, as this is all it needs to do. A typical scenario would be to apply a security mark to a 'new' packet with SECMARK, then copy that to its conntrack via CONNMARK, and then restore the security mark from the connection to established and related packets on that connection. Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/netfilter/xt_CONNSECMARK.h | 13 +++ net/netfilter/Kconfig | 11 +++ net/netfilter/Makefile | 1 + net/netfilter/xt_CONNSECMARK.c | 155 +++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 include/linux/netfilter/xt_CONNSECMARK.h create mode 100644 net/netfilter/xt_CONNSECMARK.c (limited to 'include') diff --git a/include/linux/netfilter/xt_CONNSECMARK.h b/include/linux/netfilter/xt_CONNSECMARK.h new file mode 100644 index 000000000000..c6bd75469ba2 --- /dev/null +++ b/include/linux/netfilter/xt_CONNSECMARK.h @@ -0,0 +1,13 @@ +#ifndef _XT_CONNSECMARK_H_target +#define _XT_CONNSECMARK_H_target + +enum { + CONNSECMARK_SAVE = 1, + CONNSECMARK_RESTORE, +}; + +struct xt_connsecmark_target_info { + u_int8_t mode; +}; + +#endif /*_XT_CONNSECMARK_H_target */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 023f81e5f96b..b1622b7de1cf 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -195,6 +195,17 @@ config NETFILTER_XT_TARGET_SECMARK To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_CONNSECMARK + tristate '"CONNSECMARK" target support' + depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK) + help + The CONNSECMARK target copies security markings from packets + to connections, and restores security markings from connections + to packets (if the packets are not already marked). This would + normally be used in conjunction with the SECMARK target. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_COMMENT tristate '"comment" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 3645de046890..6fa4b7580458 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o +obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o # matches obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c new file mode 100644 index 000000000000..8c011e020769 --- /dev/null +++ b/net/netfilter/xt_CONNSECMARK.c @@ -0,0 +1,155 @@ +/* + * This module is used to copy security markings from packets + * to connections, and restore security markings from connections + * back to packets. This would normally be performed in conjunction + * with the SECMARK target and state match. + * + * Based somewhat on CONNMARK: + * Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * (C) 2006 Red Hat, Inc., James Morris + * + * 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 + +#define PFX "CONNSECMARK: " + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Morris "); +MODULE_DESCRIPTION("ip[6]tables CONNSECMARK module"); +MODULE_ALIAS("ipt_CONNSECMARK"); +MODULE_ALIAS("ip6t_CONNSECMARK"); + +/* + * If the packet has a security mark and the connection does not, copy + * the security mark from the packet to the connection. + */ +static void secmark_save(struct sk_buff *skb) +{ + if (skb->secmark) { + u32 *connsecmark; + enum ip_conntrack_info ctinfo; + + connsecmark = nf_ct_get_secmark(skb, &ctinfo); + if (connsecmark && !*connsecmark) + if (*connsecmark != skb->secmark) + *connsecmark = skb->secmark; + } +} + +/* + * If packet has no security mark, and the connection does, restore the + * security mark from the connection to the packet. + */ +static void secmark_restore(struct sk_buff *skb) +{ + if (!skb->secmark) { + u32 *connsecmark; + enum ip_conntrack_info ctinfo; + + connsecmark = nf_ct_get_secmark(skb, &ctinfo); + if (connsecmark && *connsecmark) + if (skb->secmark != *connsecmark) + skb->secmark = *connsecmark; + } +} + +static unsigned int target(struct sk_buff **pskb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, + const void *targinfo, void *userinfo) +{ + struct sk_buff *skb = *pskb; + const struct xt_connsecmark_target_info *info = targinfo; + + switch (info->mode) { + case CONNSECMARK_SAVE: + secmark_save(skb); + break; + + case CONNSECMARK_RESTORE: + secmark_restore(skb); + break; + + default: + BUG(); + } + + return XT_CONTINUE; +} + +static int checkentry(const char *tablename, const void *entry, + const struct xt_target *target, void *targinfo, + unsigned int targinfosize, unsigned int hook_mask) +{ + struct xt_connsecmark_target_info *info = targinfo; + + switch (info->mode) { + case CONNSECMARK_SAVE: + case CONNSECMARK_RESTORE: + break; + + default: + printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); + return 0; + } + + return 1; +} + +static struct xt_target ipt_connsecmark_reg = { + .name = "CONNSECMARK", + .target = target, + .targetsize = sizeof(struct xt_connsecmark_target_info), + .table = "mangle", + .checkentry = checkentry, + .me = THIS_MODULE, + .family = AF_INET, + .revision = 0, +}; + +static struct xt_target ip6t_connsecmark_reg = { + .name = "CONNSECMARK", + .target = target, + .targetsize = sizeof(struct xt_connsecmark_target_info), + .table = "mangle", + .checkentry = checkentry, + .me = THIS_MODULE, + .family = AF_INET6, + .revision = 0, +}; + +static int __init xt_connsecmark_init(void) +{ + int err; + + need_conntrack(); + + err = xt_register_target(&ipt_connsecmark_reg); + if (err) + return err; + + err = xt_register_target(&ip6t_connsecmark_reg); + if (err) + xt_unregister_target(&ipt_connsecmark_reg); + + return err; +} + +static void __exit xt_connsecmark_fini(void) +{ + xt_unregister_target(&ip6t_connsecmark_reg); + xt_unregister_target(&ipt_connsecmark_reg); +} + +module_init(xt_connsecmark_init); +module_exit(xt_connsecmark_fini); -- cgit v1.2.3 From 932ff279a43ab7257942cddff2595acd541cc49b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 9 Jun 2006 12:20:56 -0700 Subject: [NET]: Add netif_tx_lock Various drivers use xmit_lock internally to synchronise with their transmission routines. They do so without setting xmit_lock_owner. This is fine as long as netpoll is not in use. With netpoll it is possible for deadlocks to occur if xmit_lock_owner isn't set. This is because if a printk occurs while xmit_lock is held and xmit_lock_owner is not set can cause netpoll to attempt to take xmit_lock recursively. While it is possible to resolve this by getting netpoll to use trylock, it is suboptimal because netpoll's sole objective is to maximise the chance of getting the printk out on the wire. So delaying or dropping the message is to be avoided as much as possible. So the only alternative is to always set xmit_lock_owner. The following patch does this by introducing the netif_tx_lock family of functions that take care of setting/unsetting xmit_lock_owner. I renamed xmit_lock to _xmit_lock to indicate that it should not be used directly. I didn't provide irq versions of the netif_tx_lock functions since xmit_lock is meant to be a BH-disabling lock. This is pretty much a straight text substitution except for a small bug fix in winbond. It currently uses netif_stop_queue/spin_unlock_wait to stop transmission. This is unsafe as an IRQ can potentially wake up the queue. So it is safer to use netif_tx_disable. The hamradio bits used spin_lock_irq but it is unnecessary as xmit_lock must never be taken in an IRQ handler. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- Documentation/networking/netdevices.txt | 8 +++--- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 6 ++-- drivers/media/dvb/dvb-core/dvb_net.c | 4 +-- drivers/net/bnx2.c | 4 +-- drivers/net/bonding/bond_main.c | 2 +- drivers/net/forcedeth.c | 18 ++++++------ drivers/net/hamradio/6pack.c | 8 +++--- drivers/net/hamradio/mkiss.c | 8 +++--- drivers/net/ifb.c | 10 +++---- drivers/net/irda/vlsi_ir.c | 2 +- drivers/net/natsemi.c | 4 +-- drivers/net/tulip/winbond-840.c | 9 +++--- drivers/net/wireless/orinoco.c | 4 ++- include/linux/netdevice.h | 38 ++++++++++++++++++++++++-- net/atm/clip.c | 4 +-- net/core/dev.c | 12 ++++---- net/core/dev_mcast.c | 28 +++++++++---------- net/core/netpoll.c | 9 ++---- net/core/pktgen.c | 4 +-- net/sched/sch_generic.c | 28 ++++++++----------- net/sched/sch_teql.c | 9 ++---- 21 files changed, 121 insertions(+), 98 deletions(-) (limited to 'include') diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index 3c0a5ba614d7..847cedb238f6 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -42,9 +42,9 @@ dev->get_stats: Context: nominally process, but don't sleep inside an rwlock dev->hard_start_xmit: - Synchronization: dev->xmit_lock spinlock. + Synchronization: netif_tx_lock spinlock. When the driver sets NETIF_F_LLTX in dev->features this will be - called without holding xmit_lock. In this case the driver + called without holding netif_tx_lock. In this case the driver has to lock by itself when needed. It is recommended to use a try lock for this and return -1 when the spin lock fails. The locking there should also properly protect against @@ -62,12 +62,12 @@ dev->hard_start_xmit: Only valid when NETIF_F_LLTX is set. dev->tx_timeout: - Synchronization: dev->xmit_lock spinlock. + Synchronization: netif_tx_lock spinlock. Context: BHs disabled Notes: netif_queue_stopped() is guaranteed true dev->set_multicast_list: - Synchronization: dev->xmit_lock spinlock. + Synchronization: netif_tx_lock spinlock. Context: BHs disabled dev->poll: diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 1dae4b238252..1d917edcf9ba 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_ptr) ipoib_mcast_stop_thread(dev, 0); - spin_lock_irqsave(&dev->xmit_lock, flags); + local_irq_save(flags); + netif_tx_lock(dev); spin_lock(&priv->lock); /* @@ -896,7 +897,8 @@ void ipoib_mcast_restart_task(void *dev_ptr) } spin_unlock(&priv->lock); - spin_unlock_irqrestore(&dev->xmit_lock, flags); + netif_tx_unlock(dev); + local_irq_restore(flags); /* We have to cancel outside of the spinlock */ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 2f0f35811bf7..9fd87521a163 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void *data) dvb_net_feed_stop(dev); priv->rx_mode = RX_MODE_UNI; - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); if (dev->flags & IFF_PROMISC) { dprintk("%s: promiscuous mode\n", dev->name); @@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void *data) } } - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); dvb_net_feed_start(dev); } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 54161aef3cac..9c5a8842ed0f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2009,7 +2009,7 @@ bnx2_poll(struct net_device *dev, int *budget) return 1; } -/* Called with rtnl_lock from vlan functions and also dev->xmit_lock +/* Called with rtnl_lock from vlan functions and also netif_tx_lock * from set_multicast. */ static void @@ -4252,7 +4252,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) } #endif -/* Called with dev->xmit_lock. +/* Called with netif_tx_lock. * hard_start_xmit is pseudo-lockless - a lock is only required when * the tx queue is full. This way, we get the benefit of lockless * operations most of the time without the complexities to handle diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 55d236726d11..46326cdfb277 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4191,7 +4191,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) */ bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - /* don't acquire bond device's xmit_lock when + /* don't acquire bond device's netif_tx_lock when * transmitting */ bond_dev->features |= NETIF_F_LLTX; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index feb5b223cd60..5a8651b4b01d 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -533,9 +533,9 @@ typedef union _ring_type { * critical parts: * - rx is (pseudo-) lockless: it relies on the single-threading provided * by the arch code for interrupts. - * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission + * - tx setup is lockless: it relies on netif_tx_lock. Actual submission * needs dev->priv->lock :-( - * - set_multicast_list: preparation lockless, relies on dev->xmit_lock. + * - set_multicast_list: preparation lockless, relies on netif_tx_lock. */ /* in dev: base, irq */ @@ -1213,7 +1213,7 @@ static void drain_ring(struct net_device *dev) /* * nv_start_xmit: dev->hard_start_xmit function - * Called with dev->xmit_lock held. + * Called with netif_tx_lock held. */ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1407,7 +1407,7 @@ static void nv_tx_done(struct net_device *dev) /* * nv_tx_timeout: dev->tx_timeout function - * Called with dev->xmit_lock held. + * Called with netif_tx_lock held. */ static void nv_tx_timeout(struct net_device *dev) { @@ -1737,7 +1737,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) * Changing the MTU is a rare event, it shouldn't matter. */ nv_disable_irq(dev); - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rx(dev); @@ -1768,7 +1768,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) nv_start_rx(dev); nv_start_tx(dev); spin_unlock(&np->lock); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); nv_enable_irq(dev); } return 0; @@ -1803,7 +1803,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN); if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); spin_lock_irq(&np->lock); /* stop rx engine */ @@ -1815,7 +1815,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) /* restart rx engine */ nv_start_rx(dev); spin_unlock_irq(&np->lock); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } else { nv_copy_mac_to_hw(dev); } @@ -1824,7 +1824,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) /* * nv_set_multicast: dev->set_multicast function - * Called with dev->xmit_lock held. + * Called with netif_tx_lock held. */ static void nv_set_multicast(struct net_device *dev) { diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 102c1f0b90da..d12605f0ac7c 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; - spin_lock_irq(&dev->xmit_lock); + netif_tx_lock_bh(dev); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); - spin_unlock_irq(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return 0; } @@ -767,9 +767,9 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, break; } - spin_lock_irq(&dev->xmit_lock); + netif_tx_lock_bh(dev); memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN); - spin_unlock_irq(&dev->xmit_lock); + netif_tx_unlock_bh(dev); err = 0; break; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d81a8e1eeb8d..3ebbbe56b6e9 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; - spin_lock_irq(&dev->xmit_lock); + netif_tx_lock_bh(dev); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); - spin_unlock_irq(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return 0; } @@ -886,9 +886,9 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, break; } - spin_lock_irq(&dev->xmit_lock); + netif_tx_lock_bh(dev); memcpy(dev->dev_addr, addr, AX25_ADDR_LEN); - spin_unlock_irq(&dev->xmit_lock); + netif_tx_unlock_bh(dev); err = 0; break; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 31fb2d75dc44..2e222ef91e22 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev) dp->st_task_enter++; if ((skb = skb_peek(&dp->tq)) == NULL) { dp->st_txq_refl_try++; - if (spin_trylock(&_dev->xmit_lock)) { + if (netif_tx_trylock(_dev)) { dp->st_rxq_enter++; while ((skb = skb_dequeue(&dp->rq)) != NULL) { skb_queue_tail(&dp->tq, skb); dp->st_rx2tx_tran++; } - spin_unlock(&_dev->xmit_lock); + netif_tx_unlock(_dev); } else { /* reschedule */ dp->st_rxq_notenter++; @@ -110,7 +110,7 @@ static void ri_tasklet(unsigned long dev) } } - if (spin_trylock(&_dev->xmit_lock)) { + if (netif_tx_trylock(_dev)) { dp->st_rxq_check++; if ((skb = skb_peek(&dp->rq)) == NULL) { dp->tasklet_pending = 0; @@ -118,10 +118,10 @@ static void ri_tasklet(unsigned long dev) netif_wake_queue(_dev); } else { dp->st_rxq_rsch++; - spin_unlock(&_dev->xmit_lock); + netif_tx_unlock(_dev); goto resched; } - spin_unlock(&_dev->xmit_lock); + netif_tx_unlock(_dev); } else { resched: dp->tasklet_pending = 1; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 97a49e0be76b..d70b9e8d6e60 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) || (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) break; udelay(100); - /* must not sleep here - we are called under xmit_lock! */ + /* must not sleep here - called under netif_tx_lock! */ } } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 90627756d6fa..2e4ecedba057 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -318,12 +318,12 @@ performance critical codepaths: The rx process only runs in the interrupt handler. Access from outside the interrupt handler is only permitted after disable_irq(). -The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap +The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap is set, then access is permitted under spin_lock_irq(&np->lock). Thus configuration functions that want to access everything must call disable_irq(dev->irq); - spin_lock_bh(dev->xmit_lock); + netif_tx_lock_bh(dev); spin_lock_irq(&np->lock); IV. Notes diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 136a70c4d5e4..56d86c7c0386 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1605,11 +1605,11 @@ static void __devexit w840_remove1 (struct pci_dev *pdev) * - get_stats: * spin_lock_irq(np->lock), doesn't touch hw if not present * - hard_start_xmit: - * netif_stop_queue + spin_unlock_wait(&dev->xmit_lock); + * synchronize_irq + netif_tx_disable; * - tx_timeout: - * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); + * netif_device_detach + netif_tx_disable; * - set_multicast_list - * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); + * netif_device_detach + netif_tx_disable; * - interrupt handler * doesn't touch hw if not present, synchronize_irq waits for * running instances of the interrupt handler. @@ -1635,11 +1635,10 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); update_csr6(dev, 0); iowrite32(0, ioaddr + IntrEnable); - netif_stop_queue(dev); spin_unlock_irq(&np->lock); - spin_unlock_wait(&dev->xmit_lock); synchronize_irq(dev->irq); + netif_tx_disable(dev); np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index c2d0b09e0418..a5fcfcde63d1 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1833,7 +1833,9 @@ static int __orinoco_program_rids(struct net_device *dev) /* Set promiscuity / multicast*/ priv->promiscuous = 0; priv->mc_count = 0; - __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */ + + /* FIXME: what about netif_tx_lock */ + __orinoco_set_multicast_list(dev); return 0; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b5760c67af9c..067b9ccafd87 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -407,7 +407,7 @@ struct net_device * One part is mostly used on xmit path (device) */ /* hard_start_xmit synchronizer */ - spinlock_t xmit_lock ____cacheline_aligned_in_smp; + spinlock_t _xmit_lock ____cacheline_aligned_in_smp; /* cpu id of processor entered to hard_start_xmit or -1, if nobody entered there. */ @@ -893,11 +893,43 @@ static inline void __netif_rx_complete(struct net_device *dev) clear_bit(__LINK_STATE_RX_SCHED, &dev->state); } +static inline void netif_tx_lock(struct net_device *dev) +{ + spin_lock(&dev->_xmit_lock); + dev->xmit_lock_owner = smp_processor_id(); +} + +static inline void netif_tx_lock_bh(struct net_device *dev) +{ + spin_lock_bh(&dev->_xmit_lock); + dev->xmit_lock_owner = smp_processor_id(); +} + +static inline int netif_tx_trylock(struct net_device *dev) +{ + int err = spin_trylock(&dev->_xmit_lock); + if (!err) + dev->xmit_lock_owner = smp_processor_id(); + return err; +} + +static inline void netif_tx_unlock(struct net_device *dev) +{ + dev->xmit_lock_owner = -1; + spin_unlock(&dev->_xmit_lock); +} + +static inline void netif_tx_unlock_bh(struct net_device *dev) +{ + dev->xmit_lock_owner = -1; + spin_unlock_bh(&dev->_xmit_lock); +} + static inline void netif_tx_disable(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); netif_stop_queue(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } /* These functions live elsewhere (drivers/net/net_init.c, but related) */ diff --git a/net/atm/clip.c b/net/atm/clip.c index 72d852982664..f92f9c94d2c7 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -98,7 +98,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n", clip_vcc); return; } - spin_lock_bh(&entry->neigh->dev->xmit_lock); /* block clip_start_xmit() */ + netif_tx_lock_bh(entry->neigh->dev); /* block clip_start_xmit() */ entry->neigh->used = jiffies; for (walk = &entry->vccs; *walk; walk = &(*walk)->next) if (*walk == clip_vcc) { @@ -122,7 +122,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc " "0x%p)\n", entry, clip_vcc); out: - spin_unlock_bh(&entry->neigh->dev->xmit_lock); + netif_tx_unlock_bh(entry->neigh->dev); } /* The neighbour entry n->lock is held. */ diff --git a/net/core/dev.c b/net/core/dev.c index 6bfa78c66c25..1b09f1cae46e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1282,15 +1282,13 @@ int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask) #define HARD_TX_LOCK(dev, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - spin_lock(&dev->xmit_lock); \ - dev->xmit_lock_owner = cpu; \ + netif_tx_lock(dev); \ } \ } #define HARD_TX_UNLOCK(dev) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - dev->xmit_lock_owner = -1; \ - spin_unlock(&dev->xmit_lock); \ + netif_tx_unlock(dev); \ } \ } @@ -1389,8 +1387,8 @@ int dev_queue_xmit(struct sk_buff *skb) /* The device has no queue. Common case for software devices: loopback, all the sorts of tunnels... - Really, it is unlikely that xmit_lock protection is necessary here. - (f.e. loopback and IP tunnels are clean ignoring statistics + Really, it is unlikely that netif_tx_lock protection is necessary + here. (f.e. loopback and IP tunnels are clean ignoring statistics counters.) However, it is possible, that they rely on protection made by us here. @@ -2805,7 +2803,7 @@ int register_netdevice(struct net_device *dev) BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); spin_lock_init(&dev->queue_lock); - spin_lock_init(&dev->xmit_lock); + spin_lock_init(&dev->_xmit_lock); dev->xmit_lock_owner = -1; #ifdef CONFIG_NET_CLS_ACT spin_lock_init(&dev->ingress_lock); diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 05d60850840e..c57d887da2ef 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -62,7 +62,7 @@ * Device mc lists are changed by bh at least if IPv6 is enabled, * so that it must be bh protected. * - * We block accesses to device mc filters with dev->xmit_lock. + * We block accesses to device mc filters with netif_tx_lock. */ /* @@ -93,9 +93,9 @@ static void __dev_mc_upload(struct net_device *dev) void dev_mc_upload(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); __dev_mc_upload(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } /* @@ -107,7 +107,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) int err = 0; struct dev_mc_list *dmi, **dmip; - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) { /* @@ -139,13 +139,13 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) */ __dev_mc_upload(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return 0; } } err = -ENOENT; done: - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return err; } @@ -160,7 +160,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC); - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 && dmi->dmi_addrlen == alen) { @@ -176,7 +176,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) } if ((dmi = dmi1) == NULL) { - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return -ENOMEM; } memcpy(dmi->dmi_addr, addr, alen); @@ -189,11 +189,11 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) __dev_mc_upload(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return 0; done: - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); kfree(dmi1); return err; } @@ -204,7 +204,7 @@ done: void dev_mc_discard(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); while (dev->mc_list != NULL) { struct dev_mc_list *tmp = dev->mc_list; @@ -215,7 +215,7 @@ void dev_mc_discard(struct net_device *dev) } dev->mc_count = 0; - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } #ifdef CONFIG_PROC_FS @@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v) struct dev_mc_list *m; struct net_device *dev = v; - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); for (m = dev->mc_list; m; m = m->next) { int i; @@ -262,7 +262,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v) seq_putc(seq, '\n'); } - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); return 0; } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e8e05cebd95a..9cb781830380 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) do { npinfo->tries--; - spin_lock(&np->dev->xmit_lock); - np->dev->xmit_lock_owner = smp_processor_id(); + netif_tx_lock(np->dev); /* * network drivers do not expect to be called if the queue is * stopped. */ if (netif_queue_stopped(np->dev)) { - np->dev->xmit_lock_owner = -1; - spin_unlock(&np->dev->xmit_lock); + netif_tx_unlock(np->dev); netpoll_poll(np); udelay(50); continue; } status = np->dev->hard_start_xmit(skb, np->dev); - np->dev->xmit_lock_owner = -1; - spin_unlock(&np->dev->xmit_lock); + netif_tx_unlock(np->dev); /* success */ if(!status) { diff --git a/net/core/pktgen.c b/net/core/pktgen.c index c23e9c06ee23..67ed14ddabd2 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2897,7 +2897,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) } } - spin_lock_bh(&odev->xmit_lock); + netif_tx_lock_bh(odev); if (!netif_queue_stopped(odev)) { atomic_inc(&(pkt_dev->skb->users)); @@ -2942,7 +2942,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->next_tx_ns = 0; } - spin_unlock_bh(&odev->xmit_lock); + netif_tx_unlock_bh(odev); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 138ea92ed268..b1e4c5e20ac7 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -72,9 +72,9 @@ void qdisc_unlock_tree(struct net_device *dev) dev->queue_lock serializes queue accesses for this device AND dev->qdisc pointer itself. - dev->xmit_lock serializes accesses to device driver. + netif_tx_lock serializes accesses to device driver. - dev->queue_lock and dev->xmit_lock are mutually exclusive, + dev->queue_lock and netif_tx_lock are mutually exclusive, if one is grabbed, another must be free. */ @@ -108,7 +108,7 @@ int qdisc_restart(struct net_device *dev) * will be requeued. */ if (!nolock) { - if (!spin_trylock(&dev->xmit_lock)) { + if (!netif_tx_trylock(dev)) { collision: /* So, someone grabbed the driver. */ @@ -126,8 +126,6 @@ int qdisc_restart(struct net_device *dev) __get_cpu_var(netdev_rx_stat).cpu_collision++; goto requeue; } - /* Remember that the driver is grabbed by us. */ - dev->xmit_lock_owner = smp_processor_id(); } { @@ -142,8 +140,7 @@ int qdisc_restart(struct net_device *dev) ret = dev->hard_start_xmit(skb, dev); if (ret == NETDEV_TX_OK) { if (!nolock) { - dev->xmit_lock_owner = -1; - spin_unlock(&dev->xmit_lock); + netif_tx_unlock(dev); } spin_lock(&dev->queue_lock); return -1; @@ -157,8 +154,7 @@ int qdisc_restart(struct net_device *dev) /* NETDEV_TX_BUSY - we need to requeue */ /* Release the driver */ if (!nolock) { - dev->xmit_lock_owner = -1; - spin_unlock(&dev->xmit_lock); + netif_tx_unlock(dev); } spin_lock(&dev->queue_lock); q = dev->qdisc; @@ -187,7 +183,7 @@ static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; - spin_lock(&dev->xmit_lock); + netif_tx_lock(dev); if (dev->qdisc != &noop_qdisc) { if (netif_device_present(dev) && netif_running(dev) && @@ -203,7 +199,7 @@ static void dev_watchdog(unsigned long arg) dev_hold(dev); } } - spin_unlock(&dev->xmit_lock); + netif_tx_unlock(dev); dev_put(dev); } @@ -227,17 +223,17 @@ void __netdev_watchdog_up(struct net_device *dev) static void dev_watchdog_up(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); __netdev_watchdog_up(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } static void dev_watchdog_down(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); + netif_tx_lock_bh(dev); if (del_timer(&dev->watchdog_timer)) dev_put(dev); - spin_unlock_bh(&dev->xmit_lock); + netif_tx_unlock_bh(dev); } void netif_carrier_on(struct net_device *dev) @@ -582,7 +578,7 @@ void dev_deactivate(struct net_device *dev) while (test_bit(__LINK_STATE_SCHED, &dev->state)) yield(); - spin_unlock_wait(&dev->xmit_lock); + spin_unlock_wait(&dev->_xmit_lock); } void dev_init_scheduler(struct net_device *dev) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 79b8ef34c6e4..4c16ad57a3e4 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -302,20 +302,17 @@ restart: switch (teql_resolve(skb, skb_res, slave)) { case 0: - if (spin_trylock(&slave->xmit_lock)) { - slave->xmit_lock_owner = smp_processor_id(); + if (netif_tx_trylock(slave)) { if (!netif_queue_stopped(slave) && slave->hard_start_xmit(skb, slave) == 0) { - slave->xmit_lock_owner = -1; - spin_unlock(&slave->xmit_lock); + netif_tx_unlock(slave); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); master->stats.tx_packets++; master->stats.tx_bytes += len; return 0; } - slave->xmit_lock_owner = -1; - spin_unlock(&slave->xmit_lock); + netif_tx_unlock(slave); } if (netif_queue_stopped(dev)) busy = 1; -- cgit v1.2.3 From 364c6badde0dd62a0a38e5ed67f85d87d6665780 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 9 Jun 2006 16:10:40 -0700 Subject: [NET]: Clean up skb_linearize The linearisation operation doesn't need to be super-optimised. So we can replace __skb_linearize with __pskb_pull_tail which does the same thing but is more general. Also, most users of skb_linearize end up testing whether the skb is linear or not so it helps to make skb_linearize do just that. Some callers of skb_linearize also use it to copy cloned data, so it's useful to have a new function skb_linearize_cow to copy the data if it's either non-linear or cloned. Last but not least, I've removed the gfp argument since nobody uses it anymore. If it's ever needed we can easily add it back. Misc bugs fixed by this patch: * via-velocity error handling (also, no SG => no frags) Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/block/aoe/aoenet.c | 3 +-- drivers/net/mv643xx_eth.c | 2 +- drivers/net/via-velocity.c | 10 +++++--- include/linux/skbuff.h | 24 +++++++++++++++--- net/core/dev.c | 63 ++-------------------------------------------- net/decnet/dn_nsp_in.c | 3 +-- net/decnet/dn_route.c | 3 +-- net/ipv4/ipcomp.c | 11 +++----- net/ipv6/ipcomp6.c | 11 +++----- 9 files changed, 39 insertions(+), 91 deletions(-) (limited to 'include') diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index fdff774b8ab9..c1434ed11880 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -116,8 +116,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) return 0; - if (skb_is_nonlinear(skb)) - if (skb_linearize(skb, GFP_ATOMIC) < 0) + if (skb_linearize(skb)) goto exit; if (!is_aoe_netif(ifp)) goto exit; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 411f4d809c47..625ff61c9988 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1200,7 +1200,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (has_tiny_unaligned_frags(skb)) { - if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { + if (__skb_linearize(skb)) { stats->tx_dropped++; printk(KERN_DEBUG "%s: failed to linearize tiny " "unaligned fragment\n", dev->name); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index ed1f837c8fda..2eb6b5f9ba0d 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) int pktlen = skb->len; +#ifdef VELOCITY_ZERO_COPY_SUPPORT + if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { + kfree_skb(skb); + return 0; + } +#endif + spin_lock_irqsave(&vptr->lock, flags); index = vptr->td_curr[qnum]; @@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) */ if (pktlen < ETH_ZLEN) { /* Cannot occur until ZC support */ - if(skb_linearize(skb, GFP_ATOMIC)) - return 0; pktlen = ETH_ZLEN; memcpy(tdinfo->buf, skb->data, skb->len); memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); @@ -1933,7 +1938,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) int nfrags = skb_shinfo(skb)->nr_frags; tdinfo->skb = skb; if (nfrags > 6) { - skb_linearize(skb, GFP_ATOMIC); memcpy(tdinfo->buf, skb->data, skb->len); tdinfo->skb_dma[0] = tdinfo->buf_dma; td_ptr->tdesc0.pktsize = diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index fe2c58e5306f..830f58fa03a2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1169,18 +1169,34 @@ static inline int skb_can_coalesce(struct sk_buff *skb, int i, return 0; } +static inline int __skb_linearize(struct sk_buff *skb) +{ + return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM; +} + /** * skb_linearize - convert paged skb to linear one * @skb: buffer to linarize - * @gfp: allocation mode * * If there is no free memory -ENOMEM is returned, otherwise zero * is returned and the old skb data released. */ -extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp); -static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp) +static inline int skb_linearize(struct sk_buff *skb) +{ + return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0; +} + +/** + * skb_linearize_cow - make sure skb is linear and writable + * @skb: buffer to process + * + * If there is no free memory -ENOMEM is returned, otherwise zero + * is returned and the old skb data released. + */ +static inline int skb_linearize_cow(struct sk_buff *skb) { - return __skb_linearize(skb, gfp); + return skb_is_nonlinear(skb) || skb_cloned(skb) ? + __skb_linearize(skb) : 0; } /** diff --git a/net/core/dev.c b/net/core/dev.c index 1b09f1cae46e..91361bc2b682 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1222,64 +1222,6 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) #define illegal_highdma(dev, skb) (0) #endif -/* Keep head the same: replace data */ -int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask) -{ - unsigned int size; - u8 *data; - long offset; - struct skb_shared_info *ninfo; - int headerlen = skb->data - skb->head; - int expand = (skb->tail + skb->data_len) - skb->end; - - if (skb_shared(skb)) - BUG(); - - if (expand <= 0) - expand = 0; - - size = skb->end - skb->head + expand; - size = SKB_DATA_ALIGN(size); - data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); - if (!data) - return -ENOMEM; - - /* Copy entire thing */ - if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) - BUG(); - - /* Set up shinfo */ - ninfo = (struct skb_shared_info*)(data + size); - atomic_set(&ninfo->dataref, 1); - ninfo->tso_size = skb_shinfo(skb)->tso_size; - ninfo->tso_segs = skb_shinfo(skb)->tso_segs; - ninfo->nr_frags = 0; - ninfo->frag_list = NULL; - - /* Offset between the two in bytes */ - offset = data - skb->head; - - /* Free old data. */ - skb_release_data(skb); - - skb->head = data; - skb->end = data + size; - - /* Set up new pointers */ - skb->h.raw += offset; - skb->nh.raw += offset; - skb->mac.raw += offset; - skb->tail += offset; - skb->data += offset; - - /* We are no longer a clone, even if we were. */ - skb->cloned = 0; - - skb->tail += skb->data_len; - skb->data_len = 0; - return 0; -} - #define HARD_TX_LOCK(dev, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ netif_tx_lock(dev); \ @@ -1326,7 +1268,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && - __skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb)) goto out_kfree_skb; /* Fragmented skb is linearized if device does not support SG, @@ -1335,7 +1277,7 @@ int dev_queue_xmit(struct sk_buff *skb) */ if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - __skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb)) goto out_kfree_skb; /* If packet is not checksummed and device does not support @@ -3473,7 +3415,6 @@ subsys_initcall(net_dev_init); EXPORT_SYMBOL(__dev_get_by_index); EXPORT_SYMBOL(__dev_get_by_name); EXPORT_SYMBOL(__dev_remove_pack); -EXPORT_SYMBOL(__skb_linearize); EXPORT_SYMBOL(dev_valid_name); EXPORT_SYMBOL(dev_add_pack); EXPORT_SYMBOL(dev_alloc_name); diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 547523b41c81..a2ba9db1c376 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -801,8 +801,7 @@ got_it: * We linearize everything except data segments here. */ if (cb->nsp_flags & ~0x60) { - if (unlikely(skb_is_nonlinear(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) + if (unlikely(skb_linearize(skb))) goto free_out; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index e172cf98d7fc..5abf7057af00 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type padlen); if (flags & DN_RT_PKT_CNTL) { - if (unlikely(skb_is_nonlinear(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) + if (unlikely(skb_linearize(skb))) goto dump_it; switch(flags & DN_RT_CNTL_MSK) { diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 8e243589045f..3ed8b57a1002 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -80,15 +80,12 @@ out: static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) { - int err = 0; + int err = -ENOMEM; struct iphdr *iph; struct ip_comp_hdr *ipch; - if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) { - err = -ENOMEM; + if (skb_linearize_cow(skb)) goto out; - } skb->ip_summed = CHECKSUM_NONE; @@ -158,10 +155,8 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) goto out_ok; } - if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) { + if (skb_linearize_cow(skb)) goto out_ok; - } err = ipcomp_compress(x, skb); iph = skb->nh.iph; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index cec3be544b69..f28cd37feed3 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -65,7 +65,7 @@ static LIST_HEAD(ipcomp6_tfms_list); static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) { - int err = 0; + int err = -ENOMEM; struct ipv6hdr *iph; struct ipv6_comp_hdr *ipch; int plen, dlen; @@ -74,11 +74,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) struct crypto_tfm *tfm; int cpu; - if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) { - err = -ENOMEM; + if (skb_linearize_cow(skb)) goto out; - } skb->ip_summed = CHECKSUM_NONE; @@ -142,10 +139,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) goto out_ok; } - if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) { + if (skb_linearize_cow(skb)) goto out_ok; - } /* compression */ plen = skb->len - hdr_len; -- cgit v1.2.3 From b38dfee3d616ffadb58d4215e3ff9d1d7921031e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 9 Jun 2006 16:13:01 -0700 Subject: [NET]: skb_trim audit I found a few more spots where pskb_trim_rcsum could be used but were not. This patch changes them to use it. Also, sk_filter can get paged skb data. Therefore we must use pskb_trim instead of skb_trim. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/sock.h | 5 +---- net/bridge/br_netfilter.c | 14 +++----------- net/ipv6/netfilter/nf_conntrack_reasm.c | 10 +++------- 3 files changed, 7 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 75b0e97ed93d..96565ff0de6a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -873,10 +873,7 @@ static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock) if (filter) { unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len); - if (!pkt_len) - err = -EPERM; - else - skb_trim(skb, pkt_len); + err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; } if (needlock) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 3da9264449f7..3e41f9d6d51c 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -407,12 +407,8 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { if (pkt_len + sizeof(struct ipv6hdr) > skb->len) goto inhdr_error; - if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { - if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr))) - goto inhdr_error; - if (skb->ip_summed == CHECKSUM_HW) - skb->ip_summed = CHECKSUM_NONE; - } + if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) + goto inhdr_error; } if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) goto inhdr_error; @@ -495,11 +491,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, if (skb->len < len || len < 4 * iph->ihl) goto inhdr_error; - if (skb->len > len) { - __pskb_trim(skb, len); - if (skb->ip_summed == CHECKSUM_HW) - skb->ip_summed = CHECKSUM_NONE; - } + pskb_trim_rcsum(skb, len); nf_bridge_put(skb->nf_bridge); if (!nf_bridge_alloc(skb)) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 3e319035f82d..c32a029e43f0 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -456,13 +456,9 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, DEBUGP("queue: message is too short.\n"); goto err; } - if (end-offset < skb->len) { - if (pskb_trim(skb, end - offset)) { - DEBUGP("Can't trim\n"); - goto err; - } - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; + if (pskb_trim_rcsum(skb, end - offset)) { + DEBUGP("Can't trim\n"); + goto err; } /* Find out which fragments are in front and at the back of us -- cgit v1.2.3 From 3cc0e873986fe594d0e96d07259b11f755325cb2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 9 Jun 2006 16:13:38 -0700 Subject: [NET]: Warn in __skb_trim if skb is paged It's better to warn and fail rather than rarely triggering BUG on paths that incorrectly call skb_trim/__skb_trim on a non-linear skb. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/skbuff.h | 24 ++++++++++++------------ net/core/skbuff.c | 7 ++----- 2 files changed, 14 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 830f58fa03a2..93e4db221585 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -975,15 +975,16 @@ static inline void skb_reserve(struct sk_buff *skb, int len) #define NET_SKB_PAD 16 #endif -extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc); +extern int ___pskb_trim(struct sk_buff *skb, unsigned int len); static inline void __skb_trim(struct sk_buff *skb, unsigned int len) { - if (!skb->data_len) { - skb->len = len; - skb->tail = skb->data + len; - } else - ___pskb_trim(skb, len, 0); + if (unlikely(skb->data_len)) { + WARN_ON(1); + return; + } + skb->len = len; + skb->tail = skb->data + len; } /** @@ -993,6 +994,7 @@ static inline void __skb_trim(struct sk_buff *skb, unsigned int len) * * 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) { @@ -1003,12 +1005,10 @@ static inline void skb_trim(struct sk_buff *skb, unsigned int len) static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) { - if (!skb->data_len) { - skb->len = len; - skb->tail = skb->data+len; - return 0; - } - return ___pskb_trim(skb, len, 1); + if (skb->data_len) + return ___pskb_trim(skb, len); + __skb_trim(skb, len); + return 0; } 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 96cdcbe24ba2..bb7210f4005e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -801,12 +801,10 @@ struct sk_buff *skb_pad(struct sk_buff *skb, int pad) return nskb; } -/* Trims skb to length len. It can change skb pointers, if "realloc" is 1. - * If realloc==0 and trimming is impossible without change of data, - * it is BUG(). +/* Trims skb to length len. It can change skb pointers. */ -int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc) +int ___pskb_trim(struct sk_buff *skb, unsigned int len) { int offset = skb_headlen(skb); int nfrags = skb_shinfo(skb)->nr_frags; @@ -816,7 +814,6 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc) int end = offset + skb_shinfo(skb)->frags[i].size; if (end > len) { if (skb_cloned(skb)) { - BUG_ON(!realloc); if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return -ENOMEM; } -- cgit v1.2.3 From bdeb04c6d9a957ae2a51c3033414467b82b2a736 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 11 Jun 2006 21:20:38 -0700 Subject: [NET]: net.ipv4.ip_autoconfig sysctl removal The sysctl net.ipv4.ip_autoconfig is a legacy value that is not used. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/ip.h | 1 - net/ipv4/sysctl_net_ipv4.c | 8 -------- 2 files changed, 9 deletions(-) (limited to 'include') diff --git a/include/net/ip.h b/include/net/ip.h index 3d2e5ca62a5a..ead233c9540d 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -147,7 +147,6 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar struct ipv4_config { int log_martians; - int autoconfig; int no_pmtu_disc; }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 6a6aa537b7aa..e7fb665873c6 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -181,14 +181,6 @@ ctl_table ipv4_table[] = { .proc_handler = &ipv4_doint_and_flush, .strategy = &ipv4_doint_and_flush_strategy, }, - { - .ctl_name = NET_IPV4_AUTOCONFIG, - .procname = "ip_autoconfig", - .data = &ipv4_config.autoconfig, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, { .ctl_name = NET_IPV4_NO_PMTU_DISC, .procname = "ip_no_pmtu_disc", -- cgit v1.2.3 From 35089bb203f44e33b6bbb6c4de0b0708f9a48921 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 13 Jun 2006 22:33:04 -0700 Subject: [TCP]: Add tcp_slow_start_after_idle sysctl. A lot of people have asked for a way to disable tcp_cwnd_restart(), and it seems reasonable to add a sysctl to do that. Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 7 +++++++ include/linux/sysctl.h | 1 + include/net/tcp.h | 1 + net/ipv4/sysctl_net_ipv4.c | 8 ++++++++ net/ipv4/tcp_output.c | 6 +++++- 5 files changed, 22 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index f12007b80a46..d46338af6002 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -362,6 +362,13 @@ tcp_workaround_signed_windows - BOOLEAN not receive a window scaling option from them. Default: 0 +tcp_slow_start_after_idle - BOOLEAN + If set, provide RFC2861 behavior and time out the congestion + window after an idle period. An idle period is defined at + the current RTO. If unset, the congestion window will not + be timed out after an idle period. + Default: 1 + IP Variables: ip_local_port_range - 2 INTEGERS diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 98338ed2c0b6..cee944dbdcd4 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -405,6 +405,7 @@ enum NET_TCP_BASE_MSS=114, NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115, NET_TCP_DMA_COPYBREAK=116, + NET_TCP_SLOW_START_AFTER_IDLE=117, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index de88c5472bfc..bfc71f954bbe 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -227,6 +227,7 @@ extern int sysctl_tcp_abc; extern int sysctl_tcp_mtu_probing; extern int sysctl_tcp_base_mss; extern int sysctl_tcp_workaround_signed_windows; +extern int sysctl_tcp_slow_start_after_idle; extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e7fb665873c6..ce4cd5f35511 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -690,6 +690,14 @@ ctl_table ipv4_table[] = { .proc_handler = &proc_dointvec }, #endif + { + .ctl_name = NET_TCP_SLOW_START_AFTER_IDLE, + .procname = "tcp_slow_start_after_idle", + .data = &sysctl_tcp_slow_start_after_idle, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f33c9dddaa12..07bb5a2b375e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -59,6 +59,9 @@ int sysctl_tcp_tso_win_divisor = 3; int sysctl_tcp_mtu_probing = 0; int sysctl_tcp_base_mss = 512; +/* By default, RFC2861 behavior. */ +int sysctl_tcp_slow_start_after_idle = 1; + static void update_send_head(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb) { @@ -138,7 +141,8 @@ static void tcp_event_data_sent(struct tcp_sock *tp, struct inet_connection_sock *icsk = inet_csk(sk); const u32 now = tcp_time_stamp; - if (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto) + if (sysctl_tcp_slow_start_after_idle && + (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)) tcp_cwnd_restart(sk, __sk_dst_get(sk)); tp->lsndtime = now; -- cgit v1.2.3 From 8648b3053bff39a7ee4c711d74268079c928a657 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 17 Jun 2006 22:06:05 -0700 Subject: [NET]: Add NETIF_F_GEN_CSUM and NETIF_F_ALL_CSUM The current stack treats NETIF_F_HW_CSUM and NETIF_F_NO_CSUM identically so we test for them in quite a few places. For the sake of brevity, I'm adding the macro NETIF_F_GEN_CSUM for these two. We also test the disjunct of NETIF_F_IP_CSUM and the other two in various places, for that purpose I've added NETIF_F_ALL_CSUM. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 7 ++----- include/linux/netdevice.h | 3 +++ net/bridge/br_if.c | 3 +-- net/core/dev.c | 6 ++---- net/core/ethtool.c | 6 ++---- net/ipv4/ip_output.c | 2 +- net/ipv4/tcp.c | 10 ++-------- 7 files changed, 13 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 46326cdfb277..8171cae06688 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1199,8 +1199,7 @@ int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) } #define BOND_INTERSECT_FEATURES \ - (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM|\ - NETIF_F_TSO|NETIF_F_UFO) + (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO) /* * Compute the common dev->feature set available to all slaves. Some @@ -1218,9 +1217,7 @@ static int bond_compute_features(struct bonding *bond) features &= (slave->dev->features & BOND_INTERSECT_FEATURES); if ((features & NETIF_F_SG) && - !(features & (NETIF_F_IP_CSUM | - NETIF_F_NO_CSUM | - NETIF_F_HW_CSUM))) + !(features & NETIF_F_ALL_CSUM)) features &= ~NETIF_F_SG; /* diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 067b9ccafd87..e432b743dda2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -312,6 +312,9 @@ struct net_device #define NETIF_F_LLTX 4096 /* LockLess TX */ #define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/ +#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) +#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM) + struct net_device *next_sched; /* Interface index. Unique device identifier */ diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f5d47bf4f967..90c95f59dc82 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -376,8 +376,7 @@ void br_features_recompute(struct net_bridge *br) checksum = br->feature_mask & NETIF_F_IP_CSUM; list_for_each_entry(p, &br->port_list, list) { - if (!(p->dev->features - & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM))) + if (!(p->dev->features & NETIF_F_ALL_CSUM)) checksum = 0; features &= p->dev->features; } diff --git a/net/core/dev.c b/net/core/dev.c index 91361bc2b682..ab39fe17cb58 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1284,7 +1284,7 @@ int dev_queue_xmit(struct sk_buff *skb) * checksumming for this protocol, complete checksumming here. */ if (skb->ip_summed == CHECKSUM_HW && - (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && + (!(dev->features & NETIF_F_GEN_CSUM) && (!(dev->features & NETIF_F_IP_CSUM) || skb->protocol != htons(ETH_P_IP)))) if (skb_checksum_help(skb, 0)) @@ -2789,9 +2789,7 @@ int register_netdevice(struct net_device *dev) /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && - !(dev->features & (NETIF_F_IP_CSUM | - NETIF_F_NO_CSUM | - NETIF_F_HW_CSUM))) { + !(dev->features & NETIF_F_ALL_CSUM)) { printk("%s: Dropping NETIF_F_SG since no checksum feature.\n", dev->name); dev->features &= ~NETIF_F_SG; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index e6f76106a99b..3f269e4e9438 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_device *dev) u32 ethtool_op_get_tx_csum(struct net_device *dev) { - return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0; + return (dev->features & NETIF_F_ALL_CSUM) != 0; } int ethtool_op_set_tx_csum(struct net_device *dev, u32 data) @@ -551,9 +551,7 @@ static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) return -EFAULT; if (edata.data && - !(dev->features & (NETIF_F_IP_CSUM | - NETIF_F_NO_CSUM | - NETIF_F_HW_CSUM))) + !(dev->features & NETIF_F_ALL_CSUM)) return -EINVAL; return __ethtool_set_sg(dev, edata.data); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index d4bb3fae4e49..8538aac3d148 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -840,7 +840,7 @@ int ip_append_data(struct sock *sk, */ if (transhdrlen && length + fragheaderlen <= mtu && - rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) && + rt->u.dst.dev->features & NETIF_F_ALL_CSUM && !exthdrlen) csummode = CHECKSUM_HW; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ff6ccda9ff46..74998f250071 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -622,14 +622,10 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, ssize_t res; struct sock *sk = sock->sk; -#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) - if (!(sk->sk_route_caps & NETIF_F_SG) || - !(sk->sk_route_caps & TCP_ZC_CSUM_FLAGS)) + !(sk->sk_route_caps & NETIF_F_ALL_CSUM)) return sock_no_sendpage(sock, page, offset, size, flags); -#undef TCP_ZC_CSUM_FLAGS - lock_sock(sk); TCP_CHECK_TIMER(sk); res = do_tcp_sendpages(sk, &page, offset, size, flags); @@ -726,9 +722,7 @@ new_segment: /* * Check whether we can use HW checksum. */ - if (sk->sk_route_caps & - (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | - NETIF_F_HW_CSUM)) + if (sk->sk_route_caps & NETIF_F_ALL_CSUM) skb->ip_summed = CHECKSUM_HW; skb_entail(sk, tp, skb); -- cgit v1.2.3 From c7ce1ae21223fe1f905feba272bc14b87994a57d Mon Sep 17 00:00:00 2001 From: Tushar Gohad Date: Sat, 17 Jun 2006 22:54:03 -0700 Subject: [PFKEYV2]: Fix inconsistent typing in struct sadb_x_kmprivate. Signed-off-by: Tushar Gohad Signed-off-by: David S. Miller --- include/linux/pfkeyv2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index bac0fb389cf1..d5dd471da225 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -159,7 +159,7 @@ struct sadb_spirange { struct sadb_x_kmprivate { uint16_t sadb_x_kmprivate_len; uint16_t sadb_x_kmprivate_exttype; - u_int32_t sadb_x_kmprivate_reserved; + uint32_t sadb_x_kmprivate_reserved; } __attribute__((packed)); /* sizeof(struct sadb_x_kmprivate) == 8 */ -- cgit v1.2.3 From 5636bef7324f49e36f05ec8a5f6284e11b1bcca4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sat, 17 Jun 2006 22:55:35 -0700 Subject: [SCTP]: Reject sctp packets with broadcast addresses. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 3 ++- net/sctp/input.c | 3 ++- net/sctp/ipv6.c | 6 ++++-- net/sctp/protocol.c | 8 +++++++- net/sctp/socket.c | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7f4fea173fb1..5f69158c1006 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -555,7 +555,8 @@ struct sctp_af { int (*to_addr_param) (const union sctp_addr *, union sctp_addr_param *); int (*addr_valid) (union sctp_addr *, - struct sctp_sock *); + struct sctp_sock *, + const struct sk_buff *); sctp_scope_t (*scope) (union sctp_addr *); void (*inaddr_any) (union sctp_addr *, unsigned short); int (*is_any) (const union sctp_addr *); diff --git a/net/sctp/input.c b/net/sctp/input.c index 1662f9cc869e..70d6606e2812 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -170,7 +170,8 @@ int sctp_rcv(struct sk_buff *skb) * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) + if (!af->addr_valid(&src, NULL, skb) || + !af->addr_valid(&dest, NULL, skb)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index c20d282fac06..8ef08070c8b6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -523,7 +523,9 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp) +static int sctp_v6_addr_valid(union sctp_addr *addr, + struct sctp_sock *sp, + const struct sk_buff *skb) { int ret = ipv6_addr_type(&addr->v6.sin6_addr); @@ -537,7 +539,7 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp) if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; sctp_v6_map_v4(addr); - return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); + return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb); } /* Is this a non-unicast address */ diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 2088aa992b7a..816c033d7886 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -365,12 +365,18 @@ static int sctp_v4_is_any(const union sctp_addr *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_sock *sp) +static int sctp_v4_addr_valid(union sctp_addr *addr, + struct sctp_sock *sp, + const struct sk_buff *skb) { /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) return 0; + /* Is this a broadcast address? */ + if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST) + return 0; + return 1; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b41dcbb89685..b811691c35bf 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -172,7 +172,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, return -EINVAL; /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr, sctp_sk(sk))) + if (!af->addr_valid(addr, sctp_sk(sk), NULL)) return -EINVAL; if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) -- cgit v1.2.3 From 4c9f5d5305a23851e67471b147e0d459a7166717 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sat, 17 Jun 2006 22:56:08 -0700 Subject: [SCTP] Reset rtt_in_progress for the chunk when processing its sack. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 2 +- net/sctp/outqueue.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index aa6033ca7cd8..b2b40f951ae6 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -255,7 +255,7 @@ extern int sctp_debug_flag; #define SCTP_DEBUG_PRINTK_IPADDR(whatever...) #define SCTP_ENABLE_DEBUG #define SCTP_DISABLE_DEBUG -#define SCTP_ASSERT(expr, str, func) +#define SCTP_ASSERT(expr, str, func) BUG_ON(!(expr)) #endif /* SCTP_DEBUG */ diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index f148f9576dd2..e5faa351aaad 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1262,6 +1262,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, if (!tchunk->tsn_gap_acked && !tchunk->resent && tchunk->rtt_in_progress) { + tchunk->rtt_in_progress = 0; rtt = jiffies - tchunk->sent_at; sctp_transport_update_rto(transport, rtt); -- cgit v1.2.3 From c138e12f3a2e0421a4c8edf02587d2d394418679 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 23 May 2006 00:47:41 +0900 Subject: [MIPS] Fix fpu_save_double on 64-bit. > Without this fix, _save_fp() in 64-bit kernel is seriously broken. > > ffffffff8010bec0 <_save_fp>: > ffffffff8010bec0: 400d6000 mfc0 t1,c0_status > ffffffff8010bec4: 000c7140 sll t2,t0,0x5 > ffffffff8010bec8: 05c10011 bgez t2,ffffffff8010bf10 <_save_fp+0x50> > ffffffff8010becc: 00000000 nop > ffffffff8010bed0: f4810328 sdc1 $f1,808(a0) > ... Fix register usage in fpu_save_double() and make fpu_restore_double() more symmetric with fpu_save_double(). Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_switch.S | 13 ++++++++----- include/asm-mips/asmmacro-32.h | 4 ++-- include/asm-mips/asmmacro-64.h | 19 +++++++++---------- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 0b1b54acee9f..db94e556fc97 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -75,8 +75,8 @@ and t0, t0, t1 LONG_S t0, ST_OFF(t3) - fpu_save_double a0 t1 t0 t2 # c0_status passed in t1 - # clobbers t0 and t2 + fpu_save_double a0 t0 t1 # c0_status passed in t0 + # clobbers t1 1: /* @@ -129,9 +129,9 @@ */ LEAF(_save_fp) #ifdef CONFIG_64BIT - mfc0 t1, CP0_STATUS + mfc0 t0, CP0_STATUS #endif - fpu_save_double a0 t1 t0 t2 # clobbers t1 + fpu_save_double a0 t0 t1 # clobbers t1 jr ra END(_save_fp) @@ -139,7 +139,10 @@ LEAF(_save_fp) * Restore a thread's fp context. */ LEAF(_restore_fp) - fpu_restore_double a0, t1 # clobbers t1 +#ifdef CONFIG_64BIT + mfc0 t0, CP0_STATUS +#endif + fpu_restore_double a0 t0 t1 # clobbers t1 jr ra END(_restore_fp) diff --git a/include/asm-mips/asmmacro-32.h b/include/asm-mips/asmmacro-32.h index 11daf5ceb7b4..5de3963f511e 100644 --- a/include/asm-mips/asmmacro-32.h +++ b/include/asm-mips/asmmacro-32.h @@ -12,7 +12,7 @@ #include #include - .macro fpu_save_double thread status tmp1=t0 tmp2 + .macro fpu_save_double thread status tmp1=t0 cfc1 \tmp1, fcr31 sdc1 $f0, THREAD_FPR0(\thread) sdc1 $f2, THREAD_FPR2(\thread) @@ -70,7 +70,7 @@ sw \tmp, THREAD_FCR31(\thread) .endm - .macro fpu_restore_double thread tmp=t0 + .macro fpu_restore_double thread status tmp=t0 lw \tmp, THREAD_FCR31(\thread) ldc1 $f0, THREAD_FPR0(\thread) ldc1 $f2, THREAD_FPR2(\thread) diff --git a/include/asm-mips/asmmacro-64.h b/include/asm-mips/asmmacro-64.h index 559c355b9b86..225feefcb25d 100644 --- a/include/asm-mips/asmmacro-64.h +++ b/include/asm-mips/asmmacro-64.h @@ -53,12 +53,12 @@ sdc1 $f31, THREAD_FPR31(\thread) .endm - .macro fpu_save_double thread status tmp1 tmp2 - sll \tmp2, \tmp1, 5 - bgez \tmp2, 2f + .macro fpu_save_double thread status tmp + sll \tmp, \status, 5 + bgez \tmp, 2f fpu_save_16odd \thread 2: - fpu_save_16even \thread \tmp1 # clobbers t1 + fpu_save_16even \thread \tmp .endm .macro fpu_restore_16even thread tmp=t0 @@ -101,13 +101,12 @@ ldc1 $f31, THREAD_FPR31(\thread) .endm - .macro fpu_restore_double thread tmp - mfc0 t0, CP0_STATUS - sll t1, t0, 5 - bgez t1, 1f # 16 register mode? + .macro fpu_restore_double thread status tmp + sll \tmp, \status, 5 + bgez \tmp, 1f # 16 register mode? - fpu_restore_16odd a0 -1: fpu_restore_16even a0, t0 # clobbers t0 + fpu_restore_16odd \thread +1: fpu_restore_16even \thread \tmp .endm .macro cpu_save_nonscratch thread -- cgit v1.2.3 From 0307e8d024dffc00743fb54b9afa920a346f1adb Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Sun, 11 Jun 2006 23:25:43 +0900 Subject: [MIPS] Fix futex_atomic_op_inuser. I found that NPTL's pthread_cond_signal() does not work properly on kernels compiled by gcc 4.1.x. I suppose inline asm for __futex_atomic_op() was wrong. I suppose: 1. "=&r" constraint should be used for oldval. 2. Instead of "r" (uaddr), "=R" (*uaddr) for output and "R" (*uaddr) for input should be used. 3. "memory" should be added to the clobber list. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- include/asm-mips/futex.h | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index 12d118f1bc9c..1f94640becc4 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -22,51 +22,53 @@ " .set push \n" \ " .set noat \n" \ " .set mips3 \n" \ - "1: ll %1, (%3) # __futex_atomic_op \n" \ + "1: ll %1, %4 # __futex_atomic_op \n" \ " .set mips0 \n" \ " " insn " \n" \ " .set mips3 \n" \ - "2: sc $1, (%3) \n" \ + "2: sc $1, %2 \n" \ " beqzl $1, 1b \n" \ __FUTEX_SMP_SYNC \ "3: \n" \ " .set pop \n" \ " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ - "4: li %0, %5 \n" \ + "4: li %0, %6 \n" \ " j 2b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=r" (oldval) \ - : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ + : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "memory"); \ } else if (cpu_has_llsc) { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ " .set mips3 \n" \ - "1: ll %1, (%3) # __futex_atomic_op \n" \ + "1: ll %1, %4 # __futex_atomic_op \n" \ " .set mips0 \n" \ " " insn " \n" \ " .set mips3 \n" \ - "2: sc $1, (%3) \n" \ + "2: sc $1, %2 \n" \ " beqz $1, 1b \n" \ __FUTEX_SMP_SYNC \ "3: \n" \ " .set pop \n" \ " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ - "4: li %0, %5 \n" \ + "4: li %0, %6 \n" \ " j 2b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=r" (oldval) \ - : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ + : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "memory"); \ } else \ ret = -ENOSYS; \ } @@ -89,23 +91,23 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg); + __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z4", + __futex_atomic_op("addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z4", + __futex_atomic_op("or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z4", + __futex_atomic_op("and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z4", + __futex_atomic_op("xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: -- cgit v1.2.3 From a240a469649eaab03f0c4c7fbb21ea5041bf5572 Mon Sep 17 00:00:00 2001 From: "Mark.Zhan" Date: Sat, 6 May 2006 17:04:20 +0800 Subject: [MIPS] Wind River 4KC PPMC Eval Board Support Support for the GT-64120-based Wind River 4KC PPMC Evaluation board. Signed-off-by: Rongkai.Zhan Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 21 + arch/mips/Makefile | 7 + arch/mips/configs/wrppmc_defconfig | 801 ++++++++++++++++++++++++++++ arch/mips/gt64120/wrppmc/Makefile | 14 + arch/mips/gt64120/wrppmc/int-handler.S | 59 ++ arch/mips/gt64120/wrppmc/irq.c | 63 +++ arch/mips/gt64120/wrppmc/pci.c | 53 ++ arch/mips/gt64120/wrppmc/reset.c | 50 ++ arch/mips/gt64120/wrppmc/setup.c | 173 ++++++ arch/mips/gt64120/wrppmc/time.c | 57 ++ arch/mips/pci/Makefile | 1 + arch/mips/pci/fixup-wrppmc.c | 37 ++ include/asm-mips/mach-wrppmc/mach-gt64120.h | 84 +++ 13 files changed, 1420 insertions(+) create mode 100644 arch/mips/configs/wrppmc_defconfig create mode 100644 arch/mips/gt64120/wrppmc/Makefile create mode 100644 arch/mips/gt64120/wrppmc/int-handler.S create mode 100644 arch/mips/gt64120/wrppmc/irq.c create mode 100644 arch/mips/gt64120/wrppmc/pci.c create mode 100644 arch/mips/gt64120/wrppmc/reset.c create mode 100644 arch/mips/gt64120/wrppmc/setup.c create mode 100644 arch/mips/gt64120/wrppmc/time.c create mode 100644 arch/mips/pci/fixup-wrppmc.c create mode 100644 include/asm-mips/mach-wrppmc/mach-gt64120.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b4d8095f0c0a..c9116a40e45a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -327,6 +327,27 @@ config MIPS_SEAD This enables support for the MIPS Technologies SEAD evaluation board. +config WR_PPMC + bool "Support for Wind River PPMC board" + select IRQ_CPU + select BOOT_ELF32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select MIPS_GT64120 + select SWAP_IO_SPACE + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS64_R1 + select SYS_HAS_CPU_NEVADA + select SYS_HAS_CPU_RM7000 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_LITTLE_ENDIAN + help + This enables support for the Wind River MIPS32 4KC PPMC evaluation + board, which is based on GT64120 bridge chip. + config MIPS_SIM bool 'MIPS simulator (MIPSsim)' select DMA_NONCOHERENT diff --git a/arch/mips/Makefile b/arch/mips/Makefile index aa37ae6cf32e..24a901cf5a45 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -286,6 +286,13 @@ core-$(CONFIG_MIPS_EV96100) += arch/mips/galileo-boards/ev96100/ cflags-$(CONFIG_MIPS_EV96100) += -Iinclude/asm-mips/mach-ev96100 load-$(CONFIG_MIPS_EV96100) += 0xffffffff80100000 +# +# Wind River PPMC Board (4KC + GT64120) +# +core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/ +cflags-$(CONFIG_WR_PPMC) += -Iinclude/asm-mips/mach-wrppmc +load-$(CONFIG_WR_PPMC) += 0xffffffff80100000 + # # Globespan IVR eval board with QED 5231 CPU # diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig new file mode 100644 index 000000000000..1997b7c11ab4 --- /dev/null +++ b/arch/mips/configs/wrppmc_defconfig @@ -0,0 +1,801 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.16.11 +# Fri May 5 17:11:22 2006 +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MIPS_MTX1 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +CONFIG_WR_PPMC=y +# CONFIG_MIPS_SIM is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MIPS_XXS1500 is not set +# CONFIG_PNX8550_V2PCI is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_CPU_BIG_ENDIAN=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_MIPS_GT64120=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_BOOT_ELF32=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +CONFIG_CPU_MIPS32_R1=y +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_SYS_HAS_CPU_MIPS32_R2=y +CONFIG_SYS_HAS_CPU_MIPS64_R1=y +CONFIG_SYS_HAS_CPU_NEVADA=y +CONFIG_SYS_HAS_CPU_RM7000=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_MIPS_MT is not set +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_KMOD is not set + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_TRAD_SIGNALS=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +CONFIG_IP_MROUTE=y +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +CONFIG_ARPD=y +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_DM9000 is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_LAN_SAA9730 is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="console=ttyS0,115200n8" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC32=y +CONFIG_LIBCRC32C=y diff --git a/arch/mips/gt64120/wrppmc/Makefile b/arch/mips/gt64120/wrppmc/Makefile new file mode 100644 index 000000000000..72606b9af12a --- /dev/null +++ b/arch/mips/gt64120/wrppmc/Makefile @@ -0,0 +1,14 @@ +# +# 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 2006 Wind River System, Inc. +# Author: Rongkai.Zhan +# +# Makefile for the Wind River MIPS 4KC PPMC Eval Board +# + +obj-y += int-handler.o irq.o reset.o setup.o time.o pci.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/gt64120/wrppmc/int-handler.S b/arch/mips/gt64120/wrppmc/int-handler.S new file mode 100644 index 000000000000..edee7b394175 --- /dev/null +++ b/arch/mips/gt64120/wrppmc/int-handler.S @@ -0,0 +1,59 @@ +/* + * 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) 1995, 1996, 1997, 2003 by Ralf Baechle + * Copyright (C) Wind River System Inc. Rongkai.Zhan + */ +#include +#include +#include +#include +#include +#include + + .align 5 + .set noat +NESTED(handle_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + .set at + + mfc0 t0, CP0_CAUSE # get pending interrupts + mfc0 t1, CP0_STATUS # get enabled interrupts + and t0, t0, t1 # get allowed interrupts + andi t0, t0, 0xFF00 + beqz t0, 1f + move a1, sp # Prepare 'struct pt_regs *regs' pointer + + andi t1, t0, CAUSEF_IP7 # CPU Compare/Count internal timer + bnez t1, handle_cputimer_irq + andi t1, t0, CAUSEF_IP6 # UART 16550 port + bnez t1, handle_uart_irq + andi t1, t0, CAUSEF_IP3 # PCI INT_A + bnez t1, handle_pci_intA_irq + + /* wrong alarm or masked ... */ +1: j spurious_interrupt + nop +END(handle_IRQ) + + .align 5 +handle_cputimer_irq: + li a0, WRPPMC_MIPS_TIMER_IRQ + jal do_IRQ + j ret_from_irq + + .align 5 +handle_uart_irq: + li a0, WRPPMC_UART16550_IRQ + jal do_IRQ + j ret_from_irq + + .align 5 +handle_pci_intA_irq: + li a0, WRPPMC_PCI_INTA_IRQ + jal do_IRQ + j ret_from_irq + diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c new file mode 100644 index 000000000000..8605687e24ed --- /dev/null +++ b/arch/mips/gt64120/wrppmc/irq.c @@ -0,0 +1,63 @@ +/* + * irq.c: GT64120 Interrupt Controller + * + * Copyright (C) 2006, Wind River System Inc. + * Author: Rongkai.Zhan, + * + * 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 + +extern asmlinkage void handle_IRQ(void); + +/** + * Initialize GT64120 Interrupt Controller + */ +void gt64120_init_pic(void) +{ + /* clear CPU Interrupt Cause Registers */ + GT_WRITE(GT_INTRCAUSE_OFS, (0x1F << 21)); + GT_WRITE(GT_HINTRCAUSE_OFS, 0x00); + + /* Disable all interrupts from GT64120 bridge chip */ + GT_WRITE(GT_INTRMASK_OFS, 0x00); + GT_WRITE(GT_HINTRMASK_OFS, 0x00); + GT_WRITE(GT_PCI0_ICMASK_OFS, 0x00); + GT_WRITE(GT_PCI0_HICMASK_OFS, 0x00); +} + +void __init arch_init_irq(void) +{ + /* enable all CPU interrupt bits. */ + set_c0_status(ST0_IM); /* IE bit is still 0 */ + + /* Install MIPS Interrupt Trap Vector */ + set_except_vector(0, handle_IRQ); + + /* IRQ 0 - 7 are for MIPS common irq_cpu controller */ + mips_cpu_irq_init(0); + + gt64120_init_pic(); +} diff --git a/arch/mips/gt64120/wrppmc/pci.c b/arch/mips/gt64120/wrppmc/pci.c new file mode 100644 index 000000000000..2fbe93467f78 --- /dev/null +++ b/arch/mips/gt64120/wrppmc/pci.c @@ -0,0 +1,53 @@ +/* + * pci.c: GT64120 PCI support. + * + * Copyright (C) 2006, Wind River System Inc. Rongkai.Zhan + * + * 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. + */ +#include +#include +#include +#include +#include + +extern struct pci_ops gt64120_pci_ops; + +static struct resource pci0_io_resource = { + .name = "pci_0 io", + .start = GT_PCI_IO_BASE, + .end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO, +}; + +static struct resource pci0_mem_resource = { + .name = "pci_0 memory", + .start = GT_PCI_MEM_BASE, + .end = GT_PCI_MEM_BASE + GT_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct pci_controller hose_0 = { + .pci_ops = >64120_pci_ops, + .io_resource = &pci0_io_resource, + .mem_resource = &pci0_mem_resource, +}; + +static int __init gt64120_pci_init(void) +{ + u32 tmp; + + tmp = GT_READ(GT_PCI0_CMD_OFS); /* Huh??? -- Ralf */ + tmp = GT_READ(GT_PCI0_BARE_OFS); + + /* reset the whole PCI I/O space range */ + ioport_resource.start = GT_PCI_IO_BASE; + ioport_resource.end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1; + + register_pci_controller(&hose_0); + return 0; +} + +arch_initcall(gt64120_pci_init); diff --git a/arch/mips/gt64120/wrppmc/reset.c b/arch/mips/gt64120/wrppmc/reset.c new file mode 100644 index 000000000000..b97039c6d3db --- /dev/null +++ b/arch/mips/gt64120/wrppmc/reset.c @@ -0,0 +1,50 @@ +/* + * 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) 1997 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include + +void wrppmc_machine_restart(char *command) +{ + /* + * Ouch, we're still alive ... This time we take the silver bullet ... + * ... and find that we leave the hardware in a state in which the + * kernel in the flush locks up somewhen during of after the PCI + * detection stuff. + */ + local_irq_disable(); + set_c0_status(ST0_BEV | ST0_ERL); + change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_c0_wired(0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void wrppmc_machine_halt(void) +{ + local_irq_disable(); + + printk(KERN_NOTICE "You can safely turn off the power\n"); + while (1) { + __asm__( + ".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0" + ); + } +} + +void wrppmc_machine_power_off(void) +{ + wrppmc_machine_halt(); +} diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c new file mode 100644 index 000000000000..20c591e49dae --- /dev/null +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -0,0 +1,173 @@ +/* + * setup.c: Setup pointers to hardware dependent routines. + * + * 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, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2006, Wind River System Inc. Rongkai.zhan + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +unsigned long gt64120_base = KSEG1ADDR(0x14000000); + +#ifdef WRPPMC_EARLY_DEBUG + +static volatile unsigned char * wrppmc_led = \ + (volatile unsigned char *)KSEG1ADDR(WRPPMC_LED_BASE); + +/* + * PPMC LED control register: + * -) bit[0] controls DS1 LED (1 - OFF, 0 - ON) + * -) bit[1] controls DS2 LED (1 - OFF, 0 - ON) + * -) bit[2] controls DS4 LED (1 - OFF, 0 - ON) + */ +void wrppmc_led_on(int mask) +{ + unsigned char value = *wrppmc_led; + + value &= (0xF8 | mask); + *wrppmc_led = value; +} + +/* If mask = 0, turn off all LEDs */ +void wrppmc_led_off(int mask) +{ + unsigned char value = *wrppmc_led; + + value |= (0x7 & mask); + *wrppmc_led = value; +} + +/* + * We assume that bootloader has initialized UART16550 correctly + */ +void __init wrppmc_early_putc(char ch) +{ + static volatile unsigned char *wrppmc_uart = \ + (volatile unsigned char *)KSEG1ADDR(WRPPMC_UART16550_BASE); + unsigned char value; + + /* Wait until Transmit-Holding-Register is empty */ + while (1) { + value = *(wrppmc_uart + 5); + if (value & 0x20) + break; + } + + *wrppmc_uart = ch; +} + +void __init wrppmc_early_printk(const char *fmt, ...) +{ + static char pbuf[256] = {'\0', }; + char *ch = pbuf; + va_list args; + unsigned int i; + + memset(pbuf, 0, 256); + va_start(args, fmt); + i = vsprintf(pbuf, fmt, args); + va_end(args); + + /* Print the string */ + while (*ch != '\0') { + wrppmc_early_putc(*ch); + /* if print '\n', also print '\r' */ + if (*ch++ == '\n') + wrppmc_early_putc('\r'); + } +} +#endif /* WRPPMC_EARLY_DEBUG */ + +unsigned long __init prom_free_prom_memory(void) +{ + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +static void wrppmc_setup_serial(void) +{ + struct uart_port up; + + memset(&up, 0x00, sizeof(struct uart_port)); + + /* + * A note about mapbase/membase + * -) mapbase is the physical address of the IO port. + * -) membase is an 'ioremapped' cookie. + */ + up.line = 0; + up.type = PORT_16550; + up.iotype = UPIO_MEM; + up.mapbase = WRPPMC_UART16550_BASE; + up.membase = ioremap(up.mapbase, 8); + up.irq = WRPPMC_UART16550_IRQ; + up.uartclk = WRPPMC_UART16550_CLOCK; + up.flags = UPF_SKIP_TEST/* | UPF_BOOT_AUTOCONF */; + up.regshift = 0; + + early_serial_setup(&up); +} +#endif + +void __init plat_setup(void) +{ + extern void wrppmc_time_init(void); + extern void wrppmc_timer_setup(struct irqaction *); + extern void wrppmc_machine_restart(char *command); + extern void wrppmc_machine_halt(void); + extern void wrppmc_machine_power_off(void); + + _machine_restart = wrppmc_machine_restart; + _machine_halt = wrppmc_machine_halt; + pm_power_off = wrppmc_machine_power_off; + + /* Use MIPS Count/Compare Timer */ + board_time_init = wrppmc_time_init; + board_timer_setup = wrppmc_timer_setup; + + /* This makes the operations of 'in/out[bwl]' to the + * physical address ( < KSEG0) can work via KSEG1 + */ + set_io_port_base(KSEG1); + +#ifdef CONFIG_SERIAL_8250 + wrppmc_setup_serial(); +#endif +} + +const char *get_system_type(void) +{ + return "Wind River PPMC (GT64120)"; +} + +/* + * Initializes basic routines and structures pointers, memory size (as + * given by the bios and saves the command line. + */ +void __init prom_init(void) +{ + mips_machgroup = MACH_GROUP_GALILEO; + mips_machtype = MACH_EV64120A; + + add_memory_region(WRPPMC_SDRAM_SCS0_BASE, WRPPMC_SDRAM_SCS0_SIZE, BOOT_MEM_RAM); + add_memory_region(WRPPMC_BOOTROM_BASE, WRPPMC_BOOTROM_SIZE, BOOT_MEM_ROM_DATA); + + wrppmc_early_printk("prom_init: GT64120 SDRAM Bank 0: 0x%x - 0x%08lx\n", + WRPPMC_SDRAM_SCS0_BASE, (WRPPMC_SDRAM_SCS0_BASE + WRPPMC_SDRAM_SCS0_SIZE)); +} diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/gt64120/wrppmc/time.c new file mode 100644 index 000000000000..175d22adb450 --- /dev/null +++ b/arch/mips/gt64120/wrppmc/time.c @@ -0,0 +1,57 @@ +/* + * time.c: MIPS CPU Count/Compare timer hookup + * + * Author: Mark.Zhan, + * + * 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, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2006, Wind River System Inc. + */ +#include +#include +#include +#include +#include /* for HZ */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#define WRPPMC_CPU_CLK_FREQ 40000000 /* 40MHZ */ + +void __init wrppmc_timer_setup(struct irqaction *irq) +{ + /* Install ISR for timer interrupt */ + setup_irq(WRPPMC_MIPS_TIMER_IRQ, irq); + + /* to generate the first timer interrupt */ + write_c0_compare(mips_hpt_frequency/HZ); + write_c0_count(0); +} + +/* + * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect + * + * NOTE: We disable all GT64120 timers, and use MIPS processor internal + * timer as the source of kernel clock tick. + */ +void __init wrppmc_time_init(void) +{ + /* Disable GT64120 timers */ + GT_WRITE(GT_TC_CONTROL_OFS, 0x00); + GT_WRITE(GT_TC0_OFS, 0x00); + GT_WRITE(GT_TC1_OFS, 0x00); + GT_WRITE(GT_TC2_OFS, 0x00); + GT_WRITE(GT_TC3_OFS, 0x00); + + /* Use MIPS compare/count internal timer */ + mips_hpt_frequency = WRPPMC_CPU_CLK_FREQ; +} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 16205b587338..fb50d410773b 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_TOSHIBA_RBTX4927) += fixup-rbtx4927.o ops-tx4927.o obj-$(CONFIG_TOSHIBA_RBTX4938) += fixup-tx4938.o ops-tx4938.o obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o +obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o diff --git a/arch/mips/pci/fixup-wrppmc.c b/arch/mips/pci/fixup-wrppmc.c new file mode 100644 index 000000000000..3357c1300bb1 --- /dev/null +++ b/arch/mips/pci/fixup-wrppmc.c @@ -0,0 +1,37 @@ +/* + * fixup-wrppmc.c: PPMC board specific PCI fixup + * + * 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) 2006, Wind River Inc. Rongkai.zhan (rongkai.zhan@windriver.com) + */ +#include +#include +#include + +/* PCI interrupt pins */ +#define PCI_INTA 1 +#define PCI_INTB 2 +#define PCI_INTC 3 +#define PCI_INTD 4 + +#define PCI_SLOT_MAXNR 32 /* Each PCI bus has 32 physical slots */ + +static char pci_irq_tab[PCI_SLOT_MAXNR][5] __initdata = { + /* 0 INTA INTB INTC INTD */ + [0] = {0, 0, 0, 0, 0}, /* Slot 0: GT64120 PCI bridge */ + [6] = {0, WRPPMC_PCI_INTA_IRQ, 0, 0, 0}, +}; + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return pci_irq_tab[slot][pin]; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/include/asm-mips/mach-wrppmc/mach-gt64120.h b/include/asm-mips/mach-wrppmc/mach-gt64120.h new file mode 100644 index 000000000000..ba9205a04582 --- /dev/null +++ b/include/asm-mips/mach-wrppmc/mach-gt64120.h @@ -0,0 +1,84 @@ +/* + * This is a direct copy of the ev96100.h file, with a global + * search and replace. The numbers are the same. + * + * The reason I'm duplicating this is so that the 64120/96100 + * defines won't be confusing in the source code. + */ +#ifndef __ASM_MIPS_GT64120_H +#define __ASM_MIPS_GT64120_H + +/* + * This is the CPU physical memory map of PPMC Board: + * + * 0x00000000-0x03FFFFFF - 64MB SDRAM (SCS[0]#) + * 0x1C000000-0x1C000000 - LED (CS0) + * 0x1C800000-0x1C800007 - UART 16550 port (CS1) + * 0x1F000000-0x1F000000 - MailBox (CS3) + * 0x1FC00000-0x20000000 - 4MB Flash (BOOT CS) + */ + +#define WRPPMC_SDRAM_SCS0_BASE 0x00000000 +#define WRPPMC_SDRAM_SCS0_SIZE 0x04000000 + +#define WRPPMC_UART16550_BASE 0x1C800000 +#define WRPPMC_UART16550_CLOCK 3686400 /* 3.68MHZ */ + +#define WRPPMC_LED_BASE 0x1C000000 +#define WRPPMC_MBOX_BASE 0x1F000000 + +#define WRPPMC_BOOTROM_BASE 0x1FC00000 +#define WRPPMC_BOOTROM_SIZE 0x00400000 /* 4M Flash */ + +#define WRPPMC_MIPS_TIMER_IRQ 7 /* MIPS compare/count timer interrupt */ +#define WRPPMC_UART16550_IRQ 6 +#define WRPPMC_PCI_INTA_IRQ 3 + +/* + * PCI Bus I/O and Memory resources allocation + * + * NOTE: We only have PCI_0 hose interface + */ +#define GT_PCI_MEM_BASE 0x13000000UL +#define GT_PCI_MEM_SIZE 0x02000000UL +#define GT_PCI_IO_BASE 0x11000000UL +#define GT_PCI_IO_SIZE 0x02000000UL +#define GT_ISA_IO_BASE PCI_IO_BASE + +/* + * PCI interrupts will come in on either the INTA or INTD interrups lines, + * which are mapped to the #2 and #5 interrupt pins of the MIPS. On our + * boards, they all either come in on IntD or they all come in on IntA, they + * aren't mixed. There can be numerous PCI interrupts, so we keep a list of the + * "requested" interrupt numbers and go through the list whenever we get an + * IntA/D. + * + * Interrupts < 8 are directly wired to the processor; PCI INTA is 8 and + * INTD is 11. + */ +#define GT_TIMER 4 +#define GT_INTA 2 +#define GT_INTD 5 + +#ifndef __ASSEMBLY__ + +/* + * GT64120 internal register space base address + */ +extern unsigned long gt64120_base; + +#define GT64120_BASE (gt64120_base) + +/* define WRPPMC_EARLY_DEBUG to enable early output something to UART */ +#undef WRPPMC_EARLY_DEBUG + +#ifdef WRPPMC_EARLY_DEBUG +extern void wrppmc_led_on(int mask); +extern void wrppmc_led_off(int mask); +extern void wrppmc_early_printk(const char *fmt, ...); +#else +#define wrppmc_early_printk(fmt, ...) do {} while (0) +#endif /* WRPPMC_EARLY_DEBUG */ + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_MIPS_GT64120_H */ -- cgit v1.2.3 From eae89076e696f51762d81d6e2538c3beb59fa7bd Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 16 May 2006 01:26:03 +0900 Subject: [MIPS] Unify mips_fpu_soft_struct and mips_fpu_hard_structs. The struct mips_fpu_soft_struct and mips_fpu_hard_struct are completely same now and the kernel fpu emulator assumes that. This patch unifies them to mips_fpu_struct and get rid of mips_fpu_union. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/asm-offsets.c | 66 ++++++++++++++++++------------------- arch/mips/kernel/branch.c | 2 +- arch/mips/kernel/irixsig.c | 2 +- arch/mips/kernel/ptrace.c | 26 +++++---------- arch/mips/kernel/ptrace32.c | 16 +++------ arch/mips/kernel/traps.c | 9 +++-- arch/mips/math-emu/cp1emu.c | 15 ++++----- arch/mips/math-emu/ieee754.h | 2 +- arch/mips/math-emu/kernel_linkage.c | 24 ++++++-------- include/asm-mips/fpu.h | 3 +- include/asm-mips/fpu_emulator.h | 4 +-- include/asm-mips/processor.h | 16 ++------- 12 files changed, 76 insertions(+), 109 deletions(-) (limited to 'include') diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 0facfaf4e950..f1bb6a2dc5fc 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -141,72 +141,72 @@ void output_thread_defines(void) void output_thread_fpu_defines(void) { offset("#define THREAD_FPR0 ", - struct task_struct, thread.fpu.hard.fpr[0]); + struct task_struct, thread.fpu.fpr[0]); offset("#define THREAD_FPR1 ", - struct task_struct, thread.fpu.hard.fpr[1]); + struct task_struct, thread.fpu.fpr[1]); offset("#define THREAD_FPR2 ", - struct task_struct, thread.fpu.hard.fpr[2]); + struct task_struct, thread.fpu.fpr[2]); offset("#define THREAD_FPR3 ", - struct task_struct, thread.fpu.hard.fpr[3]); + struct task_struct, thread.fpu.fpr[3]); offset("#define THREAD_FPR4 ", - struct task_struct, thread.fpu.hard.fpr[4]); + struct task_struct, thread.fpu.fpr[4]); offset("#define THREAD_FPR5 ", - struct task_struct, thread.fpu.hard.fpr[5]); + struct task_struct, thread.fpu.fpr[5]); offset("#define THREAD_FPR6 ", - struct task_struct, thread.fpu.hard.fpr[6]); + struct task_struct, thread.fpu.fpr[6]); offset("#define THREAD_FPR7 ", - struct task_struct, thread.fpu.hard.fpr[7]); + struct task_struct, thread.fpu.fpr[7]); offset("#define THREAD_FPR8 ", - struct task_struct, thread.fpu.hard.fpr[8]); + struct task_struct, thread.fpu.fpr[8]); offset("#define THREAD_FPR9 ", - struct task_struct, thread.fpu.hard.fpr[9]); + struct task_struct, thread.fpu.fpr[9]); offset("#define THREAD_FPR10 ", - struct task_struct, thread.fpu.hard.fpr[10]); + struct task_struct, thread.fpu.fpr[10]); offset("#define THREAD_FPR11 ", - struct task_struct, thread.fpu.hard.fpr[11]); + struct task_struct, thread.fpu.fpr[11]); offset("#define THREAD_FPR12 ", - struct task_struct, thread.fpu.hard.fpr[12]); + struct task_struct, thread.fpu.fpr[12]); offset("#define THREAD_FPR13 ", - struct task_struct, thread.fpu.hard.fpr[13]); + struct task_struct, thread.fpu.fpr[13]); offset("#define THREAD_FPR14 ", - struct task_struct, thread.fpu.hard.fpr[14]); + struct task_struct, thread.fpu.fpr[14]); offset("#define THREAD_FPR15 ", - struct task_struct, thread.fpu.hard.fpr[15]); + struct task_struct, thread.fpu.fpr[15]); offset("#define THREAD_FPR16 ", - struct task_struct, thread.fpu.hard.fpr[16]); + struct task_struct, thread.fpu.fpr[16]); offset("#define THREAD_FPR17 ", - struct task_struct, thread.fpu.hard.fpr[17]); + struct task_struct, thread.fpu.fpr[17]); offset("#define THREAD_FPR18 ", - struct task_struct, thread.fpu.hard.fpr[18]); + struct task_struct, thread.fpu.fpr[18]); offset("#define THREAD_FPR19 ", - struct task_struct, thread.fpu.hard.fpr[19]); + struct task_struct, thread.fpu.fpr[19]); offset("#define THREAD_FPR20 ", - struct task_struct, thread.fpu.hard.fpr[20]); + struct task_struct, thread.fpu.fpr[20]); offset("#define THREAD_FPR21 ", - struct task_struct, thread.fpu.hard.fpr[21]); + struct task_struct, thread.fpu.fpr[21]); offset("#define THREAD_FPR22 ", - struct task_struct, thread.fpu.hard.fpr[22]); + struct task_struct, thread.fpu.fpr[22]); offset("#define THREAD_FPR23 ", - struct task_struct, thread.fpu.hard.fpr[23]); + struct task_struct, thread.fpu.fpr[23]); offset("#define THREAD_FPR24 ", - struct task_struct, thread.fpu.hard.fpr[24]); + struct task_struct, thread.fpu.fpr[24]); offset("#define THREAD_FPR25 ", - struct task_struct, thread.fpu.hard.fpr[25]); + struct task_struct, thread.fpu.fpr[25]); offset("#define THREAD_FPR26 ", - struct task_struct, thread.fpu.hard.fpr[26]); + struct task_struct, thread.fpu.fpr[26]); offset("#define THREAD_FPR27 ", - struct task_struct, thread.fpu.hard.fpr[27]); + struct task_struct, thread.fpu.fpr[27]); offset("#define THREAD_FPR28 ", - struct task_struct, thread.fpu.hard.fpr[28]); + struct task_struct, thread.fpu.fpr[28]); offset("#define THREAD_FPR29 ", - struct task_struct, thread.fpu.hard.fpr[29]); + struct task_struct, thread.fpu.fpr[29]); offset("#define THREAD_FPR30 ", - struct task_struct, thread.fpu.hard.fpr[30]); + struct task_struct, thread.fpu.fpr[30]); offset("#define THREAD_FPR31 ", - struct task_struct, thread.fpu.hard.fpr[31]); + struct task_struct, thread.fpu.fpr[31]); offset("#define THREAD_FCR31 ", - struct task_struct, thread.fpu.hard.fcr31); + struct task_struct, thread.fpu.fcr31); linefeed; } diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index b6232d9033cb..76fd3f22c766 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -178,7 +178,7 @@ int __compute_return_epc(struct pt_regs *regs) if (is_fpu_owner()) asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); else - fcr31 = current->thread.fpu.hard.fcr31; + fcr31 = current->thread.fpu.fcr31; preempt_enable(); bit = (insn.i_format.rt >> 2); diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 8150f071f80a..a9bf6cc3abd1 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -260,7 +260,7 @@ irix_sigreturn(struct pt_regs *regs) for(i = 0; i < 32; i++) error |= __get_user(fregs[i], &context->fpregs[i]); - error |= __get_user(current->thread.fpu.hard.fcr31, &context->fpcsr); + error |= __get_user(current->thread.fpu.fcr31, &context->fpcsr); } /* XXX do sigstack crapola here... XXX */ diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 9b4733c12395..1d44025188d8 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -120,11 +120,11 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __put_user ((__u64) -1, i + (__u64 __user *) data); } + __put_user (child->thread.fpu.fcr31, data + 64); + if (cpu_has_fpu) { unsigned int flags, tmp; - __put_user (child->thread.fpu.hard.fcr31, data + 64); - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); @@ -142,7 +142,6 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) preempt_enable(); __put_user (tmp, data + 65); } else { - __put_user (child->thread.fpu.soft.fcr31, data + 64); __put_user ((__u32) 0, data + 65); } @@ -162,10 +161,7 @@ int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) for (i = 0; i < 32; i++) __get_user (fregs[i], i + (__u64 __user *) data); - if (cpu_has_fpu) - __get_user (child->thread.fpu.hard.fcr31, data + 64); - else - __get_user (child->thread.fpu.soft.fcr31, data + 64); + __get_user (child->thread.fpu.fcr31, data + 64); /* FIR may not be written. */ @@ -241,10 +237,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp = regs->lo; break; case FPC_CSR: - if (cpu_has_fpu) - tmp = child->thread.fpu.hard.fcr31; - else - tmp = child->thread.fpu.soft.fcr31; + tmp = child->thread.fpu.fcr31; break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; @@ -336,9 +329,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (!tsk_used_math(child)) { /* FP not yet used */ - memset(&child->thread.fpu.hard, ~0, - sizeof(child->thread.fpu.hard)); - child->thread.fpu.hard.fcr31 = 0; + memset(&child->thread.fpu, ~0, + sizeof(child->thread.fpu)); + child->thread.fpu.fcr31 = 0; } #ifdef CONFIG_32BIT /* @@ -369,10 +362,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) regs->lo = data; break; case FPC_CSR: - if (cpu_has_fpu) - child->thread.fpu.hard.fcr31 = data; - else - child->thread.fpu.soft.fcr31 = data; + child->thread.fpu.fcr31 = data; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 8704dc0496ea..f40ecd8be05f 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -166,10 +166,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) tmp = regs->lo; break; case FPC_CSR: - if (cpu_has_fpu) - tmp = child->thread.fpu.hard.fcr31; - else - tmp = child->thread.fpu.soft.fcr31; + tmp = child->thread.fpu.fcr31; break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; @@ -288,9 +285,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) if (!tsk_used_math(child)) { /* FP not yet used */ - memset(&child->thread.fpu.hard, ~0, - sizeof(child->thread.fpu.hard)); - child->thread.fpu.hard.fcr31 = 0; + memset(&child->thread.fpu, ~0, + sizeof(child->thread.fpu)); + child->thread.fpu.fcr31 = 0; } /* * The odd registers are actually the high order bits @@ -318,10 +315,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) regs->lo = data; break; case FPC_CSR: - if (cpu_has_fpu) - child->thread.fpu.hard.fcr31 = data; - else - child->thread.fpu.soft.fcr31 = data; + child->thread.fpu.fcr31 = data; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a7564b08eb4d..ad16eceb24dd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -65,7 +65,7 @@ extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, - struct mips_fpu_soft_struct *ctx); + struct mips_fpu_struct *ctx); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); @@ -600,8 +600,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_enable(); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (regs, - ¤t->thread.fpu.soft); + sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu); preempt_disable(); @@ -610,7 +609,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) * We can't allow the emulated instruction to leave any of * the cause bit set in $fcr31. */ - current->thread.fpu.soft.fcr31 &= ~FPU_CSR_ALL_X; + current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; /* Restore the hardware register state */ restore_fp(current); @@ -755,7 +754,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) if (!cpu_has_fpu) { int sig = fpu_emulator_cop1Handler(regs, - ¤t->thread.fpu.soft); + ¤t->thread.fpu); if (sig) force_sig(sig, current); #ifdef CONFIG_MIPS_MT_FPAFF diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index aa5818a0d884..3f0d5d26d506 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -60,15 +60,15 @@ /* Function which emulates a floating point instruction. */ -static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *, +static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, mips_instruction); #if __mips >= 4 && __mips != 32 static int fpux_emu(struct pt_regs *, - struct mips_fpu_soft_struct *, mips_instruction); + struct mips_fpu_struct *, mips_instruction); #endif -/* Further private data for which no space exists in mips_fpu_soft_struct */ +/* Further private data for which no space exists in mips_fpu_struct */ struct mips_fpu_emulator_stats fpuemustats; @@ -203,7 +203,7 @@ static int isBranchInstr(mips_instruction * i) * Two instructions if the instruction is in a branch delay slot. */ -static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) +static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) { mips_instruction ir; void * emulpc, *contpc; @@ -595,7 +595,7 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,); DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); -static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, +static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir) { unsigned rcsr = 0; /* resulting csr */ @@ -759,7 +759,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, /* * Emulate a single COP1 arithmetic instruction. */ -static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, +static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir) { int rfmt; /* resulting format */ @@ -1233,8 +1233,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, return 0; } -int fpu_emulator_cop1Handler(struct pt_regs *xcp, - struct mips_fpu_soft_struct *ctx) +int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) { unsigned long oldepc, prevepc; mips_instruction insn; diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 171f177c0f88..dd917332792c 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -329,7 +329,7 @@ struct _ieee754_csr { unsigned pad0:7; #endif }; -#define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.soft.fcr31)) +#define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) static inline unsigned ieee754_getrm(void) { diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c index d187ab71c2ff..56ca0c6a7178 100644 --- a/arch/mips/math-emu/kernel_linkage.c +++ b/arch/mips/math-emu/kernel_linkage.c @@ -39,9 +39,9 @@ void fpu_emulator_init_fpu(void) printk("Algorithmics/MIPS FPU Emulator v1.5\n"); } - current->thread.fpu.soft.fcr31 = 0; + current->thread.fpu.fcr31 = 0; for (i = 0; i < 32; i++) { - current->thread.fpu.soft.fpr[i] = SIGNALLING_NAN; + current->thread.fpu.fpr[i] = SIGNALLING_NAN; } } @@ -59,10 +59,9 @@ int fpu_emulator_save_context(struct sigcontext *sc) for (i = 0; i < 32; i++) { err |= - __put_user(current->thread.fpu.soft.fpr[i], - &sc->sc_fpregs[i]); + __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } - err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr); + err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; } @@ -74,10 +73,9 @@ int fpu_emulator_restore_context(struct sigcontext *sc) for (i = 0; i < 32; i++) { err |= - __get_user(current->thread.fpu.soft.fpr[i], - &sc->sc_fpregs[i]); + __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } - err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr); + err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; } @@ -94,10 +92,9 @@ int fpu_emulator_save_context32(struct sigcontext32 *sc) for (i = 0; i < 32; i+=2) { err |= - __put_user(current->thread.fpu.soft.fpr[i], - &sc->sc_fpregs[i]); + __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } - err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr); + err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; } @@ -109,10 +106,9 @@ int fpu_emulator_restore_context32(struct sigcontext32 *sc) for (i = 0; i < 32; i+=2) { err |= - __get_user(current->thread.fpu.soft.fpr[i], - &sc->sc_fpregs[i]); + __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } - err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr); + err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; } diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index b0f50015e252..8bf510a27c64 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h @@ -138,10 +138,9 @@ static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) if (cpu_has_fpu) { if ((tsk == current) && __is_fpu_owner()) _save_fp(current); - return tsk->thread.fpu.hard.fpr; } - return tsk->thread.fpu.soft.fpr; + return tsk->thread.fpu.fpr; } #endif /* _ASM_FPU_H */ diff --git a/include/asm-mips/fpu_emulator.h b/include/asm-mips/fpu_emulator.h index 16cb4d11dd0b..2731c38bd7ae 100644 --- a/include/asm-mips/fpu_emulator.h +++ b/include/asm-mips/fpu_emulator.h @@ -12,8 +12,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * - * Further private data for which no space exists in mips_fpu_soft_struct. - * This should be subsumed into the mips_fpu_soft_struct structure as + * Further private data for which no space exists in mips_fpu_struct. + * This should be subsumed into the mips_fpu_struct structure as * defined in processor.h as soon as the absurd wired absolute assembler * offsets become dynamic at compile time. * diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index 0fb75f0762e0..83936469fe87 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -71,11 +71,6 @@ extern unsigned int vced_count, vcei_count; typedef __u64 fpureg_t; -struct mips_fpu_hard_struct { - fpureg_t fpr[NUM_FPU_REGS]; - unsigned int fcr31; -}; - /* * It would be nice to add some more fields for emulator statistics, but there * are a number of fixed offsets in offset.h and elsewhere that would have to @@ -83,18 +78,13 @@ struct mips_fpu_hard_struct { * the FPU emulator for now. See asm-mips/fpu_emulator.h. */ -struct mips_fpu_soft_struct { +struct mips_fpu_struct { fpureg_t fpr[NUM_FPU_REGS]; unsigned int fcr31; }; -union mips_fpu_union { - struct mips_fpu_hard_struct hard; - struct mips_fpu_soft_struct soft; -}; - #define INIT_FPU { \ - {{0,},} \ + {0,} \ } #define NUM_DSP_REGS 6 @@ -133,7 +123,7 @@ struct thread_struct { unsigned long cp0_status; /* Saved fpu/fpu emulator stuff. */ - union mips_fpu_union fpu; + struct mips_fpu_struct fpu; #ifdef CONFIG_MIPS_MT_FPAFF /* Emulated instruction count */ unsigned long emulated_fp; -- cgit v1.2.3 From c583122c26ad04bb2379933dc5acc8b9479d6c67 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Mon, 15 May 2006 18:59:34 +0100 Subject: [MIPS] Qemu system shutdown support Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/qemu/Makefile | 2 +- arch/mips/qemu/q-reset.c | 34 ++++++++++++++++++++++++++++++++++ arch/mips/qemu/q-setup.c | 4 ++++ include/asm-mips/qemu.h | 6 ++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 arch/mips/qemu/q-reset.c (limited to 'include') diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile index 730f459f3e99..078cd3029c9f 100644 --- a/arch/mips/qemu/Makefile +++ b/arch/mips/qemu/Makefile @@ -2,6 +2,6 @@ # Makefile for Qemu specific kernel interface routines under Linux. # -obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o +obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o q-reset.o obj-$(CONFIG_SMP) += q-smp.o diff --git a/arch/mips/qemu/q-reset.c b/arch/mips/qemu/q-reset.c new file mode 100644 index 000000000000..c04ebcfc7843 --- /dev/null +++ b/arch/mips/qemu/q-reset.c @@ -0,0 +1,34 @@ +#include + +#include +#include +#include +#include + +static void qemu_machine_restart(char *command) +{ + volatile unsigned int *reg = (unsigned int *)QEMU_RESTART_REG; + + set_c0_status(ST0_BEV | ST0_ERL); + change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_c0_wired(0); + *reg = 42; + while (1) + cpu_wait(); +} + +static void qemu_machine_halt(void) +{ + volatile unsigned int *reg = (unsigned int *)QEMU_HALT_REG; + + *reg = 42; + while (1) + cpu_wait(); +} + +void qemu_reboot_setup(void) +{ + _machine_restart = qemu_machine_restart; + _machine_halt = qemu_machine_halt; +} diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c index 022eb1af6db1..f27155bc2d9a 100644 --- a/arch/mips/qemu/q-setup.c +++ b/arch/mips/qemu/q-setup.c @@ -2,6 +2,8 @@ #include #include +extern void qemu_reboot_setup(void); + #define QEMU_PORT_BASE 0xb4000000 const char *get_system_type(void) @@ -22,4 +24,6 @@ void __init plat_setup(void) { set_io_port_base(QEMU_PORT_BASE); board_timer_setup = qemu_timer_setup; + + qemu_reboot_setup(); } diff --git a/include/asm-mips/qemu.h b/include/asm-mips/qemu.h index 905c39585903..531caf44560c 100644 --- a/include/asm-mips/qemu.h +++ b/include/asm-mips/qemu.h @@ -21,4 +21,10 @@ */ #define QEMU_C0_COUNTER_CLOCK 100000000 +/* + * Magic qemu system control location. + */ +#define QEMU_RESTART_REG 0xBFBF0000 +#define QEMU_HALT_REG 0xBFBF0004 + #endif /* __ASM_QEMU_H */ -- cgit v1.2.3 From c0589f1ecea73e7bce09c569dca44b83e68a39b1 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 31 May 2006 16:00:05 +0900 Subject: [MIPS] Remove unused definitions from addrspace.h. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/addrspace.h | 35 ----------------------------------- 1 file changed, 35 deletions(-) (limited to 'include') diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h index 1386af1cb7d9..0cc6c7060f3c 100644 --- a/include/asm-mips/addrspace.h +++ b/include/asm-mips/addrspace.h @@ -133,57 +133,22 @@ || defined (CONFIG_CPU_NEVADA) \ || defined (CONFIG_CPU_TX49XX) \ || defined (CONFIG_CPU_MIPS64) -#define KUSIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define KUSIZE_64 _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K0SIZE _LLCONST_(0x0000001000000000) /* 2^^36 */ -#define K1SIZE _LLCONST_(0x0000001000000000) /* 2^^36 */ -#define K2SIZE _LLCONST_(0x000000ff80000000) -#define KSEGSIZE _LLCONST_(0x000000ff80000000) /* max syssegsz */ #define TO_PHYS_MASK _LLCONST_(0x0000000fffffffff) /* 2^^36 - 1 */ #endif #if defined (CONFIG_CPU_R8000) /* We keep KUSIZE consistent with R4000 for now (2^^40) instead of (2^^48) */ -#define KUSIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define KUSIZE_64 _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K0SIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K1SIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K2SIZE _LLCONST_(0x0001000000000000) -#define KSEGSIZE _LLCONST_(0x0000010000000000) /* max syssegsz */ #define TO_PHYS_MASK _LLCONST_(0x000000ffffffffff) /* 2^^40 - 1 */ #endif #if defined (CONFIG_CPU_R10000) -#define KUSIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define KUSIZE_64 _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K0SIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K1SIZE _LLCONST_(0x0000010000000000) /* 2^^40 */ -#define K2SIZE _LLCONST_(0x00000fff80000000) -#define KSEGSIZE _LLCONST_(0x00000fff80000000) /* max syssegsz */ #define TO_PHYS_MASK _LLCONST_(0x000000ffffffffff) /* 2^^40 - 1 */ #endif #if defined(CONFIG_CPU_SB1) || defined(CONFIG_CPU_SB1A) -#define KUSIZE _LLCONST_(0x0000100000000000) /* 2^^44 */ -#define KUSIZE_64 _LLCONST_(0x0000100000000000) /* 2^^44 */ -#define K0SIZE _LLCONST_(0x0000100000000000) /* 2^^44 */ -#define K1SIZE _LLCONST_(0x0000100000000000) /* 2^^44 */ -#define K2SIZE _LLCONST_(0x0000ffff80000000) -#define KSEGSIZE _LLCONST_(0x0000ffff80000000) /* max syssegsz */ #define TO_PHYS_MASK _LLCONST_(0x00000fffffffffff) /* 2^^44 - 1 */ #endif -/* - * Further names for SGI source compatibility. These are stolen from - * IRIX's . - */ -#define KUBASE _LLCONST_(0) -#define KUSIZE_32 _LLCONST_(0x0000000080000000) /* KUSIZE - for a 32 bit proc */ -#define K0BASE_EXL_WR _LLCONST_(0xa800000000000000) /* exclusive on write */ -#define K0BASE_NONCOH _LLCONST_(0x9800000000000000) /* noncoherent */ -#define K0BASE_EXL _LLCONST_(0xa000000000000000) /* exclusive */ - #ifndef CONFIG_CPU_R8000 /* -- cgit v1.2.3 From 1bd5e16168b58e73f7be432ba3558af9d38662cf Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 3 Jun 2006 21:59:51 +0100 Subject: [MIPS] Cleanup __emt() a bit. Signed-off-by: Ralf Baechle --- include/asm-mips/mipsregs.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h index 5af7517fce8a..98b68089aa53 100644 --- a/include/asm-mips/mipsregs.h +++ b/include/asm-mips/mipsregs.h @@ -1451,12 +1451,10 @@ static inline void __emt(unsigned int previous) { if ((previous & __EMT_ENABLE)) __asm__ __volatile__( - " .set noreorder \n" " .set mips32r2 \n" " .word 0x41600be1 # emt \n" " ehb \n" - " .set mips0 \n" - " .set reorder \n"); + " .set mips0 \n"); } static inline void __ehb(void) -- cgit v1.2.3 From b383f47ec71de66dbba5f7233479783041f5096a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 7 Jun 2006 20:02:21 +0100 Subject: [MIPS] IP27: Nuke last leftovers of CONFIG_SGI_IO. Signed-off-by: Ralf Baechle --- include/asm-mips/sn/addrs.h | 5 ----- include/asm-mips/sn/klconfig.h | 50 ++---------------------------------------- include/asm-mips/sn/kldir.h | 30 ------------------------- 3 files changed, 2 insertions(+), 83 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/addrs.h b/include/asm-mips/sn/addrs.h index 2b5cef1ba37f..00da24f506f6 100644 --- a/include/asm-mips/sn/addrs.h +++ b/include/asm-mips/sn/addrs.h @@ -27,13 +27,8 @@ #ifndef __ASSEMBLY__ -#if defined(CONFIG_SGI_IO) /* FIXME */ -#define PS_UINT_CAST (__psunsigned_t) -#define UINT64_CAST (__uint64_t) -#else /* CONFIG_SGI_IO */ #define PS_UINT_CAST (unsigned long) #define UINT64_CAST (unsigned long) -#endif /* CONFIG_SGI_IO */ #define HUBREG_CAST (volatile hubreg_t *) diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index 9709ff701d9b..19ece28c5e8b 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -54,12 +54,12 @@ #include #include #include -#if defined(CONFIG_SGI_IO) || defined(CONFIG_SGI_IP35) +#if defined(CONFIG_SGI_IP35) // The hack file has to be before vector and after sn0_fru.... #include #include #include -#endif /* CONFIG_SGI_IO || CONFIG_SGI_IP35 */ +#endif /* CONFIG_SGI_IP35 */ #endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */ #define KLCFGINFO_MAGIC 0xbeedbabe @@ -134,15 +134,9 @@ typedef s32 klconf_off_t; typedef struct console_s { -#if defined(CONFIG_SGI_IO) /* FIXME */ - __psunsigned_t uart_base; - __psunsigned_t config_base; - __psunsigned_t memory_base; -#else unsigned long uart_base; unsigned long config_base; unsigned long memory_base; -#endif short baud; short flag; int type; @@ -197,23 +191,13 @@ typedef struct kl_config_hdr { /* --- New Macros for the changed kl_config_hdr_t structure --- */ -#if defined(CONFIG_SGI_IO) -#define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ - ((__psunsigned_t)_k + (_k->ch_malloc_hdr_off))) -#else #define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ (unsigned long)_k + (_k->ch_malloc_hdr_off))) -#endif #define KL_CONFIG_CH_MALLOC_HDR(_n) PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n)) -#if defined(CONFIG_SGI_IO) -#define PTR_CH_CONS_INFO(_k) ((console_t *)\ - ((__psunsigned_t)_k + (_k->ch_cons_off))) -#else #define PTR_CH_CONS_INFO(_k) ((console_t *)\ ((unsigned long)_k + (_k->ch_cons_off))) -#endif #define KL_CONFIG_CH_CONS_INFO(_n) PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n)) @@ -945,36 +929,6 @@ extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class); -#if defined(CONFIG_SGI_IO) -extern xwidgetnum_t nodevertex_widgetnum_get(vertex_hdl_t node_vtx); -extern vertex_hdl_t nodevertex_xbow_peer_get(vertex_hdl_t node_vtx); -extern lboard_t *find_gfxpipe(int pipenum); -extern void setup_gfxpipe_link(vertex_hdl_t vhdl,int pipenum); -extern lboard_t *find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_class); -extern lboard_t *find_nic_lboard(lboard_t *, nic_t); -extern lboard_t *find_nic_type_lboard(nasid_t, unsigned char, nic_t); -extern lboard_t *find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot); -extern lboard_t *find_lboard_module(lboard_t *start, moduleid_t mod); -extern lboard_t *get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name); -extern int config_find_nic_router(nasid_t, nic_t, lboard_t **, klrou_t**); -extern int config_find_nic_hub(nasid_t, nic_t, lboard_t **, klhub_t**); -extern int config_find_xbow(nasid_t, lboard_t **, klxbow_t**); -extern klcpu_t *get_cpuinfo(cpuid_t cpu); -extern int update_klcfg_cpuinfo(nasid_t, int); -extern void board_to_path(lboard_t *brd, char *path); -extern moduleid_t get_module_id(nasid_t nasid); -extern void nic_name_convert(char *old_name, char *new_name); -extern int module_brds(nasid_t nasid, lboard_t **module_brds, int n); -extern lboard_t *brd_from_key(ulong_t key); -extern void device_component_canonical_name_get(lboard_t *,klinfo_t *, - char *); -extern int board_serial_number_get(lboard_t *,char *); -extern int is_master_baseio(nasid_t,moduleid_t,slotid_t); -extern nasid_t get_actual_nasid(lboard_t *brd) ; -extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int); -#else /* CONFIG_SGI_IO */ extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu); -#endif /* CONFIG_SGI_IO */ #endif /* _ASM_SN_KLCONFIG_H */ diff --git a/include/asm-mips/sn/kldir.h b/include/asm-mips/sn/kldir.h index f0efab1672ec..fa40e6794f82 100644 --- a/include/asm-mips/sn/kldir.h +++ b/include/asm-mips/sn/kldir.h @@ -13,10 +13,6 @@ #include -#if defined(CONFIG_SGI_IO) -#include -#endif - /* * The kldir memory area resides at a fixed place in each node's memory and * provides pointers to most other IP27 memory areas. This allows us to @@ -136,8 +132,6 @@ #define KLDIR_OFF_STRIDE 0x28 #endif /* __ASSEMBLY__ */ -#if !defined(CONFIG_SGI_IO) - /* * This is defined here because IP27_SYMMON_STK_SIZE must be at least what * we define here. Since it's set up in the prom. We can't redefine it later @@ -207,17 +201,11 @@ #define KLDIR_ENT_SIZE 0x40 #define KLDIR_MAX_ENTRIES (0x400 / 0x40) -#endif /* !CONFIG_SGI_IO */ - #ifndef __ASSEMBLY__ typedef struct kldir_ent_s { u64 magic; /* Indicates validity of entry */ off_t offset; /* Offset from start of node space */ -#if defined(CONFIG_SGI_IO) /* FIXME */ - __psunsigned_t pointer; /* Pointer to area in some cases */ -#else unsigned long pointer; /* Pointer to area in some cases */ -#endif size_t size; /* Size in bytes */ u64 count; /* Repeat count if array, 1 if not */ size_t stride; /* Stride if array, 0 if not */ @@ -227,22 +215,4 @@ typedef struct kldir_ent_s { } kldir_ent_t; #endif /* !__ASSEMBLY__ */ -#if defined(CONFIG_SGI_IO) - -#define KLDIR_ENT_SIZE 0x40 -#define KLDIR_MAX_ENTRIES (0x400 / 0x40) - -/* - * The actual offsets of each memory area are machine-dependent - */ -#ifdef CONFIG_SGI_IP27 -// Not yet #include -#elif defined(CONFIG_SGI_IP35) -#include -#else -#error "kldir.h is currently defined for IP27 and IP35 platforms only" -#endif - -#endif /* CONFIG_SGI_IO */ - #endif /* _ASM_SN_KLDIR_H */ -- cgit v1.2.3 From 8dbd1d3e65f0281ddf9f7b8123ef81763bc2051f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 7 Jun 2006 20:04:23 +0100 Subject: [MIPS] IP27: Nuke last leftovers from FRUTEST Signed-off-by: Ralf Baechle --- include/asm-mips/sn/klconfig.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index 19ece28c5e8b..ec469a3d2939 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -64,11 +64,7 @@ #define KLCFGINFO_MAGIC 0xbeedbabe -#ifdef FRUTEST -typedef u64 klconf_off_t; -#else typedef s32 klconf_off_t; -#endif /* * Some IMPORTANT OFFSETS. These are the offsets on all NODES. @@ -474,14 +470,6 @@ typedef struct lboard_s { #define KLCF_NUM_COMPS(_brd) ((_brd)->brd_numcompts) #define KLCF_MODULE_ID(_brd) ((_brd)->brd_module) -#ifdef FRUTEST - -#define KLCF_NEXT(_brd) ((_brd)->brd_next ? (lboard_t *)((_brd)->brd_next): NULL) -#define KLCF_COMP(_brd, _ndx) (klinfo_t *)((_brd)->brd_compts[(_ndx)]) -#define KLCF_COMP_ERROR(_brd, _comp) (_brd = _brd , (_comp)->errinfo) - -#else - #define KLCF_NEXT(_brd) \ ((_brd)->brd_next ? \ (lboard_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd), (_brd)->brd_next)):\ @@ -493,8 +481,6 @@ typedef struct lboard_s { #define KLCF_COMP_ERROR(_brd, _comp) \ (NODE_OFFSET_TO_K1(NASID_GET(_brd), (_comp)->errinfo)) -#endif - #define KLCF_COMP_TYPE(_comp) ((_comp)->struct_type) #define KLCF_BRIDGE_W_ID(_comp) ((_comp)->physid) /* Widget ID */ -- cgit v1.2.3 From edc123d18397008fcd4fdf04f60e033ba1042834 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 7 Jun 2006 20:07:29 +0100 Subject: [MIPS] IP27: Remove leftovers of sable support. Signed-off-by: Ralf Baechle --- include/asm-mips/sn/kldir.h | 4 ++-- include/asm-mips/sn/sn0/addrs.h | 5 ----- include/asm-mips/sn/sn0/arch.h | 11 ----------- include/asm-mips/sn/sn0/hub.h | 4 ---- 4 files changed, 2 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/kldir.h b/include/asm-mips/sn/kldir.h index fa40e6794f82..97ad52e3cbc7 100644 --- a/include/asm-mips/sn/kldir.h +++ b/include/asm-mips/sn/kldir.h @@ -141,7 +141,7 @@ */ #define SYMMON_STACK_SIZE 0x8000 -#if defined (PROM) || defined (SABLE) +#if defined (PROM) /* * These defines are prom version dependent. No code other than the IP27 @@ -178,7 +178,7 @@ #define IP27_FREEMEM_COUNT 1 #define IP27_FREEMEM_STRIDE 0 -#endif /* PROM || SABLE*/ +#endif /* PROM */ /* * There will be only one of these in a partition so the IO6 must set it up. */ diff --git a/include/asm-mips/sn/sn0/addrs.h b/include/asm-mips/sn/sn0/addrs.h index 398815639fb8..7cb9c31f6878 100644 --- a/include/asm-mips/sn/sn0/addrs.h +++ b/include/asm-mips/sn/sn0/addrs.h @@ -143,12 +143,7 @@ #define SN0_WIDGET_BASE(_nasid, _wid) (NODE_SWIN_BASE((_nasid), (_wid))) /* Turn on sable logging for the processors whose bits are set. */ -#ifdef SABLE -#define SABLE_LOG_TRIGGER(_map) \ - *((volatile hubreg_t *)(IO_BASE + 0x17ffff0)) = (_map) -#else #define SABLE_LOG_TRIGGER(_map) -#endif /* SABLE */ #ifndef __ASSEMBLY__ #define KERN_NMI_ADDR(nasid, slice) \ diff --git a/include/asm-mips/sn/sn0/arch.h b/include/asm-mips/sn/sn0/arch.h index fb78773a5efe..5643a6e639bd 100644 --- a/include/asm-mips/sn/sn0/arch.h +++ b/include/asm-mips/sn/sn0/arch.h @@ -13,8 +13,6 @@ #include -#ifndef SABLE - #ifndef SN0XXL /* 128 cpu SMP max */ /* * This is the maximum number of nodes that can be part of a kernel. @@ -54,15 +52,6 @@ */ #define MAX_PARTITIONS MAX_REGIONS - -#else - -#define MAX_COMPACT_NODES 4 -#define MAX_NASIDS 4 -#define MAXCPUS 8 - -#endif - #define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) /* diff --git a/include/asm-mips/sn/sn0/hub.h b/include/asm-mips/sn/sn0/hub.h index f5dbba6f4610..3e228f8e7969 100644 --- a/include/asm-mips/sn/sn0/hub.h +++ b/include/asm-mips/sn/sn0/hub.h @@ -31,10 +31,6 @@ #include //#include -#ifdef SABLE -#define IP27_NO_HUBUART_INT 1 -#endif - /* Translation of uncached attributes */ #define UATTR_HSPEC 0 #define UATTR_IO 1 -- cgit v1.2.3 From 8f2f360da9262091153c97d756c40eabdde75f1a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 7 Jun 2006 20:10:06 +0100 Subject: [MIPS] IP27: Nuke leftovers of _STANDALONE Signed-off-by: Ralf Baechle --- include/asm-mips/sn/addrs.h | 22 ------------ include/asm-mips/sn/sn0/addrs.h | 76 ++--------------------------------------- 2 files changed, 3 insertions(+), 95 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/addrs.h b/include/asm-mips/sn/addrs.h index 00da24f506f6..6c8a5577ddf1 100644 --- a/include/asm-mips/sn/addrs.h +++ b/include/asm-mips/sn/addrs.h @@ -248,14 +248,6 @@ * for _x. */ -#ifdef _STANDALONE - -/* DO NOT USE THESE DIRECTLY IN THE KERNEL. SEE BELOW. */ -#define LOCAL_HUB(_x) (HUBREG_CAST (IALIAS_BASE + (_x))) -#define REMOTE_HUB(_n, _x) (HUBREG_CAST (NODE_SWIN_BASE(_n, 1) + \ - 0x800000 + (_x))) -#endif /* _STANDALONE */ - /* * WARNING: * When certain Hub chip workaround are defined, it's not sufficient @@ -322,20 +314,6 @@ PHYS_TO_K0(NODE_OFFSET(nasid) | ARCS_SPB_OFFSET) #define ARCS_SPB_SIZE 0x0400 -#ifdef _STANDALONE - -#define ARCS_TVECTOR_OFFSET 0x2800 -#define ARCS_PVECTOR_OFFSET 0x2c00 - -/* - * These addresses are used by the master CPU to install the transfer - * and private vectors. All others use the SPB to find them. - */ -#define TVADDR (NODE_CAC_BASE(get_nasid()) + ARCS_TVECTOR_OFFSET) -#define PVADDR (NODE_CAC_BASE(get_nasid()) + ARCS_PVECTOR_OFFSET) - -#endif /* _STANDALONE */ - #define KLDIR_OFFSET 0x2000 #define KLDIR_ADDR(nasid) \ TO_NODE_UNCAC((nasid), KLDIR_OFFSET) diff --git a/include/asm-mips/sn/sn0/addrs.h b/include/asm-mips/sn/sn0/addrs.h index 7cb9c31f6878..0ee8cbcb5b03 100644 --- a/include/asm-mips/sn/sn0/addrs.h +++ b/include/asm-mips/sn/sn0/addrs.h @@ -85,15 +85,15 @@ #define NASID_GET(_pa) (int) ((UINT64_CAST (_pa) >> \ NASID_SHFT) & NASID_BITMASK) -#if !defined(__ASSEMBLY__) && !defined(_STANDALONE) +#if !defined(__ASSEMBLY__) #define NODE_SWIN_BASE(nasid, widget) \ ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN) \ : RAW_NODE_SWIN_BASE(nasid, widget)) -#else /* __ASSEMBLY__ || _STANDALONE */ +#else /* __ASSEMBLY__ */ #define NODE_SWIN_BASE(nasid, widget) \ (NODE_IO_BASE(nasid) + (UINT64_CAST (widget) << SWIN_SIZE_BITS)) -#endif /* __ASSEMBLY__ || _STANDALONE */ +#endif /* __ASSEMBLY__ */ /* * The following definitions pertain to the IO special address @@ -276,76 +276,6 @@ #define _ARCSPROM -#ifdef _STANDALONE - -/* - * The PROM needs to pass the device base address and the - * device pci cfg space address to the device drivers during - * install. The COMPONENT->Key field is used for this purpose. - * Macros needed by SN0 device drivers to convert the - * COMPONENT->Key field to the respective base address. - * Key field looks as follows: - * - * +----------------------------------------------------+ - * |devnasid | widget |pciid |hubwidid|hstnasid | adap | - * | 2 | 1 | 1 | 1 | 2 | 1 | - * +----------------------------------------------------+ - * | | | | | | | - * 64 48 40 32 24 8 0 - * - * These are used by standalone drivers till the io infrastructure - * is in place. - */ - -#ifndef __ASSEMBLY__ - -#define uchar unsigned char - -#define KEY_DEVNASID_SHFT 48 -#define KEY_WIDID_SHFT 40 -#define KEY_PCIID_SHFT 32 -#define KEY_HUBWID_SHFT 24 -#define KEY_HSTNASID_SHFT 8 - -#define MK_SN0_KEY(nasid, widid, pciid) \ - ((((__psunsigned_t)nasid)<< KEY_DEVNASID_SHFT |\ - ((__psunsigned_t)widid) << KEY_WIDID_SHFT) |\ - ((__psunsigned_t)pciid) << KEY_PCIID_SHFT) - -#define ADD_HUBWID_KEY(key,hubwid)\ - (key|=((__psunsigned_t)hubwid << KEY_HUBWID_SHFT)) - -#define ADD_HSTNASID_KEY(key,hstnasid)\ - (key|=((__psunsigned_t)hstnasid << KEY_HSTNASID_SHFT)) - -#define GET_DEVNASID_FROM_KEY(key) ((short)(key >> KEY_DEVNASID_SHFT)) -#define GET_WIDID_FROM_KEY(key) ((uchar)(key >> KEY_WIDID_SHFT)) -#define GET_PCIID_FROM_KEY(key) ((uchar)(key >> KEY_PCIID_SHFT)) -#define GET_HUBWID_FROM_KEY(key) ((uchar)(key >> KEY_HUBWID_SHFT)) -#define GET_HSTNASID_FROM_KEY(key) ((short)(key >> KEY_HSTNASID_SHFT)) - -#define PCI_64_TARGID_SHFT 60 - -#define GET_PCIBASE_FROM_KEY(key) (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_DEVIO(GET_PCIID_FROM_KEY(key))) - -#define GET_PCICFGBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_TYPE0_CFG_DEV(GET_PCIID_FROM_KEY(key))) - -#define GET_WIDBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))) - -#define PUT_INSTALL_STATUS(c,s) c->Revision = s -#define GET_INSTALL_STATUS(c) c->Revision - -#endif /* !__ASSEMBLY__ */ - -#endif /* _STANDALONE */ - #if defined (HUB_ERR_STS_WAR) #define ERR_STS_WAR_REGISTER IIO_IIBUSERR -- cgit v1.2.3 From 3e0ba410a5d5595c2b79ecbfb85fb2466b998680 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 7 Jun 2006 20:13:20 +0100 Subject: [MIPS] IP27: Remove #if 0'ed code. Signed-off-by: Ralf Baechle --- include/asm-mips/sn/klconfig.h | 23 ----------------------- include/asm-mips/sn/sn0/hubio.h | 16 ---------------- include/asm-mips/sn/sn0/hubpi.h | 18 ------------------ 3 files changed, 57 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index ec469a3d2939..5deaf1cdadde 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -69,13 +69,6 @@ typedef s32 klconf_off_t; /* * Some IMPORTANT OFFSETS. These are the offsets on all NODES. */ -#if 0 -#define RAMBASE 0 -#define ARCSSPB_OFF 0x1000 /* shift it to sys/arcs/spb.h */ - -#define OFF_HWGRAPH 0 -#endif - #define MAX_MODULE_ID 255 #define SIZE_PAD 4096 /* 4k padding for structures */ /* @@ -164,10 +157,6 @@ typedef struct kl_config_hdr { #define KL_CONFIG_HDR(_nasid) ((kl_config_hdr_t *)(KLCONFIG_ADDR(_nasid))) -#if 0 -#define KL_CONFIG_MALLOC_HDR(_nasid) \ - (KL_CONFIG_HDR(_nasid)->ch_malloc_hdr) -#endif #define KL_CONFIG_INFO_OFFSET(_nasid) \ (KL_CONFIG_HDR(_nasid)->ch_board_info) #define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off) \ @@ -601,18 +590,6 @@ typedef struct klport_s { klconf_off_t port_offset; } klport_t; -#if 0 -/* - * This is very similar to the klport_s but instead of having a componant - * offset it has a board offset. - */ -typedef struct klxbow_port_s { - nasid_t port_nasid; - unsigned char port_flag; - klconf_off_t board_offset; -} klxbow_port_t; -#endif - typedef struct klcpu_s { /* CPU */ klinfo_t cpu_info; unsigned short cpu_prid; /* Processor PRID value */ diff --git a/include/asm-mips/sn/sn0/hubio.h b/include/asm-mips/sn/sn0/hubio.h index f314da21b970..ef91b3363554 100644 --- a/include/asm-mips/sn/sn0/hubio.h +++ b/include/asm-mips/sn/sn0/hubio.h @@ -486,22 +486,6 @@ typedef union h1_icrba_u { #define ICRBN_A_CERR_SHFT 54 #define ICRBN_A_ERR_MASK 0x3ff -#if 0 /* Disabled, this causes namespace polution and break allmodconfig */ -/* - * Easy access macros. - */ -#define a_error icrba_fields_s.error -#define a_ecode icrba_fields_s.ecode -#define a_lnetuce icrba_fields_s.lnetuce -#define a_mark icrba_fields_s.mark -#define a_xerr icrba_fields_s.xerr -#define a_sidn icrba_fields_s.sidn -#define a_tnum icrba_fields_s.tnum -#define a_addr icrba_fields_s.addr -#define a_valid icrba_fields_s.valid -#define a_iow icrba_fields_s.iow -#endif - #endif /* !__ASSEMBLY__ */ #define IIO_ICRB_ADDR_SHFT 2 /* Shift to get proper address */ diff --git a/include/asm-mips/sn/sn0/hubpi.h b/include/asm-mips/sn/sn0/hubpi.h index 355bba8552e3..e39f5f9da040 100644 --- a/include/asm-mips/sn/sn0/hubpi.h +++ b/include/asm-mips/sn/sn0/hubpi.h @@ -398,24 +398,6 @@ typedef u64 rtc_time_t; /* PI_RT_FILTER_CTRL mask and shift definitions */ -#if 0 -/* - * XXX - This register's definition has changed, but it's only implemented - * in Hub 2. - */ -#define PRFC_DROP_COUNT_SHFT 27 -#define PRFC_DROP_COUNT_MASK (UINT64_CAST 0x3ff << 27) -#define PRFC_DROP_CTR_SHFT 18 -#define PRFC_DROP_CTR_MASK (UINT64_CAST 0x1ff << 18) -#define PRFC_MASK_ENABLE_SHFT 10 -#define PRFC_MASK_ENABLE_MASK (UINT64_CAST 0x7f << 10) -#define PRFC_MASK_CTR_SHFT 2 -#define PRFC_MASK_CTR_MASK (UINT64_CAST 0xff << 2) -#define PRFC_OFFSET_SHFT 0 -#define PRFC_OFFSET_MASK (UINT64_CAST 3) -#endif /* 0 */ - - /* * Bits for NACK_CNT_A/B and NACK_CMP */ -- cgit v1.2.3 From bf5a312b26e9943613b765a29a8de5f4c762df11 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 10 Jun 2006 00:37:20 +0100 Subject: [MIPS] SN: Move FRU header one level up; it is not SN0-specific. Signed-off-by: Ralf Baechle --- include/asm-mips/sn/fru.h | 44 +++++++++++++++++++++++++++++++++++++++ include/asm-mips/sn/klconfig.h | 2 +- include/asm-mips/sn/sn0/sn0_fru.h | 44 --------------------------------------- 3 files changed, 45 insertions(+), 45 deletions(-) create mode 100644 include/asm-mips/sn/fru.h delete mode 100644 include/asm-mips/sn/sn0/sn0_fru.h (limited to 'include') diff --git a/include/asm-mips/sn/fru.h b/include/asm-mips/sn/fru.h new file mode 100644 index 000000000000..b3e3606723b7 --- /dev/null +++ b/include/asm-mips/sn/fru.h @@ -0,0 +1,44 @@ +/* + * 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. + * + * Derived from IRIX + * + * Copyright (C) 1992 - 1997, 1999 Silcon Graphics, Inc. + * Copyright (C) 1999, 2006 Ralf Baechle (ralf@linux-mips) + */ +#ifndef __ASM_SN_FRU_H +#define __ASM_SN_FRU_H + +#define MAX_DIMMS 8 /* max # of dimm banks */ +#define MAX_PCIDEV 8 /* max # of pci devices on a pci bus */ + +typedef unsigned char confidence_t; + +typedef struct kf_mem_s { + confidence_t km_confidence; /* confidence level that the memory is bad + * is this necessary ? + */ + confidence_t km_dimm[MAX_DIMMS]; + /* confidence level that dimm[i] is bad + *I think this is the right number + */ + +} kf_mem_t; + +typedef struct kf_cpu_s { + confidence_t kc_confidence; /* confidence level that cpu is bad */ + confidence_t kc_icache; /* confidence level that instr. cache is bad */ + confidence_t kc_dcache; /* confidence level that data cache is bad */ + confidence_t kc_scache; /* confidence level that sec. cache is bad */ + confidence_t kc_sysbus; /* confidence level that sysad/cmd/state bus is bad */ +} kf_cpu_t; + +typedef struct kf_pci_bus_s { + confidence_t kpb_belief; /* confidence level that the pci bus is bad */ + confidence_t kpb_pcidev_belief[MAX_PCIDEV]; + /* confidence level that the pci dev is bad */ +} kf_pci_bus_t; + +#endif /* __ASM_SN_FRU_H */ diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index 5deaf1cdadde..dc706268d2cf 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -37,7 +37,7 @@ //#include // XXX Stolen from : #define MAX_ROUTER_PORTS (6) /* Max. number of ports on a router */ -#include +#include //#include //#include diff --git a/include/asm-mips/sn/sn0/sn0_fru.h b/include/asm-mips/sn/sn0/sn0_fru.h deleted file mode 100644 index 82c6377c275a..000000000000 --- a/include/asm-mips/sn/sn0/sn0_fru.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * - * Derived from IRIX - * - * Copyright (C) 1992 - 1997, 1999 Silcon Graphics, Inc. - * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) - */ -#ifndef _ASM_SN_SN0_SN0_FRU_H -#define _ASM_SN_SN0_SN0_FRU_H - -#define MAX_DIMMS 8 /* max # of dimm banks */ -#define MAX_PCIDEV 8 /* max # of pci devices on a pci bus */ - -typedef unsigned char confidence_t; - -typedef struct kf_mem_s { - confidence_t km_confidence; /* confidence level that the memory is bad - * is this necessary ? - */ - confidence_t km_dimm[MAX_DIMMS]; - /* confidence level that dimm[i] is bad - *I think this is the right number - */ - -} kf_mem_t; - -typedef struct kf_cpu_s { - confidence_t kc_confidence; /* confidence level that cpu is bad */ - confidence_t kc_icache; /* confidence level that instr. cache is bad */ - confidence_t kc_dcache; /* confidence level that data cache is bad */ - confidence_t kc_scache; /* confidence level that sec. cache is bad */ - confidence_t kc_sysbus; /* confidence level that sysad/cmd/state bus is bad */ -} kf_cpu_t; - -typedef struct kf_pci_bus_s { - confidence_t kpb_belief; /* confidence level that the pci bus is bad */ - confidence_t kpb_pcidev_belief[MAX_PCIDEV]; - /* confidence level that the pci dev is bad */ -} kf_pci_bus_t; - -#endif /* _ASM_SN_SN0_SN0_FRU_H */ -- cgit v1.2.3 From aa9772e330d6c0a8a94316cb38ae8a7495885a60 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Jun 2006 00:55:14 +0100 Subject: [MIPS] SN: Rename SGI_SN0_N_MODE -> SGI_SN_N_MODE. It's not SN0-specific. Signed-off-by: Ralf Baechle --- arch/mips/configs/ip27_defconfig | 2 +- arch/mips/sgi-ip27/Kconfig | 2 +- arch/mips/sgi-ip27/ip27-init.c | 2 +- include/asm-mips/sn/sn0/addrs.h | 6 +++--- include/asm-mips/sn/sn0/arch.h | 4 ++-- include/asm-mips/sn/sn0/hubmd.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index f724b4b2ecf2..87d27cd3d2cf 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -63,7 +63,7 @@ CONFIG_SGI_IP27=y # CONFIG_TOSHIBA_JMR3927 is not set # CONFIG_TOSHIBA_RBTX4927 is not set # CONFIG_TOSHIBA_RBTX4938 is not set -# CONFIG_SGI_SN0_N_MODE is not set +# CONFIG_SGI_SN_N_MODE is not set CONFIG_ARCH_DISCONTIGMEM_ENABLE=y CONFIG_NUMA=y # CONFIG_MAPPED_KERNEL is not set diff --git a/arch/mips/sgi-ip27/Kconfig b/arch/mips/sgi-ip27/Kconfig index 6da5926210a6..4b7c3c675174 100644 --- a/arch/mips/sgi-ip27/Kconfig +++ b/arch/mips/sgi-ip27/Kconfig @@ -4,7 +4,7 @@ # This options adds support for userspace processes upto 16TB size. # Normally the limit is just .5TB. -config SGI_SN0_N_MODE +config SGI_SN_N_MODE bool "IP27 N-Mode" depends on SGI_IP27 help diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 8651a0e75404..16c4b3410eaf 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -228,7 +228,7 @@ void __init plat_setup(void) */ n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK; printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M'); -#ifdef CONFIG_SGI_SN0_N_MODE +#ifdef CONFIG_SGI_SN_N_MODE if (!n_mode) panic("Kernel compiled for M mode."); #else diff --git a/include/asm-mips/sn/sn0/addrs.h b/include/asm-mips/sn/sn0/addrs.h index 0ee8cbcb5b03..2c4b758f6736 100644 --- a/include/asm-mips/sn/sn0/addrs.h +++ b/include/asm-mips/sn/sn0/addrs.h @@ -49,7 +49,7 @@ * so for now we just use defines bracketed by an ifdef. */ -#ifdef CONFIG_SGI_SN0_N_MODE +#ifdef CONFIG_SGI_SN_N_MODE #define NODE_SIZE_BITS 31 #define BWIN_SIZE_BITS 28 @@ -63,7 +63,7 @@ #define BDDIR_UPPER_MASK (UINT64_CAST 0x7ffff << 10) #define BDECC_UPPER_MASK (UINT64_CAST 0x3ffffff << 3) -#else /* !defined(CONFIG_SGI_SN0_N_MODE), assume that M-mode is desired */ +#else /* !defined(CONFIG_SGI_SN_N_MODE), assume that M-mode is desired */ #define NODE_SIZE_BITS 32 #define BWIN_SIZE_BITS 29 @@ -77,7 +77,7 @@ #define BDDIR_UPPER_MASK (UINT64_CAST 0xfffff << 10) #define BDECC_UPPER_MASK (UINT64_CAST 0x7ffffff << 3) -#endif /* !defined(CONFIG_SGI_SN0_N_MODE) */ +#endif /* !defined(CONFIG_SGI_SN_N_MODE) */ #define NODE_ADDRSPACE_SIZE (UINT64_CAST 1 << NODE_SIZE_BITS) diff --git a/include/asm-mips/sn/sn0/arch.h b/include/asm-mips/sn/sn0/arch.h index 5643a6e639bd..0ecbaa0d3837 100644 --- a/include/asm-mips/sn/sn0/arch.h +++ b/include/asm-mips/sn/sn0/arch.h @@ -57,9 +57,9 @@ /* * Slot constants for SN0 */ -#ifdef CONFIG_SGI_SN0_N_MODE +#ifdef CONFIG_SGI_SN_N_MODE #define MAX_MEM_SLOTS 16 /* max slots per node */ -#else /* !CONFIG_SGI_SN0_N_MODE, assume M_MODE */ +#else /* !CONFIG_SGI_SN_N_MODE, assume M_MODE */ #define MAX_MEM_SLOTS 32 /* max slots per node */ #endif /* defined(N_MODE) */ diff --git a/include/asm-mips/sn/sn0/hubmd.h b/include/asm-mips/sn/sn0/hubmd.h index a66def4e0ba0..1006aa26d771 100644 --- a/include/asm-mips/sn/sn0/hubmd.h +++ b/include/asm-mips/sn/sn0/hubmd.h @@ -92,7 +92,7 @@ #define MD_UREG1_14 0x2200f0 /* uController/UART 1 register */ #define MD_UREG1_15 0x2200f8 /* uController/UART 1 register */ -#ifdef CONFIG_SGI_SN0_N_MODE +#ifdef CONFIG_SGI_SN_N_MODE #define MD_MEM_BANKS 4 /* 4 banks of memory max in N mode */ #else #define MD_MEM_BANKS 8 /* 8 banks of memory max in M mode */ -- cgit v1.2.3 From 952fa954a61cee43de5afba91ae605e30ed2586c Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Mon, 5 Jun 2006 17:43:10 +0200 Subject: [MIPS] APM emu support Signed-off-by: Rodolfo Giometti Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 26 ++ arch/mips/kernel/Makefile | 2 + arch/mips/kernel/apm.c | 605 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-mips/apm.h | 65 +++++ 4 files changed, 698 insertions(+) create mode 100644 arch/mips/kernel/apm.c create mode 100644 include/asm-mips/apm.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1c78661abe11..ae33e0a4c18d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1890,6 +1890,32 @@ config PM bool "Power Management support (EXPERIMENTAL)" depends on EXPERIMENTAL && SOC_AU1X00 +config APM + tristate "Advanced Power Management Emulation" + depends on PM + ---help--- + APM is a BIOS specification for saving power using several different + techniques. This is mostly useful for battery powered systems with + APM compliant BIOSes. If you say Y here, the system time will be + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g. battery status change). + + In order to use APM, you will need supporting software. For location + and more information, read and the + Battery Powered Linux mini-HOWTO, available from + . + + This driver does not spin down disk drives (see the hdparm(8) + manpage ("man 8 hdparm") for that), and it doesn't turn off + VESA-compliant "green" monitors. + + Generally, if you don't have a battery in your machine, there isn't + much point in using this driver and you should say N. If you get + random kernel OOPSes or reboots that don't seem to be related to + anything, try disabling/enabling this option (or disabling/enabling + APM in your BIOS). + endmenu source "net/Kconfig" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 34e8a256765c..881c467c6982 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -13,6 +13,8 @@ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ obj-$(CONFIG_MODULES) += mips_ksyms.o module.o +obj-$(CONFIG_APM) += apm.o + obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o diff --git a/arch/mips/kernel/apm.c b/arch/mips/kernel/apm.c new file mode 100644 index 000000000000..15f46b4471fd --- /dev/null +++ b/arch/mips/kernel/apm.c @@ -0,0 +1,605 @@ +/* + * bios-less APM driver for MIPS Linux + * Jamey Hicks + * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) + * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* apm_power_info */ +#include + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * See Documentation/Config.help for the configuration options. + * + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) + * apm=on/off enable/disable APM + */ + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 16 + +struct apm_queue { + unsigned int event_head; + unsigned int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The per-file APM data + */ +struct apm_user { + struct list_head list; + + unsigned int suser: 1; + unsigned int writer: 1; + unsigned int reader: 1; + + int suspend_result; + unsigned int suspend_state; +#define SUSPEND_NONE 0 /* no suspend pending */ +#define SUSPEND_PENDING 1 /* suspend pending read */ +#define SUSPEND_READ 2 /* suspend read, pending ack */ +#define SUSPEND_ACKED 3 /* suspend acked */ +#define SUSPEND_DONE 4 /* suspend completed */ + + struct apm_queue queue; +}; + +/* + * Local variables + */ +static int suspends_pending; +static int apm_disabled; +static int mips_apm_active; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); + +/* + * This is a list of everyone who has opened /dev/apm_bios + */ +static DECLARE_RWSEM(user_list_lock); +static LIST_HEAD(apm_user_list); + +/* + * kapmd info. kapmd provides us a process context to handle + * "APM" events within - specifically necessary if we're going + * to be suspending the system. + */ +static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); +static DECLARE_COMPLETION(kapmd_exit); +static DEFINE_SPINLOCK(kapmd_queue_lock); +static struct apm_queue kapmd_queue; + + +static const char driver_version[] = "1.13"; /* no spaces */ + + + +/* + * Compatibility cruft until the IPAQ people move over to the new + * interface. + */ +static void __apm_get_power_status(struct apm_power_info *info) +{ +} + +/* + * This allows machines to provide their own "apm get power status" function. + */ +void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; +EXPORT_SYMBOL(apm_get_power_status); + + +/* + * APM event queue management. + */ +static inline int queue_empty(struct apm_queue *q) +{ + return q->event_head == q->event_tail; +} + +static inline apm_event_t queue_get_event(struct apm_queue *q) +{ + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + return q->events[q->event_tail]; +} + +static void queue_add_event(struct apm_queue *q, apm_event_t event) +{ + q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; + if (q->event_head == q->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm: an event queue overflowed\n"); + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + } + q->events[q->event_head] = event; +} + +static void queue_event_one_user(struct apm_user *as, apm_event_t event) +{ + if (as->suser && as->writer) { + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + /* + * If this user already has a suspend pending, + * don't queue another one. + */ + if (as->suspend_state != SUSPEND_NONE) + return; + + as->suspend_state = SUSPEND_PENDING; + suspends_pending++; + break; + } + } + queue_add_event(&as->queue, event); +} + +static void queue_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user *as; + + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + if (as != sender && as->reader) + queue_event_one_user(as, event); + } + up_read(&user_list_lock); + wake_up_interruptible(&apm_waitqueue); +} + +static void apm_suspend(void) +{ + struct apm_user *as; + int err = pm_suspend(PM_SUSPEND_MEM); + + /* + * Anyone on the APM queues will think we're still suspended. + * Send a message so everyone knows we're now awake again. + */ + queue_event(APM_NORMAL_RESUME, NULL); + + /* + * Finally, wake up anyone who is sleeping on the suspend. + */ + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + as->suspend_result = err; + as->suspend_state = SUSPEND_DONE; + } + up_read(&user_list_lock); + + wake_up(&apm_suspend_waitqueue); +} + +static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) +{ + struct apm_user *as = fp->private_data; + apm_event_t event; + int i = count, ret = 0; + + if (count < sizeof(apm_event_t)) + return -EINVAL; + + if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) + return -EAGAIN; + + wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); + + while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { + event = queue_get_event(&as->queue); + + ret = -EFAULT; + if (copy_to_user(buf, &event, sizeof(event))) + break; + + if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) + as->suspend_state = SUSPEND_READ; + + buf += sizeof(event); + i -= sizeof(event); + } + + if (i < count) + ret = count - i; + + return ret; +} + +static unsigned int apm_poll(struct file *fp, poll_table * wait) +{ + struct apm_user *as = fp->private_data; + + poll_wait(fp, &apm_waitqueue, wait); + return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; +} + +/* + * apm_ioctl - handle APM ioctl + * + * APM_IOC_SUSPEND + * This IOCTL is overloaded, and performs two functions. It is used to: + * - initiate a suspend + * - acknowledge a suspend read from /dev/apm_bios. + * Only when everyone who has opened /dev/apm_bios with write permission + * has acknowledge does the actual suspend happen. + */ +static int +apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) +{ + struct apm_user *as = filp->private_data; + unsigned long flags; + int err = -EINVAL; + + if (!as->suser || !as->writer) + return -EPERM; + + switch (cmd) { + case APM_IOC_SUSPEND: + as->suspend_result = -EINTR; + + if (as->suspend_state == SUSPEND_READ) { + /* + * If we read a suspend command from /dev/apm_bios, + * then the corresponding APM_IOC_SUSPEND ioctl is + * interpreted as an acknowledge. + */ + as->suspend_state = SUSPEND_ACKED; + suspends_pending--; + } else { + /* + * Otherwise it is a request to suspend the system. + * Queue an event for all readers, and expect an + * acknowledge from all writers who haven't already + * acknowledged. + */ + queue_event(APM_USER_SUSPEND, as); + } + + /* + * If there are no further acknowledges required, suspend + * the system. + */ + if (suspends_pending == 0) + apm_suspend(); + + /* + * Wait for the suspend/resume to complete. If there are + * pending acknowledges, we wait here for them. + * + * Note that we need to ensure that the PM subsystem does + * not kick us out of the wait when it suspends the threads. + */ + flags = current->flags; + current->flags |= PF_NOFREEZE; + + /* + * Note: do not allow a thread which is acking the suspend + * to escape until the resume is complete. + */ + if (as->suspend_state == SUSPEND_ACKED) + wait_event(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + else + wait_event_interruptible(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + + current->flags = flags; + err = as->suspend_result; + as->suspend_state = SUSPEND_NONE; + break; + } + + return err; +} + +static int apm_release(struct inode * inode, struct file * filp) +{ + struct apm_user *as = filp->private_data; + filp->private_data = NULL; + + down_write(&user_list_lock); + list_del(&as->list); + up_write(&user_list_lock); + + /* + * We are now unhooked from the chain. As far as new + * events are concerned, we no longer exist. However, we + * need to balance suspends_pending, which means the + * possibility of sleeping. + */ + if (as->suspend_state != SUSPEND_NONE) { + suspends_pending -= 1; + if (suspends_pending == 0) + apm_suspend(); + } + + kfree(as); + return 0; +} + +static int apm_open(struct inode * inode, struct file * filp) +{ + struct apm_user *as; + + as = (struct apm_user *)kzalloc(sizeof(*as), GFP_KERNEL); + if (as) { + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; + as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + + down_write(&user_list_lock); + list_add(&as->list, &apm_user_list); + up_write(&user_list_lock); + + filp->private_data = as; + } + + return as ? 0 : -ENOMEM; +} + +static struct file_operations apm_bios_fops = { + .owner = THIS_MODULE, + .read = apm_read, + .poll = apm_poll, + .ioctl = apm_ioctl, + .open = apm_open, + .release = apm_release, +}; + +static struct miscdevice apm_device = { + .minor = APM_MINOR_DEV, + .name = "apm_bios", + .fops = &apm_bios_fops +}; + + +#ifdef CONFIG_PROC_FS +/* + * Arguments, with symbols from linux/apm_bios.h. + * + * 0) Linux driver version (this will change if format changes) + * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + * 2) APM flags from APM Installation Check (0x00): + * bit 0: APM_16_BIT_SUPPORT + * bit 1: APM_32_BIT_SUPPORT + * bit 2: APM_IDLE_SLOWS_CLOCK + * bit 3: APM_BIOS_DISABLED + * bit 4: APM_BIOS_DISENGAGED + * 3) AC line status + * 0x00: Off-line + * 0x01: On-line + * 0x02: On backup power (BIOS >= 1.1 only) + * 0xff: Unknown + * 4) Battery status + * 0x00: High + * 0x01: Low + * 0x02: Critical + * 0x03: Charging + * 0x04: Selected battery not present (BIOS >= 1.2 only) + * 0xff: Unknown + * 5) Battery flag + * bit 0: High + * bit 1: Low + * bit 2: Critical + * bit 3: Charging + * bit 7: No system battery + * 0xff: Unknown + * 6) Remaining battery life (percentage of charge): + * 0-100: valid + * -1: Unknown + * 7) Remaining battery life (time units): + * Number of remaining minutes or seconds + * -1: Unknown + * 8) min = minutes; sec = seconds + */ +static int apm_get_info(char *buf, char **start, off_t fpos, int length) +{ + struct apm_power_info info; + char *units; + int ret; + + info.ac_line_status = 0xff; + info.battery_status = 0xff; + info.battery_flag = 0xff; + info.battery_life = -1; + info.time = -1; + info.units = -1; + + if (apm_get_power_status) + apm_get_power_status(&info); + + switch (info.units) { + default: units = "?"; break; + case 0: units = "min"; break; + case 1: units = "sec"; break; + } + + ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, APM_32_BIT_SUPPORT, + info.ac_line_status, info.battery_status, + info.battery_flag, info.battery_life, + info.time, units); + + return ret; +} +#endif + +static int kapmd(void *arg) +{ + daemonize("kapmd"); + current->flags |= PF_NOFREEZE; + + do { + apm_event_t event; + + wait_event_interruptible(kapmd_wait, + !queue_empty(&kapmd_queue) || !mips_apm_active); + + if (!mips_apm_active) + break; + + spin_lock_irq(&kapmd_queue_lock); + event = 0; + if (!queue_empty(&kapmd_queue)) + event = queue_get_event(&kapmd_queue); + spin_unlock_irq(&kapmd_queue_lock); + + switch (event) { + case 0: + break; + + case APM_LOW_BATTERY: + case APM_POWER_STATUS_CHANGE: + queue_event(event, NULL); + break; + + case APM_USER_SUSPEND: + case APM_SYS_SUSPEND: + queue_event(event, NULL); + if (suspends_pending == 0) + apm_suspend(); + break; + + case APM_CRITICAL_SUSPEND: + apm_suspend(); + break; + } + } while (1); + + complete_and_exit(&kapmd_exit, 0); +} + +static int __init apm_init(void) +{ + int ret; + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + return -ENODEV; + } + + mips_apm_active = 1; + + ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); + if (ret < 0) { + mips_apm_active = 0; + return ret; + } + +#ifdef CONFIG_PROC_FS + create_proc_info_entry("apm", 0, NULL, apm_get_info); +#endif + + ret = misc_register(&apm_device); + if (ret != 0) { + remove_proc_entry("apm", NULL); + + mips_apm_active = 0; + wake_up(&kapmd_wait); + wait_for_completion(&kapmd_exit); + } + + return ret; +} + +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + mips_apm_active = 0; + wake_up(&kapmd_wait); + wait_for_completion(&kapmd_exit); +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Stephen Rothwell"); +MODULE_DESCRIPTION("Advanced Power Management"); +MODULE_LICENSE("GPL"); + +#ifndef MODULE +static int __init apm_setup(char *str) +{ + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + apm_disabled = 1; + if (strncmp(str, "on", 2) == 0) + apm_disabled = 0; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("apm=", apm_setup); +#endif + +/** + * apm_queue_event - queue an APM event for kapmd + * @event: APM event + * + * Queue an APM event for kapmd to process and ultimately take the + * appropriate action. Only a subset of events are handled: + * %APM_LOW_BATTERY + * %APM_POWER_STATUS_CHANGE + * %APM_USER_SUSPEND + * %APM_SYS_SUSPEND + * %APM_CRITICAL_SUSPEND + */ +void apm_queue_event(apm_event_t event) +{ + unsigned long flags; + + spin_lock_irqsave(&kapmd_queue_lock, flags); + queue_add_event(&kapmd_queue, event); + spin_unlock_irqrestore(&kapmd_queue_lock, flags); + + wake_up_interruptible(&kapmd_wait); +} +EXPORT_SYMBOL(apm_queue_event); diff --git a/include/asm-mips/apm.h b/include/asm-mips/apm.h new file mode 100644 index 000000000000..e8c69208f63a --- /dev/null +++ b/include/asm-mips/apm.h @@ -0,0 +1,65 @@ +/* -*- linux-c -*- + * + * (C) 2003 zecke@handhelds.org + * + * GPL version 2 + * + * based on arch/arm/kernel/apm.c + * factor out the information needed by architectures to provide + * apm status + * + * + */ +#ifndef MIPS_ASM_SA1100_APM_H +#define MIPS_ASM_SA1100_APM_H + +#include +#include + +/* + * This structure gets filled in by the machine specific 'get_power_status' + * implementation. Any fields which are not set default to a safe value. + */ +struct apm_power_info { + unsigned char ac_line_status; +#define APM_AC_OFFLINE 0 +#define APM_AC_ONLINE 1 +#define APM_AC_BACKUP 2 +#define APM_AC_UNKNOWN 0xff + + unsigned char battery_status; +#define APM_BATTERY_STATUS_HIGH 0 +#define APM_BATTERY_STATUS_LOW 1 +#define APM_BATTERY_STATUS_CRITICAL 2 +#define APM_BATTERY_STATUS_CHARGING 3 +#define APM_BATTERY_STATUS_NOT_PRESENT 4 +#define APM_BATTERY_STATUS_UNKNOWN 0xff + + unsigned char battery_flag; +#define APM_BATTERY_FLAG_HIGH (1 << 0) +#define APM_BATTERY_FLAG_LOW (1 << 1) +#define APM_BATTERY_FLAG_CRITICAL (1 << 2) +#define APM_BATTERY_FLAG_CHARGING (1 << 3) +#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7) +#define APM_BATTERY_FLAG_UNKNOWN 0xff + + int battery_life; + int time; + int units; +#define APM_UNITS_MINS 0 +#define APM_UNITS_SECS 1 +#define APM_UNITS_UNKNOWN -1 + +}; + +/* + * This allows machines to provide their own "apm get power status" function. + */ +extern void (*apm_get_power_status)(struct apm_power_info *); + +/* + * Queue an event (APM_SYS_SUSPEND or APM_CRITICAL_SUSPEND) + */ +void apm_queue_event(apm_event_t event); + +#endif -- cgit v1.2.3 From e53639d8f313974a87540015cbb0832905be6056 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Jun 2006 09:13:56 +0100 Subject: [MIPS] Consolidate definitions of pfn_valid in one file. Signed-off-by: Ralf Baechle --- include/asm-mips/mmzone.h | 8 -------- include/asm-mips/page.h | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h index 7bde4432092b..79f4491403b6 100644 --- a/include/asm-mips/mmzone.h +++ b/include/asm-mips/mmzone.h @@ -14,14 +14,6 @@ #define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr)) #define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT) -#define pfn_valid(pfn) \ -({ \ - unsigned long __pfn = (pfn); \ - int __n = pfn_to_nid(__pfn); \ - ((__n >= 0) ? (__pfn < NODE_DATA(__n)->node_start_pfn + \ - NODE_DATA(__n)->node_spanned_pages) : 0);\ -}) - /* XXX: FIXME -- wli */ #define kern_addr_valid(addr) (0) diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index 4035ec79ecd4..3d262c01521c 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -145,6 +145,25 @@ typedef struct { unsigned long pgprot; } pgprot_t; #endif #endif +#ifdef CONFIG_FLATMEM + +#define pfn_valid(pfn) ((pfn) < max_mapnr) + +#elif defined(CONFIG_NEED_MULTIPLE_NODES) + +#define pfn_valid(pfn) \ +({ \ + unsigned long __pfn = (pfn); \ + int __n = pfn_to_nid(__pfn); \ + ((__n >= 0) ? (__pfn < NODE_DATA(__n)->node_start_pfn + \ + NODE_DATA(__n)->node_spanned_pages) \ + : 0); \ +}) + +#else +#error Provide a definition of pfn_valid +#endif + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -- cgit v1.2.3 From d9b8d0da404cf952a425d990c37c29c166eec954 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Jun 2006 12:20:09 +0100 Subject: [MIPS] Drop 0 definition for kern_addr_valid kern_addr_valid is currently only being used in kmem_ptr_validate which is making some vague attempt at verfying the validity of an address. Only IA-64, PARISC and x86-64 actually make some actual effort to verify the validity of the pointer. Most architecture definitions of kern_addr_valid() just define it as 1; the Alpha and CONFIG_DISCONTIGMEM on i386 and MIPS even as 0; the 0-definition will result in kmem_ptr_validate always failing which in turn will cause d_validate to always fail. d_validate's only two users are smbfs and ncpfs, so the 0 definition ended breaking those ... Signed-off-by: Ralf Baechle --- include/asm-mips/mmzone.h | 3 --- include/asm-mips/pgtable.h | 2 -- 2 files changed, 5 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h index 79f4491403b6..f6bd2e0c45a1 100644 --- a/include/asm-mips/mmzone.h +++ b/include/asm-mips/mmzone.h @@ -14,9 +14,6 @@ #define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr)) #define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT) -/* XXX: FIXME -- wli */ -#define kern_addr_valid(addr) (0) - #endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_MMZONE_H_ */ diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index d0af2a3b0152..be75cca20e8d 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -379,9 +379,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, __update_cache(vma, address, pte); } -#ifndef CONFIG_NEED_MULTIPLE_NODES #define kern_addr_valid(addr) (1) -#endif #ifdef CONFIG_64BIT_PHYS_ADDR extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot); -- cgit v1.2.3 From 09866258612bd9f389b0d86b3a63fe98e855d3f0 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 14 Jun 2006 08:01:30 +0100 Subject: [MIPS] IP27: Throw away old unused hacks. Signed-off-by: Ralf Baechle --- include/asm-mips/sn/sn0/ip27.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'include') diff --git a/include/asm-mips/sn/sn0/ip27.h b/include/asm-mips/sn/sn0/ip27.h index ade0e974dd78..3c97e0855c8d 100644 --- a/include/asm-mips/sn/sn0/ip27.h +++ b/include/asm-mips/sn/sn0/ip27.h @@ -6,7 +6,7 @@ * Derived from IRIX . * * Copyright (C) 1992 - 1997, 1999 Silicon Graphics, Inc. - * Copyright (C) 1999 by Ralf Baechle + * Copyright (C) 1999, 2006 by Ralf Baechle */ #ifndef _ASM_SN_SN0_IP27_H #define _ASM_SN_SN0_IP27_H @@ -82,11 +82,4 @@ #define SEND_NMI(_nasid, _slice) \ REMOTE_HUB_S((_nasid), (PI_NMI_A + ((_slice) * PI_NMI_OFFSET)), 1) -/* Sanity hazzard ... Below all the Origin hacks are following. */ - -#define SN00_BRIDGE 0x9200000008000000 -#define SN00I_BRIDGE0 0x920000000b000000 -#define SN00I_BRIDGE1 0x920000000e000000 -#define SN00I_BRIDGE2 0x920000000f000000 - #endif /* _ASM_SN_SN0_IP27_H */ -- cgit v1.2.3 From f456acae4fe9b4504db7d75c51fba6b8db787ee2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 14 Jun 2006 08:10:35 +0100 Subject: [MIPS] IP27: Cleanup N/M mode configuration. Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/Kconfig | 25 ++++++++++++++++++++----- include/asm-mips/sn/sn0/arch.h | 4 ++-- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/mips/sgi-ip27/Kconfig b/arch/mips/sgi-ip27/Kconfig index 4b7c3c675174..f14ef38646d0 100644 --- a/arch/mips/sgi-ip27/Kconfig +++ b/arch/mips/sgi-ip27/Kconfig @@ -4,14 +4,29 @@ # This options adds support for userspace processes upto 16TB size. # Normally the limit is just .5TB. +choice + prompt "Node addressing mode" + depends on SGI_IP27 + default SGI_SN_M_MODE + +config SGI_SN_M_MODE + bool "IP27 M-Mode" + help + The nodes of Origin, Onyx, Fuel and Tezro systems can be configured + in either N-Modes which allows for more nodes or M-Mode which allows + for more memory. Your hardware is almost certainly running in + M-Mode, so choose M-mode here. + config SGI_SN_N_MODE bool "IP27 N-Mode" - depends on SGI_IP27 + depends on EXPERIMENTAL help - The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be - configured in either N-Modes which allows for more nodes or M-Mode - which allows for more memory. Your system is most probably - running in M-Mode, so you should say N here. + The nodes of Origin, Onyx, Fuel and Tezro systems can be configured + in either N-Modes which allows for more nodes or M-Mode which allows + for more memory. Your hardware is almost certainly running in + M-Mode, so choose M-mode here. + +endchoice config MAPPED_KERNEL bool "Mapped kernel support" diff --git a/include/asm-mips/sn/sn0/arch.h b/include/asm-mips/sn/sn0/arch.h index 0ecbaa0d3837..f7c43fa24aa8 100644 --- a/include/asm-mips/sn/sn0/arch.h +++ b/include/asm-mips/sn/sn0/arch.h @@ -59,9 +59,9 @@ */ #ifdef CONFIG_SGI_SN_N_MODE #define MAX_MEM_SLOTS 16 /* max slots per node */ -#else /* !CONFIG_SGI_SN_N_MODE, assume M_MODE */ +#else /* !CONFIG_SGI_SN_N_MODE, assume CONFIG_SGI_SN_M_MODE */ #define MAX_MEM_SLOTS 32 /* max slots per node */ -#endif /* defined(N_MODE) */ +#endif /* CONFIG_SGI_SN_M_MODE */ #define SLOT_SHIFT (27) #define SLOT_MIN_MEM_SIZE (32*1024*1024) -- cgit v1.2.3 From 7ab2dc41d15f31e9d5472e46148337b4cf7c941c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 17 Jun 2006 14:55:40 +0100 Subject: [MIPS] SN: Declare bridge_pci_ops. Signed-off-by: Ralf Baechle --- include/asm-mips/pci/bridge.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-mips/pci/bridge.h b/include/asm-mips/pci/bridge.h index b4ee995c56e6..2bb1fca66136 100644 --- a/include/asm-mips/pci/bridge.h +++ b/include/asm-mips/pci/bridge.h @@ -848,4 +848,6 @@ struct bridge_controller { extern void register_bridge_irq(unsigned int irq); extern int request_bridge_irq(struct bridge_controller *bc); +extern struct pci_ops bridge_pci_ops; + #endif /* _ASM_PCI_BRIDGE_H */ -- cgit v1.2.3 From 2925aba4223f4532e85f0c6f64584b3e0b2849c3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 18 Jun 2006 01:32:22 +0100 Subject: [MIPS] Cleanup memory managment initialization. Historically plat_mem_setup did the entire platform initialization. This was rather impractical because it meant plat_mem_setup had to get away without any kind of memory allocator. To keep old code from breaking plat_setup was just renamed to plat_setup and a second platform initialization hook for anything else was introduced. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/setup.c | 2 +- arch/mips/cobalt/setup.c | 2 +- arch/mips/ddb5xxx/ddb5074/setup.c | 2 +- arch/mips/ddb5xxx/ddb5476/setup.c | 2 +- arch/mips/ddb5xxx/ddb5477/setup.c | 2 +- arch/mips/dec/setup.c | 2 +- arch/mips/galileo-boards/ev96100/setup.c | 2 +- arch/mips/gt64120/ev64120/setup.c | 2 +- arch/mips/gt64120/momenco_ocelot/setup.c | 2 +- arch/mips/ite-boards/generic/it8172_setup.c | 2 +- arch/mips/jazz/setup.c | 2 +- arch/mips/jmr3927/rbhma3100/setup.c | 2 +- arch/mips/kernel/setup.c | 56 ++++++++++++++++++++++------- arch/mips/lasat/setup.c | 2 +- arch/mips/mips-boards/atlas/atlas_setup.c | 2 +- arch/mips/mips-boards/malta/malta_setup.c | 2 +- arch/mips/mips-boards/sead/sead_setup.c | 2 +- arch/mips/mips-boards/sim/sim_setup.c | 2 +- arch/mips/momentum/jaguar_atx/setup.c | 2 +- arch/mips/momentum/ocelot_3/setup.c | 2 +- arch/mips/momentum/ocelot_c/setup.c | 2 +- arch/mips/momentum/ocelot_g/setup.c | 2 +- arch/mips/philips/pnx8550/common/setup.c | 2 +- arch/mips/pmc-sierra/yosemite/setup.c | 2 +- arch/mips/qemu/q-setup.c | 2 +- arch/mips/sgi-ip22/ip22-setup.c | 2 +- arch/mips/sgi-ip27/ip27-init.c | 2 +- arch/mips/sgi-ip32/ip32-setup.c | 2 +- arch/mips/sibyte/swarm/setup.c | 2 +- arch/mips/sni/setup.c | 2 +- arch/mips/tx4927/common/tx4927_setup.c | 2 +- arch/mips/tx4938/common/setup.c | 2 +- arch/mips/vr41xx/common/init.c | 2 +- include/asm-mips/bootinfo.h | 6 ++++ 34 files changed, 81 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index eb6026ef1cbb..97165b6b3894 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -55,7 +55,7 @@ extern void au1xxx_time_init(void); extern void au1xxx_timer_setup(struct irqaction *irq); extern void set_cpuspec(void); -void __init plat_setup(void) +void __init plat_mem_setup(void) { struct cpu_spec *sp; char *argptr; diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 928431a9bcb0..ca719d6398bd 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -120,7 +120,7 @@ static struct pci_controller cobalt_pci_controller = { .io_offset = 0 - GT64111_IO_BASE }; -void __init plat_setup(void) +void __init plat_mem_setup(void) { static struct uart_port uart; unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0); diff --git a/arch/mips/ddb5xxx/ddb5074/setup.c b/arch/mips/ddb5xxx/ddb5074/setup.c index 91456b068c2e..4882ad1052e7 100644 --- a/arch/mips/ddb5xxx/ddb5074/setup.c +++ b/arch/mips/ddb5xxx/ddb5074/setup.c @@ -86,7 +86,7 @@ static void __init ddb_time_init(void) -void __init plat_setup(void) +void __init plat_mem_setup(void) { set_io_port_base(NILE4_PCI_IO_BASE); isa_slot_offset = NILE4_PCI_MEM_BASE; diff --git a/arch/mips/ddb5xxx/ddb5476/setup.c b/arch/mips/ddb5xxx/ddb5476/setup.c index fc8d8bb4849c..101021afb2e4 100644 --- a/arch/mips/ddb5xxx/ddb5476/setup.c +++ b/arch/mips/ddb5xxx/ddb5476/setup.c @@ -150,7 +150,7 @@ static struct { static void ddb5476_board_init(void); -void __init plat_setup(void) +void __init plat_mem_setup(void) { set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE)); diff --git a/arch/mips/ddb5xxx/ddb5477/setup.c b/arch/mips/ddb5xxx/ddb5477/setup.c index 2f566034cc44..93167ecdb424 100644 --- a/arch/mips/ddb5xxx/ddb5477/setup.c +++ b/arch/mips/ddb5xxx/ddb5477/setup.c @@ -171,7 +171,7 @@ static void ddb5477_board_init(void); extern struct pci_controller ddb5477_ext_controller; extern struct pci_controller ddb5477_io_controller; -void __init plat_setup(void) +void __init plat_mem_setup(void) { /* initialize board - we don't trust the loader */ ddb5477_board_init(); diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index ad5d436d80c1..9c707b9ceb65 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -147,7 +147,7 @@ static void __init dec_be_init(void) extern void dec_time_init(void); extern void dec_timer_setup(struct irqaction *); -void __init plat_setup(void) +void __init plat_mem_setup(void) { board_be_init = dec_be_init; board_time_init = dec_time_init; diff --git a/arch/mips/galileo-boards/ev96100/setup.c b/arch/mips/galileo-boards/ev96100/setup.c index 78dbb18edeb8..a04aea6123da 100644 --- a/arch/mips/galileo-boards/ev96100/setup.c +++ b/arch/mips/galileo-boards/ev96100/setup.c @@ -55,7 +55,7 @@ extern void mips_reboot_setup(void); unsigned char mac_0_1[12]; -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned int config = read_c0_config(); unsigned int status = read_c0_status(); diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c index 6d859d1e7a2d..4236da31ecc6 100644 --- a/arch/mips/gt64120/ev64120/setup.c +++ b/arch/mips/gt64120/ev64120/setup.c @@ -71,7 +71,7 @@ unsigned long __init prom_free_prom_memory(void) */ extern void gt64120_time_init(void); -void __init plat_setup(void) +void __init plat_mem_setup(void) { _machine_restart = galileo_machine_restart; _machine_halt = galileo_machine_halt; diff --git a/arch/mips/gt64120/momenco_ocelot/setup.c b/arch/mips/gt64120/momenco_ocelot/setup.c index 20b65d3d2151..1193a22c4693 100644 --- a/arch/mips/gt64120/momenco_ocelot/setup.c +++ b/arch/mips/gt64120/momenco_ocelot/setup.c @@ -152,7 +152,7 @@ void PMON_v2_setup() gt64120_base = 0xe0000000; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { void (*l3func)(unsigned long)=KSEG1ADDR(&setup_l3cache); unsigned int tmpword; diff --git a/arch/mips/ite-boards/generic/it8172_setup.c b/arch/mips/ite-boards/generic/it8172_setup.c index 00844e621e5f..da6ae0991199 100644 --- a/arch/mips/ite-boards/generic/it8172_setup.c +++ b/arch/mips/ite-boards/generic/it8172_setup.c @@ -154,7 +154,7 @@ void __init it8172_init_ram_resource(unsigned long memsize) it8172_resources.ram.end = memsize; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned short dsr; char *argptr; diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 4036dc434551..c8d0df7d0c36 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -52,7 +52,7 @@ static struct resource jazz_io_resources[] = { { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, }; -void __init plat_setup(void) +void __init plat_mem_setup(void) { int i; diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 1f136551f2ac..308e6cdcd245 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -238,7 +238,7 @@ static void jmr3927_board_init(void); extern struct resource pci_io_resource; extern struct resource pci_mem_resource; -void __init plat_setup(void) +void __init plat_mem_setup(void) { char *argptr; diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 397a70e651b5..bfcec8d9bfe4 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -442,6 +442,48 @@ static inline void bootmem_init(void) #endif /* CONFIG_BLK_DEV_INITRD */ } +/* + * arch_mem_init - initialize memory managment subsystem + * + * o plat_mem_setup() detects the memory configuration and will record detected + * memory areas using add_memory_region. + * o parse_cmdline_early() parses the command line for mem= options which, + * iff detected, will override the results of the automatic detection. + * + * At this stage the memory configuration of the system is known to the + * kernel but generic memory managment system is still entirely uninitialized. + * + * o bootmem_init() + * o sparse_init() + * o paging_init() + * + * At this stage the bootmem allocator is ready to use. + * + * NOTE: historically plat_mem_setup did the entire platform initialization. + * This was rather impractical because it meant plat_mem_setup had to + * get away without any kind of memory allocator. To keep old code from + * breaking plat_setup was just renamed to plat_setup and a second platform + * initialization hook for anything else was introduced. + */ + +extern void plat_mem_setup(void); + +static void __init arch_mem_init(char **cmdline_p) +{ + /* call board setup routine */ + plat_mem_setup(); + + strlcpy(command_line, arcs_cmdline, sizeof(command_line)); + strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + + *cmdline_p = command_line; + + parse_cmdline_early(); + bootmem_init(); + sparse_init(); + paging_init(); +} + static inline void resource_init(void) { int i; @@ -495,8 +537,6 @@ static inline void resource_init(void) #undef MAXMEM #undef MAXMEM_PFN -extern void plat_setup(void); - void __init setup_arch(char **cmdline_p) { cpu_probe(); @@ -511,18 +551,8 @@ void __init setup_arch(char **cmdline_p) #endif #endif - /* call board setup routine */ - plat_setup(); + arch_mem_init(cmdline_p); - strlcpy(command_line, arcs_cmdline, sizeof(command_line)); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - - *cmdline_p = command_line; - - parse_cmdline_early(); - bootmem_init(); - sparse_init(); - paging_init(); resource_init(); #ifdef CONFIG_SMP plat_smp_setup(); diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c index bb70a8240e61..3f64277429e4 100644 --- a/arch/mips/lasat/setup.c +++ b/arch/mips/lasat/setup.c @@ -155,7 +155,7 @@ void __init serial_init(void) } #endif -void __init plat_setup(void) +void __init plat_mem_setup(void) { int i; lasat_misc = &lasat_misc_info[mips_machtype]; diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index c20d401ecf80..8cc9effcb832 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -50,7 +50,7 @@ const char *get_system_type(void) return "MIPS Atlas"; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { mips_pcibios_init(); diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index ae1de3dc71ed..0766e434b6bd 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -111,7 +111,7 @@ void __init fd_activate(void) } #endif -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned int i; diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c index 4266ce445174..6430f11f3a95 100644 --- a/arch/mips/mips-boards/sead/sead_setup.c +++ b/arch/mips/mips-boards/sead/sead_setup.c @@ -45,7 +45,7 @@ const char *get_system_type(void) return "MIPS SEAD"; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { ioport_resource.end = 0x7fffffff; diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c index a2fd62997ca3..15a5dac4ae19 100644 --- a/arch/mips/mips-boards/sim/sim_setup.c +++ b/arch/mips/mips-boards/sim/sim_setup.c @@ -50,7 +50,7 @@ const char *get_system_type(void) return "MIPSsim"; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { set_io_port_base(0xbfd00000); diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c index 1379c76845dc..df1485501ce6 100644 --- a/arch/mips/momentum/jaguar_atx/setup.c +++ b/arch/mips/momentum/jaguar_atx/setup.c @@ -359,7 +359,7 @@ static __init int __init ja_pci_init(void) arch_initcall(ja_pci_init); -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned int tmpword; diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c index c69195234309..8c53490ba6f1 100644 --- a/arch/mips/momentum/ocelot_3/setup.c +++ b/arch/mips/momentum/ocelot_3/setup.c @@ -313,7 +313,7 @@ static __init int __init ja_pci_init(void) arch_initcall(ja_pci_init); -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned int tmpword; diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c index a3e6f5575592..257e1d1b72dd 100644 --- a/arch/mips/momentum/ocelot_c/setup.c +++ b/arch/mips/momentum/ocelot_c/setup.c @@ -231,7 +231,7 @@ void momenco_time_init(void) rtc_mips_set_time = m48t37y_set_time; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { unsigned int tmpword; diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c index fed4e8eee116..72143ab1e900 100644 --- a/arch/mips/momentum/ocelot_g/setup.c +++ b/arch/mips/momentum/ocelot_g/setup.c @@ -162,7 +162,7 @@ static void __init setup_l3cache(unsigned long size) printk("Done\n"); } -void __init plat_setup(void) +void __init plat_mem_setup(void) { void (*l3func)(unsigned long) = (void *) KSEG1ADDR(setup_l3cache); unsigned int tmpword; diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c index 2b199f338080..0e791f4f6ea3 100644 --- a/arch/mips/philips/pnx8550/common/setup.c +++ b/arch/mips/philips/pnx8550/common/setup.c @@ -99,7 +99,7 @@ unsigned long get_system_mem_size(void) int pnx8550_console_port = -1; -void __init plat_setup(void) +void __init plat_mem_setup(void) { int i; char* argptr; diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 3f724d661bdb..aa0d6ff3c6ec 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -218,7 +218,7 @@ static void __init py_late_time_init(void) py_rtc_setup(); } -void __init plat_setup(void) +void __init plat_mem_setup(void) { board_time_init = yosemite_time_init; late_time_init = py_late_time_init; diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c index f27155bc2d9a..e100d6072e31 100644 --- a/arch/mips/qemu/q-setup.c +++ b/arch/mips/qemu/q-setup.c @@ -20,7 +20,7 @@ static void __init qemu_timer_setup(struct irqaction *irq) setup_irq(0, irq); } -void __init plat_setup(void) +void __init plat_mem_setup(void) { set_io_port_base(QEMU_PORT_BASE); board_timer_setup = qemu_timer_setup; diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index 7018e1833e85..d7138906eb10 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -53,7 +53,7 @@ EXPORT_SYMBOL(ip22_do_break); extern void ip22_be_init(void) __init; extern void ip22_time_init(void) __init; -void __init plat_setup(void) +void __init plat_mem_setup(void) { char *ctype; char *cserial; diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 16c4b3410eaf..a6b490e99709 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -196,7 +196,7 @@ extern void ip27_setup_console(void); extern void ip27_time_init(void); extern void ip27_reboot_setup(void); -void __init plat_setup(void) +void __init plat_mem_setup(void) { hubreg_t p, e, n_mode; nasid_t nid; diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index a2dd8ae1ea8f..acbdad06fac1 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -87,7 +87,7 @@ void __init ip32_timer_setup(struct irqaction *irq) setup_irq(IP32_R4K_TIMER_IRQ, irq); } -void __init plat_setup(void) +void __init plat_mem_setup(void) { board_be_init = ip32_be_init; diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 4b5f74ff3edd..7f646bc0719c 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -103,7 +103,7 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup) return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); } -void __init plat_setup(void) +void __init plat_mem_setup(void) { #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) bcm1480_setup(); diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index c33cb9d1e18d..635b904cabd7 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -252,7 +252,7 @@ static inline void sni_pcimt_time_init(void) rtc_mips_set_time = mc146818_set_rtc_mmss; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { sni_pcimt_detect(); sni_pcimt_sc_init(); diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c index 77c3b66fb959..81a5acfe8c42 100644 --- a/arch/mips/tx4927/common/tx4927_setup.c +++ b/arch/mips/tx4927/common/tx4927_setup.c @@ -64,7 +64,7 @@ static void tx4927_write_buffer_flush(void) } -void __init plat_setup(void) +void __init plat_mem_setup(void) { board_time_init = tx4927_time_init; board_timer_setup = tx4927_timer_setup; diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c index fc992953bf95..ef59a5cffc69 100644 --- a/arch/mips/tx4938/common/setup.c +++ b/arch/mips/tx4938/common/setup.c @@ -61,7 +61,7 @@ tx4938_write_buffer_flush(void) } void __init -plat_setup(void) +plat_mem_setup(void) { board_time_init = tx4938_time_init; board_timer_setup = tx4938_timer_setup; diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index 707bd0933eed..915bfa5c0719 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c @@ -58,7 +58,7 @@ static void __init timer_init(void) board_timer_setup = setup_timer_irq; } -void __init plat_setup(void) +void __init plat_mem_setup(void) { vr41xx_calculate_clock_frequency(); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 14fc88f27226..edf2b9a71c82 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -258,4 +258,10 @@ extern char arcs_cmdline[CL_SIZE]; * Registers a0, a1, a3 and a4 as passed to the kenrel entry by firmware */ extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; + +/* + * Platform memory detection hook called by setup_arch + */ +extern void plat_mem_setup(void); + #endif /* _ASM_BOOTINFO_H */ -- cgit v1.2.3 From eaff3888742155bd397e45a1c3323c0173042e5b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 18 Jun 2006 04:58:57 +0100 Subject: [MIPS] Remove support for NEC DDB5074. As warned several times before. Signed-off-by: Ralf Baechle --- Documentation/feature-removal-schedule.txt | 2 +- arch/mips/Kconfig | 18 -- arch/mips/Makefile | 6 - arch/mips/configs/atlas_defconfig | 1 - arch/mips/configs/bigsur_defconfig | 1 - arch/mips/configs/capcella_defconfig | 1 - arch/mips/configs/cobalt_defconfig | 1 - arch/mips/configs/db1000_defconfig | 1 - arch/mips/configs/db1100_defconfig | 1 - arch/mips/configs/db1200_defconfig | 1 - arch/mips/configs/db1500_defconfig | 1 - arch/mips/configs/db1550_defconfig | 1 - arch/mips/configs/ddb5476_defconfig | 1 - arch/mips/configs/ddb5477_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/e55_defconfig | 1 - arch/mips/configs/ev64120_defconfig | 1 - arch/mips/configs/ev96100_defconfig | 1 - arch/mips/configs/ip22_defconfig | 1 - arch/mips/configs/ip27_defconfig | 1 - arch/mips/configs/ip32_defconfig | 1 - arch/mips/configs/it8172_defconfig | 1 - arch/mips/configs/ivr_defconfig | 1 - arch/mips/configs/jaguar-atx_defconfig | 1 - arch/mips/configs/jmr3927_defconfig | 1 - arch/mips/configs/lasat200_defconfig | 1 - arch/mips/configs/malta_defconfig | 1 - arch/mips/configs/mipssim_defconfig | 1 - arch/mips/configs/mpc30x_defconfig | 1 - arch/mips/configs/ocelot_3_defconfig | 1 - arch/mips/configs/ocelot_c_defconfig | 1 - arch/mips/configs/ocelot_defconfig | 1 - arch/mips/configs/ocelot_g_defconfig | 1 - arch/mips/configs/pb1100_defconfig | 1 - arch/mips/configs/pb1500_defconfig | 1 - arch/mips/configs/pb1550_defconfig | 1 - arch/mips/configs/pnx8550-jbs_defconfig | 1 - arch/mips/configs/pnx8550-v2pci_defconfig | 1 - arch/mips/configs/qemu_defconfig | 1 - arch/mips/configs/rbhma4500_defconfig | 1 - arch/mips/configs/rm200_defconfig | 1 - arch/mips/configs/sb1250-swarm_defconfig | 1 - arch/mips/configs/sead_defconfig | 1 - arch/mips/configs/tb0226_defconfig | 1 - arch/mips/configs/tb0229_defconfig | 1 - arch/mips/configs/tb0287_defconfig | 1 - arch/mips/configs/workpad_defconfig | 1 - arch/mips/configs/wrppmc_defconfig | 1 - arch/mips/configs/yosemite_defconfig | 1 - arch/mips/ddb5xxx/common/prom.c | 5 +- arch/mips/ddb5xxx/ddb5074/Makefile | 8 - arch/mips/ddb5xxx/ddb5074/irq.c | 169 ---------------- arch/mips/ddb5xxx/ddb5074/nile4_pic.c | 286 ---------------------------- arch/mips/ddb5xxx/ddb5074/setup.c | 234 ----------------------- arch/mips/defconfig | 1 - arch/mips/pci/Makefile | 1 - arch/mips/pci/fixup-ddb5074.c | 21 -- arch/mips/pci/ops-ddb5074.c | 271 -------------------------- arch/mips/pci/pci-ddb5074.c | 79 -------- include/asm-mips/ddb5074.h | 11 -- include/asm-mips/ddb5xxx/ddb5074.h | 38 ---- include/asm-mips/ddb5xxx/ddb5xxx.h | 9 +- include/asm-mips/mach-ddb5074/mc146818rtc.h | 31 --- 63 files changed, 3 insertions(+), 1233 deletions(-) delete mode 100644 arch/mips/ddb5xxx/ddb5074/Makefile delete mode 100644 arch/mips/ddb5xxx/ddb5074/irq.c delete mode 100644 arch/mips/ddb5xxx/ddb5074/nile4_pic.c delete mode 100644 arch/mips/ddb5xxx/ddb5074/setup.c delete mode 100644 arch/mips/pci/fixup-ddb5074.c delete mode 100644 arch/mips/pci/ops-ddb5074.c delete mode 100644 arch/mips/pci/pci-ddb5074.c delete mode 100644 include/asm-mips/ddb5074.h delete mode 100644 include/asm-mips/ddb5xxx/ddb5074.h delete mode 100644 include/asm-mips/mach-ddb5074/mc146818rtc.h (limited to 'include') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 43ab119963d5..8fa7a384f250 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -212,7 +212,7 @@ Who: Greg Kroah-Hartman --------------------------- -What: Support for NEC DDB5074 and DDB5476 evaluation boards. +What: Support for NEC DDB5476 evaluation boards. When: June 2006 Why: Board specific code doesn't build anymore since ~2.6.0 and no users have complained indicating there is no more need for these diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ae33e0a4c18d..c3c8e7a15af3 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -469,24 +469,6 @@ config PNX8550_JBS select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN -config DDB5074 - bool "NEC DDB Vrc-5074 (EXPERIMENTAL)" - depends on EXPERIMENTAL - select DDB5XXX_COMMON - select DMA_NONCOHERENT - select HAVE_STD_PC_SERIAL_PORT - select HW_HAS_PCI - select IRQ_CPU - select I8259 - select ISA - select SYS_HAS_CPU_R5000 - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_LITTLE_ENDIAN - help - This enables support for the VR5000-based NEC DDB Vrc-5074 - evaluation board. - config DDB5476 bool "NEC DDB Vrc-5476" select DDB5XXX_COMMON diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 24a901cf5a45..8d1026cd0738 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -403,12 +403,6 @@ load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff80100000 # core-$(CONFIG_DDB5XXX_COMMON) += arch/mips/ddb5xxx/common/ -# -# NEC DDB Vrc-5074 -# -core-$(CONFIG_DDB5074) += arch/mips/ddb5xxx/ddb5074/ -load-$(CONFIG_DDB5074) += 0xffffffff80080000 - # # NEC DDB Vrc-5476 # diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig index 4b080bcb258f..7b6de36e5b74 100644 --- a/arch/mips/configs/atlas_defconfig +++ b/arch/mips/configs/atlas_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_ATLAS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index d85cda58d650..633cafe20418 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index ca0af1683a00..bd150ec8559f 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 7d269e609282..ad83025420ec 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_COBALT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index 579b665e3339..ba3c7b9464bf 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1000=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index e5eb53867422..321a4d00ce94 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index a43fb2329fd5..97471008f3ae 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1200=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index ad632d87c4ef..fbcc1738ff90 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1500=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index 8130e23dc255..d014cdd3e705 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1550=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig index 8d88ac1bbfeb..90cabf5419ad 100644 --- a/arch/mips/configs/ddb5476_defconfig +++ b/arch/mips/configs/ddb5476_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set CONFIG_DDB5476=y # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig index 8c911b671415..fc30ace3d737 100644 --- a/arch/mips/configs/ddb5477_defconfig +++ b/arch/mips/configs/ddb5477_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set CONFIG_DDB5477=y # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index d838496e114f..0775d7364cab 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -41,7 +41,6 @@ CONFIG_MACH_DECSTATION=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index 0760f4318910..8f9de1c3bf1e 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig index 7067f608b22c..b97c90fa5491 100644 --- a/arch/mips/configs/ev64120_defconfig +++ b/arch/mips/configs/ev64120_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_EV64120=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig index 00b56ed0e638..708b0d6896d8 100644 --- a/arch/mips/configs/ev96100_defconfig +++ b/arch/mips/configs/ev96100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_EV96100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 607e2985ffe3..f7b0beb5752f 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 87d27cd3d2cf..b4ae9cd15ba3 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 8f11d3565b2d..a95c2e847f68 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig index 757adf23853d..87c5cde49e59 100644 --- a/arch/mips/configs/it8172_defconfig +++ b/arch/mips/configs/it8172_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_ITE8172=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig index 021761a8a237..1346b683b287 100644 --- a/arch/mips/configs/ivr_defconfig +++ b/arch/mips/configs/ivr_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_IVR=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index 08f6c30b0abc..d2d1a7776362 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_JAGUAR_ATX=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index 38b1e026e10d..ba23db03ba95 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig index 4d25990a0a05..7500332c9b5c 100644 --- a/arch/mips/configs/lasat200_defconfig +++ b/arch/mips/configs/lasat200_defconfig @@ -41,7 +41,6 @@ CONFIG_LASAT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 977f52be51dc..1aac4901c57e 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_MALTA=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 00560e0143f1..011120c5033e 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_SIM=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index 286a018375b2..ca0baa29483c 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig index 1ce4310fd92a..a8d26596ca8e 100644 --- a/arch/mips/configs/ocelot_3_defconfig +++ b/arch/mips/configs/ocelot_3_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_3=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index 8a6aa5012f89..a1d6d7ff93fb 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_C=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig index f9ee35eeb762..4b72b0a2fb4b 100644 --- a/arch/mips/configs/ocelot_defconfig +++ b/arch/mips/configs/ocelot_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig index b48bdee2411f..232f13a41938 100644 --- a/arch/mips/configs/ocelot_g_defconfig +++ b/arch/mips/configs/ocelot_g_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_G=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 01aac40634b4..55da4eb76f7b 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 398c3c265b9f..348581d91b52 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1500=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index ea282a53bb66..897f76c0c8ab 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1550=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 4c57e564db0b..6289dfa73f2f 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set CONFIG_PNX8550_JBS=y -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index 3c8f35162fec..d8448fdb2514 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set CONFIG_PNX8550_V2PCI=y # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig index 4bcc01dea041..99c43c9f1595 100644 --- a/arch/mips/configs/qemu_defconfig +++ b/arch/mips/configs/qemu_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig index 3d441932e43a..c55e8e6ff207 100644 --- a/arch/mips/configs/rbhma4500_defconfig +++ b/arch/mips/configs/rbhma4500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index edfb9679a25a..6013c6533ca5 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index e388a3dae0a9..6b8441e18843 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig index 6b8a6a416a25..94d04f7a5e6b 100644 --- a/arch/mips/configs/sead_defconfig +++ b/arch/mips/configs/sead_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_SEAD=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index dba0bdcdcf29..f84864d8ec33 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index 5a924c1a5803..aeb1e85f9ce7 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index 9f215ea350dc..5f1ee08d9851 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index ac7765eb8da7..ebc25edbf73d 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index 1997b7c11ab4..03c880792163 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig @@ -42,7 +42,6 @@ CONFIG_WR_PPMC=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index b52d709de962..1c728f216fbd 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c index b8d1f7489f3b..18eecbcdfca8 100644 --- a/arch/mips/ddb5xxx/common/prom.c +++ b/arch/mips/ddb5xxx/common/prom.c @@ -56,10 +56,7 @@ void __init prom_init(void) mips_machgroup = MACH_GROUP_NEC_DDB; -#if defined(CONFIG_DDB5074) - mips_machtype = MACH_NEC_DDB5074; - add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); -#elif defined(CONFIG_DDB5476) +#if defined(CONFIG_DDB5476) mips_machtype = MACH_NEC_DDB5476; add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); #elif defined(CONFIG_DDB5477) diff --git a/arch/mips/ddb5xxx/ddb5074/Makefile b/arch/mips/ddb5xxx/ddb5074/Makefile deleted file mode 100644 index 304c02107b46..000000000000 --- a/arch/mips/ddb5xxx/ddb5074/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines -# under Linux. -# - -obj-y += setup.o irq.o nile4_pic.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/ddb5xxx/ddb5074/irq.c b/arch/mips/ddb5xxx/ddb5074/irq.c deleted file mode 100644 index 60c087b7738c..000000000000 --- a/arch/mips/ddb5xxx/ddb5074/irq.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * arch/mips/ddb5074/irq.c -- NEC DDB Vrc-5074 interrupt routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; - -#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ -#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ -#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ - -#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ -#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ -#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ - -#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ -#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ - -#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ -#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ - -#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ -#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ - - -static void m1543_irq_setup(void) -{ - /* - * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all - * the possible IO sources in the M1543 are in use by us. We will - * use the following mapping: - * - * IRQ1 - keyboard (default set by M1543) - * IRQ3 - reserved for UART B (default set by M1543) (note that - * the schematics for the DDB Vrc-5074 board seem to - * indicate that IRQ3 is connected to the DS1386 - * watchdog timer interrupt output so we might have - * a conflict) - * IRQ4 - reserved for UART A (default set by M1543) - * IRQ5 - parallel (default set by M1543) - * IRQ8 - DS1386 time of day (RTC) interrupt - * IRQ12 - mouse - */ - - /* - * Assing mouse interrupt to IRQ12 - */ - - /* Enter configuration mode */ - outb(0x51, M1543_PNP_CONFIG); - outb(0x23, M1543_PNP_CONFIG); - - /* Select logical device 7 (Keyboard) */ - outb(0x07, M1543_PNP_INDEX); - outb(0x07, M1543_PNP_DATA); - - /* Select IRQ12 */ - outb(0x72, M1543_PNP_INDEX); - outb(0x0c, M1543_PNP_DATA); - - outb(0x30, M1543_PNP_INDEX); - printk("device 7, 0x30: %02x\n",inb(M1543_PNP_DATA)); - - outb(0x70, M1543_PNP_INDEX); - printk("device 7, 0x70: %02x\n",inb(M1543_PNP_DATA)); - - /* Leave configration mode */ - outb(0xbb, M1543_PNP_CONFIG); - - -} - -static void ddb_local0_irqdispatch(struct pt_regs *regs) -{ - u32 mask; - int nile4_irq; - - mask = nile4_get_irq_stat(0); - - /* Handle the timer interrupt first */ -#if 0 - if (mask & (1 << NILE4_INT_GPT)) { - do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); - mask &= ~(1 << NILE4_INT_GPT); - } -#endif - for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) - if (mask & 1) { - if (nile4_irq == NILE4_INT_INTE) { - int i8259_irq; - - nile4_clear_irq(NILE4_INT_INTE); - i8259_irq = nile4_i8259_iack(); - do_IRQ(i8259_irq, regs); - } else - do_IRQ(nile4_to_irq(nile4_irq), regs); - - } -} - -static void ddb_local1_irqdispatch(void) -{ - printk("ddb_local1_irqdispatch called\n"); -} - -static void ddb_buserror_irq(void) -{ - printk("ddb_buserror_irq called\n"); -} - -static void ddb_8254timer_irq(void) -{ - printk("ddb_8254timer_irq called\n"); -} - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) -{ - unsigned int pending = read_c0_cause() & read_c0_status(); - - if (pending & CAUSEF_IP2) - ddb_local0_irqdispatch(regs); - else if (pending & CAUSEF_IP3) - ddb_local1_irqdispatch(); - else if (pending & CAUSEF_IP6) - ddb_buserror_irq(); - else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) - ddb_8254timer_irq(); -} - -void __init arch_init_irq(void) -{ - /* setup cascade interrupts */ - setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade); - setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade); - - nile4_irq_setup(NILE4_IRQ_BASE); - m1543_irq_setup(); - init_i8259_irqs(); - - - printk("CPU_IRQ_BASE: %d\n",CPU_IRQ_BASE); - - mips_cpu_irq_init(CPU_IRQ_BASE); - - printk("enabling 8259 cascade\n"); - - ddb5074_led_hex(0); - - /* Enable the interrupt cascade */ - nile4_enable_irq(NILE4_IRQ_BASE+IRQ_I8259_CASCADE); -} diff --git a/arch/mips/ddb5xxx/ddb5074/nile4_pic.c b/arch/mips/ddb5xxx/ddb5074/nile4_pic.c deleted file mode 100644 index 8743ffce8653..000000000000 --- a/arch/mips/ddb5xxx/ddb5074/nile4_pic.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * arch/mips/ddb5476/nile4.c -- - * low-level PIC code for NEC Vrc-5476 (Nile 4) - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - * - * Copyright 2001 MontaVista Software Inc. - * Author: jsun@mvista.com or jsun@junsun.net - * - */ -#include -#include -#include -#include -#include - -#include - -#include - -static int irq_base; - -/* - * Interrupt Programming - */ -void nile4_map_irq(int nile4_irq, int cpu_irq) -{ - u32 offset, t; - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = ddb_in32(offset); - t &= ~(7 << (nile4_irq * 4)); - t |= cpu_irq << (nile4_irq * 4); - ddb_out32(offset, t); -} - -void nile4_map_irq_all(int cpu_irq) -{ - u32 all, t; - - all = cpu_irq; - all |= all << 4; - all |= all << 8; - all |= all << 16; - t = ddb_in32(DDB_INTCTRL); - t &= 0x88888888; - t |= all; - ddb_out32(DDB_INTCTRL, t); - t = ddb_in32(DDB_INTCTRL + 4); - t &= 0x88888888; - t |= all; - ddb_out32(DDB_INTCTRL + 4, t); -} - -void nile4_enable_irq(unsigned int nile4_irq) -{ - u32 offset, t; - - nile4_irq-=irq_base; - - ddb5074_led_hex(8); - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - ddb5074_led_hex(9); - t = ddb_in32(offset); - ddb5074_led_hex(0xa); - t |= 8 << (nile4_irq * 4); - ddb_out32(offset, t); - ddb5074_led_hex(0xb); -} - -void nile4_disable_irq(unsigned int nile4_irq) -{ - u32 offset, t; - - nile4_irq-=irq_base; - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = ddb_in32(offset); - t &= ~(8 << (nile4_irq * 4)); - ddb_out32(offset, t); -} - -void nile4_disable_irq_all(void) -{ - ddb_out32(DDB_INTCTRL, 0); - ddb_out32(DDB_INTCTRL + 4, 0); -} - -u16 nile4_get_irq_stat(int cpu_irq) -{ - return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2); -} - -void nile4_enable_irq_output(int cpu_irq) -{ - u32 t; - - t = ddb_in32(DDB_INTSTAT1 + 4); - t |= 1 << (16 + cpu_irq); - ddb_out32(DDB_INTSTAT1, t); -} - -void nile4_disable_irq_output(int cpu_irq) -{ - u32 t; - - t = ddb_in32(DDB_INTSTAT1 + 4); - t &= ~(1 << (16 + cpu_irq)); - ddb_out32(DDB_INTSTAT1, t); -} - -void nile4_set_pci_irq_polarity(int pci_irq, int high) -{ - u32 t; - - t = ddb_in32(DDB_INTPPES); - if (high) - t &= ~(1 << (pci_irq * 2)); - else - t |= 1 << (pci_irq * 2); - ddb_out32(DDB_INTPPES, t); -} - -void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) -{ - u32 t; - - t = ddb_in32(DDB_INTPPES); - if (level) - t |= 2 << (pci_irq * 2); - else - t &= ~(2 << (pci_irq * 2)); - ddb_out32(DDB_INTPPES, t); -} - -void nile4_clear_irq(int nile4_irq) -{ - nile4_irq-=irq_base; - ddb_out32(DDB_INTCLR, 1 << nile4_irq); -} - -void nile4_clear_irq_mask(u32 mask) -{ - ddb_out32(DDB_INTCLR, mask); -} - -u8 nile4_i8259_iack(void) -{ - u8 irq; - u32 reg; - - /* Set window 0 for interrupt acknowledge */ - reg = ddb_in32(DDB_PCIINIT0); - - ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32); - irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); - /* restore window 0 for PCI I/O space */ - // ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); - ddb_out32(DDB_PCIINIT0, reg); - - /* i8269.c set the base vector to be 0x0 */ - return irq ; -} - -static unsigned int nile4_irq_startup(unsigned int irq) { - - nile4_enable_irq(irq); - return 0; - -} - -static void nile4_ack_irq(unsigned int irq) { - - ddb5074_led_hex(4); - - nile4_clear_irq(irq); - ddb5074_led_hex(2); - nile4_disable_irq(irq); - - ddb5074_led_hex(0); -} - -static void nile4_irq_end(unsigned int irq) { - - ddb5074_led_hex(3); - if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - ddb5074_led_hex(5); - nile4_enable_irq(irq); - ddb5074_led_hex(7); - } - - ddb5074_led_hex(1); -} - -#define nile4_irq_shutdown nile4_disable_irq - -static hw_irq_controller nile4_irq_controller = { - .typename = "nile4", - .startup = nile4_irq_startup, - .shutdown = nile4_irq_shutdown, - .enable = nile4_enable_irq, - .disable = nile4_disable_irq, - .ack = nile4_ack_irq, - .end = nile4_irq_end, -}; - -void nile4_irq_setup(u32 base) { - - int i; - - irq_base=base; - - /* Map all interrupts to CPU int #0 */ - nile4_map_irq_all(0); - - /* PCI INTA#-E# must be level triggered */ - nile4_set_pci_irq_level_or_edge(0, 1); - nile4_set_pci_irq_level_or_edge(1, 1); - nile4_set_pci_irq_level_or_edge(2, 1); - nile4_set_pci_irq_level_or_edge(3, 1); - nile4_set_pci_irq_level_or_edge(4, 1); - - /* PCI INTA#-D# must be active low, INTE# must be active high */ - nile4_set_pci_irq_polarity(0, 0); - nile4_set_pci_irq_polarity(1, 0); - nile4_set_pci_irq_polarity(2, 0); - nile4_set_pci_irq_polarity(3, 0); - nile4_set_pci_irq_polarity(4, 1); - - - for (i = 0; i < 16; i++) { - nile4_clear_irq(i); - nile4_disable_irq(i); - } - - /* Enable CPU int #0 */ - nile4_enable_irq_output(0); - - for (i= base; i< base + NUM_NILE4_INTERRUPTS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &nile4_irq_controller; - } -} - -#if defined(CONFIG_RUNTIME_DEBUG) -void nile4_dump_irq_status(void) -{ - printk(KERN_DEBUG " - CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4), - (void *) ddb_in32(DDB_CPUSTAT)); - printk(KERN_DEBUG " - INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4), - (void *) ddb_in32(DDB_INTCTRL)); - printk(KERN_DEBUG - "INTSTAT0 = %p:%p\n", - (void *) ddb_in32(DDB_INTSTAT0 + 4), - (void *) ddb_in32(DDB_INTSTAT0)); - printk(KERN_DEBUG - "INTSTAT1 = %p:%p\n", - (void *) ddb_in32(DDB_INTSTAT1 + 4), - (void *) ddb_in32(DDB_INTSTAT1)); - printk(KERN_DEBUG - "INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4), - (void *) ddb_in32(DDB_INTCLR)); - printk(KERN_DEBUG - "INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4), - (void *) ddb_in32(DDB_INTPPES)); -} - -#endif diff --git a/arch/mips/ddb5xxx/ddb5074/setup.c b/arch/mips/ddb5xxx/ddb5074/setup.c deleted file mode 100644 index 4882ad1052e7..000000000000 --- a/arch/mips/ddb5xxx/ddb5074/setup.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * arch/mips/ddb5074/setup.c -- NEC DDB Vrc-5074 setup routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; - -static void ddb_machine_restart(char *command) -{ - u32 t; - - /* PCI cold reset */ - t = nile4_in32(NILE4_PCICTRL + 4); - t |= 0x40000000; - nile4_out32(NILE4_PCICTRL + 4, t); - /* CPU cold reset */ - t = nile4_in32(NILE4_CPUSTAT); - t |= 1; - nile4_out32(NILE4_CPUSTAT, t); - /* Call the PROM */ - back_to_prom(); -} - -static void ddb_machine_halt(void) -{ - printk("DDB Vrc-5074 halted.\n"); - do { - } while (1); -} - -static void ddb_machine_power_off(void) -{ - printk("DDB Vrc-5074 halted. Please turn off the power.\n"); - do { - } while (1); -} - -extern void rtc_ds1386_init(unsigned long base); - -extern void (*board_timer_setup) (struct irqaction * irq); - -static void __init ddb_timer_init(struct irqaction *irq) -{ - /* set the clock to 1 Hz */ - nile4_out32(NILE4_T2CTRL, 1000000); - /* enable the General-Purpose Timer */ - nile4_out32(NILE4_T2CTRL + 4, 0x00000001); - /* reset timer */ - nile4_out32(NILE4_T2CNTR, 0); - /* enable interrupt */ - setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); - nile4_enable_irq(nile4_to_irq(NILE4_INT_GPT)); - change_c0_status(ST0_IM, - IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); - -} - -static void __init ddb_time_init(void) -{ - /* we have ds1396 RTC chip */ - rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE)); -} - - - -void __init plat_mem_setup(void) -{ - set_io_port_base(NILE4_PCI_IO_BASE); - isa_slot_offset = NILE4_PCI_MEM_BASE; - board_timer_setup = ddb_timer_init; - board_time_init = ddb_time_init; - - - _machine_restart = ddb_machine_restart; - _machine_halt = ddb_machine_halt; - pm_power_off = ddb_machine_power_off; - - ddb_out32(DDB_BAR0, 0); - - ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, 0x10); - ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE , 0x10); - - /* Reboot on panic */ - panic_timeout = 180; -} - -#define USE_NILE4_SERIAL 0 - -#if USE_NILE4_SERIAL -#define ns16550_in(reg) nile4_in8((reg)*8) -#define ns16550_out(reg, val) nile4_out8((reg)*8, (val)) -#else -#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) -static inline u8 ns16550_in(u32 reg) -{ - return *(volatile u8 *) (NS16550_BASE + reg); -} - -static inline void ns16550_out(u32 reg, u8 val) -{ - *(volatile u8 *) (NS16550_BASE + reg) = val; -} -#endif - -#define NS16550_RBR 0 -#define NS16550_THR 0 -#define NS16550_DLL 0 -#define NS16550_IER 1 -#define NS16550_DLM 1 -#define NS16550_FCR 2 -#define NS16550_IIR 2 -#define NS16550_LCR 3 -#define NS16550_MCR 4 -#define NS16550_LSR 5 -#define NS16550_MSR 6 -#define NS16550_SCR 7 - -#define NS16550_LSR_DR 0x01 /* Data ready */ -#define NS16550_LSR_OE 0x02 /* Overrun */ -#define NS16550_LSR_PE 0x04 /* Parity error */ -#define NS16550_LSR_FE 0x08 /* Framing error */ -#define NS16550_LSR_BI 0x10 /* Break */ -#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ -#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */ -#define NS16550_LSR_ERR 0x80 /* Error */ - - -void _serinit(void) -{ -#if USE_NILE4_SERIAL - ns16550_out(NS16550_LCR, 0x80); - ns16550_out(NS16550_DLM, 0x00); - ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ - ns16550_out(NS16550_LCR, 0x00); - ns16550_out(NS16550_LCR, 0x03); - ns16550_out(NS16550_FCR, 0x47); -#else - /* done by PMON */ -#endif -} - -void _putc(char c) -{ - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, c); - if (c == '\n') { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, '\r'); - } -} - -void _puts(const char *s) -{ - char c; - while ((c = *s++)) - _putc(c); -} - -char _getc(void) -{ - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); - return ns16550_in(NS16550_RBR); -} - -int _testc(void) -{ - return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; -} - - -/* - * Hexadecimal 7-segment LED - */ -void ddb5074_led_hex(int hex) -{ - outb(hex, 0x80); -} - - -/* - * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 - */ -struct pci_dev *pci_pmu = NULL; - -void ddb5074_led_d2(int on) -{ - u8 t; - - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0x7f; - else - t |= 0x80; - pci_write_config_byte(pci_pmu, 0x7e, t); - } -} - -void ddb5074_led_d3(int on) -{ - u8 t; - - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0xbf; - else - t |= 0x40; - pci_write_config_byte(pci_pmu, 0x7e, t); - } -} diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 607e2985ffe3..f7b0beb5752f 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5074 is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index bb6b6226a57a..d028197d8326 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o # # These are still pretty much in the old state, watch, go blind. # -obj-$(CONFIG_DDB5074) += fixup-ddb5074.o pci-ddb5074.o ops-ddb5074.o obj-$(CONFIG_DDB5476) += ops-ddb5476.o pci-ddb5476.o obj-$(CONFIG_DDB5477) += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o obj-$(CONFIG_LASAT) += pci-lasat.o diff --git a/arch/mips/pci/fixup-ddb5074.c b/arch/mips/pci/fixup-ddb5074.c deleted file mode 100644 index 5a4a7c239c42..000000000000 --- a/arch/mips/pci/fixup-ddb5074.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * It's nice to have the LEDs on the GPIO pins available for debugging - */ -static void ddb5074_fixup(struct pci_dev *dev) -{ - extern struct pci_dev *pci_pmu; - u8 t8; - - pci_pmu = dev; /* for LEDs D2 and D3 */ - /* Program the lines for LEDs D2 and D3 to output */ - pci_read_config_byte(dev, 0x7d, &t8); - t8 |= 0xc0; - pci_write_config_byte(dev, 0x7d, t8); - /* Turn LEDs D2 and D3 off */ - pci_read_config_byte(dev, 0x7e, &t8); - t8 |= 0xc0; - pci_write_config_byte(dev, 0x7e, t8); -} - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, - ddb5074_fixup); diff --git a/arch/mips/pci/ops-ddb5074.c b/arch/mips/pci/ops-ddb5074.c deleted file mode 100644 index 89f97bef4fc4..000000000000 --- a/arch/mips/pci/ops-ddb5074.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * arch/mips/ddb5xxx/ddb5476/pci_ops.c - * Define the pci_ops for DB5477. - * - * Much of the code is derived from the original DDB5074 port by - * Geert Uytterhoeven - * - * 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 - -/* - * config_swap structure records what set of pdar/pmr are used - * to access pci config space. It also provides a place hold the - * original values for future restoring. - */ -struct pci_config_swap { - u32 pdar; - u32 pmr; - u32 config_base; - u32 config_size; - u32 pdar_backup; - u32 pmr_backup; -}; - -/* - * On DDB5476, we have one set of swap registers - */ -struct pci_config_swap ext_pci_swap = { - DDB_PCIW0, - DDB_PCIINIT0, - DDB_PCI_CONFIG_BASE, - DDB_PCI_CONFIG_SIZE -}; - -static int pci_config_workaround = 1; - -/* - * access config space - */ -static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */ - u32 slot_num) -{ - u32 pci_addr = 0; - u32 pciinit_offset = 0; - u32 virt_addr = swap->config_base; - u32 option; - - if (pci_config_workaround) { - if (slot_num == 5) - slot_num = 14; - } else { - if (slot_num == 5) - return DDB_BASE + DDB_PCI_BASE; - } - - /* minimum pdar (window) size is 2MB */ - db_assert(swap->config_size >= (2 << 20)); - - db_assert(slot_num < (1 << 5)); - db_assert(bus < (1 << 8)); - - /* backup registers */ - swap->pdar_backup = ddb_in32(swap->pdar); - swap->pmr_backup = ddb_in32(swap->pmr); - - /* set the pdar (pci window) register */ - ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */ - 0, /* not on local memory bus */ - 0); /* not visible from PCI bus (N/A) */ - - /* - * calcuate the absolute pci config addr; - * according to the spec, we start scanning from adr:11 (0x800) - */ - if (bus == 0) { - /* type 0 config */ - pci_addr = 0x00040000 << slot_num; - } else { - /* type 1 config */ - pci_addr = 0x00040000 << slot_num; - panic - ("ddb_access_config_base: we don't support type 1 config Yet"); - } - - /* - * if pci_addr is less than pci config window size, we set - * pciinit_offset to 0 and adjust the virt_address. - * Otherwise we will try to adjust pciinit_offset. - */ - if (pci_addr < swap->config_size) { - virt_addr = KSEG1ADDR(swap->config_base + pci_addr); - pciinit_offset = 0; - } else { - db_assert((pci_addr & (swap->config_size - 1)) == 0); - virt_addr = KSEG1ADDR(swap->config_base); - pciinit_offset = pci_addr; - } - - /* set the pmr register */ - option = DDB_PCI_ACCESS_32; - if (bus != 0) - option |= DDB_PCI_CFGTYPE1; - ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option); - - return virt_addr; -} - -static inline void ddb_close_config_base(struct pci_config_swap *swap) -{ - ddb_out32(swap->pdar, swap->pdar_backup); - ddb_out32(swap->pmr, swap->pmr_backup); -} - -static int read_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u32 * val) -{ - u32 bus, slot_num, func_num; - u32 base; - - db_assert((where & 3) == 0); - db_assert(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - db_assert(bus != 0); - } else { - bus = 0; - } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *val = *(volatile u32 *) (base + (func_num << 8) + where); - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; -} - -static int read_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u16 * val) -{ - int status; - u32 result; - - db_assert((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return status; -} - -static int read_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u8 * val) -{ - int status; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return status; -} - -static int write_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u32 val) -{ - u32 bus, slot_num, func_num; - u32 base; - - db_assert((where & 3) == 0); - db_assert(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - db_assert(bus != 0); - } else { - bus = 0; - } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *(volatile u32 *) (base + (func_num << 8) + where) = val; - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; -} - -static int write_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u16 val) -{ - int status, shift = 0; - u32 result; - - db_assert((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -static int write_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u8 val) -{ - int status, shift = 0; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ -static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ -{ \ - return rw##_config_##unitname(pciswap, \ - dev, \ - where, \ - val); \ -} - -MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) - MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) - MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) - - MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) - MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) - MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) - -struct pci_ops ddb5476_ext_pci_ops = { - extpci_read_config_byte, - extpci_read_config_word, - extpci_read_config_dword, - extpci_write_config_byte, - extpci_write_config_word, - extpci_write_config_dword -}; diff --git a/arch/mips/pci/pci-ddb5074.c b/arch/mips/pci/pci-ddb5074.c deleted file mode 100644 index b74158d9b4b1..000000000000 --- a/arch/mips/pci/pci-ddb5074.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -static struct resource extpci_io_resource = { - .start = 0x1000, /* leave some room for ISA bus */ - .end = DDB_PCI_IO_SIZE - 1, - .name = "pci IO space", - .flags = IORESOURCE_IO -}; - -static struct resource extpci_mem_resource = { - .start = DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */ - .end = DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE - 1, - .name = "pci memory space", - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops ddb5476_ext_pci_ops; - -struct pci_controller ddb5476_controller = { - .pci_ops = &ddb5476_ext_pci_ops, - .io_resource = &extpci_io_resource, - .mem_resource = &extpci_mem_resource, -}; - -#define PCI_EXT_INTA 8 -#define PCI_EXT_INTB 9 -#define PCI_EXT_INTC 10 -#define PCI_EXT_INTD 11 -#define PCI_EXT_INTE 12 - -#define MAX_SLOT_NUM 14 - -static unsigned char irq_map[MAX_SLOT_NUM] = { - [ 0] = nile4_to_irq(PCI_EXT_INTE), - [ 1] = nile4_to_irq(PCI_EXT_INTA), - [ 2] = nile4_to_irq(PCI_EXT_INTA), - [ 3] = nile4_to_irq(PCI_EXT_INTB), - [ 4] = nile4_to_irq(PCI_EXT_INTC), - [ 5] = nile4_to_irq(NILE4_INT_UART), - [10] = nile4_to_irq(PCI_EXT_INTE), - [13] = nile4_to_irq(PCI_EXT_INTE), -}; - -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - return irq_map[slot]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} - -void __init ddb_pci_reset_bus(void) -{ - u32 temp; - - /* - * I am not sure about the "official" procedure, the following - * steps work as far as I know: - * We first set PCI cold reset bit (bit 31) in PCICTRL-H. - * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H. - * The same is true for both PCI channels. - */ - temp = ddb_in32(DDB_PCICTRL + 4); - temp |= 0x80000000; - ddb_out32(DDB_PCICTRL + 4, temp); - temp &= ~0xc0000000; - ddb_out32(DDB_PCICTRL + 4, temp); - -} diff --git a/include/asm-mips/ddb5074.h b/include/asm-mips/ddb5074.h deleted file mode 100644 index 0d09ac27f9a5..000000000000 --- a/include/asm-mips/ddb5074.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * include/asm-mips/ddb5074.h -- NEC DDB Vrc-5074 definitions - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ - -extern void ddb5074_led_hex(int hex); -extern void ddb5074_led_d2(int on); -extern void ddb5074_led_d3(int on); - diff --git a/include/asm-mips/ddb5xxx/ddb5074.h b/include/asm-mips/ddb5xxx/ddb5074.h deleted file mode 100644 index 58d88306af65..000000000000 --- a/include/asm-mips/ddb5xxx/ddb5074.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * include/asm-mips/ddb5074.h -- NEC DDB Vrc-5074 definitions - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ - -#ifndef _ASM_DDB5XXX_DDB5074_H -#define _ASM_DDB5XXX_DDB5074_H - -#include - -#define DDB_SDRAM_SIZE 0x04000000 /* 64MB */ - -#define DDB_PCI_IO_BASE 0x06000000 -#define DDB_PCI_IO_SIZE 0x02000000 /* 32 MB */ - -#define DDB_PCI_MEM_BASE 0x08000000 -#define DDB_PCI_MEM_SIZE 0x08000000 /* 128 MB */ - -#define DDB_PCI_CONFIG_BASE DDB_PCI_MEM_BASE -#define DDB_PCI_CONFIG_SIZE DDB_PCI_MEM_SIZE - -#define NILE4_PCI_IO_BASE 0xa6000000 -#define NILE4_PCI_MEM_BASE 0xa8000000 -#define NILE4_PCI_CFG_BASE NILE4_PCI_MEM_BASE -#define DDB_PCI_IACK_BASE NILE4_PCI_IO_BASE - -#define NILE4_IRQ_BASE NUM_I8259_INTERRUPTS -#define CPU_IRQ_BASE (NUM_NILE4_INTERRUPTS + NILE4_IRQ_BASE) -#define CPU_NILE4_CASCADE 2 - -extern void ddb5074_led_hex(int hex); -extern void ddb5074_led_d2(int on); -extern void ddb5074_led_d3(int on); - -extern void nile4_irq_setup(u32 base); -#endif diff --git a/include/asm-mips/ddb5xxx/ddb5xxx.h b/include/asm-mips/ddb5xxx/ddb5xxx.h index 873c03f2c5fe..2c8c93430c1c 100644 --- a/include/asm-mips/ddb5xxx/ddb5xxx.h +++ b/include/asm-mips/ddb5xxx/ddb5xxx.h @@ -174,13 +174,8 @@ static inline void ddb_sync(void) { -/* The DDB5074 doesn't seem to like these accesses. They kill the board on - * interrupt load - */ -#ifndef CONFIG_DDB5074 volatile u32 *p = (volatile u32 *)0xbfc00000; (void)(*p); -#endif } static inline void ddb_out32(u32 offset, u32 val) @@ -260,9 +255,7 @@ extern void ddb_pci_reset_bus(void); /* * include the board dependent part */ -#if defined(CONFIG_DDB5074) -#include -#elif defined(CONFIG_DDB5476) +#if defined(CONFIG_DDB5476) #include #elif defined(CONFIG_DDB5477) #include diff --git a/include/asm-mips/mach-ddb5074/mc146818rtc.h b/include/asm-mips/mach-ddb5074/mc146818rtc.h deleted file mode 100644 index 2eb9acb10a5a..000000000000 --- a/include/asm-mips/mach-ddb5074/mc146818rtc.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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) 1998, 2001, 03 by Ralf Baechle - * - * RTC routines for PC style attached Dallas chip. - */ -#ifndef __ASM_MACH_DDB5074_MC146818RTC_H -#define __ASM_MACH_DDB5074_MC146818RTC_H - -#include -#include - -#define RTC_PORT(x) (0x70 + (x)) -#define RTC_IRQ 8 - -static inline unsigned char CMOS_READ(unsigned long addr) -{ - return *(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr); -} - -static inline void CMOS_WRITE(unsigned char data, unsigned long addr) -{ - *(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr) = data; -} - -#define RTC_ALWAYS_BCD 1 - -#endif /* __ASM_MACH_DDB5074_MC146818RTC_H */ -- cgit v1.2.3 From 470b160364db5b8096b8e557a23c97eb6612be67 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 18 Jun 2006 05:28:38 +0100 Subject: [MIPS] Remove support for NEC DDB5476. As warned several times before. Signed-off-by: Ralf Baechle --- Documentation/feature-removal-schedule.txt | 9 - arch/mips/Kconfig | 21 - arch/mips/Makefile | 6 - arch/mips/configs/atlas_defconfig | 1 - arch/mips/configs/bigsur_defconfig | 1 - arch/mips/configs/capcella_defconfig | 1 - arch/mips/configs/cobalt_defconfig | 1 - arch/mips/configs/db1000_defconfig | 1 - arch/mips/configs/db1100_defconfig | 1 - arch/mips/configs/db1200_defconfig | 1 - arch/mips/configs/db1500_defconfig | 1 - arch/mips/configs/db1550_defconfig | 1 - arch/mips/configs/ddb5476_defconfig | 916 ----------------------------- arch/mips/configs/ddb5477_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/e55_defconfig | 1 - arch/mips/configs/ev64120_defconfig | 1 - arch/mips/configs/ev96100_defconfig | 1 - arch/mips/configs/ip22_defconfig | 1 - arch/mips/configs/ip27_defconfig | 1 - arch/mips/configs/ip32_defconfig | 1 - arch/mips/configs/it8172_defconfig | 1 - arch/mips/configs/ivr_defconfig | 1 - arch/mips/configs/jaguar-atx_defconfig | 1 - arch/mips/configs/jmr3927_defconfig | 1 - arch/mips/configs/lasat200_defconfig | 1 - arch/mips/configs/malta_defconfig | 1 - arch/mips/configs/mipssim_defconfig | 1 - arch/mips/configs/mpc30x_defconfig | 1 - arch/mips/configs/ocelot_3_defconfig | 1 - arch/mips/configs/ocelot_c_defconfig | 1 - arch/mips/configs/ocelot_defconfig | 1 - arch/mips/configs/ocelot_g_defconfig | 1 - arch/mips/configs/pb1100_defconfig | 1 - arch/mips/configs/pb1500_defconfig | 1 - arch/mips/configs/pb1550_defconfig | 1 - arch/mips/configs/pnx8550-jbs_defconfig | 1 - arch/mips/configs/pnx8550-v2pci_defconfig | 1 - arch/mips/configs/qemu_defconfig | 1 - arch/mips/configs/rbhma4500_defconfig | 1 - arch/mips/configs/rm200_defconfig | 1 - arch/mips/configs/sb1250-swarm_defconfig | 1 - arch/mips/configs/sead_defconfig | 1 - arch/mips/configs/tb0226_defconfig | 1 - arch/mips/configs/tb0229_defconfig | 1 - arch/mips/configs/tb0287_defconfig | 1 - arch/mips/configs/workpad_defconfig | 1 - arch/mips/configs/wrppmc_defconfig | 1 - arch/mips/configs/yosemite_defconfig | 1 - arch/mips/ddb5xxx/common/prom.c | 5 +- arch/mips/ddb5xxx/ddb5476/Makefile | 9 - arch/mips/ddb5xxx/ddb5476/dbg_io.c | 136 ----- arch/mips/ddb5xxx/ddb5476/irq.c | 165 ------ arch/mips/ddb5xxx/ddb5476/nile4_pic.c | 190 ------ arch/mips/ddb5xxx/ddb5476/setup.c | 321 ---------- arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c | 109 ---- arch/mips/defconfig | 1 - arch/mips/pci/Makefile | 1 - arch/mips/pci/ops-ddb5476.c | 286 --------- arch/mips/pci/pci-ddb5476.c | 93 --- drivers/net/tulip/tulip_core.c | 8 - include/asm-mips/ddb5xxx/ddb5476.h | 157 ----- include/asm-mips/ddb5xxx/ddb5xxx.h | 4 +- 63 files changed, 2 insertions(+), 2480 deletions(-) delete mode 100644 arch/mips/configs/ddb5476_defconfig delete mode 100644 arch/mips/ddb5xxx/ddb5476/Makefile delete mode 100644 arch/mips/ddb5xxx/ddb5476/dbg_io.c delete mode 100644 arch/mips/ddb5xxx/ddb5476/irq.c delete mode 100644 arch/mips/ddb5xxx/ddb5476/nile4_pic.c delete mode 100644 arch/mips/ddb5xxx/ddb5476/setup.c delete mode 100644 arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c delete mode 100644 arch/mips/pci/ops-ddb5476.c delete mode 100644 arch/mips/pci/pci-ddb5476.c delete mode 100644 include/asm-mips/ddb5xxx/ddb5476.h (limited to 'include') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8fa7a384f250..f50cf8fac3f0 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -212,15 +212,6 @@ Who: Greg Kroah-Hartman --------------------------- -What: Support for NEC DDB5476 evaluation boards. -When: June 2006 -Why: Board specific code doesn't build anymore since ~2.6.0 and no - users have complained indicating there is no more need for these - boards. This should really be considered a last call. -Who: Ralf Baechle - ---------------------------- - What: USB driver API moves to EXPORT_SYMBOL_GPL When: Febuary 2008 Files: include/linux/usb.h, drivers/usb/core/driver.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c3c8e7a15af3..138aac48d5d4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -469,27 +469,6 @@ config PNX8550_JBS select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN -config DDB5476 - bool "NEC DDB Vrc-5476" - select DDB5XXX_COMMON - select DMA_NONCOHERENT - select HAVE_STD_PC_SERIAL_PORT - select HW_HAS_PCI - select IRQ_CPU - select I8259 - select ISA - select SYS_HAS_CPU_R5432 - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_LITTLE_ENDIAN - help - This enables support for the R5432-based NEC DDB Vrc-5476 - evaluation board. - - Features : kernel debugging, serial terminal, NFS root fs, on-board - ether port USB, AC97, PCI, PCI VGA card & framebuffer console, - IDE controller, PS2 keyboard, PS2 mouse, etc. - config DDB5477 bool "NEC DDB Vrc-5477" select DDB5XXX_COMMON diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 8d1026cd0738..e0cab2850a72 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -403,12 +403,6 @@ load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff80100000 # core-$(CONFIG_DDB5XXX_COMMON) += arch/mips/ddb5xxx/common/ -# -# NEC DDB Vrc-5476 -# -core-$(CONFIG_DDB5476) += arch/mips/ddb5xxx/ddb5476/ -load-$(CONFIG_DDB5476) += 0xffffffff80080000 - # # NEC DDB Vrc-5477 # diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig index 7b6de36e5b74..d72acc84c481 100644 --- a/arch/mips/configs/atlas_defconfig +++ b/arch/mips/configs/atlas_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_ATLAS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 633cafe20418..4677cbbc2b46 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index bd150ec8559f..4e1937bffc80 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index ad83025420ec..7ac532070c42 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_COBALT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index ba3c7b9464bf..0efaf64ca27d 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1000=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index 321a4d00ce94..7b7a2de63495 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index 97471008f3ae..53da5d81d2d9 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1200=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index fbcc1738ff90..408af0e2c2aa 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1500=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index d014cdd3e705..f8db553dfb41 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_DB1550=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig deleted file mode 100644 index 90cabf5419ad..000000000000 --- a/arch/mips/configs/ddb5476_defconfig +++ /dev/null @@ -1,916 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.17-rc2 -# Mon Apr 24 14:51:00 2006 -# -CONFIG_MIPS=y - -# -# Machine selection -# -# CONFIG_MIPS_MTX1 is not set -# CONFIG_MIPS_BOSPORUS is not set -# CONFIG_MIPS_PB1000 is not set -# CONFIG_MIPS_PB1100 is not set -# CONFIG_MIPS_PB1500 is not set -# CONFIG_MIPS_PB1550 is not set -# CONFIG_MIPS_PB1200 is not set -# CONFIG_MIPS_DB1000 is not set -# CONFIG_MIPS_DB1100 is not set -# CONFIG_MIPS_DB1500 is not set -# CONFIG_MIPS_DB1550 is not set -# CONFIG_MIPS_DB1200 is not set -# CONFIG_MIPS_MIRAGE is not set -# CONFIG_MIPS_COBALT is not set -# CONFIG_MACH_DECSTATION is not set -# CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set -# CONFIG_MIPS_IVR is not set -# CONFIG_MIPS_ITE8172 is not set -# CONFIG_MACH_JAZZ is not set -# CONFIG_LASAT is not set -# CONFIG_MIPS_ATLAS is not set -# CONFIG_MIPS_MALTA is not set -# CONFIG_MIPS_SEAD is not set -# CONFIG_MIPS_SIM is not set -# CONFIG_MOMENCO_JAGUAR_ATX is not set -# CONFIG_MOMENCO_OCELOT is not set -# CONFIG_MOMENCO_OCELOT_3 is not set -# CONFIG_MOMENCO_OCELOT_C is not set -# CONFIG_MOMENCO_OCELOT_G is not set -# CONFIG_MIPS_XXS1500 is not set -# CONFIG_PNX8550_V2PCI is not set -# CONFIG_PNX8550_JBS is not set -CONFIG_DDB5476=y -# CONFIG_DDB5477 is not set -# CONFIG_MACH_VR41XX is not set -# CONFIG_PMC_YOSEMITE is not set -# CONFIG_QEMU is not set -# CONFIG_SGI_IP22 is not set -# CONFIG_SGI_IP27 is not set -# CONFIG_SGI_IP32 is not set -# CONFIG_SIBYTE_BIGSUR is not set -# CONFIG_SIBYTE_SWARM is not set -# CONFIG_SIBYTE_SENTOSA is not set -# CONFIG_SIBYTE_RHONE is not set -# CONFIG_SIBYTE_CARMEL is not set -# CONFIG_SIBYTE_PTSWARM is not set -# CONFIG_SIBYTE_LITTLESUR is not set -# CONFIG_SIBYTE_CRHINE is not set -# CONFIG_SIBYTE_CRHONE is not set -# CONFIG_SNI_RM200_PCI is not set -# CONFIG_TOSHIBA_JMR3927 is not set -# CONFIG_TOSHIBA_RBTX4927 is not set -# CONFIG_TOSHIBA_RBTX4938 is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_DMA_NONCOHERENT=y -CONFIG_DMA_NEED_PCI_MAP_STATE=y -CONFIG_I8259=y -# CONFIG_CPU_BIG_ENDIAN is not set -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -CONFIG_IRQ_CPU=y -CONFIG_DDB5XXX_COMMON=y -CONFIG_MIPS_L1_CACHE_SHIFT=5 -CONFIG_HAVE_STD_PC_SERIAL_PORT=y - -# -# CPU selection -# -# CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPS32_R2 is not set -# CONFIG_CPU_MIPS64_R1 is not set -# CONFIG_CPU_MIPS64_R2 is not set -# CONFIG_CPU_R3000 is not set -# CONFIG_CPU_TX39XX is not set -# CONFIG_CPU_VR41XX is not set -# CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -# CONFIG_CPU_TX49XX is not set -# CONFIG_CPU_R5000 is not set -CONFIG_CPU_R5432=y -# CONFIG_CPU_R6000 is not set -# CONFIG_CPU_NEVADA is not set -# CONFIG_CPU_R8000 is not set -# CONFIG_CPU_R10000 is not set -# CONFIG_CPU_RM7000 is not set -# CONFIG_CPU_RM9000 is not set -# CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R5432=y -CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y - -# -# Kernel type -# -CONFIG_32BIT=y -# CONFIG_64BIT is not set -CONFIG_PAGE_SIZE_4KB=y -# CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set -# CONFIG_PAGE_SIZE_64KB is not set -# CONFIG_MIPS_MT is not set -CONFIG_CPU_HAS_LLSC=y -CONFIG_CPU_HAS_SYNC=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set -CONFIG_RELAY=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -CONFIG_HOTPLUG=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# Block layer -# -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Bus options (PCI, PCMCIA, EISA, ISA, TC) -# -CONFIG_HW_HAS_PCI=y -CONFIG_PCI=y -CONFIG_ISA=y -CONFIG_MMU=y - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# PCI Hotplug Support -# -# CONFIG_HOTPLUG_PCI is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_TRAD_SIGNALS=y - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=y -CONFIG_NET_KEY=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -# CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_IEEE80211=y -# CONFIG_IEEE80211_DEBUG is not set -CONFIG_IEEE80211_CRYPT_WEP=y -CONFIG_IEEE80211_CRYPT_CCMP=y -CONFIG_IEEE80211_SOFTMAC=y -# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set -CONFIG_WIRELESS_EXT=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=y - -# -# Connector - unified userspace <-> kernelspace linker -# -CONFIG_CONNECTOR=y -CONFIG_PROC_EVENTS=y - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_SX8 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set -CONFIG_CDROM_PKTCDVD=y -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set -CONFIG_ATA_OVER_ETH=y - -# -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_ARM is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -CONFIG_RAID_ATTRS=y -# CONFIG_SCSI is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set - -# -# PHY device support -# -CONFIG_PHYLIB=y - -# -# MII PHY device drivers -# -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_CASSINI is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_DM9000 is not set -# CONFIG_NET_VENDOR_RACAL is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SIS190 is not set -# CONFIG_SKGE is not set -# CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set -# CONFIG_BNX2 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_CHELSIO_T1 is not set -# CONFIG_IXGB is not set -# CONFIG_S2IO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_PCIPS2 is not set -# CONFIG_SERIO_LIBPS2 is not set -CONFIG_SERIO_RAW=y -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_JSM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -CONFIG_FB=y -# CONFIG_FB_CFB_FILLRECT is not set -# CONFIG_FB_CFB_COPYAREA is not set -# CONFIG_FB_CFB_IMAGEBLIT is not set -# CONFIG_FB_MACMODES is not set -CONFIG_FB_FIRMWARE_EDID=y -# CONFIG_FB_MODE_HELPERS is not set -# CONFIG_FB_TILEBLITTING is not set -# CONFIG_FB_CIRRUS is not set -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_ASILIANT is not set -# CONFIG_FB_IMSTT is not set -# CONFIG_FB_S1D13XXX is not set -# CONFIG_FB_NVIDIA is not set -# CONFIG_FB_RIVA is not set -# CONFIG_FB_MATROX is not set -# CONFIG_FB_RADEON is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_SAVAGE is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_SMIVGX is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FRAMEBUFFER_CONSOLE is not set - -# -# Logo configuration -# -# CONFIG_LOGO is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y -CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# -# CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -# CONFIG_RTC_CLASS is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -# CONFIG_EXT3_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -CONFIG_FUSE_FS=y - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_TMPFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -# CONFIG_NLS is not set - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_DEBUG_FS is not set -# CONFIG_UNWIND_INFO is not set -CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="ip=any" - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_MD4=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_WP512=y -CONFIG_CRYPTO_TGR192=y -CONFIG_CRYPTO_DES=y -CONFIG_CRYPTO_BLOWFISH=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_SERPENT=y -CONFIG_CRYPTO_AES=y -CONFIG_CRYPTO_CAST5=y -CONFIG_CRYPTO_CAST6=y -CONFIG_CRYPTO_TEA=y -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_KHAZAD=y -CONFIG_CRYPTO_ANUBIS=y -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_MICHAEL_MIC=y -CONFIG_CRYPTO_CRC32C=y -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -# CONFIG_CRC_CCITT is not set -CONFIG_CRC16=y -CONFIG_CRC32=y -CONFIG_LIBCRC32C=y -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig index fc30ace3d737..6e19990139d7 100644 --- a/arch/mips/configs/ddb5477_defconfig +++ b/arch/mips/configs/ddb5477_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set CONFIG_DDB5477=y # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index 0775d7364cab..f237754a8a13 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -41,7 +41,6 @@ CONFIG_MACH_DECSTATION=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index 8f9de1c3bf1e..b06d9f1e519a 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig index b97c90fa5491..46086893674e 100644 --- a/arch/mips/configs/ev64120_defconfig +++ b/arch/mips/configs/ev64120_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_EV64120=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig index 708b0d6896d8..63c46ef26d01 100644 --- a/arch/mips/configs/ev96100_defconfig +++ b/arch/mips/configs/ev96100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_EV96100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index f7b0beb5752f..f72ba3f1b7f5 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index b4ae9cd15ba3..9ac2acc05ad7 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index a95c2e847f68..826b0183eb49 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig index 87c5cde49e59..e44481f7e487 100644 --- a/arch/mips/configs/it8172_defconfig +++ b/arch/mips/configs/it8172_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_ITE8172=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig index 1346b683b287..f8722d0ba935 100644 --- a/arch/mips/configs/ivr_defconfig +++ b/arch/mips/configs/ivr_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_IVR=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index d2d1a7776362..1eeca9fd5b27 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_JAGUAR_ATX=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index ba23db03ba95..407d8d71200c 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig index 7500332c9b5c..48c67d8dd1f1 100644 --- a/arch/mips/configs/lasat200_defconfig +++ b/arch/mips/configs/lasat200_defconfig @@ -41,7 +41,6 @@ CONFIG_LASAT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 1aac4901c57e..fd1c73f8780b 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_MALTA=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 011120c5033e..67fb9fa10870 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_SIM=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index ca0baa29483c..c9607976d132 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig index a8d26596ca8e..af43e464871e 100644 --- a/arch/mips/configs/ocelot_3_defconfig +++ b/arch/mips/configs/ocelot_3_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_3=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index a1d6d7ff93fb..e1a9a9a750ea 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_C=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig index 4b72b0a2fb4b..09a96619aedf 100644 --- a/arch/mips/configs/ocelot_defconfig +++ b/arch/mips/configs/ocelot_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig index 232f13a41938..9c02f974b882 100644 --- a/arch/mips/configs/ocelot_g_defconfig +++ b/arch/mips/configs/ocelot_g_defconfig @@ -41,7 +41,6 @@ CONFIG_MOMENCO_OCELOT_G=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 55da4eb76f7b..d803c16dccb8 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1100=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 348581d91b52..0cb83a181e8d 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1500=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index 897f76c0c8ab..c6da473a64d3 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_PB1550=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 6289dfa73f2f..746986db597d 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set CONFIG_PNX8550_JBS=y -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index d8448fdb2514..6c3c72db4b9e 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set CONFIG_PNX8550_V2PCI=y # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig index 99c43c9f1595..8c77992ab767 100644 --- a/arch/mips/configs/qemu_defconfig +++ b/arch/mips/configs/qemu_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig index c55e8e6ff207..9bb4d94335cc 100644 --- a/arch/mips/configs/rbhma4500_defconfig +++ b/arch/mips/configs/rbhma4500_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 6013c6533ca5..7dd3438b5b1f 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 6b8441e18843..e872b83dddbf 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig index 94d04f7a5e6b..6048c0d60458 100644 --- a/arch/mips/configs/sead_defconfig +++ b/arch/mips/configs/sead_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS_SEAD=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index f84864d8ec33..b6d8e1afa191 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index aeb1e85f9ce7..4875cd38ff80 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index 5f1ee08d9851..70392d50074a 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index ebc25edbf73d..cfd6434aa556 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set CONFIG_MACH_VR41XX=y # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index 03c880792163..8c0e636cb322 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig @@ -42,7 +42,6 @@ CONFIG_WR_PPMC=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index 1c728f216fbd..eef270834797 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set CONFIG_PMC_YOSEMITE=y diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c index 18eecbcdfca8..00c62c1c28a3 100644 --- a/arch/mips/ddb5xxx/common/prom.c +++ b/arch/mips/ddb5xxx/common/prom.c @@ -56,10 +56,7 @@ void __init prom_init(void) mips_machgroup = MACH_GROUP_NEC_DDB; -#if defined(CONFIG_DDB5476) - mips_machtype = MACH_NEC_DDB5476; - add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); -#elif defined(CONFIG_DDB5477) +#if defined(CONFIG_DDB5477) ddb5477_runtime_detection(); add_memory_region(0, board_ram_size, BOOT_MEM_RAM); #endif diff --git a/arch/mips/ddb5xxx/ddb5476/Makefile b/arch/mips/ddb5xxx/ddb5476/Makefile deleted file mode 100644 index ab0312cb47b4..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the NEC DDB Vrc-5476 specific kernel interface routines -# under Linux. -# - -obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o -obj-$(CONFIG_KGDB) += dbg_io.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/ddb5xxx/ddb5476/dbg_io.c b/arch/mips/ddb5xxx/ddb5476/dbg_io.c deleted file mode 100644 index f2296a999953..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/dbg_io.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * kgdb io functions for DDB5476. We use the second serial port. - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: jsun@mvista.com or jsun@junsun.net - * - * 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. - * - */ - -/* ======================= CONFIG ======================== */ - -/* [jsun] we use the second serial port for kdb */ -#define BASE 0xa60002f8 -#define MAX_BAUD 115200 - -/* distance in bytes between two serial registers */ -#define REG_OFFSET 1 - -/* - * 0 - kgdb does serial init - * 1 - kgdb skip serial init - */ -static int remoteDebugInitialized = 0; - -/* - * the default baud rate *if* kgdb does serial init - */ -#define BAUD_DEFAULT UART16550_BAUD_38400 - -/* ======================= END OF CONFIG ======================== */ - -typedef unsigned char uint8; -typedef unsigned int uint32; - -#define UART16550_BAUD_2400 2400 -#define UART16550_BAUD_4800 4800 -#define UART16550_BAUD_9600 9600 -#define UART16550_BAUD_19200 19200 -#define UART16550_BAUD_38400 38400 -#define UART16550_BAUD_57600 57600 -#define UART16550_BAUD_115200 115200 - -#define UART16550_PARITY_NONE 0 -#define UART16550_PARITY_ODD 0x08 -#define UART16550_PARITY_EVEN 0x18 -#define UART16550_PARITY_MARK 0x28 -#define UART16550_PARITY_SPACE 0x38 - -#define UART16550_DATA_5BIT 0x0 -#define UART16550_DATA_6BIT 0x1 -#define UART16550_DATA_7BIT 0x2 -#define UART16550_DATA_8BIT 0x3 - -#define UART16550_STOP_1BIT 0x0 -#define UART16550_STOP_2BIT 0x4 - -/* register offset */ -#define OFS_RCV_BUFFER 0 -#define OFS_TRANS_HOLD 0 -#define OFS_SEND_BUFFER 0 -#define OFS_INTR_ENABLE (1*REG_OFFSET) -#define OFS_INTR_ID (2*REG_OFFSET) -#define OFS_DATA_FORMAT (3*REG_OFFSET) -#define OFS_LINE_CONTROL (3*REG_OFFSET) -#define OFS_MODEM_CONTROL (4*REG_OFFSET) -#define OFS_RS232_OUTPUT (4*REG_OFFSET) -#define OFS_LINE_STATUS (5*REG_OFFSET) -#define OFS_MODEM_STATUS (6*REG_OFFSET) -#define OFS_RS232_INPUT (6*REG_OFFSET) -#define OFS_SCRATCH_PAD (7*REG_OFFSET) - -#define OFS_DIVISOR_LSB (0*REG_OFFSET) -#define OFS_DIVISOR_MSB (1*REG_OFFSET) - - -/* memory-mapped read/write of the port */ -#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) -#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) - -void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) -{ - /* disable interrupts */ - UART16550_WRITE(OFS_INTR_ENABLE, 0); - - /* set up baud rate */ - { - uint32 divisor; - - /* set DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x80); - - /* set divisor */ - divisor = MAX_BAUD / baud; - UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); - UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); - - /* clear DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x0); - } - - /* set data format */ - UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); -} - - -uint8 getDebugChar(void) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(BAUD_DEFAULT, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); - return UART16550_READ(OFS_RCV_BUFFER); -} - - -int putDebugChar(uint8 byte) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(BAUD_DEFAULT, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); - UART16550_WRITE(OFS_SEND_BUFFER, byte); - return 1; -} diff --git a/arch/mips/ddb5xxx/ddb5476/irq.c b/arch/mips/ddb5xxx/ddb5476/irq.c deleted file mode 100644 index 7583a1f30711..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/irq.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - * - * Re-write the whole thing to use new irq.c file. - * Copyright (C) 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - */ -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ -#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ -#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ - -#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ -#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ -#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ - -#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ -#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ - -#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ -#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ - -#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ -#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ - -static void m1543_irq_setup(void) -{ - /* - * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all - * the possible IO sources in the M1543 are in use by us. We will - * use the following mapping: - * - * IRQ1 - keyboard (default set by M1543) - * IRQ3 - reserved for UART B (default set by M1543) (note that - * the schematics for the DDB Vrc-5476 board seem to - * indicate that IRQ3 is connected to the DS1386 - * watchdog timer interrupt output so we might have - * a conflict) - * IRQ4 - reserved for UART A (default set by M1543) - * IRQ5 - parallel (default set by M1543) - * IRQ8 - DS1386 time of day (RTC) interrupt - * IRQ9 - USB (hardwired in ddb_setup) - * IRQ10 - PMU (hardwired in ddb_setup) - * IRQ12 - mouse - * IRQ14,15 - IDE controller (need to be confirmed, jsun) - */ - - /* - * Assing mouse interrupt to IRQ12 - */ - - /* Enter configuration mode */ - outb(0x51, M1543_PNP_CONFIG); - outb(0x23, M1543_PNP_CONFIG); - - /* Select logical device 7 (Keyboard) */ - outb(0x07, M1543_PNP_INDEX); - outb(0x07, M1543_PNP_DATA); - - /* Select IRQ12 */ - outb(0x72, M1543_PNP_INDEX); - outb(0x0c, M1543_PNP_DATA); - - /* Leave configration mode */ - outb(0xbb, M1543_PNP_CONFIG); -} - -static void nile4_irq_setup(void) -{ - int i; - - /* Map all interrupts to CPU int #0 (IP2) */ - nile4_map_irq_all(0); - - /* PCI INTA#-E# must be level triggered */ - nile4_set_pci_irq_level_or_edge(0, 1); - nile4_set_pci_irq_level_or_edge(1, 1); - nile4_set_pci_irq_level_or_edge(2, 1); - nile4_set_pci_irq_level_or_edge(3, 1); - - /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ - nile4_set_pci_irq_polarity(0, 0); - nile4_set_pci_irq_polarity(1, 0); - nile4_set_pci_irq_polarity(2, 1); - nile4_set_pci_irq_polarity(3, 0); - - for (i = 0; i < 16; i++) - nile4_clear_irq(i); - - /* Enable CPU int #0 */ - nile4_enable_irq_output(0); - - /* memory resource acquire in ddb_setup */ -} - -static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; -static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL }; - -extern int setup_irq(unsigned int irq, struct irqaction *irqaction); -extern void mips_cpu_irq_init(u32 irq_base); -extern void vrc5476_irq_init(u32 irq_base); - -extern void vrc5476_irq_dispatch(struct pt_regs *regs); - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) -{ - unsigned int pending = read_c0_cause() & read_c0_status(); - - if (pending & STATUSF_IP7) - do_IRQ(CPU_IRQ_BASE + 7, regs); - else if (pending & STATUSF_IP2) - vrc5476_irq_dispatch(regs); - else if (pending & STATUSF_IP3) - do_IRQ(CPU_IRQ_BASE + 3, regs); - else if (pending & STATUSF_IP4) - do_IRQ(CPU_IRQ_BASE + 4, regs); - else if (pending & STATUSF_IP5) - do_IRQ(CPU_IRQ_BASE + 5, regs); - else if (pending & STATUSF_IP6) - do_IRQ(CPU_IRQ_BASE + 6, regs); - else if (pending & STATUSF_IP0) - do_IRQ(CPU_IRQ_BASE, regs); - else if (pending & STATUSF_IP1) - do_IRQ(CPU_IRQ_BASE + 1, regs); - - vrc5476_irq_dispatch(regs); -} - -void __init arch_init_irq(void) -{ - /* hardware initialization */ - nile4_irq_setup(); - m1543_irq_setup(); - - /* controller setup */ - init_i8259_irqs(); - vrc5476_irq_init(VRC5476_IRQ_BASE); - mips_cpu_irq_init(CPU_IRQ_BASE); - - /* setup cascade interrupts */ - setup_irq(VRC5476_IRQ_BASE + VRC5476_I8259_CASCADE, &irq_cascade); - setup_irq(CPU_IRQ_BASE + CPU_VRC5476_CASCADE, &irq_cascade); - - /* setup error interrupts for debugging */ - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CPCE, &irq_error); - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CNTD, &irq_error); - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_MCE, &irq_error); - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error); - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error); - setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error); -} diff --git a/arch/mips/ddb5xxx/ddb5476/nile4_pic.c b/arch/mips/ddb5xxx/ddb5476/nile4_pic.c deleted file mode 100644 index e930cee7944f..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/nile4_pic.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * arch/mips/ddb5476/nile4.c -- - * low-level PIC code for NEC Vrc-5476 (Nile 4) - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - * - * Copyright 2001 MontaVista Software Inc. - * Author: jsun@mvista.com or jsun@junsun.net - * - */ -#include -#include -#include - -#include - -#include - - -/* - * Interrupt Programming - */ -void nile4_map_irq(int nile4_irq, int cpu_irq) -{ - u32 offset, t; - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = ddb_in32(offset); - t &= ~(7 << (nile4_irq * 4)); - t |= cpu_irq << (nile4_irq * 4); - ddb_out32(offset, t); -} - -void nile4_map_irq_all(int cpu_irq) -{ - u32 all, t; - - all = cpu_irq; - all |= all << 4; - all |= all << 8; - all |= all << 16; - t = ddb_in32(DDB_INTCTRL); - t &= 0x88888888; - t |= all; - ddb_out32(DDB_INTCTRL, t); - t = ddb_in32(DDB_INTCTRL + 4); - t &= 0x88888888; - t |= all; - ddb_out32(DDB_INTCTRL + 4, t); -} - -void nile4_enable_irq(int nile4_irq) -{ - u32 offset, t; - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = ddb_in32(offset); - t |= 8 << (nile4_irq * 4); - ddb_out32(offset, t); -} - -void nile4_disable_irq(int nile4_irq) -{ - u32 offset, t; - - offset = DDB_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = ddb_in32(offset); - t &= ~(8 << (nile4_irq * 4)); - ddb_out32(offset, t); -} - -void nile4_disable_irq_all(void) -{ - ddb_out32(DDB_INTCTRL, 0); - ddb_out32(DDB_INTCTRL + 4, 0); -} - -u16 nile4_get_irq_stat(int cpu_irq) -{ - return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2); -} - -void nile4_enable_irq_output(int cpu_irq) -{ - u32 t; - - t = ddb_in32(DDB_INTSTAT1 + 4); - t |= 1 << (16 + cpu_irq); - ddb_out32(DDB_INTSTAT1, t); -} - -void nile4_disable_irq_output(int cpu_irq) -{ - u32 t; - - t = ddb_in32(DDB_INTSTAT1 + 4); - t &= ~(1 << (16 + cpu_irq)); - ddb_out32(DDB_INTSTAT1, t); -} - -void nile4_set_pci_irq_polarity(int pci_irq, int high) -{ - u32 t; - - t = ddb_in32(DDB_INTPPES); - if (high) - t &= ~(1 << (pci_irq * 2)); - else - t |= 1 << (pci_irq * 2); - ddb_out32(DDB_INTPPES, t); -} - -void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) -{ - u32 t; - - t = ddb_in32(DDB_INTPPES); - if (level) - t |= 2 << (pci_irq * 2); - else - t &= ~(2 << (pci_irq * 2)); - ddb_out32(DDB_INTPPES, t); -} - -void nile4_clear_irq(int nile4_irq) -{ - ddb_out32(DDB_INTCLR, 1 << nile4_irq); -} - -void nile4_clear_irq_mask(u32 mask) -{ - ddb_out32(DDB_INTCLR, mask); -} - -u8 nile4_i8259_iack(void) -{ - u8 irq; - u32 reg; - - /* Set window 0 for interrupt acknowledge */ - reg = ddb_in32(DDB_PCIINIT0); - - ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32); - irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); - /* restore window 0 for PCI I/O space */ - // ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); - ddb_out32(DDB_PCIINIT0, reg); - - /* i8269.c set the base vector to be 0x0 */ - return irq + I8259_IRQ_BASE; -} - -#if defined(CONFIG_RUNTIME_DEBUG) -void nile4_dump_irq_status(void) -{ - printk(KERN_DEBUG " - CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4), - (void *) ddb_in32(DDB_CPUSTAT)); - printk(KERN_DEBUG " - INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4), - (void *) ddb_in32(DDB_INTCTRL)); - printk(KERN_DEBUG - "INTSTAT0 = %p:%p\n", - (void *) ddb_in32(DDB_INTSTAT0 + 4), - (void *) ddb_in32(DDB_INTSTAT0)); - printk(KERN_DEBUG - "INTSTAT1 = %p:%p\n", - (void *) ddb_in32(DDB_INTSTAT1 + 4), - (void *) ddb_in32(DDB_INTSTAT1)); - printk(KERN_DEBUG - "INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4), - (void *) ddb_in32(DDB_INTCLR)); - printk(KERN_DEBUG - "INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4), - (void *) ddb_in32(DDB_INTPPES)); -} -#endif diff --git a/arch/mips/ddb5xxx/ddb5476/setup.c b/arch/mips/ddb5xxx/ddb5476/setup.c deleted file mode 100644 index 101021afb2e4..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/setup.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// #define USE_CPU_COUNTER_TIMER /* whether we use cpu counter */ - -#ifdef USE_CPU_COUNTER_TIMER - -#define CPU_COUNTER_FREQUENCY 83000000 -#else -/* otherwise we use general purpose timer */ -#define TIMER_FREQUENCY 83000000 -#define TIMER_BASE DDB_T2CTRL -#define TIMER_IRQ (VRC5476_IRQ_BASE + VRC5476_IRQ_GPT) -#endif - -static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; - -static void ddb_machine_restart(char *command) -{ - u32 t; - - /* PCI cold reset */ - t = ddb_in32(DDB_PCICTRL + 4); - t |= 0x40000000; - ddb_out32(DDB_PCICTRL + 4, t); - /* CPU cold reset */ - t = ddb_in32(DDB_CPUSTAT); - t |= 1; - ddb_out32(DDB_CPUSTAT, t); - /* Call the PROM */ - back_to_prom(); -} - -static void ddb_machine_halt(void) -{ - printk(KERN_NOTICE "DDB Vrc-5476 halted.\n"); - while (1); -} - -static void ddb_machine_power_off(void) -{ - printk(KERN_NOTICE "DDB Vrc-5476 halted. Please turn off the power.\n"); - while (1); -} - -extern void rtc_ds1386_init(unsigned long base); - -static void __init ddb_time_init(void) -{ -#if defined(USE_CPU_COUNTER_TIMER) - mips_hpt_frequency = CPU_COUNTER_FREQUENCY; -#endif - - /* we have ds1396 RTC chip */ - rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE)); -} - - -extern int setup_irq(unsigned int irq, struct irqaction *irqaction); -static void __init ddb_timer_setup(struct irqaction *irq) -{ -#if defined(USE_CPU_COUNTER_TIMER) - - unsigned int count; - - /* we are using the cpu counter for timer interrupts */ - setup_irq(CPU_IRQ_BASE + 7, irq); - - /* to generate the first timer interrupt */ - count = read_c0_count(); - write_c0_compare(count + 1000); - -#else - - ddb_out32(TIMER_BASE, TIMER_FREQUENCY/HZ); - ddb_out32(TIMER_BASE+4, 0x1); /* enable timer */ - setup_irq(TIMER_IRQ, irq); -#endif -} - -static struct { - struct resource dma1; - struct resource timer; - struct resource rtc; - struct resource dma_page_reg; - struct resource dma2; -} ddb5476_ioport = { - { - .start = 0x00, - .end = 0x1f, - .name = "dma1", - .flags = IORESOURCE_BUSY - }, { - .start = 0x40, - .end = 0x5f, - .name = "timer", - .flags = IORESOURCE_BUSY - }, { - .start = 0x70, - .end = 0x7f, - .name = "rtc", - .flags = IORESOURCE_BUSY - }, { - .start = 0x80, - .end = 0x8f, - .name = "dma page reg", - .flags = IORESOURCE_BUSY - }, { - .start = 0xc0, - .end = 0xdf, - .name = "dma2", - .flags = IORESOURCE_BUSY - } -}; - -static struct { - struct resource nile4; -} ddb5476_iomem = { - { - .start = DDB_BASE, - .end = DDB_BASE + DDB_SIZE - 1, - .name = "Nile 4", - .flags = IORESOURCE_BUSY - } -}; - - -static void ddb5476_board_init(void); - -void __init plat_mem_setup(void) -{ - set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE)); - - board_time_init = ddb_time_init; - board_timer_setup = ddb_timer_setup; - - _machine_restart = ddb_machine_restart; - _machine_halt = ddb_machine_halt; - pm_power_off = ddb_machine_power_off; - - /* request io port/mem resources */ - if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || - request_resource(&ioport_resource, &ddb5476_ioport.timer) || - request_resource(&ioport_resource, &ddb5476_ioport.rtc) || - request_resource(&ioport_resource, - &ddb5476_ioport.dma_page_reg) - || request_resource(&ioport_resource, &ddb5476_ioport.dma2) - || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { - printk - ("ddb_setup - requesting oo port resources failed.\n"); - for (;;); - } - - /* Reboot on panic */ - panic_timeout = 180; - - /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ - /* *(long*)0xbfa00218 = 0x8; */ - - /* board initialization stuff */ - ddb5476_board_init(); -} - -/* - * We don't trust bios. We essentially does hardware re-initialization - * as complete as possible, as far as we know we can safely do. - */ -static void ddb5476_board_init(void) -{ - /* ----------- setup PDARs ------------ */ - /* check SDRAM0, whether we are on MEM bus does not matter */ - db_assert((ddb_in32(DDB_SDRAM0) & 0xffffffef) == - ddb_calc_pdar(DDB_SDRAM_BASE, DDB_SDRAM_SIZE, 32, 0, 1)); - - /* SDRAM1 should be turned off. What is this for anyway ? */ - db_assert( (ddb_in32(DDB_SDRAM1) & 0xf) == 0); - - /* flash 1&2, DDB status, DDB control */ - ddb_set_pdar(DDB_DCS2, DDB_DCS2_BASE, DDB_DCS2_SIZE, 16, 0, 0); - ddb_set_pdar(DDB_DCS3, DDB_DCS3_BASE, DDB_DCS3_SIZE, 16, 0, 0); - ddb_set_pdar(DDB_DCS4, DDB_DCS4_BASE, DDB_DCS4_SIZE, 8, 0, 0); - ddb_set_pdar(DDB_DCS5, DDB_DCS5_BASE, DDB_DCS5_SIZE, 8, 0, 0); - - /* shut off other pdar so they don't accidentally get into the way */ - ddb_set_pdar(DDB_DCS6, 0xffffffff, 0, 32, 0, 0); - ddb_set_pdar(DDB_DCS7, 0xffffffff, 0, 32, 0, 0); - ddb_set_pdar(DDB_DCS8, 0xffffffff, 0, 32, 0, 0); - - /* verify VRC5477 base addr */ - /* don't care about some details */ - db_assert((ddb_in32(DDB_INTCS) & 0xffffff0f) == - ddb_calc_pdar(DDB_INTCS_BASE, DDB_INTCS_SIZE, 8, 0, 0)); - - /* verify BOOT ROM addr */ - /* don't care about some details */ - db_assert((ddb_in32(DDB_BOOTCS) & 0xffffff0f) == - ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0)); - - /* setup PCI windows - window1 for MEM/config, window0 for IO */ - ddb_set_pdar(DDB_PCIW0, DDB_PCI_IO_BASE, DDB_PCI_IO_SIZE, 32, 0, 1); - ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); - - ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); - ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); - - /* ----------- setup PDARs ------------ */ - /* this is problematic - it will reset Aladin which cause we loose - * serial port, and we don't know how to set up Aladin chip again. - */ - // ddb_pci_reset_bus(); - - ddb_out32(DDB_BAR0, 0x00000008); - - ddb_out32(DDB_BARC, 0xffffffff); - ddb_out32(DDB_BARB, 0xffffffff); - ddb_out32(DDB_BAR1, 0xffffffff); - ddb_out32(DDB_BAR2, 0xffffffff); - ddb_out32(DDB_BAR3, 0xffffffff); - ddb_out32(DDB_BAR4, 0xffffffff); - ddb_out32(DDB_BAR5, 0xffffffff); - ddb_out32(DDB_BAR6, 0xffffffff); - ddb_out32(DDB_BAR7, 0xffffffff); - ddb_out32(DDB_BAR8, 0xffffffff); - - /* ----------- switch PCI1 to PCI CONFIG space ------------ */ - ddb_set_pdar(DDB_PCIW1, DDB_PCI_CONFIG_BASE, DDB_PCI_CONFIG_SIZE, 32, 0, 1); - ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_CFG, 0x0, DDB_PCI_ACCESS_32); - - /* ----- M1543 PCI setup ------ */ - - /* we know M1543 PCI-ISA controller is at addr:18 */ - /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ - *(volatile unsigned char *) 0xa8040072 &= 0xf0; - *(volatile unsigned char *) 0xa8040072 |= 0xa; - - /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) - * no IOCHRDY signal, (bit 7 - 1) - * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) - * Make USB Master INTAJ level to edge conversion (bit 4 - 1) - */ - *(unsigned char *) 0xa8040074 = 0xd1; - - /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) - * SCI routing to IRQ 13 disabled (bit 7 - 1) - * SCI interrupt level to edge conversion bypassed (bit 4 - 0) - */ - *(unsigned char *) 0xa8040076 = 0x83; - - /* setup IDE controller - * enable IDE controller (bit 6 - 1) - * IDE IDSEL to be addr:24 (bit 4:5 - 11) - * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) - * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) - * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 - */ - // *(unsigned char*)0xa8040058 = 0x71; - // *(unsigned char*)0xa8040058 = 0x79; - // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state - *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state - -#if 0 - /* this is not necessary if M5229 does not use SIRQ */ - *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 - *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 -#endif - - /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ - /* M5229 IDSEL is addr:24; see above setting */ - *(unsigned char *) 0xa9000050 |= 0x1; - - /* enable bus master (bit 2) and IO decoding (bit 0) */ - *(unsigned char *) 0xa9000004 |= 0x5; - - /* enable native, copied from arch/ppc/k2boot/head.S */ - /* TODO - need volatile, need to be portable */ - *(unsigned char *) 0xa9000009 = 0xff; - - /* ----- end of M1543 PCI setup ------ */ - - /* ----- reset on-board ether chip ------ */ - *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ - *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ - - /* send reset command */ - *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ - - /* disable ether chip */ - *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ - - /* put it into sleep */ - *((volatile u32 *) 0xa8020040) = 0x80000000; - - /* ----- end of reset on-board ether chip ------ */ - - /* ----------- switch PCI1 back to PCI MEM space ------------ */ - ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); - ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); -} diff --git a/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c b/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c deleted file mode 100644 index a3c5e7b18018..000000000000 --- a/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The irq controller for vrc5476. - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: jsun@mvista.com or jsun@junsun.net - * - * 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 - -static int irq_base; - -static void vrc5476_irq_enable(uint irq) -{ - nile4_enable_irq(irq - irq_base); -} - -static void vrc5476_irq_disable(uint irq) -{ - nile4_disable_irq(irq - irq_base); -} - -static unsigned int vrc5476_irq_startup(uint irq) -{ - nile4_enable_irq(irq - irq_base); - return 0; -} - -#define vrc5476_irq_shutdown vrc5476_irq_disable - -static void vrc5476_irq_ack(uint irq) -{ - nile4_clear_irq(irq - irq_base); - nile4_disable_irq(irq - irq_base); -} - -static void vrc5476_irq_end(uint irq) -{ - if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - vrc5476_irq_enable(irq); -} - -static hw_irq_controller vrc5476_irq_controller = { - .typename = "vrc5476", - .startup = vrc5476_irq_startup, - .shutdown = vrc5476_irq_shutdown, - .enable = vrc5476_irq_enable, - .disable = vrc5476_irq_disable, - .ack = vrc5476_irq_ack, - .end = vrc5476_irq_end -}; - -void __init -vrc5476_irq_init(u32 base) -{ - u32 i; - - irq_base = base; - for (i= base; i< base + NUM_VRC5476_IRQ; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &vrc5476_irq_controller; - } -} - - -void -vrc5476_irq_dispatch(struct pt_regs *regs) -{ - u32 mask; - int nile4_irq; - - mask = nile4_get_irq_stat(0); - - /* quick check for possible time interrupt */ - if (mask & (1 << VRC5476_IRQ_GPT)) { - do_IRQ(VRC5476_IRQ_BASE + VRC5476_IRQ_GPT, regs); - return; - } - - /* check for i8259 interrupts */ - if (mask & (1 << VRC5476_I8259_CASCADE)) { - int i8259_irq = nile4_i8259_iack(); - do_IRQ(I8259_IRQ_BASE + i8259_irq, regs); - return; - } - - /* regular nile4 interrupts (we should not really have any */ - for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) { - if (mask & 1) { - do_IRQ(VRC5476_IRQ_BASE + nile4_irq, regs); - return; - } - } - spurious_interrupt(regs); -} diff --git a/arch/mips/defconfig b/arch/mips/defconfig index f7b0beb5752f..f72ba3f1b7f5 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -41,7 +41,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_XXS1500 is not set # CONFIG_PNX8550_V2PCI is not set # CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set # CONFIG_MACH_VR41XX is not set # CONFIG_PMC_YOSEMITE is not set diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index d028197d8326..c5f5516f4695 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o # # These are still pretty much in the old state, watch, go blind. # -obj-$(CONFIG_DDB5476) += ops-ddb5476.o pci-ddb5476.o obj-$(CONFIG_DDB5477) += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o diff --git a/arch/mips/pci/ops-ddb5476.c b/arch/mips/pci/ops-ddb5476.c deleted file mode 100644 index 12da58e75ec7..000000000000 --- a/arch/mips/pci/ops-ddb5476.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * arch/mips/ddb5xxx/ddb5476/pci_ops.c - * Define the pci_ops for DB5477. - * - * Much of the code is derived from the original DDB5074 port by - * Geert Uytterhoeven - * - * 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 - -/* - * config_swap structure records what set of pdar/pmr are used - * to access pci config space. It also provides a place hold the - * original values for future restoring. - */ -struct pci_config_swap { - u32 pdar; - u32 pmr; - u32 config_base; - u32 config_size; - u32 pdar_backup; - u32 pmr_backup; -}; - -/* - * On DDB5476, we have one set of swap registers - */ -struct pci_config_swap ext_pci_swap = { - DDB_PCIW0, - DDB_PCIINIT0, - DDB_PCI_CONFIG_BASE, - DDB_PCI_CONFIG_SIZE -}; - -static int pci_config_workaround = 1; - -/* - * access config space - */ -static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */ - u32 slot_num) -{ - u32 pci_addr = 0; - u32 pciinit_offset = 0; - u32 virt_addr = swap->config_base; - u32 option; - - if (pci_config_workaround) { - /* [jsun] work around Vrc5476 controller itself, returnning - * slot 0 essentially makes vrc5476 invisible - */ - if (slot_num == 12) - slot_num = 0; - -#if 0 - /* BUG : skip P2P bridge for now */ - if (slot_num == 5) - slot_num = 0; -#endif - - } else { - /* now we have to be hornest, returning the true - * PCI config headers for vrc5476 - */ - if (slot_num == 12) { - swap->pdar_backup = ddb_in32(swap->pdar); - swap->pmr_backup = ddb_in32(swap->pmr); - return DDB_BASE + DDB_PCI_BASE; - } - } - - /* minimum pdar (window) size is 2MB */ - db_assert(swap->config_size >= (2 << 20)); - - db_assert(slot_num < (1 << 5)); - db_assert(bus < (1 << 8)); - - /* backup registers */ - swap->pdar_backup = ddb_in32(swap->pdar); - swap->pmr_backup = ddb_in32(swap->pmr); - - /* set the pdar (pci window) register */ - ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */ - 0, /* not on local memory bus */ - 0); /* not visible from PCI bus (N/A) */ - - /* - * calcuate the absolute pci config addr; - * according to the spec, we start scanning from adr:11 (0x800) - */ - if (bus == 0) { - /* type 0 config */ - pci_addr = 0x800 << slot_num; - } else { - /* type 1 config */ - pci_addr = (bus << 16) | (slot_num << 11); - /* panic("ddb_access_config_base: we don't support type 1 config Yet"); */ - } - - /* - * if pci_addr is less than pci config window size, we set - * pciinit_offset to 0 and adjust the virt_address. - * Otherwise we will try to adjust pciinit_offset. - */ - if (pci_addr < swap->config_size) { - virt_addr = KSEG1ADDR(swap->config_base + pci_addr); - pciinit_offset = 0; - } else { - db_assert((pci_addr & (swap->config_size - 1)) == 0); - virt_addr = KSEG1ADDR(swap->config_base); - pciinit_offset = pci_addr; - } - - /* set the pmr register */ - option = DDB_PCI_ACCESS_32; - if (bus != 0) - option |= DDB_PCI_CFGTYPE1; - ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option); - - return virt_addr; -} - -static inline void ddb_close_config_base(struct pci_config_swap *swap) -{ - ddb_out32(swap->pdar, swap->pdar_backup); - ddb_out32(swap->pmr, swap->pmr_backup); -} - -static int read_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u32 * val) -{ - u32 bus, slot_num, func_num; - u32 base; - - db_assert((where & 3) == 0); - db_assert(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - db_assert(bus != 0); - } else { - bus = 0; - } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *val = *(volatile u32 *) (base + (func_num << 8) + where); - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; -} - -static int read_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u16 * val) -{ - int status; - u32 result; - - db_assert((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return status; -} - -static int read_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u8 * val) -{ - int status; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return status; -} - -static int write_config_dword(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u32 val) -{ - u32 bus, slot_num, func_num; - u32 base; - - db_assert((where & 3) == 0); - db_assert(where < (1 << 8)); - - /* check if the bus is top-level */ - if (dev->bus->parent != NULL) { - bus = dev->bus->number; - db_assert(bus != 0); - } else { - bus = 0; - } - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - base = ddb_access_config_base(swap, bus, slot_num); - *(volatile u32 *) (base + (func_num << 8) + where) = val; - ddb_close_config_base(swap); - return PCIBIOS_SUCCESSFUL; -} - -static int write_config_word(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u16 val) -{ - int status, shift = 0; - u32 result; - - db_assert((where & 1) == 0); - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -static int write_config_byte(struct pci_config_swap *swap, - struct pci_dev *dev, u32 where, u8 val) -{ - int status, shift = 0; - u32 result; - - status = read_config_dword(swap, dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return write_config_dword(swap, dev, where & ~3, result); -} - -#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ -static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ -{ \ - return rw##_config_##unitname(pciswap, \ - dev, \ - where, \ - val); \ -} - -MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) - MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) - MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) - - MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) - MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) - MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) - -struct pci_ops ddb5476_ext_pci_ops = { - extpci_read_config_byte, - extpci_read_config_word, - extpci_read_config_dword, - extpci_write_config_byte, - extpci_write_config_word, - extpci_write_config_dword -}; diff --git a/arch/mips/pci/pci-ddb5476.c b/arch/mips/pci/pci-ddb5476.c deleted file mode 100644 index 2f44c0b783d9..000000000000 --- a/arch/mips/pci/pci-ddb5476.c +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -static struct resource extpci_io_resource = { - .start = 0x1000, /* leave some room for ISA bus */ - .end = DDB_PCI_IO_SIZE - 1, - .name = "pci IO space", - .flags = IORESOURCE_IO -}; - -static struct resource extpci_mem_resource = { - .start = DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */ - .end = DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE - 1, - .name = "pci memory space", - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops ddb5476_ext_pci_ops; - -struct pci_controller ddb5476_controller = { - .pci_ops = &ddb5476_ext_pci_ops, - .io_resource = &extpci_io_resource, - .mem_resource = &extpci_mem_resource -}; - - -/* - * we fix up irqs based on the slot number. - * The first entry is at AD:11. - * - * This does not work for devices on sub-buses yet. - */ - -/* - * temporary - */ - -#define PCI_EXT_INTA 8 -#define PCI_EXT_INTB 9 -#define PCI_EXT_INTC 10 -#define PCI_EXT_INTD 11 -#define PCI_EXT_INTE 12 - -/* - * based on ddb5477 manual page 11 - */ -#define MAX_SLOT_NUM 21 -static unsigned char irq_map[MAX_SLOT_NUM] = { - [ 2] = 9, /* AD:13 USB */ - [ 3] = 10, /* AD:14 PMU */ - [ 5] = 0, /* AD:16 P2P bridge */ - [ 6] = nile4_to_irq(PCI_EXT_INTB), /* AD:17 */ - [ 7] = nile4_to_irq(PCI_EXT_INTC), /* AD:18 */ - [ 8] = nile4_to_irq(PCI_EXT_INTD), /* AD:19 */ - [ 9] = nile4_to_irq(PCI_EXT_INTA), /* AD:20 */ - [13] = 14, /* AD:24 HD controller, M5229 */ -}; - -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - return irq_map[slot]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} - -void __init ddb_pci_reset_bus(void) -{ - u32 temp; - - /* - * I am not sure about the "official" procedure, the following - * steps work as far as I know: - * We first set PCI cold reset bit (bit 31) in PCICTRL-H. - * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H. - * The same is true for both PCI channels. - */ - temp = ddb_in32(DDB_PCICTRL + 4); - temp |= 0x80000000; - ddb_out32(DDB_PCICTRL + 4, temp); - temp &= ~0xc0000000; - ddb_out32(DDB_PCICTRL + 4, temp); - -} diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index c67c91251d04..351a45d8e4ab 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1483,14 +1483,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, sa_offset = 2; /* Grrr, damn Matrox boards. */ multiport_cnt = 4; } -#ifdef CONFIG_DDB5476 - if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 6)) { - /* DDB5476 MAC address in first EEPROM locations. */ - sa_offset = 0; - /* No media table either */ - tp->flags &= ~HAS_MEDIA_TABLE; - } -#endif #ifdef CONFIG_DDB5477 if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) { /* DDB5477 MAC address in first EEPROM locations. */ diff --git a/include/asm-mips/ddb5xxx/ddb5476.h b/include/asm-mips/ddb5xxx/ddb5476.h deleted file mode 100644 index 4c23390d9354..000000000000 --- a/include/asm-mips/ddb5xxx/ddb5476.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * header file specific for ddb5476 - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * 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. - * - */ - -/* - * Memory map (physical address) - * - * Note most of the following address must be properly aligned by the - * corresponding size. For example, if PCI_IO_SIZE is 16MB, then - * PCI_IO_BASE must be aligned along 16MB boundary. - */ -#define DDB_SDRAM_BASE 0x00000000 -#define DDB_SDRAM_SIZE 0x04000000 /* 64MB */ - -#define DDB_DCS3_BASE 0x04000000 /* flash 1 */ -#define DDB_DCS3_SIZE 0x01000000 /* 16MB */ - -#define DDB_DCS2_BASE 0x05000000 /* flash 2 */ -#define DDB_DCS2_SIZE 0x01000000 /* 16MB */ - -#define DDB_PCI_IO_BASE 0x06000000 -#define DDB_PCI_IO_SIZE 0x02000000 /* 32 MB */ - -#define DDB_PCI_MEM_BASE 0x08000000 -#define DDB_PCI_MEM_SIZE 0x08000000 /* 128 MB */ - -#define DDB_DCS5_BASE 0x13000000 /* DDB status regs */ -#define DDB_DCS5_SIZE 0x00200000 /* 2MB, 8-bit */ - -#define DDB_DCS4_BASE 0x14000000 /* DDB control regs */ -#define DDB_DCS4_SIZE 0x00200000 /* 2MB, 8-bit */ - -#define DDB_INTCS_BASE 0x1fa00000 /* VRC5476 control regs */ -#define DDB_INTCS_SIZE 0x00200000 /* 2MB */ - -#define DDB_BOOTCS_BASE 0x1fc00000 /* Boot ROM / EPROM /Flash */ -#define DDB_BOOTCS_SIZE 0x00200000 /* 2 MB - doc says 4MB */ - - -/* aliases */ -#define DDB_PCI_CONFIG_BASE DDB_PCI_MEM_BASE -#define DDB_PCI_CONFIG_SIZE DDB_PCI_MEM_SIZE - -/* PCI intr ack share PCIW0 with PCI IO */ -#define DDB_PCI_IACK_BASE DDB_PCI_IO_BASE - -/* - * Interrupt mapping - * - * We have three interrupt controllers: - * - * . CPU itself - 8 sources - * . i8259 - 16 sources - * . vrc5476 - 16 sources - * - * They connected as follows: - * all vrc5476 interrupts are routed to cpu IP2 (by software setting) - * all i2869 are routed to INTC in vrc5476 (by hardware connection) - * - * All VRC5476 PCI interrupts are level-triggered (no ack needed). - * All PCI irq but INTC are active low. - */ - -/* - * irq number block assignment - */ - -#define NUM_CPU_IRQ 8 -#define NUM_I8259_IRQ 16 -#define NUM_VRC5476_IRQ 16 - -#define DDB_IRQ_BASE 0 - -#define I8259_IRQ_BASE DDB_IRQ_BASE -#define VRC5476_IRQ_BASE (I8259_IRQ_BASE + NUM_I8259_IRQ) -#define CPU_IRQ_BASE (VRC5476_IRQ_BASE + NUM_VRC5476_IRQ) - -/* - * vrc5476 irq defs, see page 52-64 of Vrc5074 system controller manual - */ - -#define VRC5476_IRQ_CPCE 0 /* cpu parity error */ -#define VRC5476_IRQ_CNTD 1 /* cpu no target */ -#define VRC5476_IRQ_MCE 2 /* memory check error */ -#define VRC5476_IRQ_DMA 3 /* DMA */ -#define VRC5476_IRQ_UART 4 /* vrc5476 builtin UART, not used */ -#define VRC5476_IRQ_WDOG 5 /* watchdog timer */ -#define VRC5476_IRQ_GPT 6 /* general purpose timer */ -#define VRC5476_IRQ_LBRT 7 /* local bus read timeout */ -#define VRC5476_IRQ_INTA 8 /* PCI INT #A */ -#define VRC5476_IRQ_INTB 9 /* PCI INT #B */ -#define VRC5476_IRQ_INTC 10 /* PCI INT #C */ -#define VRC5476_IRQ_INTD 11 /* PCI INT #D */ -#define VRC5476_IRQ_INTE 12 /* PCI INT #E */ -#define VRC5476_IRQ_RESERVED_13 13 /* reserved */ -#define VRC5476_IRQ_PCIS 14 /* PCI SERR # */ -#define VRC5476_IRQ_PCI 15 /* PCI internal error */ - -/* - * i2859 irq assignment - */ -#define I8259_IRQ_RESERVED_0 0 -#define I8259_IRQ_KEYBOARD 1 /* M1543 default */ -#define I8259_IRQ_CASCADE 2 -#define I8259_IRQ_UART_B 3 /* M1543 default, may conflict with RTC according to schematic diagram */ -#define I8259_IRQ_UART_A 4 /* M1543 default */ -#define I8259_IRQ_PARALLEL 5 /* M1543 default */ -#define I8259_IRQ_RESERVED_6 6 -#define I8259_IRQ_RESERVED_7 7 -#define I8259_IRQ_RTC 8 /* who set this? */ -#define I8259_IRQ_USB 9 /* ddb_setup */ -#define I8259_IRQ_PMU 10 /* ddb_setup */ -#define I8259_IRQ_RESERVED_11 11 -#define I8259_IRQ_RESERVED_12 12 /* m1543_irq_setup */ -#define I8259_IRQ_RESERVED_13 13 -#define I8259_IRQ_HDC1 14 /* default and ddb_setup */ -#define I8259_IRQ_HDC2 15 /* default */ - - -/* - * misc - */ -#define VRC5476_I8259_CASCADE VRC5476_IRQ_INTC -#define CPU_VRC5476_CASCADE 2 - -#define is_i8259_irq(irq) ((irq) < NUM_I8259_IRQ) -#define nile4_to_irq(n) ((n)+NUM_I8259_IRQ) -#define irq_to_nile4(n) ((n)-NUM_I8259_IRQ) - -/* - * low-level irq functions - */ -#ifndef __ASSEMBLY__ -extern void nile4_map_irq(int nile4_irq, int cpu_irq); -extern void nile4_map_irq_all(int cpu_irq); -extern void nile4_enable_irq(int nile4_irq); -extern void nile4_disable_irq(int nile4_irq); -extern void nile4_disable_irq_all(void); -extern u16 nile4_get_irq_stat(int cpu_irq); -extern void nile4_enable_irq_output(int cpu_irq); -extern void nile4_disable_irq_output(int cpu_irq); -extern void nile4_set_pci_irq_polarity(int pci_irq, int high); -extern void nile4_set_pci_irq_level_or_edge(int pci_irq, int level); -extern void nile4_clear_irq(int nile4_irq); -extern void nile4_clear_irq_mask(u32 mask); -extern u8 nile4_i8259_iack(void); -extern void nile4_dump_irq_status(void); /* Debug */ -#endif /* !__ASSEMBLY__ */ diff --git a/include/asm-mips/ddb5xxx/ddb5xxx.h b/include/asm-mips/ddb5xxx/ddb5xxx.h index 2c8c93430c1c..2f1b191c6fff 100644 --- a/include/asm-mips/ddb5xxx/ddb5xxx.h +++ b/include/asm-mips/ddb5xxx/ddb5xxx.h @@ -255,9 +255,7 @@ extern void ddb_pci_reset_bus(void); /* * include the board dependent part */ -#if defined(CONFIG_DDB5476) -#include -#elif defined(CONFIG_DDB5477) +#if defined(CONFIG_DDB5477) #include #else #error "Unknown DDB board!" -- cgit v1.2.3 From b00f473e1af9a11454e572de1ea446eb672e700d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 17 Jun 2006 10:56:26 +0100 Subject: [MIPS] SN: include asm/sn/types.h for nasid_t. Signed-off-by: Ralf Baechle --- include/asm-mips/pci/bridge.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/asm-mips/pci/bridge.h b/include/asm-mips/pci/bridge.h index 2bb1fca66136..0c45e7598f3f 100644 --- a/include/asm-mips/pci/bridge.h +++ b/include/asm-mips/pci/bridge.h @@ -15,6 +15,7 @@ #include #include #include /* generic widget header */ +#include /* I/O page size */ -- cgit v1.2.3 From 4a0312fca6599299bbed944ce09278d90388a3e5 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Tue, 13 Jun 2006 13:59:01 +0200 Subject: [MIPS] Support SNI RM200C SNI in big endian mode and R5000 processors. Added support for RM200C machines with big endian firmware Added support for RM200-C40 (R5000 support) Signed-off-by: Florian Lohoff Signed-off-by: Thomas Bogendoerfer Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 9 +- arch/mips/pci/ops-sni.c | 12 +- arch/mips/sni/Makefile | 1 + arch/mips/sni/setup.c | 7 +- arch/mips/sni/sniprom.c | 158 +++++++++++++++++++++ .../asm-mips/mach-rm200/cpu-feature-overrides.h | 2 - include/asm-mips/sni.h | 7 +- 7 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 arch/mips/sni/sniprom.c (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 138aac48d5d4..ecf922e3dc62 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -693,8 +693,8 @@ config SIBYTE_CRHONE config SNI_RM200_PCI bool "SNI RM200 PCI" - select ARC - select ARC32 + select ARC if CPU_LITTLE_ENDIAN + select ARC32 if CPU_LITTLE_ENDIAN select ARCH_MAY_HAVE_PC_FDC select BOOT_ELF32 select DMA_NONCOHERENT @@ -705,10 +705,13 @@ config SNI_RM200_PCI select I8253 select I8259 select ISA + select SWAP_IO_SPACE if CPU_BIG_ENDIAN select SYS_HAS_CPU_R4X00 + select SYS_HAS_CPU_R5000 + select R5000_CPU_SCACHE select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_BIG_ENDIAN if EXPERIMENTAL + select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_LITTLE_ENDIAN help diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c index 62bdd19c7f8e..2b0ccd6d9dcd 100644 --- a/arch/mips/pci/ops-sni.c +++ b/arch/mips/pci/ops-sni.c @@ -47,13 +47,13 @@ static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg, switch (size) { case 1: - *val = *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)); + *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); break; case 2: - *val = *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)); + *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); break; case 4: - *val = *(volatile u32 *) PCIMT_CONFIG_DATA; + *val = inl(PCIMT_CONFIG_DATA); break; } @@ -70,13 +70,13 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, switch (size) { case 1: - *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)) = val; + outb (val, PCIMT_CONFIG_DATA + (reg & 3)); break; case 2: - *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)) = val; + outw (val, PCIMT_CONFIG_DATA + (reg & 2)); break; case 4: - *(volatile u32 *) PCIMT_CONFIG_DATA = val; + outl (val, PCIMT_CONFIG_DATA); break; } diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile index 9c7eaa5fb210..a5eb0adb87c7 100644 --- a/arch/mips/sni/Makefile +++ b/arch/mips/sni/Makefile @@ -3,5 +3,6 @@ # obj-y += irq.o pcimt_scache.o reset.o setup.o +obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 635b904cabd7..a050bb6ae704 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -21,8 +21,11 @@ #include #include +#ifdef CONFIG_ARC #include #include +#endif + #include #include #include @@ -72,8 +75,7 @@ static inline void sni_pcimt_detect(void) static void __init sni_display_setup(void) { -#ifdef CONFIG_VT -#if defined(CONFIG_VGA_CONSOLE) +#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC) struct screen_info *si = &screen_info; DISPLAY_STATUS *di; @@ -88,7 +90,6 @@ static void __init sni_display_setup(void) si->orig_video_points = 16; } #endif -#endif } static struct resource sni_io_resource = { diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c new file mode 100644 index 000000000000..d1d0f1f493b4 --- /dev/null +++ b/arch/mips/sni/sniprom.c @@ -0,0 +1,158 @@ +/* + * Big Endian PROM code for SNI RM machines + * + * 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) 2005-2006 Florian Lohoff (flo@rfc822.org) + * Copyright (C) 2005-2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include +#include +#include + +#include +#include +#include +#include + +/* special SNI prom calls */ +/* + * This does not exist in all proms - SINIX compares + * the prom env variable "version" against "2.0008" + * or greater. If lesser it tries to probe interesting + * registers + */ +#define PROM_GET_MEMCONF 58 + +#define PROM_VEC (u64 *)CKSEG1ADDR(0x1fc00000) +#define PROM_ENTRY(x) (PROM_VEC + (x)) + + +#undef DEBUG +#ifdef DEBUG +#define DBG_PRINTF(x...) prom_printf(x) +#else +#define DBG_PRINTF(x...) +#endif + +static int *(*__prom_putchar)(int) = (int *(*)(int))PROM_ENTRY(PROM_PUTCHAR); +static char *(*__prom_getenv)(char *) = (char *(*)(char *))PROM_ENTRY(PROM_GETENV); +static void (*__prom_get_memconf)(void *) = (void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF); + +char *prom_getenv (char *s) +{ + return __prom_getenv(s); +} + +void prom_printf(char *fmt, ...) +{ + va_list args; + char ppbuf[1024]; + char *bptr; + + va_start(args, fmt); + vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while (*bptr != 0) { + if (*bptr == '\n') + __prom_putchar('\r'); + + __prom_putchar(*bptr++); + } + va_end(args); +} + +unsigned long prom_free_prom_memory(void) +{ + return 0; +} + +/* + * /proc/cpuinfo system type + * + */ +static const char *systype = "Unknown"; +const char *get_system_type(void) +{ + return systype; +} + +#define SNI_IDPROM_BASE 0xbff00000 +#define SNI_IDPROM_MEMSIZE (SNI_IDPROM_BASE+0x28) /* Memsize in 16MB quantities */ +#define SNI_IDPROM_BRDTYPE (SNI_IDPROM_BASE+0x29) /* Board Type */ +#define SNI_IDPROM_CPUTYPE (SNI_IDPROM_BASE+0x30) /* CPU Type */ + +#define SNI_IDPROM_SIZE 0x1000 + +#ifdef DEBUG +static void sni_idprom_dump(void) +{ + int i; + + prom_printf("SNI IDProm dump (first 128byte):\n"); + for(i=0;i<128;i++) { + if (i%16 == 0) + prom_printf("%04x ", i); + + prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE+i)); + + if (i%16 == 15) + prom_printf("\n"); + } +} +#endif + +static void sni_mem_init(void ) +{ + int i, memsize; + struct membank { + u32 size; + u32 base; + u32 size2; + u32 pad1; + u32 pad2; + } memconf[8]; + + /* MemSIZE from prom in 16MByte chunks */ + memsize=*((unsigned char *) SNI_IDPROM_MEMSIZE) * 16; + + DBG_PRINTF("IDProm memsize: %lu MByte\n", memsize); + + /* get memory bank layout from prom */ + __prom_get_memconf(&memconf); + + DBG_PRINTF("prom_get_mem_conf memory configuration:\n"); + for(i=0;i<8 && memconf[i].size;i++) { + prom_printf("Bank%d: %08x @ %08x\n", i, + memconf[i].size, memconf[i].base); + add_memory_region(memconf[i].base, memconf[i].size, BOOT_MEM_RAM); + } +} + +void __init prom_init(void) +{ + int argc = fw_arg0; + char **argv = (void *)fw_arg1; + unsigned int sni_brd_type = *(unsigned char *) SNI_IDPROM_BRDTYPE; + int i; + + DBG_PRINTF("Found SNI brdtype %02x\n", sni_brd_type); + +#ifdef DEBUG + sni_idprom_dump(); +#endif + sni_mem_init(); + + /* copy prom cmdline parameters to kernel cmdline */ + for (i = 1; i < argc; i++) { + strcat(arcs_cmdline, argv[i]); + if (i < (argc - 1)) + strcat(arcs_cmdline, " "); + } +} + diff --git a/include/asm-mips/mach-rm200/cpu-feature-overrides.h b/include/asm-mips/mach-rm200/cpu-feature-overrides.h index 91e7cf5f2bfe..01587832bc9c 100644 --- a/include/asm-mips/mach-rm200/cpu-feature-overrides.h +++ b/include/asm-mips/mach-rm200/cpu-feature-overrides.h @@ -35,10 +35,8 @@ #define cpu_has_nofpuex 0 #define cpu_has_64bits 1 -#define cpu_has_subset_pcaches 0 /* No S-cache on R5000 I think ... */ #define cpu_dcache_line_size() 32 #define cpu_icache_line_size() 32 -#define cpu_scache_line_size() 0 /* No S-cache on R5000 I think ... */ #define cpu_has_mips32r1 0 #define cpu_has_mips32r2 0 diff --git a/include/asm-mips/sni.h b/include/asm-mips/sni.h index b3bc698dfdee..b9ba54d0dd35 100644 --- a/include/asm-mips/sni.h +++ b/include/asm-mips/sni.h @@ -15,9 +15,6 @@ /* * ASIC PCI registers for little endian configuration. */ -#ifndef __MIPSEL__ -#error "Fix me for big endian" -#endif #define PCIMT_UCONF 0xbfff0000 #define PCIMT_IOADTIMEOUT2 0xbfff0008 #define PCIMT_IOMEMCONF 0xbfff0010 @@ -51,9 +48,9 @@ #define PCIMT_PCI_CONF 0xbfff0100 /* - * Data port for the PCI bus. + * Data port for the PCI bus in IO space */ -#define PCIMT_CONFIG_DATA 0xb4000cfc +#define PCIMT_CONFIG_DATA 0x0cfc /* * Board specific registers -- cgit v1.2.3 From 355c471f2ff324c21f8a1fb8e2e242a0f2a4aa68 Mon Sep 17 00:00:00 2001 From: dmitry pervushin Date: Sun, 21 May 2006 14:53:06 +0400 Subject: [MIPS] Support for the R5500-based NEC EMMA2RH Mark-eins board Signed-off-by: dmitry pervushin Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 19 + arch/mips/Makefile | 9 + arch/mips/configs/emma2rh_defconfig | 1198 +++++++++++++++++++++++++++++ arch/mips/emma2rh/common/Makefile | 13 + arch/mips/emma2rh/common/irq.c | 108 +++ arch/mips/emma2rh/common/irq_emma2rh.c | 134 ++++ arch/mips/emma2rh/common/prom.c | 77 ++ arch/mips/emma2rh/markeins/Makefile | 13 + arch/mips/emma2rh/markeins/irq.c | 134 ++++ arch/mips/emma2rh/markeins/irq_markeins.c | 197 +++++ arch/mips/emma2rh/markeins/led.c | 60 ++ arch/mips/emma2rh/markeins/platform.c | 170 ++++ arch/mips/emma2rh/markeins/setup.c | 182 +++++ arch/mips/pci/Makefile | 1 + arch/mips/pci/fixup-emma2rh.c | 102 +++ arch/mips/pci/ops-emma2rh.c | 186 +++++ arch/mips/pci/pci-emma2rh.c | 90 +++ include/asm-mips/bootinfo.h | 6 + include/asm-mips/emma2rh/emma2rh.h | 330 ++++++++ include/asm-mips/emma2rh/markeins.h | 76 ++ include/asm-mips/mach-emma2rh/irq.h | 13 + 21 files changed, 3118 insertions(+) create mode 100644 arch/mips/configs/emma2rh_defconfig create mode 100644 arch/mips/emma2rh/common/Makefile create mode 100644 arch/mips/emma2rh/common/irq.c create mode 100644 arch/mips/emma2rh/common/irq_emma2rh.c create mode 100644 arch/mips/emma2rh/common/prom.c create mode 100644 arch/mips/emma2rh/markeins/Makefile create mode 100644 arch/mips/emma2rh/markeins/irq.c create mode 100644 arch/mips/emma2rh/markeins/irq_markeins.c create mode 100644 arch/mips/emma2rh/markeins/led.c create mode 100644 arch/mips/emma2rh/markeins/platform.c create mode 100644 arch/mips/emma2rh/markeins/setup.c create mode 100644 arch/mips/pci/fixup-emma2rh.c create mode 100644 arch/mips/pci/ops-emma2rh.c create mode 100644 arch/mips/pci/pci-emma2rh.c create mode 100644 include/asm-mips/emma2rh/emma2rh.h create mode 100644 include/asm-mips/emma2rh/markeins.h create mode 100644 include/asm-mips/mach-emma2rh/irq.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ecf922e3dc62..db3d008732c6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -530,6 +530,20 @@ config QEMU simulate actual MIPS hardware platforms. More information on Qemu can be found at http://www.linux-mips.org/wiki/Qemu. +config MARKEINS + bool "Support for NEC EMMA2RH Mark-eins" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select SWAP_IO_SPACE + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_HAS_CPU_R5000 + help + This enables support for the R5432-based NEC Mark-eins + boards with R5500 CPU. + config SGI_IP22 bool "SGI IP22 (Indy/Indigo2)" select ARC @@ -968,6 +982,11 @@ config SOC_PNX8550 config SWAP_IO_SPACE bool +config EMMA2RH + bool + depends on MARKEINS + default y + # # Unfortunately not all GT64120 systems run the chip at the same clock. # As the user for the clock rate and try to minimize the available options. diff --git a/arch/mips/Makefile b/arch/mips/Makefile index e0cab2850a72..207197b91a53 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -465,6 +465,15 @@ libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/ #cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550 load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000 +# NEC EMMA2RH boards +# +core-$(CONFIG_EMMA2RH) += arch/mips/emma2rh/common/ +cflags-$(CONFIG_EMMA2RH) += -Iinclude/asm-mips/mach-emma2rh + +# NEC EMMA2RH Mark-eins +core-$(CONFIG_MARKEINS) += arch/mips/emma2rh/markeins/ +load-$(CONFIG_MARKEINS) += 0xffffffff88100000 + # # SGI IP22 (Indy/Indigo2) # diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig new file mode 100644 index 000000000000..da1bc03fa256 --- /dev/null +++ b/arch/mips/configs/emma2rh_defconfig @@ -0,0 +1,1198 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.17 +# Sun Jun 18 13:46:53 2006 +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MIPS_MTX1 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_WR_PPMC is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MIPS_XXS1500 is not set +# CONFIG_PNX8550_V2PCI is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_DDB5477 is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +CONFIG_MARKEINS=y +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_CPU_BIG_ENDIAN=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_EMMA2RH=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_MIPS32_R1 is not set +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +CONFIG_CPU_R5000=y +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_R5000=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMTC is not set +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_VPE_LOADER is not set +# CONFIG_64BIT_PHYS_ADDR is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_BKL=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set +CONFIG_OBSOLETE_INTERMODULE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_FWMARK is not set +CONFIG_IP_ROUTE_MULTIPATH=y +# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_IPV6_TUNNEL is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +# CONFIG_IP6_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x1e000000 +CONFIG_MTD_PHYSMAP_LEN=0x02000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_DM9000 is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +CONFIG_NATSEMI=y +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_LAN_SAA9730 is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_RTC=m +CONFIG_GEN_RTC=m +CONFIG_GEN_RTC_X=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +CONFIG_I2C_DEBUG_CORE=y +# CONFIG_I2C_DEBUG_ALGO is not set +CONFIG_I2C_DEBUG_BUS=y +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_V4L2=y + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_EXPORT=y +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_FS is not set +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="console=ttyS0,115200 mem=192m ip=bootp root=/dev/nfs rw" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/mips/emma2rh/common/Makefile b/arch/mips/emma2rh/common/Makefile new file mode 100644 index 000000000000..859121b3867d --- /dev/null +++ b/arch/mips/emma2rh/common/Makefile @@ -0,0 +1,13 @@ +# +# arch/mips/emma2rh/common/Makefile +# Makefile for the common code of NEC EMMA2RH based board. +# +# Copyright (C) NEC Electronics Corporation 2005-2006 +# +# 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. +# + +obj-$(CONFIG_MARKEINS) += irq.o irq_emma2rh.o prom.o diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c new file mode 100644 index 000000000000..b075281e50e9 --- /dev/null +++ b/arch/mips/emma2rh/common/irq.c @@ -0,0 +1,108 @@ +/* + * arch/mips/emma2rh/common/irq.c + * This file is common irq dispatcher. + * + * Copyright (C) NEC Electronics Corporation 2005-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/irq.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* + * the first level int-handler will jump here if it is a emma2rh irq + */ +asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) +{ + u32 intStatus; + u32 bitmask; + u32 i; + + intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_0) + & emma2rh_in32(EMMA2RH_BHIF_INT_EN_0); + +#ifdef EMMA2RH_SW_CASCADE + if (intStatus & + (1 << ((EMMA2RH_SW_CASCADE - EMMA2RH_IRQ_INT0) & (32 - 1)))) { + u32 swIntStatus; + swIntStatus = emma2rh_in32(EMMA2RH_BHIF_SW_INT) + & emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); + for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { + if (swIntStatus & bitmask) { + do_IRQ(EMMA2RH_SW_IRQ_BASE + i, regs); + return; + } + } + } +#endif + + for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { + if (intStatus & bitmask) { + do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + return; + } + } + + intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_1) + & emma2rh_in32(EMMA2RH_BHIF_INT_EN_1); + +#ifdef EMMA2RH_GPIO_CASCADE + if (intStatus & + (1 << ((EMMA2RH_GPIO_CASCADE - EMMA2RH_IRQ_INT0) & (32 - 1)))) { + u32 gpioIntStatus; + gpioIntStatus = emma2rh_in32(EMMA2RH_GPIO_INT_ST) + & emma2rh_in32(EMMA2RH_GPIO_INT_MASK); + for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { + if (gpioIntStatus & bitmask) { + do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i, regs); + return; + } + } + } +#endif + + for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) { + if (intStatus & bitmask) { + do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + return; + } + } + + intStatus = emma2rh_in32(EMMA2RH_BHIF_INT_ST_2) + & emma2rh_in32(EMMA2RH_BHIF_INT_EN_2); + + for (i = 64, bitmask = 1; i < 96; i++, bitmask <<= 1) { + if (intStatus & bitmask) { + do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + return; + } + } +} diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c new file mode 100644 index 000000000000..b886aa94ca90 --- /dev/null +++ b/arch/mips/emma2rh/common/irq_emma2rh.c @@ -0,0 +1,134 @@ +/* + * arch/mips/emma2rh/common/irq_emma2rh.c + * This file defines the irq handler for EMMA2RH. + * + * Copyright (C) NEC Electronics Corporation 2005-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/irq_5477.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ + +/* + * EMMA2RH defines 64 IRQs. + * + * This file exports one function: + * emma2rh_irq_init(u32 irq_base); + */ + +#include +#include +#include + +#include + +#include + +/* number of total irqs supported by EMMA2RH */ +#define NUM_EMMA2RH_IRQ 96 + +static int emma2rh_irq_base = -1; + +void ll_emma2rh_irq_enable(int); +void ll_emma2rh_irq_disable(int); + +static void emma2rh_irq_enable(unsigned int irq) +{ + ll_emma2rh_irq_enable(irq - emma2rh_irq_base); +} + +static void emma2rh_irq_disable(unsigned int irq) +{ + ll_emma2rh_irq_disable(irq - emma2rh_irq_base); +} + +static unsigned int emma2rh_irq_startup(unsigned int irq) +{ + emma2rh_irq_enable(irq); + return 0; +} + +#define emma2rh_irq_shutdown emma2rh_irq_disable + +static void emma2rh_irq_ack(unsigned int irq) +{ + /* disable interrupt - some handler will re-enable the irq + * and if the interrupt is leveled, we will have infinite loop + */ + ll_emma2rh_irq_disable(irq - emma2rh_irq_base); +} + +static void emma2rh_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ll_emma2rh_irq_enable(irq - emma2rh_irq_base); +} + +hw_irq_controller emma2rh_irq_controller = { + .typename = "emma2rh_irq", + .startup = emma2rh_irq_startup, + .shutdown = emma2rh_irq_shutdown, + .enable = emma2rh_irq_enable, + .disable = emma2rh_irq_disable, + .ack = emma2rh_irq_ack, + .end = emma2rh_irq_end, + .set_affinity = NULL /* no affinity stuff for UP */ +}; + +void emma2rh_irq_init(u32 irq_base) +{ + u32 i; + + for (i = irq_base; i < irq_base + NUM_EMMA2RH_IRQ; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &emma2rh_irq_controller; + } + + emma2rh_irq_base = irq_base; +} + +void ll_emma2rh_irq_enable(int emma2rh_irq) +{ + u32 reg_value; + u32 reg_bitmask; + u32 reg_index; + + reg_index = EMMA2RH_BHIF_INT_EN_0 + + (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) + * (emma2rh_irq / 32); + reg_value = emma2rh_in32(reg_index); + reg_bitmask = 0x1 << (emma2rh_irq % 32); + db_assert((reg_value & reg_bitmask) == 0); + emma2rh_out32(reg_index, reg_value | reg_bitmask); +} + +void ll_emma2rh_irq_disable(int emma2rh_irq) +{ + u32 reg_value; + u32 reg_bitmask; + u32 reg_index; + + reg_index = EMMA2RH_BHIF_INT_EN_0 + + (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) + * (emma2rh_irq / 32); + reg_value = emma2rh_in32(reg_index); + reg_bitmask = 0x1 << (emma2rh_irq % 32); + db_assert((reg_value & reg_bitmask) != 0); + emma2rh_out32(reg_index, reg_value & ~reg_bitmask); +} diff --git a/arch/mips/emma2rh/common/prom.c b/arch/mips/emma2rh/common/prom.c new file mode 100644 index 000000000000..8bba0b02a204 --- /dev/null +++ b/arch/mips/emma2rh/common/prom.c @@ -0,0 +1,77 @@ +/* + * arch/mips/emma2rh/common/prom.c + * This file is prom file. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/common/prom.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +const char *get_system_type(void) +{ + switch (mips_machtype) { + case MACH_NEC_MARKEINS: + return "NEC EMMA2RH Mark-eins"; + default: + return "Unknown NEC board"; + } +} + +/* [jsun@junsun.net] PMON passes arguments in C main() style */ +void __init prom_init(void) +{ + int argc = fw_arg0; + char **arg = (char **)fw_arg1; + int i; + + /* if user passes kernel args, ignore the default one */ + if (argc > 1) + arcs_cmdline[0] = '\0'; + + /* arg[0] is "g", the rest is boot parameters */ + for (i = 1; i < argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) + >= sizeof(arcs_cmdline)) + break; + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + mips_machgroup = MACH_GROUP_NEC_EMMA2RH; + +#if defined(CONFIG_MARKEINS) + mips_machtype = MACH_NEC_MARKEINS; + add_memory_region(0, EMMA2RH_RAM_SIZE, BOOT_MEM_RAM); +#endif + +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/emma2rh/markeins/Makefile b/arch/mips/emma2rh/markeins/Makefile new file mode 100644 index 000000000000..14fc268b175c --- /dev/null +++ b/arch/mips/emma2rh/markeins/Makefile @@ -0,0 +1,13 @@ +# +# arch/mips/emma2rh/markeins/Makefile +# Makefile for the common code of NEC EMMA2RH based board. +# +# Copyright (C) NEC Electronics Corporation 2005-2006 +# +# 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. +# + +obj-$(CONFIG_MARKEINS) += irq.o irq_markeins.o setup.o led.o platform.o diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c new file mode 100644 index 000000000000..76dc3faeaf4e --- /dev/null +++ b/arch/mips/emma2rh/markeins/irq.c @@ -0,0 +1,134 @@ +/* + * arch/mips/emma2rh/markeins/irq.c + * This file defines the irq handler for EMMA2RH. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/irq.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * IRQ mapping + * + * 0-7: 8 CPU interrupts + * 0 - software interrupt 0 + * 1 - software interrupt 1 + * 2 - most Vrc5477 interrupts are routed to this pin + * 3 - (optional) some other interrupts routed to this pin for debugg + * 4 - not used + * 5 - not used + * 6 - not used + * 7 - cpu timer (used by default) + * + */ + +extern void emma2rh_sw_irq_init(u32 base); +extern void emma2rh_gpio_irq_init(u32 base); +extern void emma2rh_irq_init(u32 base); +extern asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs); + +static struct irqaction irq_cascade = { + .handler = no_action, + .flags = 0, + .mask = CPU_MASK_NONE, + .name = "cascade", + .dev_id = NULL, + .next = NULL, +}; + +void __init arch_init_irq(void) +{ + u32 reg; + + db_run(printk("markeins_irq_setup invoked.\n")); + + /* by default, interrupts are disabled. */ + emma2rh_out32(EMMA2RH_BHIF_INT_EN_0, 0); + emma2rh_out32(EMMA2RH_BHIF_INT_EN_1, 0); + emma2rh_out32(EMMA2RH_BHIF_INT_EN_2, 0); + emma2rh_out32(EMMA2RH_BHIF_INT1_EN_0, 0); + emma2rh_out32(EMMA2RH_BHIF_INT1_EN_1, 0); + emma2rh_out32(EMMA2RH_BHIF_INT1_EN_2, 0); + emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, 0); + + clear_c0_status(0xff00); + set_c0_status(0x0400); + +#define GPIO_PCI (0xf<<15) + /* setup GPIO interrupt for PCI interface */ + /* direction input */ + reg = emma2rh_in32(EMMA2RH_GPIO_DIR); + emma2rh_out32(EMMA2RH_GPIO_DIR, reg & ~GPIO_PCI); + /* disable interrupt */ + reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); + emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg & ~GPIO_PCI); + /* level triggerd */ + reg = emma2rh_in32(EMMA2RH_GPIO_INT_MODE); + emma2rh_out32(EMMA2RH_GPIO_INT_MODE, reg | GPIO_PCI); + reg = emma2rh_in32(EMMA2RH_GPIO_INT_CND_A); + emma2rh_out32(EMMA2RH_GPIO_INT_CND_A, reg & (~GPIO_PCI)); + /* interrupt clear */ + emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~GPIO_PCI); + + /* init all controllers */ + emma2rh_irq_init(EMMA2RH_IRQ_BASE); + emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE); + emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE); + mips_cpu_irq_init(CPU_IRQ_BASE); + + /* setup cascade interrupts */ + setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); + setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade); + setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade); +} + +asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +{ + unsigned int pending = read_c0_status() & read_c0_cause(); + + if (pending & STATUSF_IP7) + do_IRQ(CPU_IRQ_BASE + 7, regs); + else if (pending & STATUSF_IP2) + emma2rh_irq_dispatch(regs); + else if (pending & STATUSF_IP1) + do_IRQ(CPU_IRQ_BASE + 1, regs); + else if (pending & STATUSF_IP0) + do_IRQ(CPU_IRQ_BASE + 0, regs); + else + spurious_interrupt(regs); +} + + diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c new file mode 100644 index 000000000000..1783fdab6459 --- /dev/null +++ b/arch/mips/emma2rh/markeins/irq_markeins.c @@ -0,0 +1,197 @@ +/* + * arch/mips/emma2rh/markeins/irq_markeins.c + * This file defines the irq handler for Mark-eins. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/irq_5477.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ +#include +#include +#include +#include + +#include +#include + +static int emma2rh_sw_irq_base = -1; +static int emma2rh_gpio_irq_base = -1; + +void ll_emma2rh_sw_irq_enable(int reg); +void ll_emma2rh_sw_irq_disable(int reg); +void ll_emma2rh_gpio_irq_enable(int reg); +void ll_emma2rh_gpio_irq_disable(int reg); + +static void emma2rh_sw_irq_enable(unsigned int irq) +{ + ll_emma2rh_sw_irq_enable(irq - emma2rh_sw_irq_base); +} + +static void emma2rh_sw_irq_disable(unsigned int irq) +{ + ll_emma2rh_sw_irq_disable(irq - emma2rh_sw_irq_base); +} + +static unsigned int emma2rh_sw_irq_startup(unsigned int irq) +{ + emma2rh_sw_irq_enable(irq); + return 0; +} + +#define emma2rh_sw_irq_shutdown emma2rh_sw_irq_disable + +static void emma2rh_sw_irq_ack(unsigned int irq) +{ + ll_emma2rh_sw_irq_disable(irq - emma2rh_sw_irq_base); +} + +static void emma2rh_sw_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ll_emma2rh_sw_irq_enable(irq - emma2rh_sw_irq_base); +} + +hw_irq_controller emma2rh_sw_irq_controller = { + .typename = "emma2rh_sw_irq", + .startup = emma2rh_sw_irq_startup, + .shutdown = emma2rh_sw_irq_shutdown, + .enable = emma2rh_sw_irq_enable, + .disable = emma2rh_sw_irq_disable, + .ack = emma2rh_sw_irq_ack, + .end = emma2rh_sw_irq_end, + .set_affinity = NULL, +}; + +void emma2rh_sw_irq_init(u32 irq_base) +{ + u32 i; + + for (i = irq_base; i < irq_base + NUM_EMMA2RH_IRQ_SW; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 2; + irq_desc[i].handler = &emma2rh_sw_irq_controller; + } + + emma2rh_sw_irq_base = irq_base; +} + +void ll_emma2rh_sw_irq_enable(int irq) +{ + u32 reg; + + db_assert(irq >= 0); + db_assert(irq < NUM_EMMA2RH_IRQ_SW); + + reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); + reg |= 1 << irq; + emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); +} + +void ll_emma2rh_sw_irq_disable(int irq) +{ + u32 reg; + + db_assert(irq >= 0); + db_assert(irq < 32); + + reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); + reg &= ~(1 << irq); + emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); +} + +static void emma2rh_gpio_irq_enable(unsigned int irq) +{ + ll_emma2rh_gpio_irq_enable(irq - emma2rh_gpio_irq_base); +} + +static void emma2rh_gpio_irq_disable(unsigned int irq) +{ + ll_emma2rh_gpio_irq_disable(irq - emma2rh_gpio_irq_base); +} + +static unsigned int emma2rh_gpio_irq_startup(unsigned int irq) +{ + emma2rh_gpio_irq_enable(irq); + return 0; +} + +#define emma2rh_gpio_irq_shutdown emma2rh_gpio_irq_disable + +static void emma2rh_gpio_irq_ack(unsigned int irq) +{ + irq -= emma2rh_gpio_irq_base; + emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); + ll_emma2rh_gpio_irq_disable(irq); +} + +static void emma2rh_gpio_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ll_emma2rh_gpio_irq_enable(irq - emma2rh_gpio_irq_base); +} + +hw_irq_controller emma2rh_gpio_irq_controller = { + .typename = "emma2rh_gpio_irq", + .startup = emma2rh_gpio_irq_startup, + .shutdown = emma2rh_gpio_irq_shutdown, + .enable = emma2rh_gpio_irq_enable, + .disable = emma2rh_gpio_irq_disable, + .ack = emma2rh_gpio_irq_ack, + .end = emma2rh_gpio_irq_end, + .set_affinity = NULL, +}; + +void emma2rh_gpio_irq_init(u32 irq_base) +{ + u32 i; + + for (i = irq_base; i < irq_base + NUM_EMMA2RH_IRQ_GPIO; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 2; + irq_desc[i].handler = &emma2rh_gpio_irq_controller; + } + + emma2rh_gpio_irq_base = irq_base; +} + +void ll_emma2rh_gpio_irq_enable(int irq) +{ + u32 reg; + + db_assert(irq >= 0); + db_assert(irq < NUM_EMMA2RH_IRQ_GPIO); + + reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); + reg |= 1 << irq; + emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); +} + +void ll_emma2rh_gpio_irq_disable(int irq) +{ + u32 reg; + + db_assert(irq >= 0); + db_assert(irq < NUM_EMMA2RH_IRQ_GPIO); + + reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); + reg &= ~(1 << irq); + emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); +} diff --git a/arch/mips/emma2rh/markeins/led.c b/arch/mips/emma2rh/markeins/led.c new file mode 100644 index 000000000000..b65254c1bfe9 --- /dev/null +++ b/arch/mips/emma2rh/markeins/led.c @@ -0,0 +1,60 @@ +/* + * arch/mips/emma2rh/markeins/led.c + * This file defines the led display for Mark-eins. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * 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 + */ +#include +#include +#include +#include + +const unsigned long clear = 0x20202020; + +#define LED_BASE 0xb1400038 + +void markeins_led_clear(void) +{ + emma2rh_out32(LED_BASE, clear); + emma2rh_out32(LED_BASE + 4, clear); +} + +void markeins_led(const char *str) +{ + int i; + int len = strlen(str); + + markeins_led_clear(); + if (len > 8) + len = 8; + + if (emma2rh_in32(0xb0000800) & (0x1 << 18)) + for (i = 0; i < len; i++) + emma2rh_out8(LED_BASE + i, str[i]); + else + for (i = 0; i < len; i++) + emma2rh_out8(LED_BASE + (i & 4) + (3 - (i & 3)), + str[i]); +} + +void markeins_led_hex(u32 val) +{ + char str[10]; + + sprintf(str, "%08x", val); + markeins_led(str); +} diff --git a/arch/mips/emma2rh/markeins/platform.c b/arch/mips/emma2rh/markeins/platform.c new file mode 100644 index 000000000000..6c1eeae1a898 --- /dev/null +++ b/arch/mips/emma2rh/markeins/platform.c @@ -0,0 +1,170 @@ +/* + * arch/mips/emma2rh/markeins/platofrm.c + * This file sets up platform devices for EMMA2RH Mark-eins. + * + * Copyright(C) MontaVista Software Inc, 2006 + * + * Author: dmitry pervushin + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define I2C_EMMA2RH "emma2rh-iic" /* must be in sync with IIC driver */ + +static struct resource i2c_emma_resources_0[] = { + { NULL, EMMA2RH_IRQ_PIIC0, EMMA2RH_IRQ_PIIC0, IORESOURCE_IRQ }, + { NULL, KSEG1ADDR(EMMA2RH_PIIC0_BASE), KSEG1ADDR(EMMA2RH_PIIC0_BASE + 0x1000), 0 }, +}; + +struct resource i2c_emma_resources_1[] = { + { NULL, EMMA2RH_IRQ_PIIC1, EMMA2RH_IRQ_PIIC1, IORESOURCE_IRQ }, + { NULL, KSEG1ADDR(EMMA2RH_PIIC1_BASE), KSEG1ADDR(EMMA2RH_PIIC1_BASE + 0x1000), 0 }, +}; + +struct resource i2c_emma_resources_2[] = { + { NULL, EMMA2RH_IRQ_PIIC2, EMMA2RH_IRQ_PIIC2, IORESOURCE_IRQ }, + { NULL, KSEG1ADDR(EMMA2RH_PIIC2_BASE), KSEG1ADDR(EMMA2RH_PIIC2_BASE + 0x1000), 0 }, +}; + +struct platform_device i2c_emma_devices[] = { + [0] = { + .name = I2C_EMMA2RH, + .id = 0, + .resource = i2c_emma_resources_0, + .num_resources = ARRAY_SIZE(i2c_emma_resources_0), + }, + [1] = { + .name = I2C_EMMA2RH, + .id = 1, + .resource = i2c_emma_resources_1, + .num_resources = ARRAY_SIZE(i2c_emma_resources_1), + }, + [2] = { + .name = I2C_EMMA2RH, + .id = 2, + .resource = i2c_emma_resources_2, + .num_resources = ARRAY_SIZE(i2c_emma_resources_2), + }, +}; + +#define EMMA2RH_SERIAL_CLOCK 18544000 +#define EMMA2RH_SERIAL_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST + +static struct plat_serial8250_port platform_serial_ports[] = { + [0] = { + .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3), + .irq = EMMA2RH_IRQ_PFUR0, + .uartclk = EMMA2RH_SERIAL_CLOCK, + .regshift = 4, + .iotype = UPIO_MEM, + .flags = EMMA2RH_SERIAL_FLAGS, + }, + [1] = { + .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3), + .irq = EMMA2RH_IRQ_PFUR1, + .uartclk = EMMA2RH_SERIAL_CLOCK, + .regshift = 4, + .iotype = UPIO_MEM, + .flags = EMMA2RH_SERIAL_FLAGS, + }, + [2] = { + .membase = (void __iomem*)KSEG1ADDR(EMMA2RH_PFUR2_BASE + 3), + .irq = EMMA2RH_IRQ_PFUR2, + .uartclk = EMMA2RH_SERIAL_CLOCK, + .regshift = 4, + .iotype = UPIO_MEM, + .flags = EMMA2RH_SERIAL_FLAGS, + }, + [3] = { + .flags = 0, + }, +}; + +static struct platform_device serial_emma = { + .name = "serial8250", + .dev = { + .platform_data = &platform_serial_ports, + }, +}; + +static struct platform_device *devices[] = { + &i2c_emma_devices[0], + &i2c_emma_devices[1], + &i2c_emma_devices[2], + &serial_emma, +}; + +static struct mtd_partition markeins_parts[] = { + [0] = { + .name = "RootFS", + .offset = 0x00000000, + .size = 0x00c00000, + }, + [1] = { + .name = "boot code area", + .offset = MTDPART_OFS_APPEND, + .size = 0x00100000, + }, + [2] = { + .name = "kernel image", + .offset = MTDPART_OFS_APPEND, + .size = 0x00300000, + }, + [3] = { + .name = "RootFS2", + .offset = MTDPART_OFS_APPEND, + .size = 0x00c00000, + }, + [4] = { + .name = "boot code area2", + .offset = MTDPART_OFS_APPEND, + .size = 0x00100000, + }, + [5] = { + .name = "kernel image2", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static int __init platform_devices_setup(void) +{ + physmap_set_partitions(markeins_parts, ARRAY_SIZE(markeins_parts)); + return platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +arch_initcall(platform_devices_setup); + diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c new file mode 100644 index 000000000000..7d98fdbf8390 --- /dev/null +++ b/arch/mips/emma2rh/markeins/setup.c @@ -0,0 +1,182 @@ +/* + * arch/mips/emma2rh/markeins/setup.c + * This file is setup for EMMA2RH Mark-eins. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/setup.c. + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for HZ */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define USE_CPU_COUNTER_TIMER /* whether we use cpu counter */ + +extern void markeins_led(const char *); + +static int bus_frequency = 0; + +static void markeins_machine_restart(char *command) +{ + static void (*back_to_prom) (void) = (void (*)(void))0xbfc00000; + + printk("cannot EMMA2RH Mark-eins restart.\n"); + markeins_led("restart."); + back_to_prom(); +} + +static void markeins_machine_halt(void) +{ + printk("EMMA2RH Mark-eins halted.\n"); + markeins_led("halted."); + while (1) ; +} + +static void markeins_machine_power_off(void) +{ + printk("EMMA2RH Mark-eins halted. Please turn off the power.\n"); + markeins_led("poweroff."); + while (1) ; +} + +static unsigned long clock[4] = { 166500000, 187312500, 199800000, 210600000 }; + +static unsigned int __init detect_bus_frequency(unsigned long rtc_base) +{ + u32 reg; + + /* detect from boot strap */ + reg = emma2rh_in32(EMMA2RH_BHIF_STRAP_0); + reg = (reg >> 4) & 0x3; + return clock[reg]; +} + +static void __init emma2rh_time_init(void) +{ + u32 reg; + if (bus_frequency == 0) + bus_frequency = detect_bus_frequency(0); + + reg = emma2rh_in32(EMMA2RH_BHIF_STRAP_0); + if ((reg & 0x3) == 0) + reg = (reg >> 6) & 0x3; + else { + reg = emma2rh_in32(EMMA2RH_BHIF_MAIN_CTRL); + reg = (reg >> 4) & 0x3; + } + mips_hpt_frequency = (bus_frequency * (4 + reg)) / 4 / 2; +} + +static void __init emma2rh_timer_setup(struct irqaction *irq) +{ + /* we are using the cpu counter for timer interrupts */ + setup_irq(CPU_IRQ_BASE + 7, irq); +} + +static void markeins_board_init(void); +extern void markeins_irq_setup(void); + +static void inline __init markeins_sio_setup(void) +{ +#ifdef CONFIG_KGDB_8250 + struct uart_port emma_port; + + memset(&emma_port, 0, sizeof(emma_port)); + + emma_port.flags = + UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + emma_port.iotype = UPIO_MEM; + emma_port.regshift = 4; /* I/O addresses are every 8 bytes */ + emma_port.uartclk = 18544000; /* Clock rate of the chip */ + + emma_port.line = 0; + emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3); + emma_port.membase = (u8*)emma_port.mapbase; + early_serial_setup(&emma_port); + + emma_port.line = 1; + emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3); + emma_port.membase = (u8*)emma_port.mapbase; + early_serial_setup(&emma_port); + + emma_port.irq = EMMA2RH_IRQ_PFUR1; + kgdb8250_add_port(1, &emma_port); +#endif +} + +void __init plat_mem_setup(void) +{ + /* initialize board - we don't trust the loader */ + markeins_board_init(); + + set_io_port_base(KSEG1ADDR(EMMA2RH_PCI_IO_BASE)); + + board_time_init = emma2rh_time_init; + board_timer_setup = emma2rh_timer_setup; + + _machine_restart = markeins_machine_restart; + _machine_halt = markeins_machine_halt; + pm_power_off = markeins_machine_power_off; + + /* setup resource limits */ + ioport_resource.start = EMMA2RH_PCI_IO_BASE; + ioport_resource.end = EMMA2RH_PCI_IO_BASE + EMMA2RH_PCI_IO_SIZE - 1; + iomem_resource.start = EMMA2RH_IO_BASE; + iomem_resource.end = EMMA2RH_ROM_BASE - 1; + + /* Reboot on panic */ + panic_timeout = 180; + + markeins_sio_setup(); +} + +static void __init markeins_board_init(void) +{ + u32 val; + + val = emma2rh_in32(EMMA2RH_PBRD_INT_EN); /* open serial interrupts. */ + emma2rh_out32(EMMA2RH_PBRD_INT_EN, val | 0xaa); + val = emma2rh_in32(EMMA2RH_PBRD_CLKSEL); /* set serial clocks. */ + emma2rh_out32(EMMA2RH_PBRD_CLKSEL, val | 0x5); /* 18MHz */ + emma2rh_out32(EMMA2RH_PCI_CONTROL, 0); + + markeins_led("MVL E2RH"); +} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c5f5516f4695..56000a069604 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o obj-$(CONFIG_MIPS_TX3927) += ops-tx3927.o obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o +obj-$(CONFIG_MARKEINS) += ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o # # These are still pretty much in the old state, watch, go blind. diff --git a/arch/mips/pci/fixup-emma2rh.c b/arch/mips/pci/fixup-emma2rh.c new file mode 100644 index 000000000000..3a34cd0efd6b --- /dev/null +++ b/arch/mips/pci/fixup-emma2rh.c @@ -0,0 +1,102 @@ +/* + * arch/mips/pci/fixup-emma2rh.c + * This file defines the PCI configration. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/pci.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define EMMA2RH_PCI_HOST_SLOT 0x09 +#define EMMA2RH_USB_SLOT 0x03 +#define PCI_DEVICE_ID_NEC_EMMA2RH 0x014b /* EMMA2RH PCI Host */ + +/* + * we fix up irqs based on the slot number. + * The first entry is at AD:11. + * Fortunately this works because, although we have two pci buses, + * they all have different slot numbers (except for rockhopper slot 20 + * which is handled below). + * + */ + +#define MAX_SLOT_NUM 10 +static unsigned char irq_map[][5] __initdata = { + [3] = {0, MARKEINS_PCI_IRQ_INTB, MARKEINS_PCI_IRQ_INTC, + MARKEINS_PCI_IRQ_INTD, 0,}, + [4] = {0, MARKEINS_PCI_IRQ_INTA, 0, 0, 0,}, + [5] = {0, 0, 0, 0, 0,}, + [6] = {0, MARKEINS_PCI_IRQ_INTC, MARKEINS_PCI_IRQ_INTD, + MARKEINS_PCI_IRQ_INTA, MARKEINS_PCI_IRQ_INTB,}, +}; + +static void __devinit nec_usb_controller_fixup(struct pci_dev *dev) +{ + if (PCI_SLOT(dev->devfn) == EMMA2RH_USB_SLOT) + /* on board USB controller configuration */ + pci_write_config_dword(dev, 0xe4, 1 << 5); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, + nec_usb_controller_fixup); + +/* + * Prevent the PCI layer from seeing the resources allocated to this device + * if it is the host bridge by marking it as such. These resources are of + * no consequence to the PCI layer (they are handled elsewhere). + */ +static void __devinit emma2rh_pci_host_fixup(struct pci_dev *dev) +{ + int i; + + if (PCI_SLOT(dev->devfn) == EMMA2RH_PCI_HOST_SLOT) { + dev->class &= 0xff; + dev->class |= PCI_CLASS_BRIDGE_HOST << 8; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_EMMA2RH, + emma2rh_pci_host_fixup); + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return irq_map[slot][pin]; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/arch/mips/pci/ops-emma2rh.c b/arch/mips/pci/ops-emma2rh.c new file mode 100644 index 000000000000..e21b11bf66bc --- /dev/null +++ b/arch/mips/pci/ops-emma2rh.c @@ -0,0 +1,186 @@ +/* + * arch/mips/pci/ops-emma2rh.c + * This file defines the PCI operation for EMMA2RH. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/pci/ops-vr41xx.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#define RTABORT (0x1<<9) +#define RMABORT (0x1<<10) +#define EMMA2RH_PCI_SLOT_NUM 9 /* 0000:09.0 is final PCI device */ + +/* + * access config space + */ + +static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) +{ + /* check if the bus is top-level */ + if (bus->parent != NULL) { + *bus_num = bus->number; + db_assert(bus_num != 0); + } else + *bus_num = 0; + + if (*bus_num == 0) { + /* Type 0 */ + if (PCI_SLOT(devfn) >= 10) + return PCIBIOS_DEVICE_NOT_FOUND; + } else { + /* Type 1 */ + if ((*bus_num >= 64) || (PCI_SLOT(devfn) >= 16)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + return 0; +} + +static inline int set_pci_configuration_address(unsigned char bus_num, + unsigned int devfn, int where) +{ + u32 config_win0; + + emma2rh_out32(EMMA2RH_PCI_INT, ~RMABORT); + if (bus_num == 0) + /* + * Type 0 configuration + */ + config_win0 = (1 << (22 + PCI_SLOT(devfn))) | (5 << 9); + else + /* + * Type 1 configuration + */ + config_win0 = (bus_num << 26) | (PCI_SLOT(devfn) << 22) | + (1 << 15) | (5 << 9); + + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, config_win0); + + return 0; +} + +static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t * val) +{ + u32 bus_num; + u32 base = KSEG1ADDR(EMMA2RH_PCI_CONFIG_BASE); + u32 backup_win0; + u32 data; + + *val = 0xffffffffU; + + if (check_args(bus, devfn, &bus_num) == PCIBIOS_DEVICE_NOT_FOUND) + return PCIBIOS_DEVICE_NOT_FOUND; + + backup_win0 = emma2rh_in32(EMMA2RH_PCI_IWIN0_CTR); + + if (set_pci_configuration_address(bus_num, devfn, where) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + data = + *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) + + (where & 0xfffffffc)); + + switch (size) { + case 1: + *val = (data >> ((where & 3) << 3)) & 0xffU; + break; + case 2: + *val = (data >> ((where & 2) << 3)) & 0xffffU; + break; + case 4: + *val = data; + break; + default: + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0); + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0); + + if (emma2rh_in32(EMMA2RH_PCI_INT) & RMABORT) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + u32 bus_num; + u32 base = KSEG1ADDR(EMMA2RH_PCI_CONFIG_BASE); + u32 backup_win0; + u32 data; + int shift; + + if (check_args(bus, devfn, &bus_num) == PCIBIOS_DEVICE_NOT_FOUND) + return PCIBIOS_DEVICE_NOT_FOUND; + + backup_win0 = emma2rh_in32(EMMA2RH_PCI_IWIN0_CTR); + + if (set_pci_configuration_address(bus_num, devfn, where) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* read modify write */ + data = + *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) + + (where & 0xfffffffc)); + + switch (size) { + case 1: + shift = (where & 3) << 3; + data &= ~(0xffU << shift); + data |= ((val & 0xffU) << shift); + break; + case 2: + shift = (where & 2) << 3; + data &= ~(0xffffU << shift); + data |= ((val & 0xffffU) << shift); + break; + case 4: + data = val; + break; + default: + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0); + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) + + (where & 0xfffffffc)) = data; + + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0); + if (emma2rh_in32(EMMA2RH_PCI_INT) & RMABORT) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops emma2rh_pci_ops = { + .read = pci_config_read, + .write = pci_config_write, +}; diff --git a/arch/mips/pci/pci-emma2rh.c b/arch/mips/pci/pci-emma2rh.c new file mode 100644 index 000000000000..0f8b230057d3 --- /dev/null +++ b/arch/mips/pci/pci-emma2rh.c @@ -0,0 +1,90 @@ +/* + * arch/mips/pci/pci-emma2rh.c + * This file defines the PCI configration. + * + * Copyright (C) NEC Electronics Corporation 2004-2006 + * + * This file is based on the arch/mips/ddb5xxx/ddb5477/pci.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +static struct resource pci_io_resource = { + .name = "pci IO space", + .start = EMMA2RH_PCI_IO_BASE, + .end = EMMA2RH_PCI_IO_BASE + EMMA2RH_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO, +}; + +static struct resource pci_mem_resource = { + .name = "pci memory space", + .start = EMMA2RH_PCI_MEM_BASE, + .end = EMMA2RH_PCI_MEM_BASE + EMMA2RH_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +extern struct pci_ops emma2rh_pci_ops; + +static struct pci_controller emma2rh_pci_controller = { + .pci_ops = &emma2rh_pci_ops, + .mem_resource = &pci_mem_resource, + .io_resource = &pci_io_resource, + .mem_offset = -0x04000000, + .io_offset = 0, +}; + +static void __init emma2rh_pci_init(void) +{ + /* setup PCI interface */ + emma2rh_out32(EMMA2RH_PCI_ARBIT_CTR, 0x70f); + + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, 0x80000a18); + emma2rh_out32(EMMA2RH_PCI_CONFIG_BASE + PCI_COMMAND, + PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_CAP_LIST | + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + emma2rh_out32(EMMA2RH_PCI_CONFIG_BASE + PCI_BASE_ADDRESS_0, 0x10000000); + emma2rh_out32(EMMA2RH_PCI_CONFIG_BASE + PCI_BASE_ADDRESS_1, 0x00000000); + + emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, 0x12000000 | 0x218); + emma2rh_out32(EMMA2RH_PCI_IWIN1_CTR, 0x18000000 | 0x600); + emma2rh_out32(EMMA2RH_PCI_INIT_ESWP, 0x00000200); + + emma2rh_out32(EMMA2RH_PCI_TWIN_CTR, 0x00009200); + emma2rh_out32(EMMA2RH_PCI_TWIN_BADR, 0x00000000); + emma2rh_out32(EMMA2RH_PCI_TWIN0_DADR, 0x00000000); + emma2rh_out32(EMMA2RH_PCI_TWIN1_DADR, 0x00000000); +} + +static int __init emma2rh_pci_setup(void) +{ + emma2rh_pci_init(); + register_pci_controller(&emma2rh_pci_controller); + return 0; +} + +arch_initcall(emma2rh_pci_setup); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index edf2b9a71c82..72fa6dc45523 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -218,6 +218,12 @@ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ +/* + * Valid machtype for group NEC EMMA2RH + */ +#define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */ +#define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */ + #define CL_SIZE COMMAND_LINE_SIZE const char *get_system_type(void); diff --git a/include/asm-mips/emma2rh/emma2rh.h b/include/asm-mips/emma2rh/emma2rh.h new file mode 100644 index 000000000000..4fb8df71caa9 --- /dev/null +++ b/include/asm-mips/emma2rh/emma2rh.h @@ -0,0 +1,330 @@ +/* + * include/asm-mips/emma2rh/emma2rh.h + * This file is EMMA2RH common header. + * + * Copyright (C) NEC Electronics Corporation 2005-2006 + * + * This file based on include/asm-mips/ddb5xxx/ddb5xxx.h + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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_EMMA2RH_EMMA2RH_H +#define __ASM_EMMA2RH_EMMA2RH_H + +/* + * EMMA2RH registers + */ +#define REGBASE 0x10000000 + +#define EMMA2RH_BHIF_STRAP_0 (0x000010+REGBASE) +#define EMMA2RH_BHIF_INT_ST_0 (0x000030+REGBASE) +#define EMMA2RH_BHIF_INT_ST_1 (0x000034+REGBASE) +#define EMMA2RH_BHIF_INT_ST_2 (0x000038+REGBASE) +#define EMMA2RH_BHIF_INT_EN_0 (0x000040+REGBASE) +#define EMMA2RH_BHIF_INT_EN_1 (0x000044+REGBASE) +#define EMMA2RH_BHIF_INT_EN_2 (0x000048+REGBASE) +#define EMMA2RH_BHIF_INT1_EN_0 (0x000050+REGBASE) +#define EMMA2RH_BHIF_INT1_EN_1 (0x000054+REGBASE) +#define EMMA2RH_BHIF_INT1_EN_2 (0x000058+REGBASE) +#define EMMA2RH_BHIF_SW_INT (0x000070+REGBASE) +#define EMMA2RH_BHIF_SW_INT_EN (0x000080+REGBASE) +#define EMMA2RH_BHIF_SW_INT_CLR (0x000090+REGBASE) +#define EMMA2RH_BHIF_MAIN_CTRL (0x0000b4+REGBASE) +#define EMMA2RH_BHIF_EXCEPT_VECT_BASE_ADDRESS (0x0000c0+REGBASE) +#define EMMA2RH_GPIO_DIR (0x110d20+REGBASE) +#define EMMA2RH_GPIO_INT_ST (0x110d30+REGBASE) +#define EMMA2RH_GPIO_INT_MASK (0x110d3c+REGBASE) +#define EMMA2RH_GPIO_INT_MODE (0x110d48+REGBASE) +#define EMMA2RH_GPIO_INT_CND_A (0x110d54+REGBASE) +#define EMMA2RH_GPIO_INT_CND_B (0x110d60+REGBASE) +#define EMMA2RH_PBRD_INT_EN (0x100010+REGBASE) +#define EMMA2RH_PBRD_CLKSEL (0x100028+REGBASE) +#define EMMA2RH_PFUR0_BASE (0x101000+REGBASE) +#define EMMA2RH_PFUR1_BASE (0x102000+REGBASE) +#define EMMA2RH_PFUR2_BASE (0x103000+REGBASE) +#define EMMA2RH_PIIC0_BASE (0x107000+REGBASE) +#define EMMA2RH_PIIC1_BASE (0x108000+REGBASE) +#define EMMA2RH_PIIC2_BASE (0x109000+REGBASE) +#define EMMA2RH_PCI_CONTROL (0x200000+REGBASE) +#define EMMA2RH_PCI_ARBIT_CTR (0x200004+REGBASE) +#define EMMA2RH_PCI_IWIN0_CTR (0x200010+REGBASE) +#define EMMA2RH_PCI_IWIN1_CTR (0x200014+REGBASE) +#define EMMA2RH_PCI_INIT_ESWP (0x200018+REGBASE) +#define EMMA2RH_PCI_INT (0x200020+REGBASE) +#define EMMA2RH_PCI_INT_EN (0x200024+REGBASE) +#define EMMA2RH_PCI_TWIN_CTR (0x200030+REGBASE) +#define EMMA2RH_PCI_TWIN_BADR (0x200034+REGBASE) +#define EMMA2RH_PCI_TWIN0_DADR (0x200038+REGBASE) +#define EMMA2RH_PCI_TWIN1_DADR (0x20003c+REGBASE) + +/* + * Memory map (physical address) + * + * Note most of the following address must be properly aligned by the + * corresponding size. For example, if PCI_IO_SIZE is 16MB, then + * PCI_IO_BASE must be aligned along 16MB boundary. + */ + +/* the actual ram size is detected at run-time */ +#define EMMA2RH_RAM_BASE 0x00000000 +#define EMMA2RH_RAM_SIZE 0x10000000 /* less than 256MB */ + +#define EMMA2RH_IO_BASE 0x10000000 +#define EMMA2RH_IO_SIZE 0x01000000 /* 16 MB */ + +#define EMMA2RH_GENERALIO_BASE 0x11000000 +#define EMMA2RH_GENERALIO_SIZE 0x01000000 /* 16 MB */ + +#define EMMA2RH_PCI_IO_BASE 0x12000000 +#define EMMA2RH_PCI_IO_SIZE 0x02000000 /* 32 MB */ + +#define EMMA2RH_PCI_MEM_BASE 0x14000000 +#define EMMA2RH_PCI_MEM_SIZE 0x08000000 /* 128 MB */ + +#define EMMA2RH_ROM_BASE 0x1c000000 +#define EMMA2RH_ROM_SIZE 0x04000000 /* 64 MB */ + +#define EMMA2RH_PCI_CONFIG_BASE EMMA2RH_PCI_IO_BASE +#define EMMA2RH_PCI_CONFIG_SIZE EMMA2RH_PCI_IO_SIZE + +#define NUM_CPU_IRQ 8 +#define NUM_EMMA2RH_IRQ 96 + +#define CPU_EMMA2RH_CASCADE 2 +#define EMMA2RH_IRQ_BASE 0 + +/* + * emma2rh irq defs + */ + +#define EMMA2RH_IRQ_INT0 (0 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT1 (1 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT2 (2 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT3 (3 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT4 (4 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT5 (5 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT6 (6 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT7 (7 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT8 (8 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT9 (9 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT10 (10 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT11 (11 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT12 (12 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT13 (13 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT14 (14 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT15 (15 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT16 (16 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT17 (17 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT18 (18 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT19 (19 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT20 (20 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT21 (21 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT22 (22 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT23 (23 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT24 (24 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT25 (25 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT26 (26 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT27 (27 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT28 (28 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT29 (29 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT30 (30 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT31 (31 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT32 (32 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT33 (33 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT34 (34 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT35 (35 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT36 (36 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT37 (37 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT38 (38 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT39 (39 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT40 (40 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT41 (41 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT42 (42 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT43 (43 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT44 (44 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT45 (45 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT46 (46 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT47 (47 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT48 (48 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT49 (49 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT50 (50 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT51 (51 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT52 (52 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT53 (53 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT54 (54 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT55 (55 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT56 (56 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT57 (57 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT58 (58 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT59 (59 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT60 (60 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT61 (61 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT62 (62 + EMMA2RH_IRQ_BASE) +#define EMMA2RH_IRQ_INT63 (63 + EMMA2RH_IRQ_BASE) + +#define EMMA2RH_IRQ_PFUR0 EMMA2RH_IRQ_INT49 +#define EMMA2RH_IRQ_PFUR1 EMMA2RH_IRQ_INT50 +#define EMMA2RH_IRQ_PFUR2 EMMA2RH_IRQ_INT51 +#define EMMA2RH_IRQ_PIIC0 EMMA2RH_IRQ_INT56 +#define EMMA2RH_IRQ_PIIC1 EMMA2RH_IRQ_INT57 +#define EMMA2RH_IRQ_PIIC2 EMMA2RH_IRQ_INT58 + +/* + * EMMA2RH Register Access + */ + +#define EMMA2RH_BASE (0xa0000000) + +static inline void emma2rh_sync(void) +{ + volatile u32 *p = (volatile u32 *)0xbfc00000; + (void)(*p); +} + +static inline void emma2rh_out32(u32 offset, u32 val) +{ + *(volatile u32 *)(EMMA2RH_BASE | offset) = val; + emma2rh_sync(); +} + +static inline u32 emma2rh_in32(u32 offset) +{ + u32 val = *(volatile u32 *)(EMMA2RH_BASE | offset); + emma2rh_sync(); + return val; +} + +static inline void emma2rh_out16(u32 offset, u16 val) +{ + *(volatile u16 *)(EMMA2RH_BASE | offset) = val; + emma2rh_sync(); +} + +static inline u16 emma2rh_in16(u32 offset) +{ + u16 val = *(volatile u16 *)(EMMA2RH_BASE | offset); + emma2rh_sync(); + return val; +} + +static inline void emma2rh_out8(u32 offset, u8 val) +{ + *(volatile u8 *)(EMMA2RH_BASE | offset) = val; + emma2rh_sync(); +} + +static inline u8 emma2rh_in8(u32 offset) +{ + u8 val = *(volatile u8 *)(EMMA2RH_BASE | offset); + emma2rh_sync(); + return val; +} + +/** + * IIC registers map + **/ + +/*---------------------------------------------------------------------------*/ +/* CNT - Control register (00H R/W) */ +/*---------------------------------------------------------------------------*/ +#define SPT 0x00000001 +#define STT 0x00000002 +#define ACKE 0x00000004 +#define WTIM 0x00000008 +#define SPIE 0x00000010 +#define WREL 0x00000020 +#define LREL 0x00000040 +#define IICE 0x00000080 +#define CNT_RESERVED 0x000000ff /* reserved bit 0 */ + +#define I2C_EMMA_START (IICE | STT) +#define I2C_EMMA_STOP (IICE | SPT) +#define I2C_EMMA_REPSTART I2C_EMMA_START + +/*---------------------------------------------------------------------------*/ +/* STA - Status register (10H Read) */ +/*---------------------------------------------------------------------------*/ +#define MSTS 0x00000080 +#define ALD 0x00000040 +#define EXC 0x00000020 +#define COI 0x00000010 +#define TRC 0x00000008 +#define ACKD 0x00000004 +#define STD 0x00000002 +#define SPD 0x00000001 + +/*---------------------------------------------------------------------------*/ +/* CSEL - Clock select register (20H R/W) */ +/*---------------------------------------------------------------------------*/ +#define FCL 0x00000080 +#define ND50 0x00000040 +#define CLD 0x00000020 +#define DAD 0x00000010 +#define SMC 0x00000008 +#define DFC 0x00000004 +#define CL 0x00000003 +#define CSEL_RESERVED 0x000000ff /* reserved bit 0 */ + +#define FAST397 0x0000008b +#define FAST297 0x0000008a +#define FAST347 0x0000000b +#define FAST260 0x0000000a +#define FAST130 0x00000008 +#define STANDARD108 0x00000083 +#define STANDARD83 0x00000082 +#define STANDARD95 0x00000003 +#define STANDARD73 0x00000002 +#define STANDARD36 0x00000001 +#define STANDARD71 0x00000000 + +/*---------------------------------------------------------------------------*/ +/* SVA - Slave address register (30H R/W) */ +/*---------------------------------------------------------------------------*/ +#define SVA 0x000000fe + +/*---------------------------------------------------------------------------*/ +/* SHR - Shift register (40H R/W) */ +/*---------------------------------------------------------------------------*/ +#define SR 0x000000ff + +/*---------------------------------------------------------------------------*/ +/* INT - Interrupt register (50H R/W) */ +/* INTM - Interrupt mask register (60H R/W) */ +/*---------------------------------------------------------------------------*/ +#define INTE0 0x00000001 + +/*********************************************************************** + * I2C registers + *********************************************************************** + */ +#define I2C_EMMA_CNT 0x00 +#define I2C_EMMA_STA 0x10 +#define I2C_EMMA_CSEL 0x20 +#define I2C_EMMA_SVA 0x30 +#define I2C_EMMA_SHR 0x40 +#define I2C_EMMA_INT 0x50 +#define I2C_EMMA_INTM 0x60 + +/* + * include the board dependent part + */ +#if defined(CONFIG_MARKEINS) +#include +#else +#error "Unknown EMMA2RH board!" +#endif + +#endif /* __ASM_EMMA2RH_EMMA2RH_H */ diff --git a/include/asm-mips/emma2rh/markeins.h b/include/asm-mips/emma2rh/markeins.h new file mode 100644 index 000000000000..8fa766795078 --- /dev/null +++ b/include/asm-mips/emma2rh/markeins.h @@ -0,0 +1,76 @@ +/* + * include/asm-mips/emma2rh/markeins.h + * This file is EMMA2RH board depended header. + * + * Copyright (C) NEC Electronics Corporation 2005-2006 + * + * This file based on include/asm-mips/ddb5xxx/ddb5xxx.h + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 MARKEINS_H +#define MARKEINS_H + +#define NUM_EMMA2RH_IRQ_SW 32 +#define NUM_EMMA2RH_IRQ_GPIO 32 + +#define EMMA2RH_SW_CASCADE (EMMA2RH_IRQ_INT7 - EMMA2RH_IRQ_INT0) +#define EMMA2RH_GPIO_CASCADE (EMMA2RH_IRQ_INT46 - EMMA2RH_IRQ_INT0) + +#define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ) +#define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW) +#define CPU_IRQ_BASE (EMMA2RH_GPIO_IRQ_BASE + NUM_EMMA2RH_IRQ_GPIO) + +#define EMMA2RH_SW_IRQ_INT0 (0+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT1 (1+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT2 (2+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT3 (3+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT4 (4+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT5 (5+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT6 (6+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT7 (7+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT8 (8+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT9 (9+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT10 (10+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT11 (11+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT12 (12+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT13 (13+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT14 (14+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT15 (15+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT16 (16+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT17 (17+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT18 (18+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT19 (19+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT20 (20+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT21 (21+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT22 (22+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT23 (23+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT24 (24+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT25 (25+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT26 (26+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT27 (27+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT28 (28+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT29 (29+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT30 (30+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT31 (31+EMMA2RH_SW_IRQ_BASE) + +#define MARKEINS_PCI_IRQ_INTA EMMA2RH_GPIO_IRQ_BASE+15 +#define MARKEINS_PCI_IRQ_INTB EMMA2RH_GPIO_IRQ_BASE+16 +#define MARKEINS_PCI_IRQ_INTC EMMA2RH_GPIO_IRQ_BASE+17 +#define MARKEINS_PCI_IRQ_INTD EMMA2RH_GPIO_IRQ_BASE+18 + +#endif /* CONFIG_MARKEINS */ diff --git a/include/asm-mips/mach-emma2rh/irq.h b/include/asm-mips/mach-emma2rh/irq.h new file mode 100644 index 000000000000..bce64244b800 --- /dev/null +++ b/include/asm-mips/mach-emma2rh/irq.h @@ -0,0 +1,13 @@ +/* + * 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) 2003 by Ralf Baechle + */ +#ifndef __ASM_MACH_EMMA2RH_IRQ_H +#define __ASM_MACH_EMMA2RH_IRQ_H + +#define NR_IRQS 256 + +#endif /* __ASM_MACH_EMMA2RH_IRQ_H */ -- cgit v1.2.3 From 35189fad3cb5f6e3ab66c8321928a851de0cd2b1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 18 Jun 2006 16:39:46 +0100 Subject: [MIPS] Support for the RM9000-based Basler eXcite smart camera platform. Signed-off-by: Thomas Koeller Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 26 + arch/mips/Makefile | 7 + arch/mips/basler/excite/Makefile | 9 + arch/mips/basler/excite/excite_dbg_io.c | 122 ++ arch/mips/basler/excite/excite_device.c | 404 +++++++ arch/mips/basler/excite/excite_flashtest.c | 294 +++++ arch/mips/basler/excite/excite_fpga.h | 80 ++ arch/mips/basler/excite/excite_iodev.c | 183 +++ arch/mips/basler/excite/excite_iodev.h | 10 + arch/mips/basler/excite/excite_irq.c | 129 +++ arch/mips/basler/excite/excite_procfs.c | 81 ++ arch/mips/basler/excite/excite_prom.c | 148 +++ arch/mips/basler/excite/excite_setup.c | 307 +++++ arch/mips/configs/excite_defconfig | 1211 ++++++++++++++++++++ arch/mips/pci/Makefile | 1 + arch/mips/pci/fixup-excite.c | 36 + arch/mips/pci/ops-titan.c | 25 +- arch/mips/pci/pci-excite.c | 149 +++ include/asm-mips/bootinfo.h | 1 + .../asm-mips/mach-excite/cpu-feature-overrides.h | 40 + include/asm-mips/mach-excite/excite.h | 155 +++ include/asm-mips/mach-excite/excite_nandflash.h | 7 + include/asm-mips/mach-excite/rm9k_eth.h | 23 + include/asm-mips/mach-excite/rm9k_wdt.h | 12 + include/asm-mips/mach-excite/rm9k_xicap.h | 16 + include/asm-mips/rm9k-ocd.h | 56 + include/asm-mips/war.h | 5 +- 27 files changed, 3528 insertions(+), 9 deletions(-) create mode 100644 arch/mips/basler/excite/Makefile create mode 100644 arch/mips/basler/excite/excite_dbg_io.c create mode 100644 arch/mips/basler/excite/excite_device.c create mode 100644 arch/mips/basler/excite/excite_flashtest.c create mode 100644 arch/mips/basler/excite/excite_fpga.h create mode 100644 arch/mips/basler/excite/excite_iodev.c create mode 100644 arch/mips/basler/excite/excite_iodev.h create mode 100644 arch/mips/basler/excite/excite_irq.c create mode 100644 arch/mips/basler/excite/excite_procfs.c create mode 100644 arch/mips/basler/excite/excite_prom.c create mode 100644 arch/mips/basler/excite/excite_setup.c create mode 100644 arch/mips/configs/excite_defconfig create mode 100644 arch/mips/pci/fixup-excite.c create mode 100644 arch/mips/pci/pci-excite.c create mode 100644 include/asm-mips/mach-excite/cpu-feature-overrides.h create mode 100644 include/asm-mips/mach-excite/excite.h create mode 100644 include/asm-mips/mach-excite/excite_nandflash.h create mode 100644 include/asm-mips/mach-excite/rm9k_eth.h create mode 100644 include/asm-mips/mach-excite/rm9k_wdt.h create mode 100644 include/asm-mips/mach-excite/rm9k_xicap.h create mode 100644 include/asm-mips/rm9k-ocd.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index db3d008732c6..50274fcacde0 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -119,6 +119,32 @@ config MIPS_MIRAGE select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_LITTLE_ENDIAN +config BASLER_EXCITE + bool "Basler eXcite smart camera support" + select DMA_COHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select IRQ_CPU_RM9K + select SERIAL_RM9000 + select SYS_HAS_CPU_RM9000 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + help + The eXcite is a smart camera platform manufactured by + Basler Vision Technologies AG + +config BASLER_EXCITE_PROTOTYPE + bool "Support for pre-release units" + depends on BASLER_EXCITE + default n + help + Pre-series (prototype) units are different from later ones in + some ways. Select this option if you have one of these. Please + note that a kernel built with this option selected will not be + able to run on normal units. + config MIPS_COBALT bool "Cobalt Server" select DMA_NONCOHERENT diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 207197b91a53..d5930148495a 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -387,6 +387,13 @@ core-$(CONFIG_MOMENCO_OCELOT_3) += arch/mips/momentum/ocelot_3/ cflags-$(CONFIG_MOMENCO_OCELOT_3) += -Iinclude/asm-mips/mach-ocelot3 load-$(CONFIG_MOMENCO_OCELOT_3) += 0xffffffff80100000 +# +# Basler eXcite +# +core-$(CONFIG_BASLER_EXCITE) += arch/mips/basler/excite/ +cflags-$(CONFIG_BASLER_EXCITE) += -Iinclude/asm-mips/mach-excite +load-$(CONFIG_BASLER_EXCITE) += 0x80100000 + # # Momentum Jaguar ATX # diff --git a/arch/mips/basler/excite/Makefile b/arch/mips/basler/excite/Makefile new file mode 100644 index 000000000000..519142c2e4ef --- /dev/null +++ b/arch/mips/basler/excite/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Basler eXcite +# + +obj-$(CONFIG_BASLER_EXCITE) += excite_irq.o excite_prom.o excite_setup.o \ + excite_device.o excite_procfs.o + +obj-$(CONFIG_KGDB) += excite_dbg_io.o +obj-m += excite_iodev.o diff --git a/arch/mips/basler/excite/excite_dbg_io.c b/arch/mips/basler/excite/excite_dbg_io.c new file mode 100644 index 000000000000..83f6bddf578b --- /dev/null +++ b/arch/mips/basler/excite/excite_dbg_io.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_SERIAL_8250) && CONFIG_SERIAL_8250_NR_UARTS > 1 +#error Debug port used by serial driver +#endif + +#define UART_CLK 25000000 +#define BASE_BAUD (UART_CLK / 16) +#define REGISTER_BASE_0 0x0208UL +#define REGISTER_BASE_1 0x0238UL + +#define REGISTER_BASE_DBG REGISTER_BASE_1 + +#define CPRR 0x0004 +#define UACFG 0x0200 +#define UAINTS 0x0204 +#define UARBR (REGISTER_BASE_DBG + 0x0000) +#define UATHR (REGISTER_BASE_DBG + 0x0004) +#define UADLL (REGISTER_BASE_DBG + 0x0008) +#define UAIER (REGISTER_BASE_DBG + 0x000c) +#define UADLH (REGISTER_BASE_DBG + 0x0010) +#define UAIIR (REGISTER_BASE_DBG + 0x0014) +#define UAFCR (REGISTER_BASE_DBG + 0x0018) +#define UALCR (REGISTER_BASE_DBG + 0x001c) +#define UAMCR (REGISTER_BASE_DBG + 0x0020) +#define UALSR (REGISTER_BASE_DBG + 0x0024) +#define UAMSR (REGISTER_BASE_DBG + 0x0028) +#define UASCR (REGISTER_BASE_DBG + 0x002c) + +#define PARITY_NONE 0 +#define PARITY_ODD 0x08 +#define PARITY_EVEN 0x18 +#define PARITY_MARK 0x28 +#define PARITY_SPACE 0x38 + +#define DATA_5BIT 0x0 +#define DATA_6BIT 0x1 +#define DATA_7BIT 0x2 +#define DATA_8BIT 0x3 + +#define STOP_1BIT 0x0 +#define STOP_2BIT 0x4 + +#define BAUD_DBG 57600 +#define PARITY_DBG PARITY_NONE +#define DATA_DBG DATA_8BIT +#define STOP_DBG STOP_1BIT + +/* Initialize the serial port for KGDB debugging */ +void __init excite_kgdb_init(void) +{ + const u32 divisor = BASE_BAUD / BAUD_DBG; + + /* Take the UART out of reset */ + titan_writel(0x00ff1cff, CPRR); + titan_writel(0x00000000, UACFG); + titan_writel(0x00000002, UACFG); + + titan_writel(0x0, UALCR); + titan_writel(0x0, UAIER); + + /* Disable FIFOs */ + titan_writel(0x00, UAFCR); + + titan_writel(0x80, UALCR); + titan_writel(divisor & 0xff, UADLL); + titan_writel((divisor & 0xff00) >> 8, UADLH); + titan_writel(0x0, UALCR); + + titan_writel(DATA_DBG | PARITY_DBG | STOP_DBG, UALCR); + + /* Enable receiver interrupt */ + titan_readl(UARBR); + titan_writel(0x1, UAIER); +} + +int getDebugChar(void) +{ + while (!(titan_readl(UALSR) & 0x1)); + return titan_readl(UARBR); +} + +int putDebugChar(int data) +{ + while (!(titan_readl(UALSR) & 0x20)); + titan_writel(data, UATHR); + return 1; +} + +/* KGDB interrupt handler */ +asmlinkage void excite_kgdb_inthdl(struct pt_regs *regs) +{ + if (unlikely( + ((titan_readl(UAIIR) & 0x7) == 4) + && ((titan_readl(UARBR) & 0xff) == 0x3))) + set_async_breakpoint(®s->cp0_epc); +} diff --git a/arch/mips/basler/excite/excite_device.c b/arch/mips/basler/excite/excite_device.c new file mode 100644 index 000000000000..34ec76716fa0 --- /dev/null +++ b/arch/mips/basler/excite/excite_device.c @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "excite_iodev.h" + +#define RM9K_GE_UNIT 0 +#define XICAP_UNIT 0 +#define NAND_UNIT 0 + +#define DLL_TIMEOUT 3 /* seconds */ + + +#define RINIT(__start__, __end__, __name__, __parent__) { \ + .name = __name__ "_0", \ + .start = (__start__), \ + .end = (__end__), \ + .flags = 0, \ + .parent = (__parent__) \ +} + +#define RINIT_IRQ(__irq__, __name__) { \ + .name = __name__ "_0", \ + .start = (__irq__), \ + .end = (__irq__), \ + .flags = IORESOURCE_IRQ, \ + .parent = NULL \ +} + + + +enum { + slice_xicap, + slice_eth +}; + + + +static struct resource + excite_ctr_resource = { + .name = "GPI counters", + .start = 0, + .end = 5, + .flags = 0, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_gpislice_resource = { + .name = "GPI slices", + .start = 0, + .end = 1, + .flags = 0, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_mdio_channel_resource = { + .name = "MDIO channels", + .start = 0, + .end = 1, + .flags = 0, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_fifomem_resource = { + .name = "FIFO memory", + .start = 0, + .end = 767, + .flags = 0, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_scram_resource = { + .name = "Scratch RAM", + .start = EXCITE_PHYS_SCRAM, + .end = EXCITE_PHYS_SCRAM + EXCITE_SIZE_SCRAM - 1, + .flags = IORESOURCE_MEM, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_fpga_resource = { + .name = "System FPGA", + .start = EXCITE_PHYS_FPGA, + .end = EXCITE_PHYS_FPGA + EXCITE_SIZE_FPGA - 1, + .flags = IORESOURCE_MEM, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_nand_resource = { + .name = "NAND flash control", + .start = EXCITE_PHYS_NAND, + .end = EXCITE_PHYS_NAND + EXCITE_SIZE_NAND - 1, + .flags = IORESOURCE_MEM, + .parent = NULL, + .sibling = NULL, + .child = NULL + }, + excite_titan_resource = { + .name = "TITAN registers", + .start = EXCITE_PHYS_TITAN, + .end = EXCITE_PHYS_TITAN + EXCITE_SIZE_TITAN - 1, + .flags = IORESOURCE_MEM, + .parent = NULL, + .sibling = NULL, + .child = NULL + }; + + + +static void adjust_resources(struct resource *res, unsigned int n) +{ + struct resource *p; + const unsigned long mask = IORESOURCE_IO | IORESOURCE_MEM + | IORESOURCE_IRQ | IORESOURCE_DMA; + + for (p = res; p < res + n; p++) { + const struct resource * const parent = p->parent; + if (parent) { + p->start += parent->start; + p->end += parent->start; + p->flags = parent->flags & mask; + } + } +} + + + +#if defined(CONFIG_EXCITE_FCAP_GPI) || defined(CONFIG_EXCITE_FCAP_GPI_MODULE) +static struct resource xicap_rsrc[] = { + RINIT(0x4840, 0x486f, XICAP_RESOURCE_FIFO_RX, &excite_titan_resource), + RINIT(0x4940, 0x494b, XICAP_RESOURCE_FIFO_TX, &excite_titan_resource), + RINIT(0x5040, 0x5127, XICAP_RESOURCE_XDMA, &excite_titan_resource), + RINIT(0x1000, 0x112f, XICAP_RESOURCE_PKTPROC, &excite_titan_resource), + RINIT(0x1100, 0x110f, XICAP_RESOURCE_PKT_STREAM, &excite_fpga_resource), + RINIT(0x0800, 0x0bff, XICAP_RESOURCE_DMADESC, &excite_scram_resource), + RINIT(slice_xicap, slice_xicap, XICAP_RESOURCE_GPI_SLICE, &excite_gpislice_resource), + RINIT(0x0100, 0x02ff, XICAP_RESOURCE_FIFO_BLK, &excite_fifomem_resource), + RINIT_IRQ(TITAN_IRQ, XICAP_RESOURCE_IRQ) +}; + +static struct platform_device xicap_pdev = { + .name = XICAP_NAME, + .id = XICAP_UNIT, + .num_resources = ARRAY_SIZE(xicap_rsrc), + .resource = xicap_rsrc +}; + +/* + * Create a platform device for the GPI port that receives the + * image data from the embedded camera. + */ +static int __init xicap_devinit(void) +{ + unsigned long tend; + u32 reg; + int retval; + + adjust_resources(xicap_rsrc, ARRAY_SIZE(xicap_rsrc)); + + /* Power up the slice and configure it. */ + reg = titan_readl(CPTC1R); + reg &= ~(0x11100 << slice_xicap); + titan_writel(reg, CPTC1R); + + /* Enable slice & DLL. */ + reg= titan_readl(CPRR); + reg &= ~(0x00030003 << (slice_xicap * 2)); + titan_writel(reg, CPRR); + + /* Wait for DLLs to lock */ + tend = jiffies + DLL_TIMEOUT * HZ; + while (time_before(jiffies, tend)) { + if (!(~titan_readl(CPDSR) & (0x1 << (slice_xicap * 4)))) + break; + yield(); + } + + if (~titan_readl(CPDSR) & (0x1 << (slice_xicap * 4))) { + printk(KERN_ERR "%s: DLL not locked after %u seconds\n", + xicap_pdev.name, DLL_TIMEOUT); + retval = -ETIME; + } else { + /* Register platform device */ + retval = platform_device_register(&xicap_pdev); + } + + return retval; +} + +device_initcall(xicap_devinit); +#endif /* defined(CONFIG_EXCITE_FCAP_GPI) || defined(CONFIG_EXCITE_FCAP_GPI_MODULE) */ + + + +#if defined(CONFIG_WDT_RM9K_GPI) || defined(CONFIG_WDT_RM9K_GPI_MODULE) +static struct resource wdt_rsrc[] = { + RINIT(0, 0, WDT_RESOURCE_COUNTER, &excite_ctr_resource), + RINIT(0x0084, 0x008f, WDT_RESOURCE_REGS, &excite_titan_resource), + RINIT_IRQ(TITAN_IRQ, WDT_RESOURCE_IRQ) +}; + +static struct platform_device wdt_pdev = { + .name = WDT_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(wdt_rsrc), + .resource = wdt_rsrc +}; + +/* + * Create a platform device for the GPI port that receives the + * image data from the embedded camera. + */ +static int __init wdt_devinit(void) +{ + adjust_resources(wdt_rsrc, ARRAY_SIZE(wdt_rsrc)); + return platform_device_register(&wdt_pdev); +} + +device_initcall(wdt_devinit); +#endif /* defined(CONFIG_WDT_RM9K_GPI) || defined(CONFIG_WDT_RM9K_GPI_MODULE) */ + + + +static struct resource excite_nandflash_rsrc[] = { + RINIT(0x2000, 0x201f, EXCITE_NANDFLASH_RESOURCE_REGS, &excite_nand_resource) +}; + +static struct platform_device excite_nandflash_pdev = { + .name = "excite_nand", + .id = NAND_UNIT, + .num_resources = ARRAY_SIZE(excite_nandflash_rsrc), + .resource = excite_nandflash_rsrc +}; + +/* + * Create a platform device for the access to the nand-flash + * port + */ +static int __init excite_nandflash_devinit(void) +{ + adjust_resources(excite_nandflash_rsrc, ARRAY_SIZE(excite_nandflash_rsrc)); + + /* nothing to be done here */ + + /* Register platform device */ + return platform_device_register(&excite_nandflash_pdev); +} + +device_initcall(excite_nandflash_devinit); + + + +static struct resource iodev_rsrc[] = { + RINIT_IRQ(FPGA1_IRQ, IODEV_RESOURCE_IRQ) +}; + +static struct platform_device io_pdev = { + .name = IODEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(iodev_rsrc), + .resource = iodev_rsrc +}; + +/* + * Create a platform device for the external I/O ports. + */ +static int __init io_devinit(void) +{ + adjust_resources(iodev_rsrc, ARRAY_SIZE(iodev_rsrc)); + return platform_device_register(&io_pdev); +} + +device_initcall(io_devinit); + + + + +#if defined(CONFIG_RM9K_GE) || defined(CONFIG_RM9K_GE_MODULE) +static struct resource rm9k_ge_rsrc[] = { + RINIT(0x2200, 0x27ff, RM9K_GE_RESOURCE_MAC, &excite_titan_resource), + RINIT(0x1800, 0x1fff, RM9K_GE_RESOURCE_MSTAT, &excite_titan_resource), + RINIT(0x2000, 0x212f, RM9K_GE_RESOURCE_PKTPROC, &excite_titan_resource), + RINIT(0x5140, 0x5227, RM9K_GE_RESOURCE_XDMA, &excite_titan_resource), + RINIT(0x4870, 0x489f, RM9K_GE_RESOURCE_FIFO_RX, &excite_titan_resource), + RINIT(0x494c, 0x4957, RM9K_GE_RESOURCE_FIFO_TX, &excite_titan_resource), + RINIT(0x0000, 0x007f, RM9K_GE_RESOURCE_FIFOMEM_RX, &excite_fifomem_resource), + RINIT(0x0080, 0x00ff, RM9K_GE_RESOURCE_FIFOMEM_TX, &excite_fifomem_resource), + RINIT(0x0180, 0x019f, RM9K_GE_RESOURCE_PHY, &excite_titan_resource), + RINIT(0x0000, 0x03ff, RM9K_GE_RESOURCE_DMADESC_RX, &excite_scram_resource), + RINIT(0x0400, 0x07ff, RM9K_GE_RESOURCE_DMADESC_TX, &excite_scram_resource), + RINIT(slice_eth, slice_eth, RM9K_GE_RESOURCE_GPI_SLICE, &excite_gpislice_resource), + RINIT(0, 0, RM9K_GE_RESOURCE_MDIO_CHANNEL, &excite_mdio_channel_resource), + RINIT_IRQ(TITAN_IRQ, RM9K_GE_RESOURCE_IRQ_MAIN), + RINIT_IRQ(PHY_IRQ, RM9K_GE_RESOURCE_IRQ_PHY) +}; + +static struct platform_device rm9k_ge_pdev = { + .name = RM9K_GE_NAME, + .id = RM9K_GE_UNIT, + .num_resources = ARRAY_SIZE(rm9k_ge_rsrc), + .resource = rm9k_ge_rsrc +}; + + + +/* + * Create a platform device for the Ethernet port. + */ +static int __init rm9k_ge_devinit(void) +{ + u32 reg; + + adjust_resources(rm9k_ge_rsrc, ARRAY_SIZE(rm9k_ge_rsrc)); + + /* Power up the slice and configure it. */ + reg = titan_readl(CPTC1R); + reg &= ~(0x11000 << slice_eth); + reg |= 0x100 << slice_eth; + titan_writel(reg, CPTC1R); + + /* Take the MAC out of reset, reset the DLLs. */ + reg = titan_readl(CPRR); + reg &= ~(0x00030000 << (slice_eth * 2)); + reg |= 0x3 << (slice_eth * 2); + titan_writel(reg, CPRR); + + return platform_device_register(&rm9k_ge_pdev); +} + +device_initcall(rm9k_ge_devinit); +#endif /* defined(CONFIG_RM9K_GE) || defined(CONFIG_RM9K_GE_MODULE) */ + + + +static int __init excite_setup_devs(void) +{ + int res; + u32 reg; + + /* Enable xdma and fifo interrupts */ + reg = titan_readl(0x0050); + titan_writel(reg | 0x18000000, 0x0050); + + res = request_resource(&iomem_resource, &excite_titan_resource); + if (res) + return res; + res = request_resource(&iomem_resource, &excite_scram_resource); + if (res) + return res; + res = request_resource(&iomem_resource, &excite_fpga_resource); + if (res) + return res; + res = request_resource(&iomem_resource, &excite_nand_resource); + if (res) + return res; + excite_fpga_resource.flags = excite_fpga_resource.parent->flags & + ( IORESOURCE_IO | IORESOURCE_MEM + | IORESOURCE_IRQ | IORESOURCE_DMA); + excite_nand_resource.flags = excite_nand_resource.parent->flags & + ( IORESOURCE_IO | IORESOURCE_MEM + | IORESOURCE_IRQ | IORESOURCE_DMA); + + return 0; +} + +arch_initcall(excite_setup_devs); + diff --git a/arch/mips/basler/excite/excite_flashtest.c b/arch/mips/basler/excite/excite_flashtest.c new file mode 100644 index 000000000000..f0024a8e3294 --- /dev/null +++ b/arch/mips/basler/excite/excite_flashtest.c @@ -0,0 +1,294 @@ +/* +* Copyright (C) 2005 by Basler Vision Technologies AG +* Author: Thies Moeller +* +* 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 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include // for ocd_write +#include // for queue + +#include "excite_nandflash.h" +#include "nandflash.h" + +#define PFX "excite flashtest: " +typedef void __iomem *io_reg_t; + +#define io_readb(__a__) __raw_readb((__a__)) +#define io_writeb(__v__, __a__) __raw_writeb((__v__), (__a__)) + + + +static inline const struct resource *excite_nandflash_get_resource( + struct platform_device *d, unsigned long flags, const char *basename) +{ + const char fmt[] = "%s_%u"; + char buf[80]; + + if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf)) + return NULL; + + return platform_get_resource_byname(d, flags, buf); +} + +static inline io_reg_t +excite_nandflash_map_regs(struct platform_device *d, const char *basename) +{ + void *result = NULL; + const struct resource *const r = + excite_nandflash_get_resource(d, IORESOURCE_MEM, basename); + if (r) + result = ioremap_nocache(r->start, r->end + 1 - r->start); + return result; +} + +/* controller and mtd information */ + +struct excite_nandflash_drvdata { + struct mtd_info board_mtd; + struct nand_chip board_chip; + io_reg_t regs; +}; + + +/* command and control functions */ +static void excite_nandflash_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + io_reg_t regs = container_of(mtd,struct excite_nandflash_drvdata,board_mtd)->regs; + + switch (cmd) { + /* Select the command latch */ + case NAND_CTL_SETCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_CMD; + break; + /* Deselect the command latch */ + case NAND_CTL_CLRCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; + break; + /* Select the address latch */ + case NAND_CTL_SETALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_ADDR; + break; + /* Deselect the address latch */ + case NAND_CTL_CLRALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; + break; + /* Select the chip -- not used */ + case NAND_CTL_SETNCE: + break; + /* Deselect the chip -- not used */ + case NAND_CTL_CLRNCE: + break; + } + + this->IO_ADDR_R = this->IO_ADDR_W; +} + +/* excite_nandflash_devready() + * + * returns 0 if the nand is busy, 1 if it is ready + */ +static int excite_nandflash_devready(struct mtd_info *mtd) +{ + struct excite_nandflash_drvdata *drvdata = + container_of(mtd, struct excite_nandflash_drvdata, board_mtd); + + return io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); +} + +/* device management functions */ + +/* excite_nandflash_remove + * + * called by device layer to remove the driver + * the binding to the mtd and all allocated + * resources are released + */ +static int excite_nandflash_remove(struct device *dev) +{ + struct excite_nandflash_drvdata *this = dev_get_drvdata(dev); + + pr_info(PFX "remove"); + + dev_set_drvdata(dev, NULL); + + if (this == NULL) { + pr_debug(PFX "call remove without private data!!"); + return 0; + } + + + /* free the common resources */ + if (this->regs != NULL) { + iounmap(this->regs); + this->regs = NULL; + } + + kfree(this); + + return 0; +} + +static int elapsed; + +void my_workqueue_handler(void *arg) +{ + elapsed = 1; +} + +DECLARE_WORK(sigElapsed, my_workqueue_handler, 0); + + +/* excite_nandflash_probe + * + * called by device layer when it finds a device matching + * one our driver can handled. This code checks to see if + * it can allocate all necessary resources then calls the + * nand layer to look for devices +*/ +static int excite_nandflash_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + struct excite_nandflash_drvdata *drvdata; /* private driver data */ + struct nand_chip *board_chip; /* private flash chip data */ + struct mtd_info *board_mtd; /* mtd info for this board */ + + int err = 0; + int count = 0; + struct timeval tv,endtv; + unsigned int dt; + + pr_info(PFX "probe dev: (%p)\n", dev); + + pr_info(PFX "adjust LB timing\n"); + ocd_writel(0x00000330, LDP2); + + drvdata = kmalloc(sizeof(*drvdata), GFP_KERNEL); + if (unlikely(!drvdata)) { + printk(KERN_ERR PFX "no memory for drvdata\n"); + err = -ENOMEM; + goto mem_error; + } + + /* Initialize structures */ + memset(drvdata, 0, sizeof(*drvdata)); + + /* bind private data into driver */ + dev_set_drvdata(dev, drvdata); + + /* allocate and map the resource */ + drvdata->regs = + excite_nandflash_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS); + + if (unlikely(!drvdata->regs)) { + printk(KERN_ERR PFX "cannot reserve register region\n"); + err = -ENXIO; + goto io_error; + } + + /* initialise our chip */ + board_chip = &drvdata->board_chip; + + board_chip->IO_ADDR_R = drvdata->regs + EXCITE_NANDFLASH_DATA; + board_chip->IO_ADDR_W = drvdata->regs + EXCITE_NANDFLASH_DATA; + + board_chip->hwcontrol = excite_nandflash_hwcontrol; + board_chip->dev_ready = excite_nandflash_devready; + + board_chip->chip_delay = 25; + #if 0 + /* TODO: speedup the initial scan */ + board_chip->options = NAND_USE_FLASH_BBT; + #endif + board_chip->eccmode = NAND_ECC_SOFT; + + /* link chip to mtd */ + board_mtd = &drvdata->board_mtd; + board_mtd->priv = board_chip; + + + pr_info(PFX "FlashTest\n"); + elapsed = 0; +/* schedule_delayed_work(&sigElapsed, 1*HZ); + while (!elapsed) { + io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); + count++; + } + pr_info(PFX "reads in 1 sec --> %d\n",count); +*/ + do_gettimeofday(&tv); + for (count = 0 ; count < 1000000; count ++) { + io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); + } + do_gettimeofday(&endtv); + dt = (endtv.tv_sec - tv.tv_sec) * 1000000 + endtv.tv_usec - tv.tv_usec; + pr_info(PFX "%8d us timeval\n",dt); + pr_info(PFX "EndFlashTest\n"); + +/* return with error to unload everything +*/ +io_error: + iounmap(drvdata->regs); + +mem_error: + kfree(drvdata); + + if (err == 0) + err = -EINVAL; + return err; +} + +static struct device_driver excite_nandflash_driver = { + .name = "excite_nand", + .bus = &platform_bus_type, + .probe = excite_nandflash_probe, + .remove = excite_nandflash_remove, +}; + +static int __init excite_nandflash_init(void) +{ + pr_info(PFX "register Driver (Rev: $Revision:$)\n"); + return driver_register(&excite_nandflash_driver); +} + +static void __exit excite_nandflash_exit(void) +{ + driver_unregister(&excite_nandflash_driver); + pr_info(PFX "Driver unregistered"); +} + +module_init(excite_nandflash_init); +module_exit(excite_nandflash_exit); + +MODULE_AUTHOR("Thies Moeller "); +MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/basler/excite/excite_fpga.h b/arch/mips/basler/excite/excite_fpga.h new file mode 100644 index 000000000000..38fcda703a0b --- /dev/null +++ b/arch/mips/basler/excite/excite_fpga.h @@ -0,0 +1,80 @@ +#ifndef EXCITE_FPGA_H_INCLUDED +#define EXCITE_FPGA_H_INCLUDED + + +/** + * Adress alignment of the individual FPGA bytes. + * The address arrangement of the individual bytes of the FPGA is two + * byte aligned at the embedded MK2 platform. + */ +#ifdef EXCITE_CCI_FPGA_MK2 +typedef unsigned char excite_cci_fpga_align_t __attribute__ ((aligned(2))); +#else +typedef unsigned char excite_cci_fpga_align_t; +#endif + + +/** + * Size of Dual Ported RAM. + */ +#define EXCITE_DPR_SIZE 263 + + +/** + * Size of Reserved Status Fields in Dual Ported RAM. + */ +#define EXCITE_DPR_STATUS_SIZE 7 + + + +/** + * FPGA. + * Hardware register layout of the FPGA interface. The FPGA must accessed + * byte wise solely. + * @see EXCITE_CCI_DPR_MK2 + */ +typedef struct excite_fpga { + + /** + * Dual Ported RAM. + */ + excite_cci_fpga_align_t dpr[EXCITE_DPR_SIZE]; + + /** + * Status. + */ + excite_cci_fpga_align_t status[EXCITE_DPR_STATUS_SIZE]; + +#ifdef EXCITE_CCI_FPGA_MK2 + /** + * RM9000 Interrupt. + * Write access initiates interrupt at the RM9000 (MIPS) processor of the eXcite. + */ + excite_cci_fpga_align_t rm9k_int; +#else + /** + * MK2 Interrupt. + * Write access initiates interrupt at the ARM processor of the MK2. + */ + excite_cci_fpga_align_t mk2_int; + + excite_cci_fpga_align_t gap[0x1000-0x10f]; + + /** + * IRQ Source/Acknowledge. + */ + excite_cci_fpga_align_t rm9k_irq_src; + + /** + * IRQ Mask. + * Set bits enable the related interrupt. + */ + excite_cci_fpga_align_t rm9k_irq_mask; +#endif + + +} excite_fpga; + + + +#endif /* ndef EXCITE_FPGA_H_INCLUDED */ diff --git a/arch/mips/basler/excite/excite_iodev.c b/arch/mips/basler/excite/excite_iodev.c new file mode 100644 index 000000000000..91121e523043 --- /dev/null +++ b/arch/mips/basler/excite/excite_iodev.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2005 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "excite_iodev.h" + + + +static const struct resource *iodev_get_resource(struct platform_device *, const char *, unsigned int); +static int __init iodev_probe(struct device *); +static int __exit iodev_remove(struct device *); +static int iodev_open(struct inode *, struct file *); +static int iodev_release(struct inode *, struct file *); +static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *); +static unsigned int iodev_poll(struct file *, struct poll_table_struct *); +static irqreturn_t iodev_irqhdl(int, void *, struct pt_regs *); + + + +static const char iodev_name[] = "iodev"; +static unsigned int iodev_irq; +static DECLARE_WAIT_QUEUE_HEAD(wq); + + + +static struct file_operations fops = +{ + .owner = THIS_MODULE, + .open = iodev_open, + .release = iodev_release, + .read = iodev_read, + .poll = iodev_poll +}; + +static struct miscdevice miscdev = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = iodev_name, + .fops = &fops +}; + +static struct device_driver iodev_driver = +{ + .name = (char *) iodev_name, + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .probe = iodev_probe, + .remove = __exit_p(iodev_remove) +}; + + + +static const struct resource * +iodev_get_resource(struct platform_device *pdv, const char *name, + unsigned int type) +{ + char buf[80]; + if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) + return NULL; + return platform_get_resource_byname(pdv, type, buf); +} + + + +/* No hotplugging on the platform bus - use __init */ +static int __init iodev_probe(struct device *dev) +{ + struct platform_device * const pdv = to_platform_device(dev); + const struct resource * const ri = + iodev_get_resource(pdv, IODEV_RESOURCE_IRQ, IORESOURCE_IRQ); + + if (unlikely(!ri)) + return -ENXIO; + + iodev_irq = ri->start; + return misc_register(&miscdev); +} + + + +static int __exit iodev_remove(struct device *dev) +{ + return misc_deregister(&miscdev); +} + + + +static int iodev_open(struct inode *i, struct file *f) +{ + return request_irq(iodev_irq, iodev_irqhdl, SA_INTERRUPT, + iodev_name, &miscdev); +} + + + +static int iodev_release(struct inode *i, struct file *f) +{ + free_irq(iodev_irq, &miscdev); + return 0; +} + + + + +static ssize_t +iodev_read(struct file *f, char __user *d, size_t s, loff_t *o) +{ + ssize_t ret; + DEFINE_WAIT(w); + + prepare_to_wait(&wq, &w, TASK_INTERRUPTIBLE); + if (!signal_pending(current)) + schedule(); + ret = signal_pending(current) ? -ERESTARTSYS : 0; + finish_wait(&wq, &w); + return ret; +} + + +static unsigned int iodev_poll(struct file *f, struct poll_table_struct *p) +{ + poll_wait(f, &wq, p); + return POLLOUT | POLLWRNORM; +} + + + + +static irqreturn_t iodev_irqhdl(int irq, void *ctxt, struct pt_regs *regs) +{ + wake_up(&wq); + return IRQ_HANDLED; +} + + + +static int __init iodev_init_module(void) +{ + return driver_register(&iodev_driver); +} + + + +static void __exit iodev_cleanup_module(void) +{ + driver_unregister(&iodev_driver); +} + +module_init(iodev_init_module); +module_exit(iodev_cleanup_module); + + + +MODULE_AUTHOR("Thomas Koeller "); +MODULE_DESCRIPTION("Basler eXcite i/o interrupt handler"); +MODULE_VERSION("0.0"); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/basler/excite/excite_iodev.h b/arch/mips/basler/excite/excite_iodev.h new file mode 100644 index 000000000000..cbfbb5d2ee62 --- /dev/null +++ b/arch/mips/basler/excite/excite_iodev.h @@ -0,0 +1,10 @@ +#ifndef __EXCITE_IODEV_H__ +#define __EXCITE_IODEV_H__ + +/* Device name */ +#define IODEV_NAME "iodev" + +/* Resource names */ +#define IODEV_RESOURCE_IRQ "excite_iodev_irq" + +#endif /* __EXCITE_IODEV_H__ */ diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c new file mode 100644 index 000000000000..511ad8730f54 --- /dev/null +++ b/arch/mips/basler/excite/excite_irq.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern asmlinkage void excite_handle_int(void); + +/* + * Initialize the interrupt handler + */ +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(0); + rm7k_cpu_irq_init(8); + rm9k_cpu_irq_init(12); + +#ifdef CONFIG_KGDB + excite_kgdb_init(); +#endif +} + +asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +{ + const u32 + interrupts = read_c0_cause() >> 8, + mask = ((read_c0_status() >> 8) & 0x000000ff) | + (read_c0_intcontrol() & 0x0000ff00), + pending = interrupts & mask; + u32 msgintflags, msgintmask, msgint; + + /* process timer interrupt */ + if (pending & (1 << TIMER_IRQ)) { + do_IRQ(TIMER_IRQ, regs); + return; + } + + /* Process PCI interrupts */ +#if USB_IRQ < 10 + msgintflags = ocd_readl(INTP0Status0 + (USB_MSGINT / 0x20 * 0x10)); + msgintmask = ocd_readl(INTP0Mask0 + (USB_MSGINT / 0x20 * 0x10)); + msgint = msgintflags & msgintmask & (0x1 << (USB_MSGINT % 0x20)); + if ((pending & (1 << USB_IRQ)) && msgint) { +#else + if (pending & (1 << USB_IRQ)) { +#endif + do_IRQ(USB_IRQ, regs); + return; + } + + /* Process TITAN interrupts */ + msgintflags = ocd_readl(INTP0Status0 + (TITAN_MSGINT / 0x20 * 0x10)); + msgintmask = ocd_readl(INTP0Mask0 + (TITAN_MSGINT / 0x20 * 0x10)); + msgint = msgintflags & msgintmask & (0x1 << (TITAN_MSGINT % 0x20)); + if ((pending & (1 << TITAN_IRQ)) && msgint) { + ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10)); +#if defined(CONFIG_KGDB) + excite_kgdb_inthdl(regs); +#endif + do_IRQ(TITAN_IRQ, regs); + return; + } + + /* Process FPGA line #0 interrupts */ + msgintflags = ocd_readl(INTP0Status0 + (FPGA0_MSGINT / 0x20 * 0x10)); + msgintmask = ocd_readl(INTP0Mask0 + (FPGA0_MSGINT / 0x20 * 0x10)); + msgint = msgintflags & msgintmask & (0x1 << (FPGA0_MSGINT % 0x20)); + if ((pending & (1 << FPGA0_IRQ)) && msgint) { + do_IRQ(FPGA0_IRQ, regs); + return; + } + + /* Process FPGA line #1 interrupts */ + msgintflags = ocd_readl(INTP0Status0 + (FPGA1_MSGINT / 0x20 * 0x10)); + msgintmask = ocd_readl(INTP0Mask0 + (FPGA1_MSGINT / 0x20 * 0x10)); + msgint = msgintflags & msgintmask & (0x1 << (FPGA1_MSGINT % 0x20)); + if ((pending & (1 << FPGA1_IRQ)) && msgint) { + do_IRQ(FPGA1_IRQ, regs); + return; + } + + /* Process PHY interrupts */ + msgintflags = ocd_readl(INTP0Status0 + (PHY_MSGINT / 0x20 * 0x10)); + msgintmask = ocd_readl(INTP0Mask0 + (PHY_MSGINT / 0x20 * 0x10)); + msgint = msgintflags & msgintmask & (0x1 << (PHY_MSGINT % 0x20)); + if ((pending & (1 << PHY_IRQ)) && msgint) { + do_IRQ(PHY_IRQ, regs); + return; + } + + /* Process spurious interrupts */ + spurious_interrupt(regs); +} diff --git a/arch/mips/basler/excite/excite_procfs.c b/arch/mips/basler/excite/excite_procfs.c new file mode 100644 index 000000000000..c62be0341fb8 --- /dev/null +++ b/arch/mips/basler/excite/excite_procfs.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004, 2005 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * Procfs support for Basler eXcite + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static int excite_get_unit_id(char *buf, char **addr, off_t offs, int size) +{ + const int len = snprintf(buf, PAGE_SIZE, "%06x", unit_id); + const int w = len - offs; + *addr = buf + offs; + return w < size ? w : size; +} + +static int +excite_bootrom_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + void __iomem * src; + + if (off >= EXCITE_SIZE_BOOTROM) { + *eof = 1; + return 0; + } + + if ((off + count) > EXCITE_SIZE_BOOTROM) + count = EXCITE_SIZE_BOOTROM - off; + + src = ioremap(EXCITE_PHYS_BOOTROM + off, count); + if (src) { + memcpy_fromio(page, src, count); + iounmap(src); + *start = page; + } else { + count = -ENOMEM; + } + + return count; +} + +void excite_procfs_init(void) +{ + /* Create & populate /proc/excite */ + struct proc_dir_entry * const pdir = proc_mkdir("excite", &proc_root); + if (pdir) { + struct proc_dir_entry * e; + + e = create_proc_info_entry("unit_id", S_IRUGO, pdir, + excite_get_unit_id); + if (e) e->size = 6; + + e = create_proc_read_entry("bootrom", S_IRUGO, pdir, + excite_bootrom_read, NULL); + if (e) e->size = EXCITE_SIZE_BOOTROM; + } +} diff --git a/arch/mips/basler/excite/excite_prom.c b/arch/mips/basler/excite/excite_prom.c new file mode 100644 index 000000000000..84724b270753 --- /dev/null +++ b/arch/mips/basler/excite/excite_prom.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2004, 2005 by Thomas Koeller (thomas.koeller@baslerweb.com) + * Based on the PMC-Sierra Yosemite board support by Ralf Baechle and + * Manish Lachwani. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* This struct is used by Redboot to pass arguments to the kernel */ +typedef struct +{ + char *name; + char *val; +} t_env_var; + +struct parmblock { + t_env_var memsize; + t_env_var modetty0; + t_env_var ethaddr; + t_env_var env_end; + char *argv[2]; + char text[0]; +}; + +static unsigned int prom_argc; +static const char ** prom_argv; +static const t_env_var * prom_env; + +static void prom_halt(void) __attribute__((noreturn)); +static void prom_exit(void) __attribute__((noreturn)); + + + +const char *get_system_type(void) +{ + return "Basler eXcite"; +} + +/* + * Halt the system + */ +static void prom_halt(void) +{ + printk(KERN_NOTICE "\n** System halted.\n"); + while (1) + asm volatile ( + "\t.set\tmips3\n" + "\twait\n" + "\t.set\tmips0\n" + ); +} + +/* + * Reset the CPU and re-enter Redboot + */ +static void prom_exit(void) +{ + unsigned int i; + volatile unsigned char * const flg = + (volatile unsigned char *) (EXCITE_ADDR_FPGA + EXCITE_FPGA_DPR); + + /* Clear the watchdog reset flag, set the reboot flag */ + *flg &= ~0x01; + *flg |= 0x80; + + for (i = 0; i < 10; i++) { + *(volatile unsigned char *) (EXCITE_ADDR_FPGA + EXCITE_FPGA_SYSCTL) = 0x02; + iob(); + mdelay(1000); + } + + printk(KERN_NOTICE "Reset failed\n"); + prom_halt(); +} + +static const char __init *prom_getenv(char *name) +{ + const t_env_var * p; + for (p = prom_env; p->name != NULL; p++) + if(strcmp(name, p->name) == 0) + break; + return p->val; +} + +/* + * Init routine which accepts the variables from Redboot + */ +void __init prom_init(void) +{ + const struct parmblock * const pb = (struct parmblock *) fw_arg2; + + prom_argc = fw_arg0; + prom_argv = (const char **) fw_arg1; + prom_env = &pb->memsize; + + /* Callbacks for halt, restart */ + _machine_restart = (void (*)(char *)) prom_exit; + _machine_halt = prom_halt; + +#ifdef CONFIG_32BIT + /* copy command line */ + strcpy(arcs_cmdline, prom_argv[1]); + memsize = simple_strtol(prom_getenv("memsize"), NULL, 16); + strcpy(modetty, prom_getenv("modetty0")); +#endif /* CONFIG_32BIT */ + +#ifdef CONFIG_64BIT +# error 64 bit support not implemented +#endif /* CONFIG_64BIT */ + + mips_machgroup = MACH_GROUP_TITAN; + mips_machtype = MACH_TITAN_EXCITE; +} + +/* This is called from free_initmem(), so we need to provide it */ +void __init prom_free_prom_memory(void) +{ + /* Nothing to do */ +} diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c new file mode 100644 index 000000000000..005b025605e6 --- /dev/null +++ b/arch/mips/basler/excite/excite_setup.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2004, 2005 by Basler Vision Technologies AG + * Author: Thomas Koeller + * Based on the PMC-Sierra Yosemite board support by Ralf Baechle and + * Manish Lachwani. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TITAN_UART_CLK 25000000 + +#if 1 +/* normal serial port assignment */ +#define REGBASE_SER0 0x0208 +#define REGBASE_SER1 0x0238 +#define MASK_SER0 0x1 +#define MASK_SER1 0x2 +#else +/* serial ports swapped */ +#define REGBASE_SER0 0x0238 +#define REGBASE_SER1 0x0208 +#define MASK_SER0 0x2 +#define MASK_SER1 0x1 +#endif + +unsigned long memsize; +char modetty[30]; +unsigned int titan_irq = TITAN_IRQ; +static void __iomem * ctl_regs; +u32 unit_id; + +volatile void __iomem * const ocd_base = (void *) (EXCITE_ADDR_OCD); +volatile void __iomem * const titan_base = (void *) (EXCITE_ADDR_TITAN); + +/* Protect access to shared GPI registers */ +spinlock_t titan_lock = SPIN_LOCK_UNLOCKED; +int titan_irqflags; + + +static void excite_timer_init(void) +{ + const u32 modebit5 = ocd_readl(0x00e4); + unsigned int + mult = ((modebit5 >> 11) & 0x1f) + 2, + div = ((modebit5 >> 16) & 0x1f) + 2; + + if (div == 33) div = 1; + mips_hpt_frequency = EXCITE_CPU_EXT_CLOCK * mult / div / 2; +} + +static void excite_timer_setup(struct irqaction *irq) +{ + /* The eXcite platform uses the alternate timer interrupt */ + set_c0_intcontrol(0x80); + setup_irq(TIMER_IRQ, irq); +} + +static int __init excite_init_console(void) +{ +#if defined(CONFIG_SERIAL_8250) + static __initdata char serr[] = + KERN_ERR "Serial port #%u setup failed\n"; + struct uart_port up; + + /* Take the DUART out of reset */ + titan_writel(0x00ff1cff, CPRR); + +#if defined(CONFIG_KGDB) || (CONFIG_SERIAL_8250_NR_UARTS > 1) + /* Enable both ports */ + titan_writel(MASK_SER0 | MASK_SER1, UACFG); +#else + /* Enable port #0 only */ + titan_writel(MASK_SER0, UACFG); +#endif /* defined(CONFIG_KGDB) */ + + /* + * Set up serial port #0. Do not use autodetection; the result is + * not what we want. + */ + memset(&up, 0, sizeof(up)); + up.membase = (char *) titan_addr(REGBASE_SER0); + up.irq = TITAN_IRQ; + up.uartclk = TITAN_UART_CLK; + up.regshift = 0; + up.iotype = UPIO_MEM32; + up.type = PORT_RM9000; + up.flags = UPF_SHARE_IRQ; + up.line = 0; + if (early_serial_setup(&up)) + printk(serr, up.line); + +#if CONFIG_SERIAL_8250_NR_UARTS > 1 + /* And now for port #1. */ + up.membase = (char *) titan_addr(REGBASE_SER1); + up.line = 1; + if (early_serial_setup(&up)) + printk(serr, up.line); +#endif /* CONFIG_SERIAL_8250_NR_UARTS > 1 */ +#else + /* Leave the DUART in reset */ + titan_writel(0x00ff3cff, CPRR); +#endif /* defined(CONFIG_SERIAL_8250) */ + + return 0; +} + +static int __init excite_platform_init(void) +{ + unsigned int i; + unsigned char buf[3]; + u8 reg; + void __iomem * dpr; + + /* BIU buffer allocations */ + ocd_writel(8, CPURSLMT); /* CPU */ + titan_writel(4, CPGRWL); /* GPI / Ethernet */ + + /* Map control registers located in FPGA */ + ctl_regs = ioremap_nocache(EXCITE_PHYS_FPGA + EXCITE_FPGA_SYSCTL, 16); + if (!ctl_regs) + panic("eXcite: failed to map platform control registers\n"); + memcpy_fromio(buf, ctl_regs + 2, ARRAY_SIZE(buf)); + unit_id = buf[0] | (buf[1] << 8) | (buf[2] << 16); + + /* Clear the reboot flag */ + dpr = ioremap_nocache(EXCITE_PHYS_FPGA + EXCITE_FPGA_DPR, 1); + reg = __raw_readb(dpr); + __raw_writeb(reg & 0x7f, dpr); + iounmap(dpr); + + /* Interrupt controller setup */ + for (i = INTP0Status0; i < INTP0Status0 + 0x80; i += 0x10) { + ocd_writel(0x00000000, i + 0x04); + ocd_writel(0xffffffff, i + 0x0c); + } + ocd_writel(0x2, NMICONFIG); + + ocd_writel(0x1 << (TITAN_MSGINT % 0x20), + INTP0Mask0 + (0x10 * (TITAN_MSGINT / 0x20))); + ocd_writel((0x1 << (FPGA0_MSGINT % 0x20)) + | ocd_readl(INTP0Mask0 + (0x10 * (FPGA0_MSGINT / 0x20))), + INTP0Mask0 + (0x10 * (FPGA0_MSGINT / 0x20))); + ocd_writel((0x1 << (FPGA1_MSGINT % 0x20)) + | ocd_readl(INTP0Mask0 + (0x10 * (FPGA1_MSGINT / 0x20))), + INTP0Mask0 + (0x10 * (FPGA1_MSGINT / 0x20))); + ocd_writel((0x1 << (PHY_MSGINT % 0x20)) + | ocd_readl(INTP0Mask0 + (0x10 * (PHY_MSGINT / 0x20))), + INTP0Mask0 + (0x10 * (PHY_MSGINT / 0x20))); +#if USB_IRQ < 10 + ocd_writel((0x1 << (USB_MSGINT % 0x20)) + | ocd_readl(INTP0Mask0 + (0x10 * (USB_MSGINT / 0x20))), + INTP0Mask0 + (0x10 * (USB_MSGINT / 0x20))); +#endif + /* Enable the packet FIFO, XDMA and XDMA arbiter */ + titan_writel(0x00ff18ff, CPRR); + + /* + * Set up the PADMUX. Power down all ethernet slices, + * they will be powered up and configured at device startup. + */ + titan_writel(0x00878206, CPTC1R); + titan_writel(0x00001100, CPTC0R); /* latch PADMUX, enable WCIMODE */ + + /* Reset and enable the FIFO block */ + titan_writel(0x00000001, SDRXFCIE); + titan_writel(0x00000001, SDTXFCIE); + titan_writel(0x00000100, SDRXFCIE); + titan_writel(0x00000000, SDTXFCIE); + + /* + * Initialize the common interrupt shared by all components of + * the GPI/Ethernet subsystem. + */ + titan_writel((EXCITE_PHYS_OCD >> 12), CPCFG0); + titan_writel(TITAN_MSGINT, CPCFG1); + + /* + * XDMA configuration. + * In order for the XDMA to be sharable among multiple drivers, + * the setup must be done here in the platform. The reason is that + * this setup can only be done while the XDMA is in reset. If this + * were done in a driver, it would interrupt all other drivers + * using the XDMA. + */ + titan_writel(0x80021dff, GXCFG); /* XDMA reset */ + titan_writel(0x00000000, CPXCISRA); + titan_writel(0x00000000, CPXCISRB); /* clear pending interrupts */ +#if defined (CONFIG_HIGHMEM) +# error change for HIGHMEM support! +#else + titan_writel(0x00000000, GXDMADRPFX); /* buffer address prefix */ +#endif + titan_writel(0, GXDMA_DESCADR); + + for (i = 0x5040; i <= 0x5300; i += 0x0040) + titan_writel(0x80080000, i); /* reset channel */ + + titan_writel((0x1 << 29) /* no sparse tx descr. */ + | (0x1 << 28) /* no sparse rx descr. */ + | (0x1 << 23) | (0x1 << 24) /* descriptor coherency */ + | (0x1 << 21) | (0x1 << 22) /* data coherency */ + | (0x1 << 17) + | 0x1dff, + GXCFG); + +#if defined(CONFIG_SMP) +# error No SMP support +#else + /* All interrupts go to core #0 only. */ + titan_writel(0x1f007fff, CPDST0A); + titan_writel(0x00000000, CPDST0B); + titan_writel(0x0000ff3f, CPDST1A); + titan_writel(0x00000000, CPDST1B); + titan_writel(0x00ffffff, CPXDSTA); + titan_writel(0x00000000, CPXDSTB); +#endif + + /* Enable DUART interrupts, disable everything else. */ + titan_writel(0x04000000, CPGIG0ER); + titan_writel(0x000000c0, CPGIG1ER); + + excite_procfs_init(); + return 0; +} + +void __init plat_setup(void) +{ + volatile u32 * const boot_ocd_base = (u32 *) 0xbf7fc000; + + /* Announce RAM to system */ + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); + + /* Set up timer initialization hooks */ + board_time_init = excite_timer_init; + board_timer_setup = excite_timer_setup; + + /* Set up the peripheral address map */ + *(boot_ocd_base + (LKB9 / sizeof (u32))) = 0; + *(boot_ocd_base + (LKB10 / sizeof (u32))) = 0; + *(boot_ocd_base + (LKB11 / sizeof (u32))) = 0; + *(boot_ocd_base + (LKB12 / sizeof (u32))) = 0; + wmb(); + *(boot_ocd_base + (LKB0 / sizeof (u32))) = EXCITE_PHYS_OCD >> 4; + wmb(); + + ocd_writel((EXCITE_PHYS_TITAN >> 4) | 0x1UL, LKB5); + ocd_writel(((EXCITE_SIZE_TITAN >> 4) & 0x7fffff00) - 0x100, LKM5); + ocd_writel((EXCITE_PHYS_SCRAM >> 4) | 0x1UL, LKB13); + ocd_writel(((EXCITE_SIZE_SCRAM >> 4) & 0xffffff00) - 0x100, LKM13); + + /* Local bus slot #0 */ + ocd_writel(0x00040510, LDP0); + ocd_writel((EXCITE_PHYS_BOOTROM >> 4) | 0x1UL, LKB9); + ocd_writel(((EXCITE_SIZE_BOOTROM >> 4) & 0x03ffff00) - 0x100, LKM9); + + /* Local bus slot #2 */ + ocd_writel(0x00000330, LDP2); + ocd_writel((EXCITE_PHYS_FPGA >> 4) | 0x1, LKB11); + ocd_writel(((EXCITE_SIZE_FPGA >> 4) - 0x100) & 0x03ffff00, LKM11); + + /* Local bus slot #3 */ + ocd_writel(0x00123413, LDP3); + ocd_writel((EXCITE_PHYS_NAND >> 4) | 0x1, LKB12); + ocd_writel(((EXCITE_SIZE_NAND >> 4) - 0x100) & 0x03ffff00, LKM12); +} + + + +console_initcall(excite_init_console); +arch_initcall(excite_platform_init); + +EXPORT_SYMBOL(titan_lock); +EXPORT_SYMBOL(titan_irqflags); +EXPORT_SYMBOL(titan_irq); +EXPORT_SYMBOL(ocd_base); +EXPORT_SYMBOL(titan_base); diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig new file mode 100644 index 000000000000..3240962ef585 --- /dev/null +++ b/arch/mips/configs/excite_defconfig @@ -0,0 +1,1211 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.16-rc4 +# Thu Feb 23 13:15:27 2006 +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MIPS_MTX1 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MIPS_XXS1500 is not set +# CONFIG_PNX8550_V2PCI is not set +# CONFIG_PNX8550_JBS is not set +CONFIG_BASLER_EXCITE=y +# CONFIG_BASLER_EXCITE_PROTOTYPE is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_DMA_COHERENT=y +CONFIG_SERIAL_RM9000=y +CONFIG_CPU_BIG_ENDIAN=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_IRQ_CPU_RM7K=y +CONFIG_IRQ_CPU_RM9K=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_MIPS32_R1 is not set +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +CONFIG_CPU_RM9000=y +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_RM9000=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_MIPS_MT is not set +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SMP is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_BKL=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_PCI_LEGACY_PROC is not set +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_VERIFY_WRITE=y +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +CONFIG_MTD_NAND_BASLER_EXCITE=y +# CONFIG_MTD_NAND_BASLER_EXCITE_RDNBY is not set +# CONFIG_MTD_NAND_BASLER_EXCITE_PERF is not set +# CONFIG_MTD_NAND_NANDSIM is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_TITAN_GE is not set +CONFIG_RM9K_GE=m + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_WDT_RM9K_GPI=m + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_SMIVGX is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_DD=y + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +# CONFIG_LOGO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +CONFIG_USB_ARTTFT=m +# CONFIG_USB_ARTTOUCH is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETKIT is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# EDAC - error detection and reporting (RAS) +# + +# +# eXcite frame capture support +# +CONFIG_EXCITE_FCAP=m +CONFIG_EXCITE_FCAP_GPI=m + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=m +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 56000a069604..465778c5d816 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MARKEINS) += ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o # # These are still pretty much in the old state, watch, go blind. # +obj-$(CONFIG_BASLER_EXCITE) = ops-titan.o pci-excite.o fixup-excite.o obj-$(CONFIG_DDB5477) += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o diff --git a/arch/mips/pci/fixup-excite.c b/arch/mips/pci/fixup-excite.c new file mode 100644 index 000000000000..1da696d43f00 --- /dev/null +++ b/arch/mips/pci/fixup-excite.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ +#include +#include +#include +#include + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (pin == 0) + return -1; + + return USB_IRQ; /* USB controller is the only PCI device */ +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/arch/mips/pci/ops-titan.c b/arch/mips/pci/ops-titan.c index 233ec6f2054d..ebf8fc40e9b2 100644 --- a/arch/mips/pci/ops-titan.c +++ b/arch/mips/pci/ops-titan.c @@ -26,8 +26,19 @@ #include #include -#include +#include +#include +#include +/* + * PCI specific defines + */ +#define TITAN_PCI_0_CONFIG_ADDRESS 0x780 +#define TITAN_PCI_0_CONFIG_DATA 0x784 + +/* + * Titan PCI Config Read Byte + */ static int titan_read_config(struct pci_bus *bus, unsigned int devfn, int reg, int size, u32 * val) { @@ -43,8 +54,8 @@ static int titan_read_config(struct pci_bus *bus, unsigned int devfn, int reg, /* start the configuration cycle */ - TITAN_WRITE(TITAN_PCI_0_CONFIG_ADDRESS, address); - tmp = TITAN_READ(TITAN_PCI_0_CONFIG_DATA) >> ((reg & 3) << 3); + ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); + tmp = ocd_readl(TITAN_PCI_0_CONFIG_DATA) >> ((reg & 3) << 3); switch (size) { case 1: @@ -71,20 +82,20 @@ static int titan_write_config(struct pci_bus *bus, unsigned int devfn, int reg, (reg & 0xfc) | 0x80000000; /* start the configuration cycle */ - TITAN_WRITE(TITAN_PCI_0_CONFIG_ADDRESS, address); + ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); /* write the data */ switch (size) { case 1: - TITAN_WRITE_8(TITAN_PCI_0_CONFIG_DATA + (~reg & 0x3), val); + ocd_writeb(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x3)); break; case 2: - TITAN_WRITE_16(TITAN_PCI_0_CONFIG_DATA + (~reg & 0x2), val); + ocd_writew(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x2)); break; case 4: - TITAN_WRITE(TITAN_PCI_0_CONFIG_DATA, val); + ocd_writel(val, TITAN_PCI_0_CONFIG_DATA); break; } diff --git a/arch/mips/pci/pci-excite.c b/arch/mips/pci/pci-excite.c new file mode 100644 index 000000000000..3c86c77cb74f --- /dev/null +++ b/arch/mips/pci/pci-excite.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * Based on the PMC-Sierra Yosemite board support by 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. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include + + +extern struct pci_ops titan_pci_ops; + + +static struct resource + mem_resource = { + .name = "PCI memory", + .start = EXCITE_PHYS_PCI_MEM, + .end = EXCITE_PHYS_PCI_MEM + EXCITE_SIZE_PCI_MEM - 1, + .flags = IORESOURCE_MEM + }, + io_resource = { + .name = "PCI I/O", + .start = EXCITE_PHYS_PCI_IO, + .end = EXCITE_PHYS_PCI_IO + EXCITE_SIZE_PCI_IO - 1, + .flags = IORESOURCE_IO + }; + + +static struct pci_controller bx_controller = { + .pci_ops = &titan_pci_ops, + .mem_resource = &mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &io_resource, + .io_offset = 0x00000000UL +}; + + +static char + iopage_failed[] __initdata = "Cannot allocate PCI I/O page", + modebits_no_pci[] __initdata = "PCI is not configured in mode bits"; + +#define RM9000x2_OCD_HTSC 0x0604 +#define RM9000x2_OCD_HTBHL 0x060c +#define RM9000x2_OCD_PCIHRST 0x078c + +#define RM9K_OCD_MODEBIT1 0x00d4 /* (MODEBIT1) Mode Bit 1 */ +#define RM9K_OCD_CPHDCR 0x00f4 /* CPU-PCI/HT Data Control. */ + +#define PCISC_FB2B 0x00000200 +#define PCISC_MWICG 0x00000010 +#define PCISC_EMC 0x00000004 +#define PCISC_ERMA 0x00000002 + + + +static int __init basler_excite_pci_setup(void) +{ + const unsigned int fullbars = memsize / (256 << 20); + unsigned int i; + + /* Check modebits to see if PCI is really enabled. */ + if (!((ocd_readl(RM9K_OCD_MODEBIT1) >> (47-32)) & 0x1)) + panic(modebits_no_pci); + + if (NULL == request_mem_region(EXCITE_PHYS_PCI_IO, EXCITE_SIZE_PCI_IO, + "Memory-mapped PCI I/O page")) + panic(iopage_failed); + + /* Enable PCI 0 as master for config cycles */ + ocd_writel(PCISC_EMC | PCISC_ERMA, RM9000x2_OCD_HTSC); + + + /* Set up latency timer */ + ocd_writel(0x8008, RM9000x2_OCD_HTBHL); + + /* Setup host IO and Memory space */ + ocd_writel((EXCITE_PHYS_PCI_IO >> 4) | 1, LKB7); + ocd_writel(((EXCITE_SIZE_PCI_IO >> 4) & 0x7fffff00) - 0x100, LKM7); + ocd_writel((EXCITE_PHYS_PCI_MEM >> 4) | 1, LKB8); + ocd_writel(((EXCITE_SIZE_PCI_MEM >> 4) & 0x7fffff00) - 0x100, LKM8); + + /* Set up PCI BARs to map all installed memory */ + for (i = 0; i < 6; i++) { + const unsigned int bar = 0x610 + i * 4; + + if (i < fullbars) { + ocd_writel(0x10000000 * i, bar); + ocd_writel(0x01000000 * i, bar + 0x140); + ocd_writel(0x0ffff029, bar + 0x100); + continue; + } + + if (i == fullbars) { + int o; + u32 mask; + + const unsigned long rem = memsize - i * 0x10000000; + if (!rem) { + ocd_writel(0x00000000, bar + 0x100); + continue; + } + + o = ffs(rem) - 1; + if (rem & ~(0x1 << o)) + o++; + mask = ((0x1 << o) & 0x0ffff000) - 0x1000; + ocd_writel(0x10000000 * i, bar); + ocd_writel(0x01000000 * i, bar + 0x140); + ocd_writel(0x00000029 | mask, bar + 0x100); + continue; + } + + ocd_writel(0x00000000, bar + 0x100); + } + + /* Finally, enable the PCI interupt */ +#if USB_IRQ > 7 + set_c0_intcontrol(1 << USB_IRQ); +#else + set_c0_status(1 << (USB_IRQ + 8)); +#endif + + ioport_resource.start = EXCITE_PHYS_PCI_IO; + ioport_resource.end = EXCITE_PHYS_PCI_IO + EXCITE_SIZE_PCI_IO - 1; + set_io_port_base((unsigned long) ioremap_nocache(EXCITE_PHYS_PCI_IO, EXCITE_SIZE_PCI_IO)); + register_pci_controller(&bx_controller); + return 0; +} + + +arch_initcall(basler_excite_pci_setup); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 72fa6dc45523..3b745e76f429 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -217,6 +217,7 @@ */ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ +#define MACH_TITAN_EXCITE 2 /* Basler eXcite */ /* * Valid machtype for group NEC EMMA2RH diff --git a/include/asm-mips/mach-excite/cpu-feature-overrides.h b/include/asm-mips/mach-excite/cpu-feature-overrides.h new file mode 100644 index 000000000000..abb76b2fd865 --- /dev/null +++ b/include/asm-mips/mach-excite/cpu-feature-overrides.h @@ -0,0 +1,40 @@ +/* + * 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) 2004 Thomas Koeller + */ +#ifndef __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H + +/* + * Basler eXcite has an RM9122 processor. + */ +#define cpu_has_watch 1 +#define cpu_has_mips16 0 +#define cpu_has_divec 0 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 0 +#define cpu_has_ejtag 0 + +#define cpu_has_llsc 1 +#define cpu_has_vtag_icache 0 +#define cpu_has_dc_aliases 0 +#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_dsp 0 +#define cpu_icache_snoops_remote_store 0 + +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 1 + +#define cpu_has_subset_pcaches 0 + +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 +#define cpu_scache_line_size() 32 + +#endif /* __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H */ diff --git a/include/asm-mips/mach-excite/excite.h b/include/asm-mips/mach-excite/excite.h new file mode 100644 index 000000000000..c52610de2b3a --- /dev/null +++ b/include/asm-mips/mach-excite/excite.h @@ -0,0 +1,155 @@ +#ifndef __EXCITE_H__ +#define __EXCITE_H__ + +#include +#include +#include +#include + +#define EXCITE_CPU_EXT_CLOCK 100000000 + +#if !defined(__ASSEMBLER__) +void __init excite_kgdb_init(void); +void excite_procfs_init(void); +extern unsigned long memsize; +extern char modetty[]; +extern u32 unit_id; +#endif + +/* Base name for XICAP devices */ +#define XICAP_NAME "xicap_gpi" + +/* OCD register offsets */ +#define LKB0 0x0038 +#define LKB5 0x0128 +#define LKM5 0x012C +#define LKB7 0x0138 +#define LKM7 0x013c +#define LKB8 0x0140 +#define LKM8 0x0144 +#define LKB9 0x0148 +#define LKM9 0x014c +#define LKB10 0x0150 +#define LKM10 0x0154 +#define LKB11 0x0158 +#define LKM11 0x015c +#define LKB12 0x0160 +#define LKM12 0x0164 +#define LKB13 0x0168 +#define LKM13 0x016c +#define LDP0 0x0200 +#define LDP1 0x0210 +#define LDP2 0x0220 +#define LDP3 0x0230 +#define INTPIN0 0x0A40 +#define INTPIN1 0x0A44 +#define INTPIN2 0x0A48 +#define INTPIN3 0x0A4C +#define INTPIN4 0x0A50 +#define INTPIN5 0x0A54 +#define INTPIN6 0x0A58 +#define INTPIN7 0x0A5C + + + + +/* TITAN register offsets */ +#define CPRR 0x0004 +#define CPDSR 0x0008 +#define CPTC0R 0x000c +#define CPTC1R 0x0010 +#define CPCFG0 0x0020 +#define CPCFG1 0x0024 +#define CPDST0A 0x0028 +#define CPDST0B 0x002c +#define CPDST1A 0x0030 +#define CPDST1B 0x0034 +#define CPXDSTA 0x0038 +#define CPXDSTB 0x003c +#define CPXCISRA 0x0048 +#define CPXCISRB 0x004c +#define CPGIG0ER 0x0050 +#define CPGIG1ER 0x0054 +#define CPGRWL 0x0068 +#define CPURSLMT 0x00f8 +#define UACFG 0x0200 +#define UAINTS 0x0204 +#define SDRXFCIE 0x4828 +#define SDTXFCIE 0x4928 +#define INTP0Status0 0x1B00 +#define INTP0Mask0 0x1B04 +#define INTP0Set0 0x1B08 +#define INTP0Clear0 0x1B0C +#define GXCFG 0x5000 +#define GXDMADRPFX 0x5018 +#define GXDMA_DESCADR 0x501c +#define GXCH0TDESSTRT 0x5054 + +/* IRQ definitions */ +#define NMICONFIG 0xac0 +#define TITAN_MSGINT 0xc4 +#define TITAN_IRQ ((TITAN_MSGINT / 0x20) + 2) +#define FPGA0_MSGINT 0x5a +#define FPGA0_IRQ ((FPGA0_MSGINT / 0x20) + 2) +#define FPGA1_MSGINT 0x7b +#define FPGA1_IRQ ((FPGA1_MSGINT / 0x20) + 2) +#define PHY_MSGINT 0x9c +#define PHY_IRQ ((PHY_MSGINT / 0x20) + 2) + +#if defined(CONFIG_BASLER_EXCITE_PROTOTYPE) +/* Pre-release units used interrupt pin #9 */ +#define USB_IRQ 11 +#else +/* Re-designed units use interrupt pin #1 */ +#define USB_MSGINT 0x39 +#define USB_IRQ ((USB_MSGINT / 0x20) + 2) +#endif +#define TIMER_IRQ 12 + + +/* Device address ranges */ +#define EXCITE_OFFS_OCD 0x1fffc000 +#define EXCITE_SIZE_OCD (16 * 1024) +#define EXCITE_PHYS_OCD CPHYSADDR(EXCITE_OFFS_OCD) +#define EXCITE_ADDR_OCD CKSEG1ADDR(EXCITE_OFFS_OCD) + +#define EXCITE_OFFS_SCRAM 0x1fffa000 +#define EXCITE_SIZE_SCRAM (8 << 10) +#define EXCITE_PHYS_SCRAM CPHYSADDR(EXCITE_OFFS_SCRAM) +#define EXCITE_ADDR_SCRAM CKSEG1ADDR(EXCITE_OFFS_SCRAM) + +#define EXCITE_OFFS_PCI_IO 0x1fff8000 +#define EXCITE_SIZE_PCI_IO (8 << 10) +#define EXCITE_PHYS_PCI_IO CPHYSADDR(EXCITE_OFFS_PCI_IO) +#define EXCITE_ADDR_PCI_IO CKSEG1ADDR(EXCITE_OFFS_PCI_IO) + +#define EXCITE_OFFS_TITAN 0x1fff0000 +#define EXCITE_SIZE_TITAN (32 << 10) +#define EXCITE_PHYS_TITAN CPHYSADDR(EXCITE_OFFS_TITAN) +#define EXCITE_ADDR_TITAN CKSEG1ADDR(EXCITE_OFFS_TITAN) + +#define EXCITE_OFFS_PCI_MEM 0x1ffe0000 +#define EXCITE_SIZE_PCI_MEM (64 << 10) +#define EXCITE_PHYS_PCI_MEM CPHYSADDR(EXCITE_OFFS_PCI_MEM) +#define EXCITE_ADDR_PCI_MEM CKSEG1ADDR(EXCITE_OFFS_PCI_MEM) + +#define EXCITE_OFFS_FPGA 0x1ffdc000 +#define EXCITE_SIZE_FPGA (16 << 10) +#define EXCITE_PHYS_FPGA CPHYSADDR(EXCITE_OFFS_FPGA) +#define EXCITE_ADDR_FPGA CKSEG1ADDR(EXCITE_OFFS_FPGA) + +#define EXCITE_OFFS_NAND 0x1ffd8000 +#define EXCITE_SIZE_NAND (16 << 10) +#define EXCITE_PHYS_NAND CPHYSADDR(EXCITE_OFFS_NAND) +#define EXCITE_ADDR_NAND CKSEG1ADDR(EXCITE_OFFS_NAND) + +#define EXCITE_OFFS_BOOTROM 0x1f000000 +#define EXCITE_SIZE_BOOTROM (8 << 20) +#define EXCITE_PHYS_BOOTROM CPHYSADDR(EXCITE_OFFS_BOOTROM) +#define EXCITE_ADDR_BOOTROM CKSEG1ADDR(EXCITE_OFFS_BOOTROM) + +/* FPGA address offsets */ +#define EXCITE_FPGA_DPR 0x0104 /* dual-ported ram */ +#define EXCITE_FPGA_SYSCTL 0x0200 /* system control register block */ + +#endif /* __EXCITE_H__ */ diff --git a/include/asm-mips/mach-excite/excite_nandflash.h b/include/asm-mips/mach-excite/excite_nandflash.h new file mode 100644 index 000000000000..c4cf6140622e --- /dev/null +++ b/include/asm-mips/mach-excite/excite_nandflash.h @@ -0,0 +1,7 @@ +#ifndef __EXCITE_NANDFLASH_H__ +#define __EXCITE_NANDFLASH_H__ + +/* Resource names */ +#define EXCITE_NANDFLASH_RESOURCE_REGS "excite_nandflash_regs" + +#endif /* __EXCITE_NANDFLASH_H__ */ diff --git a/include/asm-mips/mach-excite/rm9k_eth.h b/include/asm-mips/mach-excite/rm9k_eth.h new file mode 100644 index 000000000000..94705a46f72e --- /dev/null +++ b/include/asm-mips/mach-excite/rm9k_eth.h @@ -0,0 +1,23 @@ +#if !defined(__RM9K_ETH_H__) +#define __RM9K_ETH_H__ + +#define RM9K_GE_NAME "rm9k_ge" + +/* Resource names */ +#define RM9K_GE_RESOURCE_MAC "rm9k_ge_mac" +#define RM9K_GE_RESOURCE_MSTAT "rm9k_ge_mstat" +#define RM9K_GE_RESOURCE_PKTPROC "rm9k_ge_pktproc" +#define RM9K_GE_RESOURCE_XDMA "rm9k_ge_xdma" +#define RM9K_GE_RESOURCE_FIFO_RX "rm9k_ge_fifo_rx" +#define RM9K_GE_RESOURCE_FIFO_TX "rm9k_ge_fifo_tx" +#define RM9K_GE_RESOURCE_FIFOMEM_RX "rm9k_ge_fifo_memory_rx" +#define RM9K_GE_RESOURCE_FIFOMEM_TX "rm9k_ge_fifo_memory_tx" +#define RM9K_GE_RESOURCE_PHY "rm9k_ge_phy" +#define RM9K_GE_RESOURCE_DMADESC_RX "rm9k_ge_dmadesc_rx" +#define RM9K_GE_RESOURCE_DMADESC_TX "rm9k_ge_dmadesc_tx" +#define RM9K_GE_RESOURCE_IRQ_MAIN "rm9k_ge_irq_main" +#define RM9K_GE_RESOURCE_IRQ_PHY "rm9k_ge_irq_phy" +#define RM9K_GE_RESOURCE_GPI_SLICE "rm9k_ge_gpi_slice" +#define RM9K_GE_RESOURCE_MDIO_CHANNEL "rm9k_ge_mdio_channel" + +#endif /* !defined(__RM9K_ETH_H__) */ diff --git a/include/asm-mips/mach-excite/rm9k_wdt.h b/include/asm-mips/mach-excite/rm9k_wdt.h new file mode 100644 index 000000000000..3fa3c08d2da7 --- /dev/null +++ b/include/asm-mips/mach-excite/rm9k_wdt.h @@ -0,0 +1,12 @@ +#ifndef __RM9K_WDT_H__ +#define __RM9K_WDT_H__ + +/* Device name */ +#define WDT_NAME "wdt_gpi" + +/* Resource names */ +#define WDT_RESOURCE_REGS "excite_watchdog_regs" +#define WDT_RESOURCE_IRQ "excite_watchdog_irq" +#define WDT_RESOURCE_COUNTER "excite_watchdog_counter" + +#endif /* __RM9K_WDT_H__ */ diff --git a/include/asm-mips/mach-excite/rm9k_xicap.h b/include/asm-mips/mach-excite/rm9k_xicap.h new file mode 100644 index 000000000000..009577734a8d --- /dev/null +++ b/include/asm-mips/mach-excite/rm9k_xicap.h @@ -0,0 +1,16 @@ +#ifndef __EXCITE_XICAP_H__ +#define __EXCITE_XICAP_H__ + + +/* Resource names */ +#define XICAP_RESOURCE_FIFO_RX "xicap_fifo_rx" +#define XICAP_RESOURCE_FIFO_TX "xicap_fifo_tx" +#define XICAP_RESOURCE_XDMA "xicap_xdma" +#define XICAP_RESOURCE_DMADESC "xicap_dmadesc" +#define XICAP_RESOURCE_PKTPROC "xicap_pktproc" +#define XICAP_RESOURCE_IRQ "xicap_irq" +#define XICAP_RESOURCE_GPI_SLICE "xicap_gpi_slice" +#define XICAP_RESOURCE_FIFO_BLK "xicap_fifo_blocks" +#define XICAP_RESOURCE_PKT_STREAM "xicap_pkt_stream" + +#endif /* __EXCITE_XICAP_H__ */ diff --git a/include/asm-mips/rm9k-ocd.h b/include/asm-mips/rm9k-ocd.h new file mode 100644 index 000000000000..b0b80d9ecf96 --- /dev/null +++ b/include/asm-mips/rm9k-ocd.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 + */ + +#if !defined(_ASM_RM9K_OCD_H) +#define _ASM_RM9K_OCD_H + +#include +#include +#include + +extern volatile void __iomem * const ocd_base; +extern volatile void __iomem * const titan_base; + +#define ocd_addr(__x__) (ocd_base + (__x__)) +#define titan_addr(__x__) (titan_base + (__x__)) +#define scram_addr(__x__) (scram_base + (__x__)) + +/* OCD register access */ +#define ocd_readl(__offs__) __raw_readl(ocd_addr(__offs__)) +#define ocd_readw(__offs__) __raw_readw(ocd_addr(__offs__)) +#define ocd_readb(__offs__) __raw_readb(ocd_addr(__offs__)) +#define ocd_writel(__val__, __offs__) \ + __raw_writel((__val__), ocd_addr(__offs__)) +#define ocd_writew(__val__, __offs__) \ + __raw_writew((__val__), ocd_addr(__offs__)) +#define ocd_writeb(__val__, __offs__) \ + __raw_writeb((__val__), ocd_addr(__offs__)) + +/* TITAN register access - 32 bit-wide only */ +#define titan_readl(__offs__) __raw_readl(titan_addr(__offs__)) +#define titan_writel(__val__, __offs__) \ + __raw_writel((__val__), titan_addr(__offs__)) + +/* Protect access to shared TITAN registers */ +extern spinlock_t titan_lock; +extern int titan_irqflags; +#define lock_titan_regs() spin_lock_irqsave(&titan_lock, titan_irqflags) +#define unlock_titan_regs() spin_unlock_irqrestore(&titan_lock, titan_irqflags) + +#endif /* !defined(_ASM_RM9K_OCD_H) */ diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h index ad374bd3f130..70636b41832c 100644 --- a/include/asm-mips/war.h +++ b/include/asm-mips/war.h @@ -172,7 +172,8 @@ * On the RM9000 there is a problem which makes the CreateDirtyExclusive * cache operation unusable on SMP systems. */ -#if defined(CONFIG_MOMENCO_JAGUAR_ATX) || defined(CONFIG_PMC_YOSEMITE) +#if defined(CONFIG_MOMENCO_JAGUAR_ATX) || defined(CONFIG_PMC_YOSEMITE) || \ + defined(CONFIG_BASLER_EXCITE) #define RM9000_CDEX_SMP_WAR 1 #endif @@ -182,7 +183,7 @@ * being fetched may case spurious exceptions. */ #if defined(CONFIG_MOMENCO_JAGUAR_ATX) || defined(CONFIG_MOMENCO_OCELOT_3) || \ - defined(CONFIG_PMC_YOSEMITE) + defined(CONFIG_PMC_YOSEMITE) || defined(CONFIG_BASLER_EXCITE) #define ICACHE_REFILLS_WORKAROUND_WAR 1 #endif -- cgit v1.2.3 From 2493921c284813b9f512c95d972a302cf82296cb Mon Sep 17 00:00:00 2001 From: Kumba Date: Sun, 18 Jun 2006 02:16:53 -0400 Subject: [MIPS] Add Missing R4K Cache Macros to IP27 & IP32 Keeping in accordance with other machines, IP27 and IP32 lack a few macros. IP27 lacks cpu_has_4kex & cpu_has_4k_cache macros while IP32 lacks just the cpu_has_4k_cache macro. Signed-off-by: Joshua Kinard Signed-off-by: Ralf Baechle --- include/asm-mips/mach-ip27/cpu-feature-overrides.h | 3 +++ include/asm-mips/mach-ip32/cpu-feature-overrides.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/include/asm-mips/mach-ip27/cpu-feature-overrides.h b/include/asm-mips/mach-ip27/cpu-feature-overrides.h index 2d2f5b91e47f..19c2d135985b 100644 --- a/include/asm-mips/mach-ip27/cpu-feature-overrides.h +++ b/include/asm-mips/mach-ip27/cpu-feature-overrides.h @@ -31,6 +31,9 @@ #define cpu_has_nofpuex 0 #define cpu_has_64bits 1 +#define cpu_has_4kex 1 +#define cpu_has_4k_cache 1 + #define cpu_has_subset_pcaches 1 #define cpu_dcache_line_size() 32 diff --git a/include/asm-mips/mach-ip32/cpu-feature-overrides.h b/include/asm-mips/mach-ip32/cpu-feature-overrides.h index 36070b5654ab..f0ef1ac9ecd7 100644 --- a/include/asm-mips/mach-ip32/cpu-feature-overrides.h +++ b/include/asm-mips/mach-ip32/cpu-feature-overrides.h @@ -38,6 +38,8 @@ #define cpu_has_vtag_icache 0 #define cpu_has_ic_fills_f_dc 0 #define cpu_has_dsp 0 +#define cpu_has_4k_cache 1 + #define cpu_has_mips32r1 0 #define cpu_has_mips32r2 0 -- cgit v1.2.3 From c3b1c2de2254aa4721e7e3c8d418fa9302e6acb0 Mon Sep 17 00:00:00 2001 From: Kumba Date: Sun, 18 Jun 2006 02:17:01 -0400 Subject: [MIPS] Fix R4K cache macro names Several machines have the R4K cache macro name spelled incorrectly. Namely, they have cpu_has_4kcache defined instead of cpu_has_4k_cache. Signed-off-by: Joshua Kinard Signed-off-by: Ralf Baechle --- include/asm-mips/mach-ip22/cpu-feature-overrides.h | 2 +- include/asm-mips/mach-mips/cpu-feature-overrides.h | 4 ++-- include/asm-mips/mach-rm200/cpu-feature-overrides.h | 2 +- include/asm-mips/mach-sim/cpu-feature-overrides.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mach-ip22/cpu-feature-overrides.h b/include/asm-mips/mach-ip22/cpu-feature-overrides.h index 2a37bedb4053..f7c5dc8a5336 100644 --- a/include/asm-mips/mach-ip22/cpu-feature-overrides.h +++ b/include/asm-mips/mach-ip22/cpu-feature-overrides.h @@ -13,7 +13,7 @@ */ #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 #define cpu_has_fpu 1 #define cpu_has_32fpr 1 #define cpu_has_counter 1 diff --git a/include/asm-mips/mach-mips/cpu-feature-overrides.h b/include/asm-mips/mach-mips/cpu-feature-overrides.h index e06af6c86f86..12c937283bb4 100644 --- a/include/asm-mips/mach-mips/cpu-feature-overrides.h +++ b/include/asm-mips/mach-mips/cpu-feature-overrides.h @@ -17,7 +17,7 @@ #ifdef CONFIG_CPU_MIPS32 #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 /* #define cpu_has_fpu ? */ /* #define cpu_has_32fpr ? */ #define cpu_has_counter 1 @@ -47,7 +47,7 @@ #ifdef CONFIG_CPU_MIPS64 #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 /* #define cpu_has_fpu ? */ /* #define cpu_has_32fpr ? */ #define cpu_has_counter 1 diff --git a/include/asm-mips/mach-rm200/cpu-feature-overrides.h b/include/asm-mips/mach-rm200/cpu-feature-overrides.h index 01587832bc9c..11410ae10d36 100644 --- a/include/asm-mips/mach-rm200/cpu-feature-overrides.h +++ b/include/asm-mips/mach-rm200/cpu-feature-overrides.h @@ -14,7 +14,7 @@ #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 #define cpu_has_fpu 1 #define cpu_has_32fpr 1 #define cpu_has_counter 1 diff --git a/include/asm-mips/mach-sim/cpu-feature-overrides.h b/include/asm-mips/mach-sim/cpu-feature-overrides.h index cadbe8eda79c..d9653e47d5fc 100644 --- a/include/asm-mips/mach-sim/cpu-feature-overrides.h +++ b/include/asm-mips/mach-sim/cpu-feature-overrides.h @@ -16,7 +16,7 @@ #ifdef CONFIG_CPU_MIPS32 #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 #define cpu_has_fpu 0 /* #define cpu_has_32fpr ? */ #define cpu_has_counter 1 @@ -41,7 +41,7 @@ #ifdef CONFIG_CPU_MIPS64 #define cpu_has_tlb 1 #define cpu_has_4kex 1 -#define cpu_has_4kcache 1 +#define cpu_has_4k_cache 1 /* #define cpu_has_fpu ? */ /* #define cpu_has_32fpr ? */ #define cpu_has_counter 1 -- cgit v1.2.3 From 1723b4a34af85447684c9696af83929d2c1e8e6b Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 20 Jun 2006 00:19:13 +0900 Subject: [MIPS] Make timer interrupt frequency configurable from kconfig. Make HZ configurable. DECSTATION can select 128/256/1024 HZ, JAZZ can only select 100 HZ, others can select 100/128/250/256/1000/1024 HZ if not explicitly specified). Also remove all mach-xxx/param.h files and update all defconfigs according to current HZ value. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 75 +++++++++++++++++++++++++++++++ arch/mips/configs/atlas_defconfig | 9 ++++ arch/mips/configs/bigsur_defconfig | 9 ++++ arch/mips/configs/capcella_defconfig | 9 ++++ arch/mips/configs/cobalt_defconfig | 9 ++++ arch/mips/configs/db1000_defconfig | 9 ++++ arch/mips/configs/db1100_defconfig | 9 ++++ arch/mips/configs/db1200_defconfig | 9 ++++ arch/mips/configs/db1500_defconfig | 9 ++++ arch/mips/configs/db1550_defconfig | 9 ++++ arch/mips/configs/ddb5477_defconfig | 9 ++++ arch/mips/configs/decstation_defconfig | 11 +++++ arch/mips/configs/e55_defconfig | 9 ++++ arch/mips/configs/emma2rh_defconfig | 9 ++++ arch/mips/configs/ev64120_defconfig | 9 ++++ arch/mips/configs/ev96100_defconfig | 9 ++++ arch/mips/configs/excite_defconfig | 9 ++++ arch/mips/configs/ip22_defconfig | 9 ++++ arch/mips/configs/ip27_defconfig | 9 ++++ arch/mips/configs/ip32_defconfig | 9 ++++ arch/mips/configs/it8172_defconfig | 9 ++++ arch/mips/configs/ivr_defconfig | 9 ++++ arch/mips/configs/jaguar-atx_defconfig | 9 ++++ arch/mips/configs/jmr3927_defconfig | 9 ++++ arch/mips/configs/lasat200_defconfig | 9 ++++ arch/mips/configs/malta_defconfig | 9 ++++ arch/mips/configs/mipssim_defconfig | 9 ++++ arch/mips/configs/mpc30x_defconfig | 9 ++++ arch/mips/configs/ocelot_3_defconfig | 9 ++++ arch/mips/configs/ocelot_c_defconfig | 9 ++++ arch/mips/configs/ocelot_defconfig | 9 ++++ arch/mips/configs/ocelot_g_defconfig | 9 ++++ arch/mips/configs/pb1100_defconfig | 9 ++++ arch/mips/configs/pb1500_defconfig | 9 ++++ arch/mips/configs/pb1550_defconfig | 9 ++++ arch/mips/configs/pnx8550-jbs_defconfig | 9 ++++ arch/mips/configs/pnx8550-v2pci_defconfig | 9 ++++ arch/mips/configs/qemu_defconfig | 9 ++++ arch/mips/configs/rbhma4500_defconfig | 9 ++++ arch/mips/configs/rm200_defconfig | 9 ++++ arch/mips/configs/sb1250-swarm_defconfig | 9 ++++ arch/mips/configs/sead_defconfig | 9 ++++ arch/mips/configs/tb0226_defconfig | 9 ++++ arch/mips/configs/tb0229_defconfig | 9 ++++ arch/mips/configs/tb0287_defconfig | 9 ++++ arch/mips/configs/workpad_defconfig | 9 ++++ arch/mips/configs/wrppmc_defconfig | 9 ++++ arch/mips/configs/yosemite_defconfig | 9 ++++ arch/mips/dec/time.c | 2 +- arch/mips/defconfig | 9 ++++ include/asm-mips/mach-dec/param.h | 18 -------- include/asm-mips/mach-generic/param.h | 13 ------ include/asm-mips/mach-jazz/param.h | 16 ------- include/asm-mips/mach-mips/param.h | 13 ------ include/asm-mips/mach-qemu/param.h | 13 ------ include/asm-mips/param.h | 2 +- 56 files changed, 511 insertions(+), 75 deletions(-) delete mode 100644 include/asm-mips/mach-dec/param.h delete mode 100644 include/asm-mips/mach-generic/param.h delete mode 100644 include/asm-mips/mach-jazz/param.h delete mode 100644 include/asm-mips/mach-mips/param.h delete mode 100644 include/asm-mips/mach-qemu/param.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 50274fcacde0..35e038a974c6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -168,6 +168,9 @@ config MACH_DECSTATION select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_128HZ + select SYS_SUPPORTS_256HZ + select SYS_SUPPORTS_1024HZ help This enables support for DEC's MIPS based workstations. For details see the Linux/MIPS FAQ on and the @@ -265,6 +268,7 @@ config MACH_JAZZ select SYS_HAS_CPU_R4X00 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL + select SYS_SUPPORTS_100HZ help This a family of machines based on the MIPS R4030 chipset which was used by several vendors to build RISC/os and Windows NT workstations. @@ -1707,6 +1711,77 @@ config NR_CPUS This is purely to save memory - each supported CPU adds approximately eight kilobytes to the kernel image. +# +# Timer Interrupt Frequency Configuration +# + +choice + prompt "Timer frequency" + default HZ_250 + help + Allows the configuration of the timer frequency. + + config HZ_48 + bool "48 HZ" if SYS_SUPPORTS_48HZ + + config HZ_100 + bool "100 HZ" if SYS_SUPPORTS_100HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_128 + bool "128 HZ" if SYS_SUPPORTS_128HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_250 + bool "250 HZ" if SYS_SUPPORTS_250HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_256 + bool "256 HZ" if SYS_SUPPORTS_256HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_1000 + bool "1000 HZ" if SYS_SUPPORTS_1000HZ || SYS_SUPPORTS_ARBIT_HZ + + config HZ_1024 + bool "1024 HZ" if SYS_SUPPORTS_1024HZ || SYS_SUPPORTS_ARBIT_HZ + +endchoice + +config SYS_SUPPORTS_48HZ + bool + +config SYS_SUPPORTS_100HZ + bool + +config SYS_SUPPORTS_128HZ + bool + +config SYS_SUPPORTS_250HZ + bool + +config SYS_SUPPORTS_256HZ + bool + +config SYS_SUPPORTS_1000HZ + bool + +config SYS_SUPPORTS_1024HZ + bool + +config SYS_SUPPORTS_ARBIT_HZ + bool + default y if !SYS_SUPPORTS_48HZ && !SYS_SUPPORTS_100HZ && \ + !SYS_SUPPORTS_128HZ && !SYS_SUPPORTS_250HZ && \ + !SYS_SUPPORTS_256HZ && !SYS_SUPPORTS_1000HZ && \ + !SYS_SUPPORTS_1024HZ + +config HZ + int + default 48 if HZ_48 + default 100 if HZ_100 + default 128 if HZ_128 + default 250 if HZ_250 + default 256 if HZ_256 + default 1000 if HZ_1000 + default 1024 if HZ_1024 + source "kernel/Kconfig.preempt" config RTC_DS1742 diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig index d72acc84c481..0cc1b3c51959 100644 --- a/arch/mips/configs/atlas_defconfig +++ b/arch/mips/configs/atlas_defconfig @@ -141,6 +141,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +CONFIG_HZ_100=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 4677cbbc2b46..dabf90a94b21 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -143,6 +143,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_SMP=y CONFIG_NR_CPUS=4 CONFIG_PREEMPT_NONE=y diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index 4e1937bffc80..aeb7be804799 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -130,6 +130,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 7ac532070c42..d680d3e17112 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -127,6 +127,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index 0efaf64ca27d..6a7aa401462f 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index 7b7a2de63495..5c2da563e528 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index 53da5d81d2d9..85ef90ce0944 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index 408af0e2c2aa..6f757d8a5a6c 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -130,6 +130,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index f8db553dfb41..da4c7e811bef 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -129,6 +129,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig index 6e19990139d7..c1c6bfee970e 100644 --- a/arch/mips/configs/ddb5477_defconfig +++ b/arch/mips/configs/ddb5477_defconfig @@ -127,6 +127,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index f237754a8a13..d5d0d3faae94 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -126,6 +126,17 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_128=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_128HZ=y +CONFIG_SYS_SUPPORTS_256HZ=y +CONFIG_SYS_SUPPORTS_1024HZ=y +CONFIG_HZ=128 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index b06d9f1e519a..439677ba751c 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig index da1bc03fa256..01f29f44f3e8 100644 --- a/arch/mips/configs/emma2rh_defconfig +++ b/arch/mips/configs/emma2rh_defconfig @@ -133,6 +133,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig index 46086893674e..5248a1d8131d 100644 --- a/arch/mips/configs/ev64120_defconfig +++ b/arch/mips/configs/ev64120_defconfig @@ -129,6 +129,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig index 63c46ef26d01..4858491ce669 100644 --- a/arch/mips/configs/ev96100_defconfig +++ b/arch/mips/configs/ev96100_defconfig @@ -133,6 +133,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig index 3240962ef585..f2ce64cb41a8 100644 --- a/arch/mips/configs/excite_defconfig +++ b/arch/mips/configs/excite_defconfig @@ -132,6 +132,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_SMP is not set # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index f72ba3f1b7f5..879ba1ad99ca 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 9ac2acc05ad7..bb1426806430 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -133,6 +133,15 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_NEED_MULTIPLE_NODES=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_MIGRATION=y CONFIG_SMP=y CONFIG_NR_CPUS=64 diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 826b0183eb49..31b3c92a3841 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig index e44481f7e487..809bae9013ac 100644 --- a/arch/mips/configs/it8172_defconfig +++ b/arch/mips/configs/it8172_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig index f8722d0ba935..55108fd67844 100644 --- a/arch/mips/configs/ivr_defconfig +++ b/arch/mips/configs/ivr_defconfig @@ -125,6 +125,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index 1eeca9fd5b27..ef2843436057 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_SMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index 407d8d71200c..5ef5a08289a5 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -123,6 +123,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig index 48c67d8dd1f1..eabcff26fc0e 100644 --- a/arch/mips/configs/lasat200_defconfig +++ b/arch/mips/configs/lasat200_defconfig @@ -132,6 +132,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index fd1c73f8780b..b73cff0d83ca 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -152,6 +152,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +CONFIG_HZ_100=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 67fb9fa10870..8dd27b55413d 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -136,6 +136,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index c9607976d132..5d6ff3c352c9 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -130,6 +130,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig index af43e464871e..fe5e3dd915f5 100644 --- a/arch/mips/configs/ocelot_3_defconfig +++ b/arch/mips/configs/ocelot_3_defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_SMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index e1a9a9a750ea..f4a33ce47e50 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig @@ -131,6 +131,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig index 09a96619aedf..21dea9549feb 100644 --- a/arch/mips/configs/ocelot_defconfig +++ b/arch/mips/configs/ocelot_defconfig @@ -135,6 +135,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig index 9c02f974b882..c63b1ca8c8b3 100644 --- a/arch/mips/configs/ocelot_g_defconfig +++ b/arch/mips/configs/ocelot_g_defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index d803c16dccb8..6f5c7261e9de 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -130,6 +130,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 0cb83a181e8d..5676f3747fd5 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -129,6 +129,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index c6da473a64d3..a1c479fa613b 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -129,6 +129,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 746986db597d..b2d991b80309 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index 6c3c72db4b9e..fe092ac92e89 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig index 8c77992ab767..db8701344cee 100644 --- a/arch/mips/configs/qemu_defconfig +++ b/arch/mips/configs/qemu_defconfig @@ -126,6 +126,15 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_SMP is not set +# CONFIG_HZ_48 is not set +CONFIG_HZ_100=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig index 9bb4d94335cc..b16731f3684b 100644 --- a/arch/mips/configs/rbhma4500_defconfig +++ b/arch/mips/configs/rbhma4500_defconfig @@ -136,6 +136,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 7dd3438b5b1f..8b0dd8651264 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -136,6 +136,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index e872b83dddbf..ff34ed66fe65 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -147,6 +147,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_PREEMPT_NONE=y diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig index 6048c0d60458..77edeae7f018 100644 --- a/arch/mips/configs/sead_defconfig +++ b/arch/mips/configs/sead_defconfig @@ -132,6 +132,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index b6d8e1afa191..6aa229d54851 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -132,6 +132,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index 4875cd38ff80..a187b1f0004c 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig @@ -132,6 +132,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index 70392d50074a..258457fcbe11 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -133,6 +133,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index cfd6434aa556..68af54f746e1 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index 8c0e636cb322..40572a3c8cac 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig @@ -136,6 +136,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index eef270834797..7ece2c008e9b 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig @@ -128,6 +128,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_PREEMPT_NONE=y diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 74cb055d4bf6..76e4d09ff4d2 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -181,7 +181,7 @@ void __init dec_time_init(void) } /* Set up the rate of periodic DS1287 interrupts. */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A); + CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); } EXPORT_SYMBOL(do_settimeofday); diff --git a/arch/mips/defconfig b/arch/mips/defconfig index f72ba3f1b7f5..879ba1ad99ca 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -134,6 +134,15 @@ CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set diff --git a/include/asm-mips/mach-dec/param.h b/include/asm-mips/mach-dec/param.h deleted file mode 100644 index 3e4f0e390847..000000000000 --- a/include/asm-mips/mach-dec/param.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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) 2003 by Ralf Baechle - */ -#ifndef __ASM_MACH_DEC_PARAM_H -#define __ASM_MACH_DEC_PARAM_H - -/* - * log2(HZ), change this here if you want another HZ value. This is also - * used in dec_time_init. Minimum is 1, Maximum is 15. - */ -#define LOG_2_HZ 7 -#define HZ (1 << LOG_2_HZ) - -#endif /* __ASM_MACH_DEC_PARAM_H */ diff --git a/include/asm-mips/mach-generic/param.h b/include/asm-mips/mach-generic/param.h deleted file mode 100644 index a0d12f964e4f..000000000000 --- a/include/asm-mips/mach-generic/param.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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) 2003 by Ralf Baechle - */ -#ifndef __ASM_MACH_GENERIC_PARAM_H -#define __ASM_MACH_GENERIC_PARAM_H - -#define HZ 1000 /* Internal kernel timer frequency */ - -#endif /* __ASM_MACH_GENERIC_PARAM_H */ diff --git a/include/asm-mips/mach-jazz/param.h b/include/asm-mips/mach-jazz/param.h deleted file mode 100644 index 639763a517bc..000000000000 --- a/include/asm-mips/mach-jazz/param.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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) 2003 by Ralf Baechle - */ -#ifndef __ASM_MACH_JAZZ_PARAM_H -#define __ASM_MACH_JAZZ_PARAM_H - -/* - * Jazz is currently using the internal 100Hz timer of the R4030 - */ -#define HZ 100 /* Internal kernel timer frequency */ - -#endif /* __ASM_MACH_JAZZ_PARAM_H */ diff --git a/include/asm-mips/mach-mips/param.h b/include/asm-mips/mach-mips/param.h deleted file mode 100644 index 805ef6d27d3c..000000000000 --- a/include/asm-mips/mach-mips/param.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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) 2003 by Ralf Baechle - */ -#ifndef __ASM_MACH_MIPS_PARAM_H -#define __ASM_MACH_MIPS_PARAM_H - -#define HZ 100 /* Internal kernel timer frequency */ - -#endif /* __ASM_MACH_MIPS_PARAM_H */ diff --git a/include/asm-mips/mach-qemu/param.h b/include/asm-mips/mach-qemu/param.h deleted file mode 100644 index cb30ee490ae6..000000000000 --- a/include/asm-mips/mach-qemu/param.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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) 2005 by Ralf Baechle - */ -#ifndef __ASM_MACH_QEMU_PARAM_H -#define __ASM_MACH_QEMU_PARAM_H - -#define HZ 100 /* Internal kernel timer frequency */ - -#endif /* __ASM_MACH_QEMU_PARAM_H */ diff --git a/include/asm-mips/param.h b/include/asm-mips/param.h index 2bead8273ced..1d9bb8c5ab24 100644 --- a/include/asm-mips/param.h +++ b/include/asm-mips/param.h @@ -11,7 +11,7 @@ #ifdef __KERNEL__ -# include /* Internal kernel timer frequency */ +# define HZ CONFIG_HZ /* Internal kernel timer frequency */ # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif -- cgit v1.2.3 From 557240b48e2dc4f6fa878afc3fc767ad745ca7ed Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 19 Jun 2006 18:16:01 -0700 Subject: Add support for suspending and resuming the whole console subsystem Trying to suspend/resume with console messages flying all around is doomed to failure, when the devices that the messages are trying to go to are being shut down. Signed-off-by: Linus Torvalds --- include/linux/console.h | 4 ++++ kernel/power/main.c | 2 ++ kernel/printk.c | 28 +++++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/console.h b/include/linux/console.h index 721371382ae5..08734e660d41 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -117,6 +117,10 @@ extern void console_stop(struct console *); extern void console_start(struct console *); extern int is_console_locked(void); +/* Suspend and resume console messages over PM events */ +extern void suspend_console(void); +extern void resume_console(void); + /* Some debug stub to catch some of the obvious races in the VT code */ #if 1 #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) diff --git a/kernel/power/main.c b/kernel/power/main.c index a6d9ef46009e..0a907f0dc56b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -86,6 +86,7 @@ static int suspend_prepare(suspend_state_t state) goto Thaw; } + suspend_console(); if ((error = device_suspend(PMSG_SUSPEND))) { printk(KERN_ERR "Some devices failed to suspend\n"); goto Finish; @@ -133,6 +134,7 @@ int suspend_enter(suspend_state_t state) static void suspend_finish(suspend_state_t state) { device_resume(); + resume_console(); thaw_processes(); enable_nonboot_cpus(); if (pm_ops && pm_ops->finish) diff --git a/kernel/printk.c b/kernel/printk.c index c056f3324432..19a955619294 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -67,6 +67,7 @@ EXPORT_SYMBOL(oops_in_progress); * driver system. */ static DECLARE_MUTEX(console_sem); +static DECLARE_MUTEX(secondary_console_sem); struct console *console_drivers; /* * This is used for debugging the mess that is the VT code by @@ -76,7 +77,7 @@ struct console *console_drivers; * path in the console code where we end up in places I want * locked without the console sempahore held */ -static int console_locked; +static int console_locked, console_suspended; /* * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars @@ -697,6 +698,23 @@ int __init add_preferred_console(char *name, int idx, char *options) return 0; } +/** + * suspend_console - suspend the console subsystem + * + * This disables printk() while we go into suspend states + */ +void suspend_console(void) +{ + acquire_console_sem(); + console_suspended = 1; +} + +void resume_console(void) +{ + console_suspended = 0; + release_console_sem(); +} + /** * acquire_console_sem - lock the console system for exclusive use. * @@ -708,6 +726,10 @@ int __init add_preferred_console(char *name, int idx, char *options) void acquire_console_sem(void) { BUG_ON(in_interrupt()); + if (console_suspended) { + down(&secondary_console_sem); + return; + } down(&console_sem); console_locked = 1; console_may_schedule = 1; @@ -750,6 +772,10 @@ void release_console_sem(void) unsigned long _con_start, _log_end; unsigned long wake_klogd = 0; + if (console_suspended) { + up(&secondary_console_sem); + return; + } for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); wake_klogd |= log_start - log_end; -- cgit v1.2.3