diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/core-card.c | 41 | ||||
-rw-r--r-- | drivers/firewire/core-cdev.c | 50 | ||||
-rw-r--r-- | drivers/firewire/net.c | 53 | ||||
-rw-r--r-- | drivers/firewire/ohci.c | 17 |
4 files changed, 114 insertions, 47 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 7083bcc1b9c7..5045156c5313 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c | |||
@@ -57,6 +57,8 @@ static LIST_HEAD(descriptor_list); | |||
57 | static int descriptor_count; | 57 | static int descriptor_count; |
58 | 58 | ||
59 | static __be32 tmp_config_rom[256]; | 59 | static __be32 tmp_config_rom[256]; |
60 | /* ROM header, bus info block, root dir header, capabilities = 7 quadlets */ | ||
61 | static size_t config_rom_length = 1 + 4 + 1 + 1; | ||
60 | 62 | ||
61 | #define BIB_CRC(v) ((v) << 0) | 63 | #define BIB_CRC(v) ((v) << 0) |
62 | #define BIB_CRC_LENGTH(v) ((v) << 16) | 64 | #define BIB_CRC_LENGTH(v) ((v) << 16) |
@@ -73,7 +75,7 @@ static __be32 tmp_config_rom[256]; | |||
73 | #define BIB_CMC ((1) << 30) | 75 | #define BIB_CMC ((1) << 30) |
74 | #define BIB_IMC ((1) << 31) | 76 | #define BIB_IMC ((1) << 31) |
75 | 77 | ||
76 | static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom) | 78 | static void generate_config_rom(struct fw_card *card, __be32 *config_rom) |
77 | { | 79 | { |
78 | struct fw_descriptor *desc; | 80 | struct fw_descriptor *desc; |
79 | int i, j, k, length; | 81 | int i, j, k, length; |
@@ -130,23 +132,30 @@ static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom) | |||
130 | for (i = 0; i < j; i += length + 1) | 132 | for (i = 0; i < j; i += length + 1) |
131 | length = fw_compute_block_crc(config_rom + i); | 133 | length = fw_compute_block_crc(config_rom + i); |
132 | 134 | ||
133 | return j; | 135 | WARN_ON(j != config_rom_length); |
134 | } | 136 | } |
135 | 137 | ||
136 | static void update_config_roms(void) | 138 | static void update_config_roms(void) |
137 | { | 139 | { |
138 | struct fw_card *card; | 140 | struct fw_card *card; |
139 | size_t length; | ||
140 | 141 | ||
141 | list_for_each_entry (card, &card_list, link) { | 142 | list_for_each_entry (card, &card_list, link) { |
142 | length = generate_config_rom(card, tmp_config_rom); | 143 | generate_config_rom(card, tmp_config_rom); |
143 | card->driver->set_config_rom(card, tmp_config_rom, length); | 144 | card->driver->set_config_rom(card, tmp_config_rom, |
145 | config_rom_length); | ||
144 | } | 146 | } |
145 | } | 147 | } |
146 | 148 | ||
149 | static size_t required_space(struct fw_descriptor *desc) | ||
150 | { | ||
151 | /* descriptor + entry into root dir + optional immediate entry */ | ||
152 | return desc->length + 1 + (desc->immediate > 0 ? 1 : 0); | ||
153 | } | ||
154 | |||
147 | int fw_core_add_descriptor(struct fw_descriptor *desc) | 155 | int fw_core_add_descriptor(struct fw_descriptor *desc) |
148 | { | 156 | { |
149 | size_t i; | 157 | size_t i; |
158 | int ret; | ||
150 | 159 | ||
151 | /* | 160 | /* |
152 | * Check descriptor is valid; the length of all blocks in the | 161 | * Check descriptor is valid; the length of all blocks in the |
@@ -162,15 +171,21 @@ int fw_core_add_descriptor(struct fw_descriptor *desc) | |||
162 | 171 | ||
163 | mutex_lock(&card_mutex); | 172 | mutex_lock(&card_mutex); |
164 | 173 | ||
165 | list_add_tail(&desc->link, &descriptor_list); | 174 | if (config_rom_length + required_space(desc) > 256) { |
166 | descriptor_count++; | 175 | ret = -EBUSY; |
167 | if (desc->immediate > 0) | 176 | } else { |
177 | list_add_tail(&desc->link, &descriptor_list); | ||
178 | config_rom_length += required_space(desc); | ||
168 | descriptor_count++; | 179 | descriptor_count++; |
169 | update_config_roms(); | 180 | if (desc->immediate > 0) |
181 | descriptor_count++; | ||
182 | update_config_roms(); | ||
183 | ret = 0; | ||
184 | } | ||
170 | 185 | ||
171 | mutex_unlock(&card_mutex); | 186 | mutex_unlock(&card_mutex); |
172 | 187 | ||
173 | return 0; | 188 | return ret; |
174 | } | 189 | } |
175 | EXPORT_SYMBOL(fw_core_add_descriptor); | 190 | EXPORT_SYMBOL(fw_core_add_descriptor); |
176 | 191 | ||
@@ -179,6 +194,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) | |||
179 | mutex_lock(&card_mutex); | 194 | mutex_lock(&card_mutex); |
180 | 195 | ||
181 | list_del(&desc->link); | 196 | list_del(&desc->link); |
197 | config_rom_length -= required_space(desc); | ||
182 | descriptor_count--; | 198 | descriptor_count--; |
183 | if (desc->immediate > 0) | 199 | if (desc->immediate > 0) |
184 | descriptor_count--; | 200 | descriptor_count--; |
@@ -428,7 +444,6 @@ EXPORT_SYMBOL(fw_card_initialize); | |||
428 | int fw_card_add(struct fw_card *card, | 444 | int fw_card_add(struct fw_card *card, |
429 | u32 max_receive, u32 link_speed, u64 guid) | 445 | u32 max_receive, u32 link_speed, u64 guid) |
430 | { | 446 | { |
431 | size_t length; | ||
432 | int ret; | 447 | int ret; |
433 | 448 | ||
434 | card->max_receive = max_receive; | 449 | card->max_receive = max_receive; |
@@ -437,8 +452,8 @@ int fw_card_add(struct fw_card *card, | |||
437 | 452 | ||
438 | mutex_lock(&card_mutex); | 453 | mutex_lock(&card_mutex); |
439 | 454 | ||
440 | length = generate_config_rom(card, tmp_config_rom); | 455 | generate_config_rom(card, tmp_config_rom); |
441 | ret = card->driver->enable(card, tmp_config_rom, length); | 456 | ret = card->driver->enable(card, tmp_config_rom, config_rom_length); |
442 | if (ret == 0) | 457 | if (ret == 0) |
443 | list_add_tail(&card->link, &card_list); | 458 | list_add_tail(&card->link, &card_list); |
444 | 459 | ||
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index e6d63849e78e..4eeaed57e219 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/preempt.h> | 35 | #include <linux/preempt.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/spinlock.h> | 37 | #include <linux/spinlock.h> |
38 | #include <linux/string.h> | ||
38 | #include <linux/time.h> | 39 | #include <linux/time.h> |
39 | #include <linux/uaccess.h> | 40 | #include <linux/uaccess.h> |
40 | #include <linux/vmalloc.h> | 41 | #include <linux/vmalloc.h> |
@@ -595,13 +596,20 @@ static int ioctl_send_request(struct client *client, void *buffer) | |||
595 | client->device->max_speed); | 596 | client->device->max_speed); |
596 | } | 597 | } |
597 | 598 | ||
599 | static inline bool is_fcp_request(struct fw_request *request) | ||
600 | { | ||
601 | return request == NULL; | ||
602 | } | ||
603 | |||
598 | static void release_request(struct client *client, | 604 | static void release_request(struct client *client, |
599 | struct client_resource *resource) | 605 | struct client_resource *resource) |
600 | { | 606 | { |
601 | struct inbound_transaction_resource *r = container_of(resource, | 607 | struct inbound_transaction_resource *r = container_of(resource, |
602 | struct inbound_transaction_resource, resource); | 608 | struct inbound_transaction_resource, resource); |
603 | 609 | ||
604 | if (r->request) | 610 | if (is_fcp_request(r->request)) |
611 | kfree(r->data); | ||
612 | else | ||
605 | fw_send_response(client->device->card, r->request, | 613 | fw_send_response(client->device->card, r->request, |
606 | RCODE_CONFLICT_ERROR); | 614 | RCODE_CONFLICT_ERROR); |
607 | kfree(r); | 615 | kfree(r); |
@@ -616,6 +624,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request, | |||
616 | struct address_handler_resource *handler = callback_data; | 624 | struct address_handler_resource *handler = callback_data; |
617 | struct inbound_transaction_resource *r; | 625 | struct inbound_transaction_resource *r; |
618 | struct inbound_transaction_event *e; | 626 | struct inbound_transaction_event *e; |
627 | void *fcp_frame = NULL; | ||
619 | int ret; | 628 | int ret; |
620 | 629 | ||
621 | r = kmalloc(sizeof(*r), GFP_ATOMIC); | 630 | r = kmalloc(sizeof(*r), GFP_ATOMIC); |
@@ -627,6 +636,18 @@ static void handle_request(struct fw_card *card, struct fw_request *request, | |||
627 | r->data = payload; | 636 | r->data = payload; |
628 | r->length = length; | 637 | r->length = length; |
629 | 638 | ||
639 | if (is_fcp_request(request)) { | ||
640 | /* | ||
641 | * FIXME: Let core-transaction.c manage a | ||
642 | * single reference-counted copy? | ||
643 | */ | ||
644 | fcp_frame = kmemdup(payload, length, GFP_ATOMIC); | ||
645 | if (fcp_frame == NULL) | ||
646 | goto failed; | ||
647 | |||
648 | r->data = fcp_frame; | ||
649 | } | ||
650 | |||
630 | r->resource.release = release_request; | 651 | r->resource.release = release_request; |
631 | ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); | 652 | ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); |
632 | if (ret < 0) | 653 | if (ret < 0) |
@@ -640,13 +661,15 @@ static void handle_request(struct fw_card *card, struct fw_request *request, | |||
640 | e->request.closure = handler->closure; | 661 | e->request.closure = handler->closure; |
641 | 662 | ||
642 | queue_event(handler->client, &e->event, | 663 | queue_event(handler->client, &e->event, |
643 | &e->request, sizeof(e->request), payload, length); | 664 | &e->request, sizeof(e->request), r->data, length); |
644 | return; | 665 | return; |
645 | 666 | ||
646 | failed: | 667 | failed: |
647 | kfree(r); | 668 | kfree(r); |
648 | kfree(e); | 669 | kfree(e); |
649 | if (request) | 670 | kfree(fcp_frame); |
671 | |||
672 | if (!is_fcp_request(request)) | ||
650 | fw_send_response(card, request, RCODE_CONFLICT_ERROR); | 673 | fw_send_response(card, request, RCODE_CONFLICT_ERROR); |
651 | } | 674 | } |
652 | 675 | ||
@@ -717,18 +740,17 @@ static int ioctl_send_response(struct client *client, void *buffer) | |||
717 | 740 | ||
718 | r = container_of(resource, struct inbound_transaction_resource, | 741 | r = container_of(resource, struct inbound_transaction_resource, |
719 | resource); | 742 | resource); |
720 | if (r->request) { | 743 | if (is_fcp_request(r->request)) |
721 | if (request->length < r->length) | 744 | goto out; |
722 | r->length = request->length; | 745 | |
723 | if (copy_from_user(r->data, u64_to_uptr(request->data), | 746 | if (request->length < r->length) |
724 | r->length)) { | 747 | r->length = request->length; |
725 | ret = -EFAULT; | 748 | if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) { |
726 | kfree(r->request); | 749 | ret = -EFAULT; |
727 | goto out; | 750 | kfree(r->request); |
728 | } | 751 | goto out; |
729 | fw_send_response(client->device->card, r->request, | ||
730 | request->rcode); | ||
731 | } | 752 | } |
753 | fw_send_response(client->device->card, r->request, request->rcode); | ||
732 | out: | 754 | out: |
733 | kfree(r); | 755 | kfree(r); |
734 | 756 | ||
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index cbaf420c36c5..2d3dc7ded0a9 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c | |||
@@ -893,20 +893,31 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, | |||
893 | 893 | ||
894 | static struct kmem_cache *fwnet_packet_task_cache; | 894 | static struct kmem_cache *fwnet_packet_task_cache; |
895 | 895 | ||
896 | static void fwnet_free_ptask(struct fwnet_packet_task *ptask) | ||
897 | { | ||
898 | dev_kfree_skb_any(ptask->skb); | ||
899 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
900 | } | ||
901 | |||
896 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); | 902 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); |
897 | 903 | ||
898 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | 904 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) |
899 | { | 905 | { |
900 | struct fwnet_device *dev; | 906 | struct fwnet_device *dev = ptask->dev; |
901 | unsigned long flags; | 907 | unsigned long flags; |
902 | 908 | bool free; | |
903 | dev = ptask->dev; | ||
904 | 909 | ||
905 | spin_lock_irqsave(&dev->lock, flags); | 910 | spin_lock_irqsave(&dev->lock, flags); |
906 | list_del(&ptask->pt_link); | ||
907 | spin_unlock_irqrestore(&dev->lock, flags); | ||
908 | 911 | ||
909 | ptask->outstanding_pkts--; /* FIXME access inside lock */ | 912 | ptask->outstanding_pkts--; |
913 | |||
914 | /* Check whether we or the networking TX soft-IRQ is last user. */ | ||
915 | free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link)); | ||
916 | |||
917 | if (ptask->outstanding_pkts == 0) | ||
918 | list_del(&ptask->pt_link); | ||
919 | |||
920 | spin_unlock_irqrestore(&dev->lock, flags); | ||
910 | 921 | ||
911 | if (ptask->outstanding_pkts > 0) { | 922 | if (ptask->outstanding_pkts > 0) { |
912 | u16 dg_size; | 923 | u16 dg_size; |
@@ -951,10 +962,10 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
951 | ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; | 962 | ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; |
952 | } | 963 | } |
953 | fwnet_send_packet(ptask); | 964 | fwnet_send_packet(ptask); |
954 | } else { | ||
955 | dev_kfree_skb_any(ptask->skb); | ||
956 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
957 | } | 965 | } |
966 | |||
967 | if (free) | ||
968 | fwnet_free_ptask(ptask); | ||
958 | } | 969 | } |
959 | 970 | ||
960 | static void fwnet_write_complete(struct fw_card *card, int rcode, | 971 | static void fwnet_write_complete(struct fw_card *card, int rcode, |
@@ -977,6 +988,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
977 | unsigned tx_len; | 988 | unsigned tx_len; |
978 | struct rfc2734_header *bufhdr; | 989 | struct rfc2734_header *bufhdr; |
979 | unsigned long flags; | 990 | unsigned long flags; |
991 | bool free; | ||
980 | 992 | ||
981 | dev = ptask->dev; | 993 | dev = ptask->dev; |
982 | tx_len = ptask->max_payload; | 994 | tx_len = ptask->max_payload; |
@@ -1022,12 +1034,16 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1022 | generation, SCODE_100, 0ULL, ptask->skb->data, | 1034 | generation, SCODE_100, 0ULL, ptask->skb->data, |
1023 | tx_len + 8, fwnet_write_complete, ptask); | 1035 | tx_len + 8, fwnet_write_complete, ptask); |
1024 | 1036 | ||
1025 | /* FIXME race? */ | ||
1026 | spin_lock_irqsave(&dev->lock, flags); | 1037 | spin_lock_irqsave(&dev->lock, flags); |
1027 | list_add_tail(&ptask->pt_link, &dev->broadcasted_list); | 1038 | |
1039 | /* If the AT tasklet already ran, we may be last user. */ | ||
1040 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | ||
1041 | if (!free) | ||
1042 | list_add_tail(&ptask->pt_link, &dev->broadcasted_list); | ||
1043 | |||
1028 | spin_unlock_irqrestore(&dev->lock, flags); | 1044 | spin_unlock_irqrestore(&dev->lock, flags); |
1029 | 1045 | ||
1030 | return 0; | 1046 | goto out; |
1031 | } | 1047 | } |
1032 | 1048 | ||
1033 | fw_send_request(dev->card, &ptask->transaction, | 1049 | fw_send_request(dev->card, &ptask->transaction, |
@@ -1035,12 +1051,19 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1035 | ptask->generation, ptask->speed, ptask->fifo_addr, | 1051 | ptask->generation, ptask->speed, ptask->fifo_addr, |
1036 | ptask->skb->data, tx_len, fwnet_write_complete, ptask); | 1052 | ptask->skb->data, tx_len, fwnet_write_complete, ptask); |
1037 | 1053 | ||
1038 | /* FIXME race? */ | ||
1039 | spin_lock_irqsave(&dev->lock, flags); | 1054 | spin_lock_irqsave(&dev->lock, flags); |
1040 | list_add_tail(&ptask->pt_link, &dev->sent_list); | 1055 | |
1056 | /* If the AT tasklet already ran, we may be last user. */ | ||
1057 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | ||
1058 | if (!free) | ||
1059 | list_add_tail(&ptask->pt_link, &dev->sent_list); | ||
1060 | |||
1041 | spin_unlock_irqrestore(&dev->lock, flags); | 1061 | spin_unlock_irqrestore(&dev->lock, flags); |
1042 | 1062 | ||
1043 | dev->netdev->trans_start = jiffies; | 1063 | dev->netdev->trans_start = jiffies; |
1064 | out: | ||
1065 | if (free) | ||
1066 | fwnet_free_ptask(ptask); | ||
1044 | 1067 | ||
1045 | return 0; | 1068 | return 0; |
1046 | } | 1069 | } |
@@ -1298,6 +1321,8 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1298 | spin_unlock_irqrestore(&dev->lock, flags); | 1321 | spin_unlock_irqrestore(&dev->lock, flags); |
1299 | 1322 | ||
1300 | ptask->max_payload = max_payload; | 1323 | ptask->max_payload = max_payload; |
1324 | INIT_LIST_HEAD(&ptask->pt_link); | ||
1325 | |||
1301 | fwnet_send_packet(ptask); | 1326 | fwnet_send_packet(ptask); |
1302 | 1327 | ||
1303 | return NETDEV_TX_OK; | 1328 | return NETDEV_TX_OK; |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index a61571c63c59..43ebf337b131 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -2101,11 +2101,6 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, | |||
2101 | u32 payload_index, payload_end_index, next_page_index; | 2101 | u32 payload_index, payload_end_index, next_page_index; |
2102 | int page, end_page, i, length, offset; | 2102 | int page, end_page, i, length, offset; |
2103 | 2103 | ||
2104 | /* | ||
2105 | * FIXME: Cycle lost behavior should be configurable: lose | ||
2106 | * packet, retransmit or terminate.. | ||
2107 | */ | ||
2108 | |||
2109 | p = packet; | 2104 | p = packet; |
2110 | payload_index = payload; | 2105 | payload_index = payload; |
2111 | 2106 | ||
@@ -2135,6 +2130,14 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, | |||
2135 | if (!p->skip) { | 2130 | if (!p->skip) { |
2136 | d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); | 2131 | d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); |
2137 | d[0].req_count = cpu_to_le16(8); | 2132 | d[0].req_count = cpu_to_le16(8); |
2133 | /* | ||
2134 | * Link the skip address to this descriptor itself. This causes | ||
2135 | * a context to skip a cycle whenever lost cycles or FIFO | ||
2136 | * overruns occur, without dropping the data. The application | ||
2137 | * should then decide whether this is an error condition or not. | ||
2138 | * FIXME: Make the context's cycle-lost behaviour configurable? | ||
2139 | */ | ||
2140 | d[0].branch_address = cpu_to_le32(d_bus | z); | ||
2138 | 2141 | ||
2139 | header = (__le32 *) &d[1]; | 2142 | header = (__le32 *) &d[1]; |
2140 | header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) | | 2143 | header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) | |
@@ -2420,6 +2423,7 @@ static void ohci_pmac_off(struct pci_dev *dev) | |||
2420 | 2423 | ||
2421 | #define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT | 2424 | #define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT |
2422 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 | 2425 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 |
2426 | #define PCI_DEVICE_ID_TI_TSB43AB23 0x8024 | ||
2423 | 2427 | ||
2424 | static int __devinit pci_probe(struct pci_dev *dev, | 2428 | static int __devinit pci_probe(struct pci_dev *dev, |
2425 | const struct pci_device_id *ent) | 2429 | const struct pci_device_id *ent) |
@@ -2488,7 +2492,8 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
2488 | #if !defined(CONFIG_X86_32) | 2492 | #if !defined(CONFIG_X86_32) |
2489 | /* dual-buffer mode is broken with descriptor addresses above 2G */ | 2493 | /* dual-buffer mode is broken with descriptor addresses above 2G */ |
2490 | if (dev->vendor == PCI_VENDOR_ID_TI && | 2494 | if (dev->vendor == PCI_VENDOR_ID_TI && |
2491 | dev->device == PCI_DEVICE_ID_TI_TSB43AB22) | 2495 | (dev->device == PCI_DEVICE_ID_TI_TSB43AB22 || |
2496 | dev->device == PCI_DEVICE_ID_TI_TSB43AB23)) | ||
2492 | ohci->use_dualbuffer = false; | 2497 | ohci->use_dualbuffer = false; |
2493 | #endif | 2498 | #endif |
2494 | 2499 | ||